FPGA图像处理系列——RGB转HSV
发布者:jackzhang
时间:2015-11-04 17:13:05
通常来说,记录及显示彩色图像时,RGB是最常见的一种方
案。但是RGB色彩空间注重颜色的合成而将颜色的属性相混合,在某些图像处理中,如果不均匀改变RGB,会改变亮度和饱和度,由此带来的RGB比例改变甚
至会改变色调。HSV(Hue, Saturation,
Value)是一种比较直观的颜色模型,它将颜色的亮度、色调和饱和度属性分离,因此采用HSV颜色空间来实现颜色的检测效果会更好。
RGB色空间和HSV空间之间的转换为非线性的,硬件实现需要考虑时钟同步、算法优化、实时性等问题。本实例通过调用了低延迟的除法器实现Hue分量与Saturation分量的高速计算,从而实现了RGB转换成HSV。
色彩空间从RGB到HSV的转换公式如下:设(r,g,b)是颜色的红绿蓝坐标,取值范围都是[0,1]。设max为r,g,b中最大值,min为最小值。设色调值h范围[0,360),s,l∈[0,1]分别是饱和度和亮度。
实现转换操作最重要的是除法运算,本实例调用了一个低延迟的移位减法除法器(延迟时间不到两个像素时钟)来实现高速除法,得到h、s的值。最后要注意保证h,s,v三个分量的延迟都一致。用Verilog实现RGB转HSV的流程如下:
verilog源码如下:
- module rgb2hsv_top(
- input pclk,
- input [23:0]RGB24,
- output[23:0]HSV24
- );
- reg [7:0]max,min;
-
- //input rgb
- wire [7:0] Red,Green,Blue;
- reg [7:0]R_reg,G_reg,B_reg;
- assign Red = RGB24[23:16];
- assign Green = RGB24[15:8];
- assign Blue = RGB24[7:0];
-
-
- reg [7:0] Hue,Saturation,Value;
- assign HSV24[23:16] = Hue;
- assign HSV24[15:8] = Saturation;
- assign HSV24[7:0] = Value;
-
-
- always@(posedge pclk)begin
- R_reg <= Red;
- G_reg <= Green;
- B_reg <= Blue;
- end
- /*************find max,min***********/
- always@(posedge pclk)begin
- if(Red >= Green)
- begin
- if(Red >= Blue)
- max <= Red;
- else //r<b
- max <= Blue;
- end
- else //r<g
- begin
- if(Green >= Blue)
- max <= Green;
- else //g<b
- max <= Blue;
- end
- end
-
- always@(posedge pclk)begin
- if(Red <= Green)
- begin
- if(Red <= Blue)
- min <= Red;
- else //r<b
- min <= Blue;
- end
- else //r>g
- begin
- if(Green <= Blue)
- min <= Green;
- else //g>b
- min <= Blue;
- end
- end
-
- reg [14:0] h_dividend;
- reg [7:0] h_divisor;
- wire [14:0] h_quotient;
- reg [8:0] h_add;
- reg [16:0] s_dividend;
- reg [7:0] s_divisor;
- wire [16:0] s_quotient;
- reg [7:0] v;
- reg sign_flag;
- always@(posedge pclk)begin
- if(max == min)
- begin
- sign_flag <= 0;
- h_dividend <= 0;
- h_divisor <= 1;//
- h_add <= 0;
- s_dividend <= 0;
- s_divisor <= 1;
- v <= max;
- end
- else if(max == R_reg && G_reg >= B_reg)
- begin
- sign_flag <= 0;
- h_dividend <= 60 * (G_reg - B_reg);
- h_divisor <= max - min;
- h_add <= 0;
- s_dividend <= 255 * (max - min);
- s_divisor <= max;
- v <= max;
- end
- else if(max == R_reg && G_reg < B_reg )
- begin
- sign_flag <= 1;
- h_dividend <= 60 * (B_reg - G_reg);
- h_divisor <= max - min;
- h_add <= 360;
- s_dividend <= 255 * (max - min);
- s_divisor <= max;
- v <= max;
- end
- else if(max == G_reg)
- begin
- if(B_reg >= R_reg)
- begin
- sign_flag <= 0;
- h_dividend <= 60 * (B_reg - R_reg);
- end
- else
- begin
- sign_flag <= 1;
- h_dividend <= 60 * (R_reg - B_reg);
- end
-
- h_divisor <= max - min;
- h_add <= 120;
- s_dividend <= 255 * (max - min) ;
- s_divisor <= max;
- v <= max;
- end
- else if(max == B_reg)
- begin
- if(R_reg >= G_reg)
- begin
- sign_flag <= 0;
- h_dividend <= 60 * (R_reg - G_reg);
- end
- else
- begin
- sign_flag <= 1;
- h_dividend <= 60 * (G_reg - R_reg);
- end
-
- h_divisor <= max - min;
- h_add <= 240;
- s_dividend <= 255 * (max - min);
- s_divisor <= max;
- v <= max;
- end
- end
- wire [31:0]yshang_h,yshang_s;
- div_rill u_div_h (
- .a({17'b0,h_dividend}),
- .b({24'b0,h_divisor}),
- .yshang(yshang_h),
- .yyushu()
- );
- assign h_quotient = yshang_h[14:0];
- div_rill u_div_s (
- .a({15'b0,s_dividend}),
- .b({24'b0,s_divisor}),
- .yshang(yshang_s),
- .yyushu()
- );
- assign s_quotient = yshang_s[16:0];
-
- always@(posedge pclk)begin
- if(sign_flag == 0)
- Hue <= (h_quotient + h_add)/2;
- else
- Hue <= (h_add - h_quotient)/2;
- Saturation <= s_quotient;
- Value <= v;
- end
-
- endmodule