图像预处理算法————灰度化处理

图像预处理算法————灰度化处理图像预处理算法适合在 FPGA 上完成 原理简单且需要快速处理 通常有灰度化 中值 均值滤波等 以及颜色空间转换算法

大家好,欢迎来到IT知识分享网。

图像预处理算法适合在FPGA上完成,原理简单且需要快速处理,通常有灰度化、中值、均值滤波等,以及颜色空间转换算法。

灰度图像是一种特殊的彩色图像(R=G=B的彩色图像) 只有一种颜色分量,单通道的0-255

方法:一般有分量法、最大值法、平均值法、加权平均法四种方法对彩色图像进行灰度化。

一:最大值法

将彩色图像中的三分量亮度
R

G

B
的最大值作为灰度图的灰度值。具体表达式如下。
                                           
                                             gray(i, j) = max[𝑅(𝑖,𝑗),𝐺(𝑖,𝑗),𝐵(𝑖,𝑗)]

二:平均值法

1.原理

将彩色图像中的三分量亮度求平均得到一个灰度值。如下
                             gray(i, j) = { 𝑅(𝑖,𝑗) + 𝐺(𝑖,𝑗) + 𝐵(𝑖,𝑗) }  / 3
上式中有除法,考虑到在
FPGA 中实现除法比较的消耗资源(除法就可以使用
移位的方式
实现),这里在实现前可以先做如下的近似处理:

图像预处理算法————灰度化处理

 除以256可以看作是向右移8位,同样,512,1024,2048等2的n次都可以

2.verilog实现

分析:只有加法乘法以及移位操作

module rgb2gray ( input clk, //时钟 input reset_p, //复位 input rgb_valid, //rgb输入有效标识 input rgb_hs, //rgb输入行信号 input rgb_vs, //rgb输入场信号 input [7:0] red_8b_i, //R输入 input [7:0] green_8b_i, //G输入 input [7:0] blue_8b_i, //B输入 output [7:0] gray_8b_o, //GRAY输出 output reg gray_valid, //gray输出有效标识 output reg gray_hs, //gray输出行信号 output reg gray_vs //gray输出场信号 );

//求平均法GRAY = (R+B+G)/3=((R+B+G)*85)>>8 =((R+B+G)*(64+16+4+1))>>8

=(R+B+G)*64+(R+B+G)*16+(R+B+G)*4+(R+B+G) >>8

= (sum << 6)+(sum << 4)+(sum << 2)+ sum >>8

 wire [9:0]sum; reg [15:0]gray_r; assign sum = red_8b_i + green_8b_i + blue_8b_i; always@(posedge clk or posedge reset_p) begin if(reset_p) gray_r <= 16'd0; else if(rgb_valid) gray_r <= (sum << 6)+(sum << 4)+(sum << 2)+ sum; else gray_r <= 16'd0; end
 assign gray_8b_o = gray_r[15:8]; //>>8右移8位 always@(posedge clk) begin gray_valid <= rgb_valid; gray_hs <= rgb_hs; gray_vs <= rgb_vs; end
避免除法做近似处理计算的
gray
和 直接通过除法求的平均值 
是稍存在偏差的。这个是可以接收的误差范围。

三,加权平均 RGB–Ycbcr

1.基本原理

Y’为颜色的亮度(luma)分量、而CB和CR则为蓝色和红色的浓度偏移量成份。常见的3 个基本色彩模型是RGB,CMYK和YUV。YCbCr是YUV经过缩放和偏移的翻版,JPEG、MPEG均采用此格式。主要的子采样格式有 YCbCr 4:2:0、YCbCr 4:2:2 和 YCbCr 4:4:4。

RGB888 转 YCbCr 的公式,
图像预处理算法————灰度化处理
效果如下:
图像预处理算法————灰度化处理

图来自:FPGA实现图像灰度转换(2):RGB转YCbCr转Gray – 咸鱼IC – 博客园 (cnblogs.com)

将三个分量以不同的权值进行加权平均:

gray(i, j) = 0.299 ∗ 𝑅(𝑖,𝑗) + 0.587 ∗ 𝐺(𝑖,𝑗) + 0.114 ∗ 𝐵(𝑖,𝑗)

在实际应用时,为了能避免低速的浮点运算以及除法运算,先将式子缩放 1024 倍来实现运算算法,如下:

gray(i, j) = [0.299 ∗ 𝑅(𝑖,𝑗) + 0.587 ∗ 𝐺(𝑖,𝑗) + 0.114 ∗ 𝐵(𝑖,𝑗)] ∗ 1024/1024
近似取整处理后:
gray(i, j) ≈ [306 ∗ 𝑅(𝑖,𝑗) + 601 ∗ 𝐺(𝑖,𝑗) + 117 ∗ 𝐵(𝑖,𝑗)]/1024

除以1024使用向右移10位:

gray(i, j) ≈ [306 ∗ 𝑅(𝑖,𝑗) + 601 ∗ 𝐺(𝑖,𝑗) + 117 ∗ 𝐵(𝑖,𝑗)] ≫ 10
也可以压缩到
8
位以内,式子变为如下。具体压缩到多少位可以根据实际需求:
gray(i, j) = [77 ∗ 𝑅(𝑖,𝑗) + 150 ∗ 𝐺(𝑖,𝑗) + 29 ∗ 𝐵(𝑖,𝑗)] ≫ 8

2.代码实现

1)公式计算法实现:

首先将RGB565转RGB888形式:

 rgb2gray #( .PROC_METHOD ( "FORMULA" )//"AVERAGE" :求平均法 //or "FORMULA" :直接公式法 //or "LUT" :查找表法 )rgb2gray ( .clk (loc_clk50m ),//input .reset_p (g_rst_p ),//input .rgb_valid (image_data_valid ),//input .rgb_hs (image_data_hs ),//input .rgb_vs (image_data_vs ),//input .red_8b_i ({image_data[15:11],3'b000}),//input R[7:0] .green_8b_i ({image_data[10:5],2'b00} ),//input G[7:0] .blue_8b_i ({image_data[4:0],3'b000} ),//input B[7:0] .gray_8b_o (image_gray_data ),//output [7:0] .gray_valid (image_gray_data_valid ),//output reg .gray_hs ( ),//output reg .gray_vs ( ) //output reg ); 
 wire [15:0]red_x77; wire [15:0]green_x150; wire [15:0]blue_x29; reg [15:0]sum; //乘法转换成移位相加方式 assign red_x77 = (red_8b_i << 6) + (red_8b_i << 3) + (red_8b_i << 2) + red_8b_i; assign green_x150 = (green_8b_i<< 7) + (green_8b_i<< 4) + (green_8b_i<< 2) + (green_8b_i<<1); assign blue_x29 = (blue_8b_i << 4) + (blue_8b_i << 3) + (blue_8b_i << 2) + blue_8b_i; always@(posedge clk or posedge reset_p) begin if(reset_p) sum <= 16'd0; else if(rgb_valid) sum <= red_x77 + green_x150 + blue_x29; else sum <= 16'd0; end //提取Y亮度为灰度输出 assign gray_8b_o = sum[15:8]; //打拍计算 always@(posedge clk) begin gray_valid <= rgb_valid; gray_hs <= rgb_hs; gray_vs <= rgb_vs; end
进行打拍计算,在图像处理时,我们是有数据的同步信号的,有的是数据使能信号,有的还有行同步信号和帧同步信号。经过图像处理后的数据延迟了拍数,这些同步信号也要相应的打拍,否则最终的图像显示会出问题。
Y,Cb,Cr分量都获取的代码实现办法:
module rgb2gray ( input clk, //时钟 input reset_p, //复位 input rgb_valid, //rgb输入有效标识 input rgb_hs, //rgb输入行信号 input rgb_vs, //rgb输入场信号 input [7:0] red_8b_i, //R输入 input [7:0] green_8b_i, //G输入 input [7:0] blue_8b_i, //B输入 output reg [7:0] gray_8b_o, //GRAY输出 output gray_valid, //gray输出有效标识 output gray_hs, //gray输出行信号 output gray_vs //gray输出场信号 );
//典型灰度转换公式Gray = R*0.299+G*0.587+B*0.114=(R*77 + G*150 + B*29) >>8 // Y = 0.299*R + 0.587*G + 0.114*B // Cb = 0.586*(B-Y) + 128 = -0.172*R - 0.339*G + 0.511*B + 128 // Cr = 0.713*(R-Y) + 128 = 0.511*R - 0.428*G - 0.083*B + 128 // ---> // Y = ( 77*R + 150*G + 29*B) >> 8 // Cb = (-43*R - 85*G + 128*B) >> 8 + 128 // Cr = (128*R - 107*G - 21*B) >> 8 + 128 // ---> // Y = ( 77*R + 150*G + 29*B) >> 8 // Cb = (-43*R - 85*G + 128*B + 32768) >> 8 // Cr = (128*R - 107*G - 21*B + 32768) >> 8
 reg [15:0] R1; reg [15:0] R2; reg [15:0] R3; reg [15:0] G1; reg [15:0] G2; reg [15:0] G3; reg [15:0] B1; reg [15:0] B2; reg [15:0] B3; reg [15:0] Y1; reg [15:0] Cb1; reg [15:0] Cr1; reg [7:0] Y2,Cb2,Cr2; reg [3:0] rgb_valid_r; //rgb输入有效标识 reg [3:0] rgb_hs_r; //rgb输入行信号 reg [3:0] rgb_vs_r; //rgb输入场信号
提取三种分量的RGB值,并且进行相加得到
 always@(posedge clk or negedge reset_p) begin if (reset_p) begin {R1,G1,B1} <= {16'd0,16'd0,16'd0}; {R2,G2,B2} <= {16'd0,16'd0,16'd0}; {R3,G3,B3} <= {16'd0,16'd0,16'd0}; end else begin {R1,G1,B1} <= { 
     {red_8b_i * 16'd77},{green_8b_i * 16'd150},{blue_8b_i * 16'd29}}; {R2,G2,B2} <= { 
     {red_8b_i * 16'd43},{green_8b_i * 16'd85},{blue_8b_i * 16'd128}}; {R3,G3,B3} <= { 
     {red_8b_i * 16'd128},{green_8b_i * 16'd107},{blue_8b_i * 16'd21}}; end end always@(posedge clk or negedge reset_p) begin if (reset_p) begin Y1 <= 16'd0; Cb1 <= 16'd0; Cr1 <= 16'd0; end else begin Y1 <= R1+G1+B1; Cb1 <= B2 - R2 - G2 + 16'd32768;//128扩大256倍 Cr1 <= R3 - G3 - B3 + 16'd32768; //128扩大256倍 end end //右移8位得到 always@(posedge clk or negedge reset_p) begin if (reset_p) begin Y2 <= 8'd0; Cb2 <= 8'd0; Cr2 <= 8'd0; end else begin Y2 <= Y1[15:8]; Cb2 <= Cb1[15:8]; Cr2 <= Cr1[15:8]; end end 
最终输出Y分量为灰度:
assign gray_8b_o = Y2; 
在HDMI显示屏上进行显示灰度处理实现的效果:

图像预处理算法————灰度化处理

也可以只提取77 < Cb < 127,133 < Cr < 173输出值为8’hFF,也就是说将该范围内的图像标记出来。即肤色提取:

 always@(posedge clk or negedge reset_p) begin if (reset_p) gray_8b_o <= 8'h0; else if ( (Cb2 > 77) && (Cb2 < 127) && (Cr2 > 133) && (Cr2 < 173)) gray_8b_o <= 8'hFF; else gray_8b_o <= 8'h0; end
在HDMI显示屏上进行显示肤色提取实现的效果:

图像预处理算法————灰度化处理

 可以发现,它的椒盐噪声太多,需要进行滤波处理来减少椒盐噪声。

2)查找表法:
采用查找表方法实现,主要的优势是直接通过 访问 ROM 内的数据,相对使用移位相加实现乘法使用的 LUT 资源会少点,但占用的存储器会更多。
需要将
R

G

B
乘以系数之后的数值存储在
ROM
中,然后通过读取 ROM 方式来得到计算之后的数值。使用 Vivado 添加 3 个 ROM IP 核,分别通过 R*75、G*147、B*36(0≤R≤255,0≤G≤255,0≤B≤255)的计算值建立 3 个初始化 coe 文件.
 rom_red_x77 rom_red_x77( .clka (clk ), // input wire clka .ena (rgb_valid ), // input wire ena .addra (red_8b_i ), // input wire [7 : 0] addra .douta (red_x77 ) // output wire [14 : 0] douta ); rom_green_x150 rom_green_x150( .clka (clk ), // input wire clka .ena (rgb_valid ), // input wire ena .addra (green_8b_i ), // input wire [7 : 0] addra .douta (green_x150 ) // output wire [15 : 0] douta ); rom_blue_x29 rom_blue_x29( .clka (clk ), // input wire clka .ena (rgb_valid ), // input wire ena .addra (blue_8b_i ), // input wire [7 : 0] addra .douta (blue_x29 ) // output wire [13 : 0] douta );
 always@(posedge clk or posedge reset_p) begin if(reset_p) sum <= 16'd0; else if(rgb_valid_dly1) sum <= red_x77 + green_x150 + blue_x29; else sum <= 16'd0; end assign gray_8b_o = sum[15:8];
 always@(posedge clk) begin rgb_valid_dly1 <= rgb_valid; rgb_hs_dly1 <= rgb_hs; rgb_vs_dly1 <= rgb_vs; end
 always@(posedge clk) begin gray_valid <= rgb_valid_dly1; gray_hs <= rgb_hs_dly1; gray_vs <= rgb_vs_dly1; end
如果能将多种实现方法的.v 文件整合到一个模块保存在一个
.v
文件,使用起来就更加的方便。
整合方法1:
宏定义法
通过不同的宏定义条件编译方式进行选择某种实现方式
//`define AVERAGE //求平均法 //`define FORMULA //直接公式法 `define LUT //查找表法
module rgb2gray ( clk, rst_n, rgb_valid, red_8b_i, green_8b_i, blue_8b_i, gray_8b_o, gray_valid ); `ifdef AVERAGE //求平均法 GRAY=(R+B+G)/3=((R+B+G)*85)>>8 ...//方法 1 `endif `ifdef FORMULA //灰度转换公式 Gray = R*0.299+G*0.587+B*0.114 ...//方法 2 `endif `ifdef LUT//查找表方式 ...//方法 3 `endif endmodule

整合方法2:
使用
generate -if
方法
添加三种方法名称的定义
module rgb2gray #( parameter PROC_METHOD = "AVERAGE" //"AVERAGE" :求平均法 //or "FORMULA" :直接公式法 //or "LUT" :查找表法 )
( clk, rst_n, rgb_valid, red_8b_i, green_8b_i, blue_8b_i, gray_8b_o, gray_valid );
generate if (PROC_METHOD == "AVERAGE") begin: PROC_AVERAGE //--------------------------------------------- //求平均法 GRAY = (R+B+G)/3=((R+B+G)*85)>>8 //方法 1 //--------------------------------------------- end else if (PROC_METHOD == "FORMULA") begin: PROC_FORMULA //--------------------------------------------- //典型灰度转换公式 Gray = R*0.299+G*0.587+B*0.114=(R*77 + G*150 + B*29) >>8 //方法 2 //--------------------------------------------- end else if(PROC_METHOD == "LUT") begin: PROC_LUT //--------------------------------------------- //查找表方式,可以省去公式法中乘法运算 Gray =(R*77 + G*150 + B*29) >>8,将 3 个分量 乘以系数后的数值存储在 ROM 中 //方法 3 //--------------------------------------------- end endgenerate endmodule
以上两种方法直接在例化模块时就可通过
重定义参数 PROC_METHOD

实现不同方法的设置,例化:
 rgb2gray #( .PROC_METHOD("FORMULA") //"AVERAGE" :求平均法 //or "FORMULA" :直接公式法 //or "LUT" :查找表法 )rgb2gray_average
 ( .clk (clk ), . reset_p (reset_p ), .rgb_valid (rgb_valid ), .red_8b_i (red_8b_i ), .green_8b_i(green_8b_i), .blue_8b_i (blue_8b_i ), .gray_8b_o (gray_8b_o ), .gray_valid(gray_valid) );

记录学习过程,搬运于小梅哥的文档,非原创!!侵权请联系删除。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/130833.html

(0)
上一篇 2025-08-12 16:45
下一篇 2025-08-12 17:00

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信