跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
编程语言算法

FPGA 实现任意角度图像旋转原理与代码设计

FPGA 图像旋转核心在于坐标变换与流水线设计。通过计算正余弦值确定旋转矩阵,利用多级流水线完成从屏幕坐标到中心坐标系再到原始图像地址的转换。关键点包括动态计算旋转后图像尺寸、LCD 时序匹配、定点数运算精度处理以及 ROM 地址防溢出校验。该方案支持任意角度旋转,适用于嵌入式显示系统。

DotNetGuy发布于 2026/4/8更新于 2026/9/953 浏览

1. 摘要

基于前文推导的正余弦数值,即可进行旋转公式的计算。图像旋转的本质是实现坐标变换,核心在于两个基本公式。以下按照实际编写思路记录关键设计点。

2. 图像旋转代码设计思路

2.1 旋转后的图像尺寸

图像旋转后像素位置发生变化,虽然总面积不变,但显示范围需扩大以容纳旋转后的对角线长度。通过勾股定理计算原始图像对角线,作为旋转后图像的最大显示范围。

reg [12:0] row_size ;
reg [12:0] col_size ;
assign Pixel_X = row_size ;
assign Pixel_Y = col_size ;
wire [31:0] cosout_abs = (cosout[31]) ? -cosout : cosout;
wire [31:0] sinout_abs = (sinout[31]) ? -sinout : sinout;
always @(posedge clk_i, negedge rstn_i) begin
    if (!rstn_i) begin
        row_size <= 'd0 ;
        col_size <= 'd0 ;
    end else begin
        // h --> row
        // w --> col
        row_size <= (ROW*cosout_abs + COL*sinout_abs) >>14 ;
        col_size <= (COL*cosout_abs + ROW*sinout_abs) >>14 ;
    end
end

2.2 旋转后图像的有效位置

有效区域可自由设定,通常以屏幕中心为基准。假设使用标准 LCD 接口,需根据行场同步信号计算数据请求窗口。以屏幕中点为旋转中心,结合流水线延迟调整偏移量,确保时序对齐。

//parameter define localparam H_SYNC = 11'd41 , //行同步
H_BACK = 11'd2 , //行时序后沿
H_LEFT = 11'd0 , //行时序左边框
H_VALID = 11'd480 , //行有效数据
H_RIGHT = 11'd0 , //行时序右边框
H_FRONT = 11'd2 , //行时序前沿
H_TOTAL = 11'd525 ; //行扫描周期
localparam V_SYNC = 11'd10 , //场同步
V_BACK = 11'd2 , //场时序后沿
V_TOP = 11'd0 , //场时序左边框
V_VALID = 11'd272 , //场有效数据
V_BOTTOM = 11'd0 , //场时序右边框
V_FRONT = 11'd2 , //场时序前沿
V_TOTAL = 11'd286 ; //场扫描周期
//cnt_h:行扫描计数器
//cnt_v:场扫描计数器
//data_req:数据请求信号
wire data_req = (((cnt_h >= (((H_VALID - Pixel_X)>>1) + H_SYNC + H_BACK - 'd5)) && (cnt_h < (((H_VALID - Pixel_X)>>1) + Pixel_X + H_SYNC + H_BACK - 'd5))) &&((cnt_v >= ((V_VALID - Pixel_Y)>>1) + V_SYNC + V_BACK - 'd5) && ((cnt_v < (((V_VALID - Pixel_Y)>>1) + Pixel_Y + V_SYNC + V_BACK - 'd5)))));

2.3 第一级流水线

在图像有效信号期间进行行场计数,这是基础操作。同时生成旋转使能信号和结束标志。

always @(posedge clk_i, negedge rstn_i) begin
    if (!rstn_i) r_rotate_valid <= 1'b0 ;
    else r_rotate_valid <= data_req ;
end
always @(posedge clk_i, negedge rstn_i) begin
    if (!rstn_i) r_rotate_end <= 'd0 ;
    else if (r_rotate_valid && (vcnt == row_abs - 1) && (hcnt == col_abs - 2)) r_rotate_end <= 'd1 ;
    else r_rotate_end <= 'd0 ;
end
always @(posedge clk_i, negedge rstn_i) begin
    if (!rstn_i) hcnt <= 'd0 ;
    else if (r_rotate_valid && (r_rotate_end || (hcnt == col_abs - 1))) hcnt <= 'd0 ;
    else if (r_rotate_valid) hcnt <= hcnt + 'd1 ;
end
always @(posedge clk_i, negedge rstn_i) begin
    if (!rstn_i) vcnt <= 'd0 ;
    else if (r_rotate_valid && r_rotate_end) vcnt <= 'd0 ;
    else if (r_rotate_valid && (hcnt == col_abs - 1)) vcnt <= vcnt + 'd1 ;
end

2.4 第二级流水

开始计算图像旋转公式。以中心点为起始坐标 (0,0),覆盖四个象限。组合公式并右移 14 位处理定点数精度。

reg signed [12:0] x_cos ;
reg signed [12:0] y_sin ;
reg signed [12:0] y_cos ;
reg signed [12:0] x_sin ;
assign row_abs = row_size;
assign col_abs = col_size;
// 得到旋转后图片的中点
assign row1 = row_abs >> 1 ;
assign col1 = col_abs >> 1 ;
always @(posedge clk_i, negedge rstn_i) begin
    if (!rstn_i) x_cos <= 'd0 ;
    else if(r_rotate_valid_1d) x_cos <= ((hcnt - col1 ) * cosout) >>>14;
    else x_cos <= x_cos ;
end
always @(posedge clk_i, negedge rstn_i) begin
    if (!rstn_i) y_sin <= 'd0 ;
    else if(r_rotate_valid_1d) y_sin <= ((vcnt-row1 ) * sinout) >>>14;
    else y_sin <= y_sin ;
end
always @(posedge clk_i, negedge rstn_i) begin
    if (!rstn_i) y_cos <= 'd0 ;
    else if(r_rotate_valid_1d) y_cos <= ((vcnt - row1 ) * cosout) >>>14;
    else y_cos <= y_cos ;
end
always @(posedge clk_i, negedge rstn_i) begin
    if (!rstn_i) x_sin <= 'd0 ;
    else if(r_rotate_valid_1d) x_sin <= ((hcnt - col1 ) * sinout) >>>14;
    else x_sin <= x_sin ;
end

2.5 第三级流水

将旋转后的坐标映射回原始图像坐标。流程为:屏幕坐标转中心坐标系 -> 应用旋转公式 -> 转回屏幕坐标系。注意中间减去的半宽半高需在最后加回。

always @(posedge clk_i, negedge rstn_i) begin
    if (!rstn_i) r_rotate_valid_2d <= 'd0 ;
    else r_rotate_valid_2d <= r_rotate_valid_1d ;
end
always @(posedge clk_i, negedge rstn_i) begin
    if (!rstn_i) hcnt_rotate <= 'd0 ;
    else if(r_rotate_valid_2d==1'b1) hcnt_rotate <= x_cos - y_sin + (COL>>1 ) ;
    else hcnt_rotate <= 'd0 ;
end
always @(posedge clk_i, negedge rstn_i) begin
    if (!rstn_i) vcnt_rotate <= 'd0 ;
    else if(r_rotate_valid_2d==1'b1) vcnt_rotate <= y_cos + x_sin + (ROW>>1) ;
    else vcnt_rotate <= 'd0 ;
end

2.6 第四级流水线

读取原始图像数据。需校验 hcnt_rotate 和 vcnt_rotate 是否在原图范围内,防止地址溢出。ROM IP 核存放预处理的图像数据,读出数据存在单时钟延迟,因此第五级流水用于对齐。

always @(posedge clk_i, negedge rstn_i) begin
    if (!rstn_i) r_rotate_valid_3d <= 'd0 ;
    else r_rotate_valid_3d <= r_rotate_valid_2d ;
end
always @(posedge clk_i, negedge rstn_i) begin
    if (!rstn_i) begin
        rden <= 'd0 ;
        addra <= 'd0 ;
    end else if(r_rotate_valid_3d==1'b1) begin
        if((hcnt_rotate>='d0)&&(hcnt_rotate<COL)&&(vcnt_rotate>='d0)&&(vcnt_rotate<ROW)&&data_cnt<ROW*COL) begin
            rden <= 1'b1 ;
            addra<= COL*vcnt_rotate + hcnt_rotate ;
        end else begin
            rden <= 1'b0 ;
            addra<= 'd0 ;
        end
    end else begin
        rden <= 'd0 ;
        addra <= 'd0 ;
    end
end
always @(posedge clk_i, negedge rstn_i) begin
    if (!rstn_i) data_cnt <= 'd0 ;
    else if (data_cnt == ROW*COL - 1) data_cnt <= 'd0 ;
    else if (r_rotate_valid_3d && (hcnt_rotate>='d0)&&(hcnt_rotate<COL)&&(vcnt_rotate>='d0)&&(vcnt_rotate<ROW)) data_cnt <= data_cnt + 'd1 ;
end
img_mem_gen img_mem_gen_inst (
    .address ( addra ),
    .clock ( clk_i ),
    .rden ( rden ),
    .q ( rom_data )
);

3. 仿真结果

测试了不同角度的旋转效果。

  • 30°旋转:逆时针旋转,图像边缘完整。
  • -30°旋转:顺时针旋转,无畸变。
  • 228°旋转:大角度旋转,坐标映射准确。

任意角度、任意方向均可支持,其他角度未一一列举。

4. 结语

本方案基于 FPGA 逻辑实现,重点在于坐标变换与时序控制。实际项目中需根据具体硬件平台调整 LCD 时序参数及 ROM 深度。代码架构遵循流水线设计,保证了实时性。若在实际应用中遇到时序问题,建议优先检查行场计数器的对齐情况。

目录

  1. 1. 摘要
  2. 2. 图像旋转代码设计思路
  3. 2.1 旋转后的图像尺寸
  4. 2.2 旋转后图像的有效位置
  5. 2.3 第一级流水线
  6. 2.4 第二级流水
  7. 2.5 第三级流水
  8. 2.6 第四级流水线
  9. 3. 仿真结果
  10. 4. 结语

更多推荐文章

查看全部
  • 如何在Llama-Factory中自定义损失函数?高级用法指南
  • Axure 制作 AI 自动对话机器人原型教程
  • Webnovel Writer:基于 Claude Code 的长篇网文 AI 创作系统
  • 无人机航拍图像处理:目标跟踪与场景重建
  • Cursor 中 MCP 服务配置与使用指南
  • 算法实战:位运算解法详解(两数之和、唯一数字、消失数字)
  • 高防服务器防御 DDoS 攻击的核心策略与实战
  • Go 语言高频面试题核心解析与实战指南
  • Ψ0 人形全身 VLA:人类视频预训练 + 机器人后训练 + RL 跟踪
  • 英伟达与 GitHub 免费获取大模型 API Key 实战指南
  • ESP32 无人机远程识别:ArduRemoteID 配置指南
  • 前端 React 50 个基础高频面试题精选
  • 大模型时代人形机器人感知:视觉 - 语言模型在机器人中的应用
  • CosyVoice 安装 openai-whisper 时报错 pkg_resources 缺失原因及解决
  • Effective Modern C++ 条款 39:一次性事件通信的优雅方案
  • Java 后端 Web API 开发全流程实战
  • 向日葵连接 Ubuntu 22.04 黑屏解决方案
  • 基于 AI 辅助的学生成绩综合统计分析系统设计与实现
  • Playwright 现代 Web 自动化测试入门与实战
  • 前端网页开发学习路径:HTML+CSS+JS

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online