FPGA学习笔记——图像处理之对比度调节(直方图均衡化)
目录
一、任务
二、直方图均衡化
三、代码
1.v文件
(1)RGB2YUV
(2)histogram_adjust
(3)equalization
(4)Histogram_top
2.仿真文件
(1)tb_his
(2)video_sour
四、实验现象
一、任务
将下面这幅图片进行对比度调节,用直方图均衡化。
二、直方图均衡化
第一步:计算原始直方图,统计每个灰度级 k 的像素数量:
第二步:计算归一化直方图(概率分布),M,N分别代表图像的长宽
第三步:计算累积分布函数(CDF),CDF 表示灰度值 ≤ k 的像素占比
第四步:计算均衡化后的灰度值,将 CDF 映射到 [0, 255] ,S(k) 是原始灰度 k 映射后的新灰度值。
RGB转YUV:
思路:先把RGB转成YUV(这里只涉及到了灰度),然后进行四个步骤(具体看代码)。
三、代码
1.v文件
(1)RGB2YUV
`timescale 1ns / 1ps
module RGB2YUV(input clk ,input rst_n ,input [23:0] i_rgb ,input i_valid ,input i_hsync ,input i_vsync ,output [7:0] o_y , //灰度值output o_valid ,output o_hsync ,output o_vsync );parameter C0 = 76 ,C1 = 150,C2 = 29 ;reg [15:0] temp0_r;reg [15:0] temp0_g;reg [15:0] temp0_b;reg [15:0] temp1_y;reg [1:0] valid_reg; reg [1:0] hsync_reg; reg [1:0] vsync_reg; always @(posedge clk)beginif(!rst_n)begintemp0_r <= 0;temp0_g <= 0;temp0_b <= 0;endelse begintemp0_r <= i_rgb[23:16]*C0;temp0_g <= i_rgb[15:8]*C1;temp0_b <= i_rgb[7:0]*C2;endendalways @(posedge clk)beginif(!rst_n)temp1_y <= 0;else temp1_y <= temp0_r + temp0_g + temp0_b;endalways @(posedge clk)beginvalid_reg <= {valid_reg[0],i_valid};hsync_reg <= {hsync_reg[0],i_hsync};vsync_reg <= {vsync_reg[0],i_vsync};end assign o_y = temp1_y[15:8];assign o_valid = valid_reg[1];assign o_hsync = hsync_reg[1];assign o_vsync = vsync_reg[1];endmodule
(2)histogram_adjust
`timescale 1ns / 1ps
module histogram_adjust(input clk ,input rst_n ,input [7:0] i_y ,input i_valid ,input i_hsync ,input i_vsync ,//----输出统计结果------------------------------output [19:0] o_histogram,output reg o_histogram_valid);reg [19:0] data [255:0] ;reg [1:0] vsync_reg ;reg [7:0] addr;integer i;always @(posedge clk)beginif(!rst_n || (~vsync_reg[0] && vsync_reg[1]))begin //下降沿 对存储器清零for(i=0; i < 256;i=i+1)begindata[i] <= 0; endendelse if(i_valid)begindata[i_y] <= data[i_y]+1;endendalways @(posedge clk)beginvsync_reg <= {vsync_reg[0],i_vsync};end//---输出统计结果-----------------------------------always @(posedge clk)beginif(!rst_n || addr == 255)o_histogram_valid <= 0;else if(vsync_reg[0] && ~vsync_reg[1]) //上升沿o_histogram_valid <= 1;endalways @(posedge clk)beginif(!rst_n)addr <= 0;else if(o_histogram_valid)beginif(addr == 255)addr <= 0;elseaddr <= addr+1;endendassign o_histogram = data[addr];endmodule
(3)equalization
`timescale 1ns / 1ps
module equalization(input clk ,input rst_n ,input [7:0] i_y ,input i_valid ,input i_hsync ,input i_vsync ,output [7:0] o_y ,output reg o_valid ,output reg o_hsync ,output reg o_vsync ,//--灰度直方图统计结果-----------------------input [19:0] i_histogram,input i_histogram_valid);reg [19:0] data [255:0] ;reg [7:0] addr;reg [19:0] equalization;integer i;always @(posedge clk)beginif(!rst_n)addr <= 0;else if(i_histogram_valid)addr <= addr+1;endalways @ (posedge clk)beginif(!rst_n )begin //下降沿 对存储器清零for(i=0; i < 256;i=i+1)begindata[i] <= 0; endendelse if(i_histogram_valid) beginif(addr == 0)data[0] <= i_histogram;else data[addr] <= i_histogram+data[addr-1]; //当前输入值 + 加上上一次的总和endendalways @(posedge clk)beginif(!rst_n)equalization <= 0;else equalization <= data[i_y];endalways @(posedge clk)begino_valid <= i_valid;o_hsync <= i_hsync;o_vsync <= i_vsync;endassign o_y = equalization[19:12];endmodule
(4)Histogram_top
`timescale 1ns / 1ps
module Histogram_top(
input clk ,
input rst_n ,
input [23:0] i_rgb ,
input i_vsync ,
input i_hsync ,
input i_valid ,
output [7:0] o_y ,
output o_vsync ,
output o_hsync ,
output o_valid );wire [19:0] i_histogram;wire i_histogram_valid;wire [7:0] y_o;wire o_valid_r;wire o_hsync_r;wire o_vsync_r;RGB2YUV RGB2YUV_u(
. clk (clk),
. rst_n (rst_n),
. i_rgb (i_rgb),
. i_valid(i_valid),
. i_hsync(i_hsync),
. i_vsync(i_vsync),
. o_y (y_o), //灰度值
. o_valid(o_valid_r),
. o_hsync(o_hsync_r),
. o_vsync(o_vsync_r));histogram_adjust histogram_adjust_u(
. clk (clk) ,
. rst_n (rst_n) ,
. i_y (y_o) ,
. i_valid (o_valid_r) ,
. i_hsync (o_hsync_r) ,
. i_vsync (o_vsync_r) ,
. o_histogram (i_histogram) ,
. o_histogram_valid(i_histogram_valid));equalization equalization_u(
. clk (clk) ,
. rst_n (rst_n) ,
. i_y (y_o) ,
. i_valid (o_valid_r) ,
. i_hsync (o_hsync_r) ,
. i_vsync (o_vsync_r) ,
. o_y (o_y) ,
. o_valid (o_valid) ,
. o_hsync (o_hsync) ,
. o_vsync (o_vsync) ,
. i_histogram (i_histogram) ,
. i_histogram_valid(i_histogram_valid));endmodule
2.仿真文件
(1)tb_his
`timescale 1ns / 1ps
module tb_his();reg clk = 0;reg rst_n = 0;wire [23:0] i_rgb;wire i_valid;wire i_vsync;wire [7:0] o_y;wire o_valid;always #10 clk = ~clk;initial begin#100 rst_n = 1;endHistogram_top Histogram_top_u(.clk (clk),.rst_n (rst_n),.i_rgb (i_rgb),.i_valid (i_valid),.i_hsync (),.i_vsync (i_vsync),.o_y (o_y), //灰度值.o_valid (o_valid),.o_hsync (),.o_vsync ());video_sour video_sour_u(.pclk (clk),.rstn (rst_n),
//----图像输出----------------------.o_vs (i_vsync),.source_de_o (i_valid),.source_data_o(i_rgb),
//----图像输入----------------------.de_i (o_valid),.data_i ({o_y,o_y,o_y}));endmodule
(2)video_sour
`timescale 1ns / 1ps
`define VIDEO_1280_720
module video_sour#(
parameter VSYNC=720,HSYNC=1280,DELAY1=50_000_000 //图像处理延迟)(
input pclk ,
input rstn ,
//----图像输出----------------------
output reg o_vs ,
output reg source_de_o ,
output [23:0] source_data_o,
//----图像输入----------------------
input de_i ,
input [23:0] data_i);
//1280X720 74.25MHZ
`ifdef VIDEO_1280_720
parameter H_ACTIVE = 1280;// 行数据有效时间
parameter H_FRONT_PORCH = 110; // 行消隐前肩时间
parameter H_SYNC_TIME = 40; // 行同步信号时间
parameter H_BACK_PORCH = 220; // 行消隐后肩时间
parameter H_POLARITY = 1; // 行同步极性
parameter V_ACTIVE = 720; // 列数据有效时间
parameter V_FRONT_PORCH = 5; // 列消隐前肩时间
parameter V_SYNC_TIME = 5; // 列同步信号时间
parameter V_BACK_PORCH = 20; // 列消隐后肩时间
parameter V_POLARITY = 1; // 场同步极性
`endiflocalparam addr_size=HSYNC*VSYNC*3+54; //总字节数
//文件名
integer bmp_file_id;
integer bmp_dout_id;
//文件句柄
integer h;
reg [7:0] rd_data [addr_size-1:0]; //根据自己图片大小 BMP格式为:位图文件头(14字节)+位图信息头(40字节)+实际像素点占内存
reg [7:0] wr_data [addr_size-1:0];
integer i=0;
integer addr_rd=54;
integer addr_wr=54;initial beginbmp_file_id = $fopen("D:/intelFPGA_lite/haiyunjiexun/text_Vivado/image_isp/image_1.bmp","rb"); //打开原始图像bmp_dout_id = $fopen("D:/intelFPGA_lite/haiyunjiexun/text_Vivado/image_isp/image_1_out.bmp","wb"); //打开输出图像h = $fread(rd_data,bmp_file_id); //读取bmp文件 读取到的数据将会依次放入rd_data中$fclose(bmp_file_id); //读取完毕#DELAY1 ; //图像处理延迟for(i = 0; i < addr_size; i = i + 1)begin //图像数据写入文件if(i < 54)$fwrite(bmp_dout_id, "%c", rd_data[i]);//注意参数%celse $fwrite(bmp_dout_id, "%c", wr_data[i]);//注意参数%cend$fclose(bmp_dout_id);#100;$stop ;end//----读出图像数据--------------------------------
always@(posedge pclk)beginif(source_de_o) beginif(addr_rd >= addr_size-3)addr_rd<=54;elseaddr_rd<=addr_rd+3;end
endassign source_data_o={rd_data[addr_rd],rd_data[addr_rd+1],rd_data[addr_rd+2]}; //R + G + B//----写入图像数据--------------------------------
always@(posedge pclk)beginif(de_i) beginif(addr_wr >= addr_size-3)addr_wr<=54;elseaddr_wr<=addr_wr+3;end
endalways@(posedge pclk)beginwr_data[addr_wr]=data_i[23:16]; //写入存储器wr_data[addr_wr+1]=data_i[15:8];wr_data[addr_wr+2]=data_i[7:0];
endlocalparam H_TOTAL_TIME=H_ACTIVE+H_FRONT_PORCH+H_SYNC_TIME+H_BACK_PORCH;
localparam V_TOTAL_TIME=V_ACTIVE+V_FRONT_PORCH+V_SYNC_TIME+V_BACK_PORCH;
reg [31:0] cnt_v; //场同步计数器
reg [31:0] cnt_h; //行同步计数器always@(posedge pclk)beginif(!rstn)source_de_o<=0;else if(( cnt_h > (H_SYNC_TIME + H_BACK_PORCH -1)) && (cnt_h <= (H_SYNC_TIME + H_BACK_PORCH + H_ACTIVE -1)) && (cnt_v > (V_SYNC_TIME + V_BACK_PORCH-1)) && (cnt_v <= (V_SYNC_TIME + V_BACK_PORCH + V_ACTIVE-1)))source_de_o<=1;elsesource_de_o<=0;
endalways@(posedge pclk)beginif(!rstn)cnt_h<=0;else if(cnt_h == H_TOTAL_TIME-1)cnt_h<=0;elsecnt_h<=cnt_h+1;
endalways@(posedge pclk)beginif(!rstn)cnt_v<=0;else if(cnt_h == H_TOTAL_TIME-1)beginif(cnt_v == V_TOTAL_TIME-1)cnt_v<=0;elsecnt_v<=cnt_v+1;end
end// 场同步控制
always@(posedge pclk)
beginif(cnt_v < V_SYNC_TIME) o_vs <= V_POLARITY;else o_vs <= ~V_POLARITY;
endendmodule
四、实验现象
均衡化之前:
均衡化之后:
以上就是图像处理之对比度调节(直方图均衡化)。(如果有错误的地方,还请大家指出来,谢谢!)