问答 店铺
热搜: ZYNQ FPGA discuz

QQ登录

只需一步,快速开始

微信登录

微信扫码,快速开始

微信扫一扫 分享朋友圈

已有 148 人浏览分享

开启左侧

[MLKPAI-F01-EG4D]FPGA图像入门连载_02FPGA实现彩色图像转灰度图像

[复制链接]
148 0
安路-FPGA课程
安路课程: 图像算法 » 图像新手入门实验
安路系列: EG4
本帖最后由 UT发布 于 2025-4-19 10:13 编辑

软件版本: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、 二值图像

除了灰度图,还有一种图像叫二值图,也就是灰度只有0255,这才是真正的黑白图像,因为0代表黑色,255代表白色。我们设定一个阈值T,当某像素点的灰度值大于T时,设定该像素点的值为255,当小于T时,设定为0

5、 反转图像

反转图像公式:I(x,y) = 255- I_Gray(x,y)。反转图像特别适用于增强暗色图像中的白色或灰色细节。

3算法仿真
3.1Matlab算法仿真
3.1.1Matlab算法代码分析

源代码如下:

  1. %   0.299 * R + 0.587 * G + 0.114 * B
  2. %
  3. image_in = imread('lena_1280x720.jpg');
  4.   
  5. image_in_r = image_in(:,:,1);         
  6. image_in_g = image_in(:,:,2);         
  7. image_in_b = image_in(:,:,3);  
  8. %直接进行乘法运算
  9. gray1 =  0.299 * image_in_r + 0.587 * image_in_g + 0.114 * image_in_b;
  10. gray2 = rgb2gray(image_in);
  11. figure
  12. subplot(221);
  13. imshow(image_in);
  14. subplot(222);
  15. imshow(gray1);
  16. subplot(223);
  17. imshow(image_in);
  18. subplot(224);
  19. 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执行仿真代码,文件内容如下:

  1. #
  2. # Create work library
  3. #
  4. vlib work
  5. #
  6. # Compile sources
  7. #
  8. vlog "../src/*.v"
  9. vlog "../tb/*.v"
  10. #
  11. # Call vsim to invoke simulator
  12. #
  13. vsim -voptargs=+acc work.top_tb
  14. #
  15. # Add waves
  16. #
  17. do wave.do
  18. #
  19. # Run simulation
  20. #
  21. run -all
  22. #
  23. # End
复制代码

图像输入代码部分:

  1. reg                 en;
  2. reg [12:0]         h_syn_cnt = 'd0;
  3. reg [12:0]         v_syn_cnt = 'd0;
  4. reg [23:0]         image [0 : H_ACTIVE*V_ACTIVE-1];
  5. reg [31:0]         image_cnt = 'd0;
  6. //读取txt文件到image数组中
  7. initial begin
  8.         $readmemh("../../matlab_src/image_720_1280_3.txt", image);
  9. end
  10. // 行扫描计数器
  11. always@(posedge i_clk)
  12. begin
  13.         if(h_syn_cnt == H_TOTAL_TIME-1)
  14.         h_syn_cnt <= 0;
  15.     else
  16.         h_syn_cnt <= h_syn_cnt + 1;
  17. end
  18. // 列扫描计数器
  19. always@(posedge i_clk)
  20. begin
  21.         if(h_syn_cnt == H_TOTAL_TIME-1)
  22.         begin
  23.         if(v_syn_cnt == V_TOTAL_TIME-1)
  24.             v_syn_cnt <= 0;
  25.         else
  26.             v_syn_cnt <= v_syn_cnt + 1;
  27.         end
  28. end
  29. // 行同步控制
  30. always@(posedge i_clk)
  31. begin
  32.     if(h_syn_cnt < H_SYNC_TIME)
  33.         o_hsyn <= 0;
  34.     else
  35.         o_hsyn <= 1;
  36. end
  37. // 场同步控制
  38. always@(posedge i_clk)
  39. begin
  40.     if(v_syn_cnt < V_SYNC_TIME)
  41.         o_vsyn <= 0;
  42.     else
  43.         o_vsyn <= 1;
  44. end
  45. // 坐标使能.
  46. always@(posedge i_clk)
  47. begin
  48.     if(v_syn_cnt >= V_SYNC_TIME + V_BACK_PORCH && v_syn_cnt < V_SYNC_TIME + V_BACK_PORCH + V_ACTIVE)
  49.     begin
  50.         if(h_syn_cnt >= H_SYNC_TIME + H_BACK_PORCH && h_syn_cnt < H_SYNC_TIME + H_BACK_PORCH + H_ACTIVE)
  51.             en <= 1;
  52.         else
  53.             en <= 0;
  54.     end
  55.     else
  56.         en <= 0;
  57. end
  58. always@(posedge i_clk)
  59. begin
  60.     if(en)
  61.         begin
  62.                 o_r                     <= image[image_cnt][23:16];
  63.                 o_g                 <= image[image_cnt][15:8];
  64.                 o_b                 <= image[image_cnt][7:0];
  65.             image_cnt         <= image_cnt + 1;
  66.         end
  67.         else if(image_cnt == H_ACTIVE*V_ACTIVE)
  68.         begin
  69.                 o_r                     <= 8'h00;
  70.                 o_g                 <= 8'h00;
  71.                 o_b                 <= 8'h00;
  72.             image_cnt         <= 'd0;
  73.         end        
  74.     else
  75.         begin
  76.                 o_r                     <= 8'h00;
  77.                 o_g                 <= 8'h00;
  78.                 o_b                 <= 8'h00;
  79.             image_cnt         <= image_cnt;
  80.         end        
  81. end
  82. always@(posedge i_clk)
  83. begin
  84.         o_en <= en;
  85. end
复制代码

图形输出保存代码部分:

  1. reg             clk;
  2. reg             rst_n;
  3. integer                 image_txt;
  4. reg [31:0]                 pixel_cnt;
  5. wire[23:0]          data;
  6. wire            de;
  7. wire [7:0]                y;
  8. wire [7:0]                cb;
  9. wire [7:0]                cr;
  10. top u_top
  11. (
  12.     .i_clk                 (clk                ),
  13.     .i_rst_n           (rst_n              ),
  14.         .o_hsyn     (                   ),
  15.         .o_vsyn     (                   ),
  16.         .o_y        (y                  ),
  17.         .o_cb       (cb                 ),
  18.         .o_cr       (cr                 ),
  19.         .o_de       (de                 )
  20. );
  21. assign data = {y,cb,cr};
  22. always #(1) clk = ~clk;
  23. initial
  24. begin
  25.         clk   = 1;
  26.     rst_n = 0;         
  27.         #100
  28.     rst_n = 1;
  29.         
  30. end
  31. initial
  32. begin
  33.     image_txt = $fopen("../../matlab_src/image_720_1280_rgb2ycbcr_out.txt");
  34. end
  35. always@(posedge clk or negedge rst_n)
  36. begin
  37.     if(!rst_n)
  38.         begin
  39.         pixel_cnt <= 0;
  40.     end
  41.     else if(de)
  42.         begin
  43.         pixel_cnt = pixel_cnt + 1;
  44.         $fwrite(image_txt,"%h\n",data);
  45.     end
  46. end
  47. always@(posedge clk )
  48. begin
  49.         if(pixel_cnt == 720*1280)
  50.         begin
  51.                 $display("*******************************************************************************");               
  52.                 $display("*** Success:image_720_1280_rgb2ycbcr_out.txt is output complete! %t", $realtime, "ps***");
  53.                 $display("*******************************************************************************");
  54.                         $fclose(image_txt);
  55.                 $stop;
  56.         end        
  57. end
复制代码
3.2.1.3Modelsim实验结果

matlab查看输入输出的图像代码部分:

  1. clear;clear all;clc;
  2. row = 720;  
  3. col = 1280;  
  4. n   = 3;   
  5. image_sim_pass = uint8(zeros(row,col,n));
  6. fid = fopen('image_720_1280_3_out.txt','r');
  7. for x = 1:row
  8.     for y = 1:col
  9.         RGB = fscanf(fid,'%s',1);
  10.         image_sim_pass(x,y,1) = uint8(hex2dec(RGB(1:2)));
  11.         image_sim_pass(x,y,2) = uint8(hex2dec(RGB(3:4)));
  12.         image_sim_pass(x,y,3) = uint8(hex2dec(RGB(5:6)));              
  13.     end
  14. end
  15. fclose(fid);
  16. image_1 = imread('lena_1280x720.jpg');
  17. subplot(121);
  18. imshow(image_1), title('The original image');
  19. subplot(122);
  20. imshow(image_sim_pass),title('After processing images');
  21. 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;

我们将乘法运算单独在一个时钟周期中完成,代码如下:

  1. always@(posedge i_clk or negedge i_rst_n)
  2. begin
  3.     if(!i_rst_n)
  4.         begin
  5.         r_d0 <= 16'd0;
  6.         g_d0 <= 16'd0;
  7.         b_d0 <= 16'd0;
  8.     end
  9.     else
  10.         begin
  11.         r_d0 <= 77  * i_r;
  12.         g_d0 <= 150 * i_g;
  13.         b_d0 <= 29  * i_b;               
  14.     end
  15. end
复制代码

完成乘法后进行加减法运算:

  1. always@(posedge i_clk or negedge i_rst_n)
  2. begin
  3.     if(!i_rst_n)
  4.         begin
  5.                 gray_d0 <= 16'd0;
  6.     end
  7.     else
  8.         begin
  9.                 gray_d0 <= r_d0 + g_d0 + b_d0;         
  10.     end
  11. end
复制代码

最后进行信号的同步:

  1. always@(posedge i_clk )
  2. begin
  3.         hsyn        <= {hsyn[0],i_hsyn};
  4.         vsyn        <= {vsyn[0],i_vsyn};
  5.         de                <= {de[0],i_de};
  6. end
复制代码

输出赋值

  1. assign o_gray_hsyn = hsyn[1];
  2. assign o_gray_vsyn = vsyn[1];
  3. assign o_gray_data = {gray_d0[15:8],gray_d0[15:8],gray_d0[15:8]};
  4. assign o_gray_de   = de[1];
复制代码
4.2工程结构

工程结构如图所示:


图像数据通过摄像头采集进来,先缓存在fifo中,然后通过写状态机,将图像数据送进DDR进行缓存,缓存后的图像数据从DDR中取出,通过读状态机送出到fifo中,然后算法处理模块在fifo中取出数据,完成数据处理后送到LCD进行显示输出。

5上板实验

点击下载后,可以看到正常的输出如下所示,摄像头的分辨率为640x480


您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

0

关注

0

粉丝

293

主题
精彩推荐
热门资讯
网友晒图
图文推荐

  • 微信公众平台

  • 扫描访问手机版