本帖最后由 UT发布 于 2025-3-31 13:42 编辑
软件版本:Anlogic -TD5.6.1-64bit
操作系统:WIN10 64bit
硬件平台:适用安路(Anlogic)FPGA
登录“米联客”FPGA社区-www.uisrc.com视频课程、答疑解惑!
1概述本文简述了彩色图像转灰度图像的基本原理,在此基础上进行verilog代码的编写,最后进行上板实验。 2算法原理简介日常生活中遇到的图像基本都是彩色图像,在工业应用领域常常需要将彩色图像转换成灰度图像。彩色图像是三个通道RGB,灰度图像只有一个通道。 彩色转灰度比较简单的方法就是直接拿RGB中的一个通道来显示灰度图像,这种方法简单且不做任何的处理。 下面介绍几种常用的求取灰度图像的方法: 1、 平均法 I(x,y)表示灰度图像,取彩色图像RGB三个通道每个值的1/3相加,公式如下: I(x,y) = 1/3 * I_R(x,y) +1/3 * I_G(x,y)+ 1/3 * I_B(x,y) 2、 加权均值法 I(x,y)表示灰度图像,取彩色图像RGB三个通道每个值乘相应的权值后相加,公式如下: I(x,y) = 0.299 * I_R(x,y) +0.587 * I_G(x,y)+ 0.114 * I_B(x,y) 这是最流行的方法。几个加权系数0.299,0.587,0.114是根据人的亮度感知系统调节出来的参数,是个广泛使用的标准化参数。 3、 最大最小平均法 I(x,y)表示灰度图像,取彩色图像RGB三个通道中最大和最小值的1/2相加,公式如下: I(x,y) = 1/2 * max(I_R(x,y), I_G(x,y), I_B(x,y))+ 1/2 * min(I_R(x,y), I_G(x,y), I_B(x,y)) 4、 二值图像 除了灰度图,还有一种图像叫二值图,也就是灰度只有0和255,这才是真正的黑白图像,因为0代表黑色,255代表白色。我们设定一个阈值T,当某像素点的灰度值大于T时,设定该像素点的值为255,当小于T时,设定为0。 5、 反转图像 反转图像公式:I(x,y) = 255- I_Gray(x,y)。反转图像特别适用于增强暗色图像中的白色或灰色细节。 3算法仿真
3.1Matlab算法仿真
3.1.1Matlab算法代码分析源代码如下:
- % 0.299 * R + 0.587 * G + 0.114 * B
- %
- image_in = imread('lena_1280x720.jpg');
-
- image_in_r = image_in(:,:,1);
- image_in_g = image_in(:,:,2);
- image_in_b = image_in(:,:,3);
- %直接进行乘法运算
- gray1 = 0.299 * image_in_r + 0.587 * image_in_g + 0.114 * image_in_b;
-
- gray2 = rgb2gray(image_in);
-
- figure
- subplot(221);
- imshow(image_in);
- subplot(222);
- imshow(gray1);
- subplot(223);
- imshow(image_in);
- subplot(224);
- imshow(gray2);
复制代码
3.1.2Matlab实验结果
3.2Verilog算法仿真
3.2.1Modelsim仿真
3.2.1.1仿真执行在件夹Algorithm_simulation下进行算法的仿真,分为sim,src和tb三个子文件夹。在sim文件夹下有win系统的快捷执行文件sim.bat,可以一键进行仿真,src文件下放的是Verilog的核心图像算法及其顶层与输入图像激励,tb文件下放的是测试激励文件及输出图像的保存。 双击执行sim文件夹下sim.bat,自动打开Modelsim仿真,自动添加仿真波形,执行完成后自动保存图像,仿真波形如图所示: 3.2.1.2仿真关键部分代码解析Sim.do执行仿真代码,文件内容如下: - #
- # Create work library
- #
- vlib work
- #
- # Compile sources
- #
- vlog "../src/*.v"
- vlog "../tb/*.v"
- #
- # Call vsim to invoke simulator
- #
- vsim -voptargs=+acc work.top_tb
- #
- # Add waves
- #
- do wave.do
- #
- # Run simulation
- #
- run -all
- #
- # End
复制代码
图像输入代码部分: - reg en;
- reg [12:0] h_syn_cnt = 'd0;
- reg [12:0] v_syn_cnt = 'd0;
- reg [23:0] image [0 : H_ACTIVE*V_ACTIVE-1];
- reg [31:0] image_cnt = 'd0;
-
- //读取txt文件到image数组中
- initial begin
- $readmemh("../../matlab_src/image_720_1280_3.txt", image);
- end
-
- // 行扫描计数器
- always@(posedge i_clk)
- begin
- if(h_syn_cnt == H_TOTAL_TIME-1)
- h_syn_cnt <= 0;
- else
- h_syn_cnt <= h_syn_cnt + 1;
- end
-
- // 列扫描计数器
- always@(posedge i_clk)
- begin
- if(h_syn_cnt == H_TOTAL_TIME-1)
- begin
- if(v_syn_cnt == V_TOTAL_TIME-1)
- v_syn_cnt <= 0;
- else
- v_syn_cnt <= v_syn_cnt + 1;
- end
- end
-
- // 行同步控制
- always@(posedge i_clk)
- begin
- if(h_syn_cnt < H_SYNC_TIME)
- o_hsyn <= 0;
- else
- o_hsyn <= 1;
- end
-
- // 场同步控制
- always@(posedge i_clk)
- begin
- if(v_syn_cnt < V_SYNC_TIME)
- o_vsyn <= 0;
- else
- o_vsyn <= 1;
- end
-
- // 坐标使能.
- always@(posedge i_clk)
- begin
- if(v_syn_cnt >= V_SYNC_TIME + V_BACK_PORCH && v_syn_cnt < V_SYNC_TIME + V_BACK_PORCH + V_ACTIVE)
- begin
- if(h_syn_cnt >= H_SYNC_TIME + H_BACK_PORCH && h_syn_cnt < H_SYNC_TIME + H_BACK_PORCH + H_ACTIVE)
- en <= 1;
- else
- en <= 0;
- end
- else
- en <= 0;
- end
-
- always@(posedge i_clk)
- begin
- if(en)
- begin
- o_r <= image[image_cnt][23:16];
- o_g <= image[image_cnt][15:8];
- o_b <= image[image_cnt][7:0];
- image_cnt <= image_cnt + 1;
- end
- else if(image_cnt == H_ACTIVE*V_ACTIVE)
- begin
- o_r <= 8'h00;
- o_g <= 8'h00;
- o_b <= 8'h00;
- image_cnt <= 'd0;
- end
- else
- begin
- o_r <= 8'h00;
- o_g <= 8'h00;
- o_b <= 8'h00;
- image_cnt <= image_cnt;
- end
- end
-
- always@(posedge i_clk)
- begin
- o_en <= en;
- end
- 图形输出保存代码部分:
- reg clk;
- reg rst_n;
-
- integer image_txt;
-
- reg [31:0] pixel_cnt;
- wire[23:0] data;
- wire de;
- wire [7:0] y;
- wire [7:0] cb;
- wire [7:0] cr;
-
- top u_top
- (
- .i_clk (clk ),
- .i_rst_n (rst_n ),
- .o_hsyn ( ),
- .o_vsyn ( ),
- .o_y (y ),
- .o_cb (cb ),
- .o_cr (cr ),
- .o_de (de )
- );
-
- assign data = {y,cb,cr};
-
- always #(1) clk = ~clk;
-
- initial
- begin
- clk = 1;
- rst_n = 0;
- #100
- rst_n = 1;
-
- end
-
- initial
- begin
- image_txt = $fopen("../../matlab_src/image_720_1280_rgb2ycbcr_out.txt");
- end
-
- always@(posedge clk or negedge rst_n)
- begin
- if(!rst_n)
- begin
- pixel_cnt <= 0;
- end
- else if(de)
- begin
- pixel_cnt = pixel_cnt + 1;
- $fwrite(image_txt,"%h\n",data);
- end
- end
-
- always@(posedge clk )
- begin
- if(pixel_cnt == 720*1280)
- begin
- $display("*******************************************************************************");
- $display("*** Success:image_720_1280_rgb2ycbcr_out.txt is output complete! %t", $realtime, "ps***");
- $display("*******************************************************************************");
- $fclose(image_txt);
- $stop;
- end
- end
复制代码
3.2.1.3Modelsim实验结果matlab查看输入输出的图像代码部分: - clear;clear all;clc;
-
- row = 720;
- col = 1280;
- n = 3;
-
- image_sim_pass = uint8(zeros(row,col,n));
- fid = fopen('image_720_1280_3_out.txt','r');
- for x = 1:row
- for y = 1:col
- RGB = fscanf(fid,'%s',1);
- image_sim_pass(x,y,1) = uint8(hex2dec(RGB(1:2)));
- image_sim_pass(x,y,2) = uint8(hex2dec(RGB(3:4)));
- image_sim_pass(x,y,3) = uint8(hex2dec(RGB(5:6)));
- end
- end
- fclose(fid);
-
- image_1 = imread('lena_1280x720.jpg');
-
- subplot(121);
- imshow(image_1), title('The original image');
-
- subplot(122);
- imshow(image_sim_pass),title('After processing images');
-
- imwrite(image_sim_pass,'lena_1280x720_sim_pass.jpg');
复制代码
使用matlab查看输入输出的图像,如图所示: 4工程实现 4.1Verilog代码分析按照上节中的公式中进行公式变换: // gray1 = 0.299 * image_in_r + 0.587 * image_in_g + 0.114 * image_in_b; 先乘以256然后右移8位。 // gray1 = 256*(0.299 * image_in_r + 0.587 * image_in_g + 0.114 * image_in_b)>>8; 最终结果如下: // gray1 = (77 * image_in_r + 150 * image_in_g + 29 * image_in_b)>>8; 我们将乘法运算单独在一个时钟周期中完成,代码如下: - always@(posedge i_clk or negedge i_rst_n)
- begin
- if(!i_rst_n)
- begin
- r_d0 <= 16'd0;
- g_d0 <= 16'd0;
- b_d0 <= 16'd0;
- end
- else
- begin
- r_d0 <= 77 * i_r;
- g_d0 <= 150 * i_g;
- b_d0 <= 29 * i_b;
- end
- end
复制代码
完成乘法后进行加减法运算: - always@(posedge i_clk or negedge i_rst_n)
- begin
- if(!i_rst_n)
- begin
- gray_d0 <= 16'd0;
- end
- else
- begin
- gray_d0 <= r_d0 + g_d0 + b_d0;
- end
- end
复制代码
最后进行信号的同步: - always@(posedge i_clk )
- begin
- hsyn <= {hsyn[0],i_hsyn};
- vsyn <= {vsyn[0],i_vsyn};
- de <= {de[0],i_de};
- end
复制代码
输出赋值 - assign o_gray_hsyn = hsyn[1];
- assign o_gray_vsyn = vsyn[1];
- assign o_gray_data = {gray_d0[15:8],gray_d0[15:8],gray_d0[15:8]};
- assign o_gray_de = de[1];
复制代码
4.2工程结构工程结构如图所示:
图像数据通过摄像头采集进来,先缓存在fifo中,然后通过写状态机,将图像数据送进DDR进行缓存,缓存后的图像数据从DDR中取出,通过读状态机送出到fifo中,然后算法处理模块在fifo中取出数据,完成数据处理后送到LCD进行显示输出。 5上板实验
点击下载后,可以看到正常的输出如下所示,摄像头的分辨率为640x480,
|