图像对比度调节FPGA实现

文章目录

1.什么是对比度

  对比度Contrast是指一幅图像中明暗区域最亮的白和最暗的黑之间不同亮度层级的测量,即一幅图像灰度反差的大小,差异范围越大代表对比越大,差异范围越小代表对比越小。一般来说,对比度越大,图像越清晰、醒目,色彩也显得越鲜明艳丽;反之对比度降低,则整个画面都变得灰蒙蒙的。对比度差异如下图展现出了更高的对比度,因此房屋屋顶的颜色层次、山峰岩石的颜色层次、绿植的颜色层次等都显得更加丰富一些。

2.对比度调节原理

  原理:将以中间灰为基准,把每个像素与基准的差距按增益 c 缩放。

c 大于1时差距拉大,亮的更亮、暗的更暗; c 小于1时整体亮度趋向于中间灰度。

P_out = (P_in - 128) * C + 128

P_in:输入的8位像素值(范围0-255)。

P_out:输出的8位像素值。

C:对比度系数。当 C > 1 时增加对比度,C < 1 时降低对比度,C = 1 时保持不变。

128 是8位数据的中间灰度值(对于0-255的范围)。

  具体实现时,c用放大4096倍的数值表示,即用整数乘法代替小数乘法,2048表示增益为1,小于2048表示增益小于1,大于2048表示增益大于1,运算完可以右移11位将数据还原。最后的运算结果还需要防止溢出,必须限制到 0 到 255。

3.FPGA实现代码

powershell 复制代码
module contrast_adjust_rgb #(
    parameter CONTRAST_BITS = 12,          // 对比度系数位宽
    parameter MID_GRAY      = 8'd128,      // 8位图像中间灰度值
    parameter NEUTRAL       = 1 << (CONTRAST_BITS - 1) // 中性点 = 2048
)(
    input  wire                     clk,
    input  wire                     rst_n,
    input  wire                     data_valid_in,   // 输入有效标志
    input  wire [7:0]               r_in,
    input  wire [7:0]               g_in,
    input  wire [7:0]               b_in,
    input  wire [CONTRAST_BITS-1:0] contrast_val,    // 12位对比度系数
    output reg  [7:0]               r_out,
    output reg  [7:0]               g_out,
    output reg  [7:0]               b_out,
    output reg                      data_valid_out   // 输出有效标志,与数据同步
);

localparam [19:0] PSET = MID_GRAY * NEUTRAL; // 补偿值 = 128 * 2048

// ---------- 流水线延迟寄存器(用于data_valid) ----------
reg data_valid_d1;

// ---------- 有符号差值 (9位) ----------
wire signed [8:0] r_diff ={1'b0, r_in} - {1'b0,MID_GRAY};
wire signed [8:0] g_diff ={1'b0, g_in} - {1'b0,MID_GRAY};
wire signed [8:0] b_diff ={1'b0, b_in} - {1'b0,MID_GRAY};

// ---------- 乘法结果:9位 × 13位 = 22位 (有符号) ----------
wire signed [21:0] r_prod = r_diff * $signed({1'b0, contrast_val});
wire signed [21:0] g_prod = g_diff * $signed({1'b0, contrast_val});
wire signed [21:0] b_prod = b_diff * $signed({1'b0, contrast_val});

// ---------- 中间和寄存器 (21位) ----------
reg signed [21:0] r_sum, g_sum, b_sum;

// ---------- 输出数据计算 ----------
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        r_out <= 8'b0;
        g_out <= 8'b0;
        b_out <= 8'b0;
        r_sum <= 32'b0;
        g_sum <= 32'b0;
        b_sum <= 32'b0;
    end else begin
            // 第1级:乘法结果已在组合逻辑中,直接使用
            r_sum <= r_prod + PSET;   // 补偿值 = 128 * 2048
            g_sum <= g_prod + PSET;
            b_sum <= b_prod + PSET;

            // 第2级:加法 + 右移, 右移11位并限幅 (结果在下一拍输出)
            r_out <= (r_sum[21:19] == 3'b001) ? 8'd255 :
                     (r_sum[21:19] == 3'b111) ? 8'd0 : 
                     (r_sum[21:19] == 3'b000) ? r_sum[20:11] : 8'd0;
            g_out <= (g_sum[21:19] == 3'b001) ? 8'd255 :
                     (g_sum[21:19] == 3'b111) ? 8'd0 : 
                     (g_sum[21:19] == 3'b000) ? g_sum[20:11] : 8'd0;
            b_out <= (b_sum[21:19] == 3'b001) ? 8'd255 :
                     (b_sum[21:19] == 3'b111) ? 8'd0 : 
                     (b_sum[21:19] == 3'b000) ? b_sum[20:11] : 8'd0;
    end
end

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        data_valid_d1 <= 1'b0;
        data_valid_out <= 1'b0;
    end else begin
        // 延迟有效信号
        data_valid_d1 <= data_valid_in;
        data_valid_out <= data_valid_d1;
    end
end

endmodule

4.效果对比

(1)对比度提升效果

  调用模块,对比度系数contrast_val取2800时效果。

(2)对比度降低效果

  调用模块,对比度系数contrast_val取1600时效果。