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

rust 复制代码
`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)begin
        if(!rst_n)begin
            temp0_r <= 0;
            temp0_g <= 0;
            temp0_b <= 0;
        end
        else begin
            temp0_r <= i_rgb[23:16]*C0;
            temp0_g <= i_rgb[15:8]*C1;
            temp0_b <= i_rgb[7:0]*C2;
        end
    end
    
    always @(posedge clk)begin
        if(!rst_n)
            temp1_y <= 0;
        else 
            temp1_y <= temp0_r + temp0_g + temp0_b;
    end
    
    always @(posedge clk)begin
        valid_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

rust 复制代码
`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)begin
        if(!rst_n || (~vsync_reg[0] && vsync_reg[1]))begin   //下降沿 对存储器清零
            for(i=0; i < 256;i=i+1)begin
                data[i] <= 0; 
            end
        end
        else if(i_valid)begin
            data[i_y] <= data[i_y]+1;
        end
    end
    
    always @(posedge clk)begin
        vsync_reg <= {vsync_reg[0],i_vsync};
    end
    
    //---输出统计结果-----------------------------------
    always @(posedge clk)begin
        if(!rst_n || addr == 255)
            o_histogram_valid <= 0;
        else if(vsync_reg[0] && ~vsync_reg[1])   //上升沿
            o_histogram_valid <= 1;
    end
    
    always @(posedge clk)begin
        if(!rst_n)
            addr <= 0;
        else if(o_histogram_valid)begin
            if(addr == 255)
                addr <= 0;
            else
                addr <= addr+1;
        end
    end
    
    assign o_histogram = data[addr];
    
    
endmodule

(3)equalization

rust 复制代码
`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)begin
        if(!rst_n)
            addr <= 0;
        else if(i_histogram_valid)
            addr <= addr+1;
    end
    

    always @ (posedge clk)begin
        if(!rst_n )begin   //下降沿 对存储器清零
            for(i=0; i < 256;i=i+1)begin
                data[i] <= 0; 
            end
        end
        else if(i_histogram_valid) begin
            if(addr == 0)
                data[0] <= i_histogram;
            else 
                data[addr] <= i_histogram+data[addr-1];   //当前输入值 + 加上上一次的总和
        end
    end
    
    always @(posedge clk)begin
        if(!rst_n)
            equalization <= 0;
        else 
            equalization <= data[i_y];
    end
    
    
    always @(posedge clk)begin
        o_valid <= i_valid;
        o_hsync <= i_hsync;
        o_vsync <= i_vsync;
    end
    
    
    assign o_y =  equalization[19:12];
    
endmodule

(4)Histogram_top

rust 复制代码
`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

rust 复制代码
`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;
    end

    Histogram_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

rust 复制代码
`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;   // 场同步极性
`endif

localparam 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 begin
    bmp_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]);//注意参数%c
	   else       
           $fwrite(bmp_dout_id, "%c", wr_data[i]);//注意参数%c
    end
    $fclose(bmp_dout_id);
    #100;
    $stop ;
    
end


//----读出图像数据--------------------------------
always@(posedge pclk)begin
    if(source_de_o) begin
        if(addr_rd >= addr_size-3)
            addr_rd<=54;
        else
            addr_rd<=addr_rd+3;
    end
end


assign source_data_o={rd_data[addr_rd],rd_data[addr_rd+1],rd_data[addr_rd+2]};    //R + G + B

//----写入图像数据--------------------------------
always@(posedge pclk)begin
    if(de_i) begin
        if(addr_wr >= addr_size-3)
            addr_wr<=54;
        else
            addr_wr<=addr_wr+3;
    end
end

always@(posedge pclk)begin
    wr_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];
end

localparam  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)begin
    if(!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;
   else
        source_de_o<=0;
end

always@(posedge pclk)begin
    if(!rstn)
        cnt_h<=0;
    else if(cnt_h == H_TOTAL_TIME-1)
        cnt_h<=0;
    else
        cnt_h<=cnt_h+1;
end

always@(posedge pclk)begin
    if(!rstn)
        cnt_v<=0;
    else if(cnt_h == H_TOTAL_TIME-1)begin
        if(cnt_v == V_TOTAL_TIME-1)
            cnt_v<=0;
        else
            cnt_v<=cnt_v+1;
    end
end

// 场同步控制
always@(posedge pclk)
begin
    if(cnt_v < V_SYNC_TIME) o_vs <= V_POLARITY;
    else o_vs <= ~V_POLARITY;
end


endmodule

四、实验现象

均衡化之前:

均衡化之后:


以上就是图像处理之对比度调节(直方图均衡化)。(如果有错误的地方,还请大家指出来,谢谢!)

相关推荐
go_bai2 小时前
Linux--常见工具
linux·开发语言·经验分享·笔记·vim·学习方法
!chen3 小时前
学习 React 前掌握 JavaScript 核心概念
javascript·学习·react.js
Hey! Hey!3 小时前
DBA 系统学习计划(从入门到进阶)
数据库·学习·dba
leo_yu_yty3 小时前
Mysql DBA学习笔记(客户端常用工具)
学习·mysql·dba
蜉蝣之翼❉3 小时前
图像交互工具:像素矩阵与卷积核可视化分析
图像处理
小狗爱吃黄桃罐头4 小时前
正点原子【第四期】Linux之驱动开发学习笔记-6.1 pinctrl和gpio子系统
linux·驱动开发·学习
咩?4 小时前
深度学习中的关键工具与数据处理方法
深度学习·学习
szxinmai主板定制专家4 小时前
基于ZYNQ的ARM+FPGA+yolo AI火灾实时监测与识别系统
arm开发·yolo·fpga开发
sjh21005 小时前
【学习笔记】20年前的微芯an1078foc技术,smo滑模位置估计,反电动势波形还不错,为何位置估计反而超前了呢?
笔记·学习