凡亿专栏 | 技术干货:FPGA实现图像镜像变换功能
技术干货:FPGA实现图像镜像变换功能

相机影像技术已成为现代年轻人购买智能手机的主要考虑因素之一,在此趋势下,各大手机厂商纷纷主打相机功能及配置,这也考验工程师的图像转换能力,今天我们来分析如何用FPGA实现图像变换,希望对小伙伴们有所帮助。
一般来说,镜像变换可分为水平镜像和竖直镜像,前者是指将图像左半部分和右半部分以图像竖直中轴线进行对换;后者是指将图像上半部分和下半部分以图像水平中轴线为中心轴进行对换。
那么我们如何用FPGA实现图像镜像变换功能
镜像是以一整帧的像素进行坐标转换,因此需要对一帧突破进行缓存,假设我们有一个缓存器,可通过公式计算到变换后的坐标和数值的对应关系,写入缓存器,然后从缓存区顺序独处,最后可输出镜像。
1、端口信号
module Mirror
(
//system --------------------------------------------
input wire rst_n , //复位,低电平有效
//uart ----------------------------------------------
input wire wr_clk , //50m
input wire [15:0] din ,
input wire din_vld ,
//key -----------------------------------------------
input wire key_vld , //按键切换模式
//TFT_driver ----------------------------------------
input wire rd_clk , //9m
input wire [ 9:0] TFT_x , //得到显示区域横坐标
input wire [ 9:0] TFT_y , //得到显示区域纵坐标
output wire [15:0] TFT_data //输出图像数据
);
2、参数设计
parameter COL = 10'd140 ; //图片长度
parameter ROW = 10'd140 ; //图片高度
parameter IMG_x = 10'd170 ; //图片起始横坐标
parameter IMG_y = 10'd66 ; //图片起始纵坐标
3、缓存
定义:reg [15:0] buffer[COL*ROW-1:0] ;
//写数据
//---------------------------------------------------
always @(posedge wr_clk) begin
buffer[wr_addr] <= din;
end
//写地址
//---------------------------------------------------
always @(posedge wr_clk or negedge rst_n) begin
if(!rst_n) begin
wr_addr <= 'd0;
end
else if(din_vld) begin
wr_addr <= wr_addr + 1'b1;
end
end
4、读使能
//读使能,确定显示位置
assign rd_en = (TFT_x >= IMG_x) && (TFT_x < IMG_x + COL) &&
(TFT_y >= IMG_y) && (TFT_y < IMG_y + ROW)
? 1'b1 : 1'b0;
5、行列规划
//行计数
always @(posedge rd_clk or negedge rst_n) begin
if(!rst_n)
cnt_col <= 10'd0;
else if(add_cnt_col) begin
if(end_cnt_col)
cnt_col <= 10'd0;
else
cnt_col <= cnt_col + 10'd1;
end
end
assign add_cnt_col = rd_en;
assign end_cnt_col = add_cnt_col && cnt_col== COL-10'd1;
//列计数
always @(posedge rd_clk or negedge rst_n) begin
if(!rst_n)
cnt_row <= 10'd0;
else if(add_cnt_row) begin
if(end_cnt_row)
cnt_row <= 10'd0;
else
cnt_row <= cnt_row + 10'd1;
end
assign add_cnt_row = end_cnt_col;
assign end_cnt_row = add_cnt_row && cnt_row== ROW-10'd1;
6、镜像操作
//== 镜像操作,读地址重规划
always @(posedge rd_clk or negedge rst_n) begin
if(!rst_n) begin
mode <= 2'b00;
end
else if(key_vld) begin
mode <= mode + 1'b1;
end
end

always @(*) begin
case(mode)
2'b00 : begin //原图
mirror_x = cnt_col;
mirror_y = cnt_row;
end
2'b01 : begin //水平镜像
mirror_x = (COL-1) - cnt_col;
mirror_y = cnt_row;
end
2'b10 : begin //垂直镜像
mirror_x = cnt_col;
mirror_y = (ROW-1) - cnt_row;
end
2'b11 : begin //水平垂直镜像
mirror_x = (COL-1) - cnt_col;
mirror_y = (ROW-1) - cnt_row;
end
default : begin
mirror_x = cnt_col;
mirror_y = cnt_row;
end
endcase
end
end
7、缓存buffer读操作
always @(posedge rd_clk or negedge rst_n) begin
if(!rst_n)
rd_addr <= 'd0;
else
rd_addr <= mirror_y * COL + mirror_x;
end
always @(posedge rd_clk) begin
rd_en_r <= rd_en;
end
assign TFT_data = rd_en_r ? buffer[rd_addr] : 16'hffff;
8、上板验证
如图所示:

aab702fca84d4bfdcedcc085d37e67.png

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表凡亿课堂立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。
相关阅读
进入分区查看更多精彩内容>
精彩评论

暂无评论