HSV颜色模型
HSV(Hue, Saturation, Value)颜色模型是一种常用的色彩表示方式,特别适用于图像处理、计算机图形学和色彩选取工具中。它通过将颜色的表示从传统的RGB(红、绿、蓝)模型转换为更符合人类视觉感知的方式来描述颜色。以下是HSV模型的三个主要分
Hue(色调,H):色调表示颜色的种类,通常用角度来表示,范围从0°到360°。在HSV模型的色轮中:0°代表红色,120°代表绿色,240°代表蓝色。其他角度代表这些基本颜色之间的过渡色,例如30°为橙色,60°为黄色。
Saturation(饱和度,S):饱和度描述颜色的纯度或浓度,表示色彩的鲜艳程度。S的取值范围是从0到100%,或者在某些情况下是0到1。
当S为0时,颜色是完全无色的(灰色),这意味着色调无关紧要。
当S为100%(或1)时,颜色是完全饱和的,这意味着没有混入任何白色。
Value(明度,V):明度表示颜色的亮度,取值范围也是0到100%或0到1。
当V为0时,颜色是完全黑色的。
当V为100%(或1)时,颜色是最亮的,显示的是色调本身的颜色。
FPGA 实现
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2024/01/28 01:40:35
// Design Name:
// Module Name: divide
// Project Name:
// Target Devices:
// Tool Versions:
// Description: 除法
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module divide#(
parameter I_W = 32,
parameter D_W = 9,
parameter O_W = I_W - D_W
)
(
input clk,
input reset,
input valid_i,
input [I_W - 1 : 0] dividend, //被除数
input [D_W - 1 : 0]divisor, //除数
output valid_o,
output [O_W - 1 : 0]quotient,//商
output [D_W - 1 : 0]remaind //余数
);
//变量声明
localparam B_W = I_W + 1;
genvar i;
reg [D_W-1:0] divisor_buf [0:O_W+1];
reg valid_buf [0:O_W+1];
reg [B_W-1:0] dividend_buf [0:O_W+1];
reg [O_W:0] quotient_buf [0:O_W+1];
//赋初值
always @(*) begin
dividend_buf[0] = {1'b0, dividend};
divisor_buf[0] = divisor;
valid_buf[0] = valid_i;
quotient_buf[0] = 0;
end
//除法计算
generate for(i=1;i<=(O_W+1);i=i+1)
begin
always @(posedge clk or posedge reset) begin
if(reset) begin
dividend_buf[i] <= 'b0;
quotient_buf[i] <= 'b0;
end else if(valid_buf[i-1]) begin
if(divisor_buf[i-1] == 'b0) begin //除数为0的情况
dividend_buf[i] <= 'b0;
quotient_buf[i] <= 'b0;
end else if(dividend_buf[i-1][B_W-1:O_W] >= {1'b0, divisor_buf[i-1]}) begin //可能出现上一步的余数最高位也是1的情况
dividend_buf[i][B_W-1:O_W+1] <= dividend_buf[i-1][B_W-1:O_W] - divisor_buf[i-1];
dividend_buf[i][O_W:0] <= {dividend_buf[i-1][O_W-1:0], 1'b0};
quotient_buf[i] <= {quotient_buf[i-1][O_W:0],1'b1};
end else begin
dividend_buf[i][B_W-1:O_W+1] <= dividend_buf[i-1][B_W-1:O_W];
dividend_buf[i][O_W:0] <= {dividend_buf[i-1][O_W-1:0], 1'b0};
quotient_buf[i] <= {quotient_buf[i-1][O_W:0],1'b0};
end
end else begin
dividend_buf[i] <= 'b0;
quotient_buf[i] <= 'b0;
end
end
always @(posedge clk ) begin
valid_buf[i] <= valid_buf[i-1];
divisor_buf[i] <= divisor_buf[i-1];
end
end
endgenerate
assign valid_o = valid_buf[O_W+1];
assign quotient = quotient_buf[O_W+1];
assign remaind = dividend_buf[O_W+1][B_W-1:O_W+1];
endmodule
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2024/08/07 19:14:25
// Design Name:
// Module Name: image_rgb_to_hsv
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module image_rgb_to_hsv(
input clk ,
input rst ,
input [ 23: 0] img_data_i ,
input valid_i ,
output [ 23: 0] img_data_o ,
output valid_o
);
/*
R,Gand Binput range=0- 255
H,Sand Voutputrange=0- 1.0
var_R=(R/255)
var_G=(G/255)
var_B=(B/255)
var_Min=min(var_R,var_G,var_B) //Min. value of RGB
var_Max=max(var_R,var_G,var_B) //Max. value of RGB
del_Max=var_Max-var_Min //Delta RGB value
V = var_Max
if(del_Max ==0) This is a gray,no chroma.
H =0
S=0
else Chromatic data...
S= del_Max/var_Max
del_R=(((var_Max-var_R)/6)+(del_Max/2))/ del_Max
de1_G=(((var_Max-var_G)/6)+(del_Max/2))/ del_Max
del_B=(((var_Max-var_B)/6)+(del_Max/2))/ del_Max
if (var_R==var_Max)
H=del_B-del_G
else if(var_G==var_Max)
H=(1/3)+ del_R- del_B
else if(var_B==var_Max)
H=(2/3)+ del_G- del_R
if(H<0) H+= 1
if(H>1) H-= 1
转换成整数运算,所有运算常量都乘以255
//R, G and B input range = 0 ~ 255
//H, S and V output range = 0 ~ 255
var_R = R
var_G = G
var_B = B
var_Min = min( var_R, var_G, var_B ) //Min. value of RGB
var_Max = max( var_R, var_G, var_B ) //Max. value of RGB
del_Max = var_Max - var_Min //Delta RGB value
V = var_Max
if ( del_Max == 0 ) //This is a gray, no chroma...
{
H = 0
S = 0
}
else //Chromatic data...
{
S = (del_Max / var_Max) * 255
del_R = ( ( ( var_Max - var_R ) / 6 ) + ( del_Max / 2 ) ) / del_Max * 255
del_G = ( ( ( var_Max - var_G ) / 6 ) + ( del_Max / 2 ) ) / del_Max * 255
del_B = ( ( ( var_Max - var_B ) / 6 ) + ( del_Max / 2 ) ) / del_Max * 255
if ( var_R == var_Max ) H = del_B - del_G
else if ( var_G == var_Max ) H = ( 1 / 3 )*255 + del_R - del_B
else if ( var_B == var_Max ) H = ( 2 / 3 )*255 + del_G - del_R
if ( H < 0 ) H += 1
if ( H > 1 ) H -= 1
}
//简化公式
del_R = ( var_Max - var_R + 3*del_Max) / (6*del_Max) * 255
del_G = ( var_Max - var_G + 3*del_Max) / (6*del_Max) * 255
del_B = ( var_Max - var_B + 3*del_Max) / (6*del_Max) * 255
if ( var_R == var_Max ) H = del_B - del_G = ( var_G - var_B)/ (6*del_Max) * 255
else if ( var_G == var_Max ) H = ( 1 / 3 )*255 + del_R - del_B = 85 + ( var_B - var_R)/ (6*del_Max) * 255
else if ( var_B == var_Max ) H = ( 2 / 3 )*255 + del_G - del_R = 170 + ( var_R - var_G)/ (6*del_Max) * 255
//最后简化公式为
var_R = R
var_G = G
var_B = B
var_Min = min( var_R, var_G, var_B ) //Min. value of RGB
var_Max = max( var_R, var_G, var_B ) //Max. value of RGB
del_Max = var_Max - var_Min //Delta RGB value
if ( var_R == var_Max ) H = ( var_G - var_B)/ (6*del_Max) * 255
else if ( var_G == var_Max ) H = ( 2*del_Max + var_B - var_R)/ (6*del_Max) * 255
else if ( var_B == var_Max ) H = ( 4*del_Max + var_R - var_G)/ (6*del_Max) * 255
S = (del_Max / var_Max) * 255
V = var_Max
*/
wire [ 7: 0] R,G,B ;
assign {R,G,B} = img_data_i;
reg valid_d1 ;
reg valid_d2 ;
reg valid_d3 ;
reg [ 7: 0] var_min ;
reg [ 7: 0] var_max ;
reg [ 8: 0] var_ext ;
reg [ 1: 0] var_max_id ;
reg [ 7: 0] R_d1,G_d1,B_d1 ;
wire [ 7: 0] del_max_w ;
reg [ 15: 0] del_max_m255 ;
reg [ 10: 0] del_max_m6 ;
reg [ 7: 0] var_max_d1 ;
wire [ 10: 0] h_w ;
reg [ 18: 0] h_del ;
reg [8*9-1: 0] var_max_d1_shift_r ;
wire s_div_valid_w ;
wire [ 7: 0] S ;
wire h_div_valid_w ;
wire [ 7: 0] H ;
wire [ 7: 0] V ;
always @ (posedge clk or posedge rst)
if (rst)begin
valid_d1 <= 0;
var_min <= 0;
var_max <= 0;
var_ext <= 0;
var_max_id <= 0;
{R_d1,G_d1,B_d1} <= 0;
end else begin
valid_d1 <= valid_i;
if (valid_i)begin
var_min <= (R > G) ? ((G > B)? B : R) :((R > B) ? B:R);
if (R > G)begin
if (R > B)begin
var_max <= R;
var_max_id <= 0;
var_ext <= (G > B) ? G - B : 0;
end
else begin
var_max <= B;
var_max_id <= 2;
var_ext <= R - {1'b0,G};
end
end
else if (G > B)begin
var_max <= G ;
var_max_id <= 1;
var_ext <= B - {1'b0,R};
end else begin
var_max <= B ;
var_max_id <= 2;
var_ext <= R - {1'b0,G};
end
end
{R_d1,G_d1,B_d1} <= {R,G,B};
end
//计算最大差值
assign del_max_w = var_max - var_min;
//有符号数运算
assign h_w = (var_max_id == 0) ? {2'b0, var_ext} : (var_max_id == 1) ?
({del_max_w, 1'b0} + {{2{var_ext[8]}}, var_ext}) : ({del_max_w, 2'b0} + {{2{var_ext[8]}}, var_ext});
always @ (posedge clk or posedge rst)
if (rst)begin
valid_d2 <= 0;
del_max_m255 <= 0;
del_max_m6 <= 0;
h_del <= 0;
var_max_d1 <= 0;
end else begin
valid_d2 <= valid_d1;
if (valid_d1)begin
del_max_m255 <= {del_max_w, 8'b0} - del_max_w;
del_max_m6 <= {del_max_w, 2'b0} + {del_max_w, 1'b0};
h_del <= h_w[10]||(del_max_w == 0) ? 0 : {h_w, 8'b0} - h_w;
end
var_max_d1 <= var_max;
end
//VarMax做延时处理
always @(posedge clk)
var_max_d1_shift_r <= {var_max_d1_shift_r,var_max_d1};
//除法计算
//计算S,延时16-8+1=9
divide#(
.I_W (16 ),
.D_W (8 )
)u_divide0(
.clk (clk ),
.reset (rst ),
.valid_i (valid_d2 ),
.dividend (del_max_m255 ),
.divisor (var_max_d1 ),
.valid_o (s_div_valid_w ),
.quotient (S ),
.remaind ( )
);
//计算H,延时19-11+1=9
divide#(
.I_W (19 ),
.D_W (11 )
)u_divide1(
.clk (clk ),
.reset (rst ),
.valid_i (valid_d2 ),
.dividend (h_del ),
.divisor (del_max_m6 ),
.valid_o (h_div_valid_w ),
.quotient (H ),
.remaind ( )
);
//计算V
assign V = var_max_d1_shift_r[8*9-1:8*8];
assign valid_o = s_div_valid_w;
assign img_data_o = {H, S, V};
endmodule
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2024/01/28 12:45:31
// Design Name:
// Module Name: image_hsv_to_rgb
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module image_hsv_to_rgb(
input clk ,
input rst ,
input [ 23: 0] img_data_i ,
input valid_i ,
output [ 23: 0] img_data_o ,
output valid_o
);
/*
HSV转RGB
H,S and V input range=0/1.0
R,GandB output range=0/255
if(S==0){
R=V* 255
G=V* 255
B=V* 255
J
else
var_h =H* 6
if(var_h==6)var_h= 0
var_i = int(var_h )
var_1=V*(1-S)
var_2=V*(1-S*(var_h-var_i))
var_3=V*(1-S*(1-(var_h-var_i)))
if (var_i ==0){var_r =V var_g=var_3 var b=var_1}
else if (var_i ==1){var_r =var_2 var_g=V var_b=var 1}
else if (var_i ==2){var_r =var_1 var_g=V var_b=var 3}
else if (var_i ==3){var_r =var_1 var_g=var_2 var_b=V }
else if (var_i ==4){var_r =var_3 var_g=var_1 var_b=V }
else {var_r =V var_g=var_1 var b=var_2}
R= var_r * 255
G= var_g * 255
B= var b * 255
简化公式,我们的HSV都是整数
if ( S == 0 )
{
R = V
G = V
B = V
}
else
{
var_h = H * 6
if ( H == 255 ) var_h = 0 //H must be < 1
var_i = var_h[10:8] //Or ... var_i = floor( var_h )
var_1 = V * ( 1 - S ) = V - V*S/255
var_2 = V * ( 1 - S * ( var_h - var_i ) ) = V - V*S*( var_h - var_i )/255/255
var_3 = V * ( 1 - S * ( 1 - ( var_h - var_i ) ) ) = V - V*S/255 + V*S*( var_h - var_i )/255/255
if ( var_i == 0 ) { R = V ; G = var_3 ; B = var_1 }
else if ( var_i == 1 ) { R = var_2 ; G = V ; B = var_1 }
else if ( var_i == 2 ) { R = var_1 ; G = V ; B = var_3 }
else if ( var_i == 3 ) { R = var_1 ; G = var_2 ; B = V }
else if ( var_i == 4 ) { R = var_3 ; G = var_1 ; B = V }
else { R = V ; G = var_1 ; B = var_2 }
}
*/
wire [ 7: 0] H,S,V ;
assign {H,S,V } = img_data_i;
reg valid_d1 ;
reg valid_d2 ;
reg valid_d3 ;
reg valid_d4 ;
wire [ 10: 0] var_h ;
assign var_h = (H == 'd255) ? 0 : {H, 2'b0} + {H, 1'b0};
reg [ 2: 0] var_i ;
reg [ 7: 0] var_h_sub_var_i ;
reg [ 15: 0] V_m_S ;
reg [ 7: 0] V_d1 ;
reg S_zero ;
reg [ 23: 0] V_m_S_m_h ;
reg [ 15: 0] V_m_S_d1 ;
reg [ 7: 0] V_d2 ;
reg [ 2: 0] var_i_d1 ;
reg S_zero_d1 ;
reg [ 7: 0] var_1,var_2,var_3 ;
reg [ 2: 0] var_i_d2 ;
reg [ 7: 0] V_d3 ;
reg S_zero_d2 ;
reg [ 7: 0] R,G,B ;
always @ (posedge clk or posedge rst)
if (rst)begin
valid_d1 <= 0;
var_i <= 0;
var_h_sub_var_i <= 0;
V_m_S <= 0;
S_zero <= 0;
V_d1 <= 0;
end else begin
valid_d1 <= valid_i;
var_i <= var_h[10:8];
var_h_sub_var_i <= var_h - var_i;
V_m_S <= V*S;
S_zero <= (S == 0) ? 1'b1 : 1'b0;
V_d1 <= V;
end
always @ (posedge clk or posedge rst)
if (rst)begin
valid_d2 <= 0;
V_m_S_m_h <= 0;
V_m_S_d1 <= 0;
V_d2 <= 0;
var_i_d1 <= 0;
S_zero_d1 <= 0;
end else begin
valid_d2 <= valid_d1;
V_m_S_m_h <= V_m_S*var_h_sub_var_i;
V_m_S_d1 <= V_m_S;
V_d2 <= V_d1;
var_i_d1 <= var_i;
S_zero_d1 <= S_zero;
end
always @ (posedge clk or posedge rst)
if (rst)begin
valid_d3 <= 0;
{var_1,var_2,var_3 } <= 0;
var_i_d2 <= 0;
V_d3 <= 0;
S_zero_d2 <= 0;
end else begin
valid_d3 <= valid_d2;
//简化除法运算,1/255直接等效于1/256
//var_1 = V * ( 1 - S ) = V - V*S/255
var_1 <= V_d2 - V_m_S_d1[15:8];
//var_2 = V * ( 1 - S * ( var_h - var_i ) ) = V - V*S*( var_h - var_i )/255/255
var_2 <= V_d2 - V_m_S_m_h[23:16];
//var_3 = V * ( 1 - S * ( 1 - ( var_h - var_i ) ) ) = V - V*S/255 + V*S*( var_h - var_i )/255/255
var_3 <= V_d2 - V_m_S_d1[15:8] + V_m_S_m_h[23:16];
var_i_d2 <= var_i_d1;
V_d3 <= V_d2;
S_zero_d2 <= S_zero_d1;
end
always @ (posedge clk or posedge rst)
if (rst)begin
valid_d4 <= 0;
{R,G,B } <= 0;
end else begin
valid_d4 <= valid_d3;
if (S_zero_d2)begin
{R, G, B} <= {3{V_d3}};
end else begin
case (var_i_d2)
0: begin R <= V_d3 ; G <= var_3 ; B <= var_1; end
1: begin R <= var_2 ; G <= V_d3 ; B <= var_1; end
2: begin R <= var_1 ; G <= V_d3 ; B <= var_3; end
3: begin R <= var_1 ; G <= var_2 ; B <= V_d3 ; end
4: begin R <= var_3 ; G <= var_1 ; B <= V_d3 ; end
default: begin R <= V_d3 ; G <= var_1 ; B <= var_2; end
endcase
end
end
assign valid_o = valid_d4;
assign img_data_o = {R, G, B};
endmodule
仿真
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2024/08/01 20:54:28
// Design Name:
// Module Name: tb
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
`define INPUT_FILE "../../../../test_img/in/1024x600.bmp" //input image
`define IMG_WIDTH 1024 //Image width
`define IMG_HEIGHT 600 //Image height
`define H_BLANK 400 //横向消影区,仿真可自由设定
`define V_BLANK 30 //纵向消影区,仿真可自由设定
`define OUTPUT_FILE "../../../../test_img/out/result.bmp" //result image frame1
`define LEN_HEADER 54 // 0x33
`define IMG_ALL (`IMG_HEIGHT*`IMG_WIDTH*3)
`define IMG_SIZE (`IMG_HEIGHT*`IMG_WIDTH)
`define IMG_BMP_SIZE (`IMG_ALL + `LEN_HEADER)
`define NULL 0
`define DATA_WIDTH 8
`define SEEK_SET 0
`define SEEK_CUR 1
`define SEEK_END 2
module tb;
parameter TIME = 2 ;
integer fdI ;
integer fdO ;
integer ret, i,j,idx,file_end_offset,zero_len;
reg [`DATA_WIDTH-1: 0]bmp_head_r[0:`LEN_HEADER-1] ;//Image 1 Header
reg [`DATA_WIDTH-1: 0]imgR_r[0:`IMG_SIZE-1] ;//Image-- R Channel
reg [`DATA_WIDTH-1: 0]imgG_r[0:`IMG_SIZE-1] ;//Image-- G Channel
reg [`DATA_WIDTH-1: 0]imgB_r[0:`IMG_SIZE-1] ;//Image-- B Channel
wire [ 31: 0] bmp_size, bmp_width,bmp_height;
reg init_r ;
reg clk =1'b0;
reg rst ;
reg [ 31: 0] h_cnt_r, v_cnt_r;
reg [ 31: 0] data_cnt_r ;
reg [ 31: 0] addr_r ;
wire valid_i ;
wire [`DATA_WIDTH*3-1: 0]img_data_i ;
wire valid_o ;
wire [`DATA_WIDTH*3-1: 0]img_data_o ;
reg [ 31: 0] out_data_cnt_r ;
reg valid_o_r ;
wire [`DATA_WIDTH-1: 0]R_o_w, G_o_w,B_o_w;
always
begin
#(TIME/2) clk = ~clk;
end
initial begin
rst = 1'b1;
zero_len = 'b0;
#(TIME*10);
rst = 1'b0;
wait(init_r);
$display("> Initial Done");
wait(out_data_cnt_r == (`IMG_SIZE-1)); //检测一幅图像完成?
#(TIME*2);
//文件末尾补0
$fseek(fdO, 0, `SEEK_END);
zero_len = $ftell(fdO);
zero_len = 4- zero_len[1:0];
for(i=0;i < zero_len;i=i+1)
$fwrite(fdO, "%c", 0);
$fclose(fdO);
$display("> Simulate Done");
$stop;
end
///读取BMP文件
assign bmp_size = {bmp_head_r[5], bmp_head_r[4], bmp_head_r[3], bmp_head_r[2]};
assign bmp_width = {bmp_head_r[21], bmp_head_r[20], bmp_head_r[19], bmp_head_r[18]};
assign bmp_height = {bmp_head_r[25], bmp_head_r[24], bmp_head_r[23], bmp_head_r[22]};
initial begin
init_r = 1'b0;
for (i = 0; i < `IMG_SIZE; i=i+1)begin
imgB_r[i] = 0;
imgG_r[i] = 0;
imgR_r[i] = 0;
end
fdI = $fopen(`INPUT_FILE,"rb");
if (fdI == `NULL) begin
$display("> OPEN FAIL: The file not exist !!!");
end else begin
$display("> OPEN file SUCCESS !");
//读取bmp文件头
ret = $fread(bmp_head_r, fdI, 0, `LEN_HEADER);
//读取图像RGB分量值?
//BMP倒序存储数据时,从下到上,从左到右
for(i=`IMG_HEIGHT - 1;i >= 0;i=i-1)
for(j=0;j <`IMG_WIDTH;j=j+1) begin
idx = i*`IMG_WIDTH + j;
imgB_r[idx] = $fgetc(fdI); //b
imgG_r[idx] = $fgetc(fdI); //g
imgR_r[idx] = $fgetc(fdI); //r
end
$display("> Read b,g,r Successful !");
end
fdO = $fopen(`OUTPUT_FILE,"wb");
//写入文件头
for(i=0;i < `LEN_HEADER;i=i+1) begin
$fwrite(fdO, "%c", bmp_head_r[i]);
end
//移动到图片数据最后一行起始位置
file_end_offset = `IMG_ALL + `LEN_HEADER - `IMG_WIDTH*3;
$fseek(fdO, file_end_offset, `SEEK_SET);
init_r = 1'b1;
end
wire [ 23: 0] img_data_hsv ;
wire valid_hsv ;
image_rgb_to_hsv image_rgb_to_hsv(
.clk (clk ),
.rst (rst ),
.img_data_i (img_data_i ),
.valid_i (valid_i ),
.img_data_o (img_data_hsv ),
.valid_o (valid_hsv )
);
image_hsv_to_rgb u_image_hsv_to_rgb(
.clk (clk ),
.rst (rst ),
.img_data_i (img_data_hsv ),
.valid_i (valid_hsv ),
.img_data_o (img_data_o ),
.valid_o (valid_o )
);
always @(posedge clk or posedge rst) begin
if (rst) begin
{h_cnt_r, v_cnt_r} <= 'b0;
addr_r <= 'b0;
data_cnt_r <= 'b0;
end else begin
h_cnt_r <= (h_cnt_r == `IMG_WIDTH + `H_BLANK - 1) ? 'b0 : h_cnt_r + 1'b1;
v_cnt_r <= (h_cnt_r == `IMG_WIDTH + `H_BLANK - 1) ? ((v_cnt_r == `IMG_HEIGHT + `V_BLANK - 1) ? 'b0 : v_cnt_r + 1'b1) : v_cnt_r;
addr_r <= (addr_r == `IMG_SIZE - 1) ? 'b0 : valid_i ? (addr_r + 'd1) : addr_r;
data_cnt_r <= valid_i ? ((data_cnt_r == `IMG_WIDTH - 1) ? 'b0 : data_cnt_r + 1) : data_cnt_r;
end
end
assign valid_i = (h_cnt_r < `IMG_WIDTH)&&(v_cnt_r < `IMG_HEIGHT) ? 1'b1 : 1'b0;
assign img_data_i = {imgR_r[addr_r], imgG_r[addr_r], imgB_r[addr_r]};
///写入BMP文件
assign {R_o_w, G_o_w, B_o_w} = img_data_o;
always @(posedge clk or posedge rst) begin
if (rst) begin
out_data_cnt_r <= 'b0;
valid_o_r <= 'b0;
end else begin
valid_o_r <= valid_o;
if(valid_o) begin
$fwrite(fdO, "%c", B_o_w);
$fwrite(fdO, "%c", G_o_w);
$fwrite(fdO, "%c", R_o_w);
out_data_cnt_r <= out_data_cnt_r + 1'b1;
end else if(valid_o_r) begin //行结束
file_end_offset = file_end_offset - `IMG_WIDTH*3;
$fseek(fdO, file_end_offset, `SEEK_SET);
end
end
end
endmodule
结果
原图
仿真图
标签:fpga,Max,var,RGB,valid,del,互转,reg,255 From: https://blog.csdn.net/weixin_62953178/article/details/141035265