rgb色彩空间对人的友好性远不及hsv色彩空间,在hsv空间,我们可以容易区分不同颜色,可以将亮度信息与颜色信息分离开来,也可以单纯增强图像色彩的饱和度,比如让花瓣更红更饱满。hsv在彩色边缘分割也大有用处,传统的边缘提取都是依靠灰度信息,其实灰度图往往只能保留90%的边缘信息,剩余的10%是无法体现出来的。这就需要彩色边缘分割来进行补充,标量的梯度就自然而然转为向量的梯度(rgb/hsv/hsi)。
先给出rgb 转 hsv 公式
可以借助quartus 自带的颜色选择来观察HSV 与 RGB之间的关系。
(Tools -> Options -> Colors)
彩色边缘应用的注意点
{
从图中观察到红色最为特殊,它是0°线的左右两方区域,这里容易出错,如果你求hs分量的欧式距离,那么红色的距离会一大一小分两端。解决办法可以让 h <10 范围的值转化成 360 - h 。(10是估计值)
还需要注意饱和度 S ,饱和度和掺杂白光的程度成反比,对于饱和度S < 30,亮度 V > 220 统一认为是白色。
亮度 V < 46 的所有颜色统一认为是黑色。
}
RGB转HSV的检测结果经过验证和软件里的高度一致
module rgb_hsv(
input clk,
input rst,
input [7:0] rgb_r,
input [7:0] rgb_g,
input [7:0] rgb_b,
output reg [8:0] hsv_h,// 0 - 360
output reg [7:0] hsv_s,// 0- 255
output reg [7:0] hsv_v // 0- 255
);
reg [7:0] top;//分子
reg [13:0] top_60;//*60
reg [2:0] rgb_se;
reg [2:0] rgb_se_n;//方向
reg [7:0] max;//最大分量
reg [7:0] min;//最小分量
reg [7:0] max_min;//max - min
reg [7:0] hsv_s_m;
reg [7:0] max_n;
reg [7:0] division;//除法
//find max min 1----
assign r_g = (rgb_r > rgb_g)? 1'b1:1'b0;
assign r_b = (rgb_r > rgb_b)? 1'b1:1'b0;
assign g_b = (rgb_g > rgb_b)? 1'b1:1'b0;
always @ (posedge clk or negedge rst)
begin
if (!rst)
begin
max <= 8'd0;
min <= 8'd0;
top <= 8'd0;
rgb_se <= 3'b010;
end
else
begin
case ({r_g,r_b,g_b})
3'b000:
begin//b g r
max <= rgb_b;
min <= rgb_r;
top <= rgb_g - rgb_r;//-
rgb_se <= 3'b000;
end
3'b001:
begin//g b r
max <= rgb_g;
min <= rgb_r;
top <= rgb_b - rgb_r;//+
rgb_se <= 3'b001;
end
3'b011:
begin//g r b
max <= rgb_g;
min <= rgb_b;
top <= rgb_r - rgb_b;//-
rgb_se <= 3'b011;
end
3'b100:
begin//b r g
max <= rgb_b;
min <= rgb_g;
top <= rgb_r - rgb_g;//+
rgb_se <= 3'b100;
end
3'b110:
begin//r b g
max <= rgb_r;
min <= rgb_g;
top <= rgb_b - rgb_g;//+
rgb_se <= 3'b110;
end
3'b111:
begin//r g b
max <= rgb_r;
min <= rgb_b;
top <= rgb_g - rgb_b;//-
rgb_se <= 3'b111;
end
default
begin
max <= 8'd0;
min <= 8'd0;
top <= 8'd0;
rgb_se <= 3'b010;
end
endcase
end
end
// *60 max - min 2-----------------
always @ (posedge clk or negedge rst)
begin
if (!rst)
begin
top_60 <= 14'd0;
rgb_se_n <= 3'b010;
max_min <= 8'd0;
max_n <= 8'd0;
end
else
begin
top_60 <= {top,6'b000000} - {top,2'b00};//60 = 2^6 - 2^2
rgb_se_n <= rgb_se;
max_min <= max - min;
max_n <= max;
end
end
// /(max - min) 3----------------------
always @ (*)
begin
division = (max_min > 8'd0) ? top_60 / max_min : 8'd240;//注意max = min
end
// + - 120 240 360
always @ (posedge clk or negedge rst)
begin
if (!rst)
hsv_h <= 9'd0;
else
begin
case (rgb_se_n)
3'b000:
//b g r
hsv_h <= 9'd240 - division;//-
3'b001:
//g b r
hsv_h <= 9'd120 + division;//+
3'b011:
//g r b
hsv_h <= 9'd120 - division;//-
3'b100:
//b r g
hsv_h <= 9'd240 + division;//+
3'b110:
//r b g
hsv_h <= 9'd360 - division;//-
3'b111:
//r g b
hsv_h <= division;//+
default
hsv_h <= 9'd0;
endcase
end
end
// s=(max - min)/max * 256
always @ (*)
begin
hsv_s_m = (max_n > 8'd0)? {max_min[7:0],8'b00000000} / max_n : 8'd0;
end
always@(posedge clk or negedge rst)
begin
if (!rst)
hsv_s <= 8'd0;
else
hsv_s <= hsv_s_m;
end
// hsv_v = max
always@(posedge clk or negedge rst)
begin
if (!rst)
hsv_v <= 8'd0;
else
hsv_v <= max_n;
end
// 3-------------------
endmodule