问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

ISP算法之黑电平BLC校正

创作时间:
作者:
@小白创作中心

ISP算法之黑电平BLC校正

引用
CSDN
1.
https://blog.csdn.net/qq_46144191/article/details/144568056

黑电平校正是图像信号处理(ISP)中的一个重要环节,主要用于消除传感器在无光条件下产生的暗电流影响,从而提高图像质量。本文将详细介绍黑电平的形成原因、校正方法及其在实际应用中的具体实现。

黑电平形成原因

Sensor本身问题

CMOS Sensor本身的电路会存在暗电流(dark current),在没有光照条件下,感光器件等也会存在流动的电流,在光敏二极管器的伏安特性曲线中反向截止区电流并不为零(如下图)。导致在Sensor遮黑状态下光电转换输出的电压不是零,且这个暗电流与温度、电压稳定性、曝光时间(按行来计算)、模拟增益都有关系且不同的位置暗电流一般是不同的。如果这个暗电流比较大,在拍摄正常图像的时候就会有色差。

曝光时间:非全局曝光的CMOS Sensor(卷帘曝光Rolling Shutter),曝光控制是以行为单位进行的(最小单位为行),在对1行进行曝光前,需将其reset(清0),然后等待一段时间(曝光时间,以行为单位),再读取这1行,读完这1行才算曝光完毕,在下一次reset之前,这些行处于自由曝光状态。因此曝光时间越长,暗电流积攒的越多。

模拟增益:在上述CMOS Sensor构造中,有一个AMP(amplifier),也就是放大器,这个放大器是用于控制模拟增益的,因此模拟增益越大,暗电流增益也会越大

并且对于Bayer滤光片来说,四个通道(R、Gr、Gb、B)的这个暗电流值也有可能是不一样的

AD转换过程添加的固定值

在CMOS Sensor中有一个ADC模数转换过程,目的是将光电感应的模拟电压转换为10/12/14位的数字信号(RAW10//RAW12/RAW14),而AD芯片都会有一个灵敏度,当电压低于这个阈值的时候无法进行AD转换,从而导致暗态细节损失。所以通常会在ADC模数转换之前添加一个稳定的参考电压REF,使整体信号值放大,有效保留了电压值很小的暗部细节,使得低于阈值部分的电压也能被转换。而这个固定的REF电压模数转换后是一个固定的偏移,对于Bayer图像的四个通道来说应该是一样的。因此这个值一般在ISP端减去固定值即可,一般厂家会给出,没给出就得自己标定了,且不一定准,因为由于暗电流引起的黑电平存在不好确定。

黑电平BLC校正

通常Sensor端的黑电平在Sensor端已经处理好了,例如下列OV5640手册给出的像素阵列。

在感光阵列中会有一片遮黑区域(光学暗区OB区域),这些区域镀的膜是不透光的,通过该区域可以统计出当前Bayer四个通道的暗电流值,遮黑区域与其他正常的像素区域经过相同的曝光时间和模拟增益后经过ADC后会有一个BLC数值,后续将正常像素区域的值减去遮黑区域的均值(分通道进行)合并为一路即可。如下OV5640手册中描述:

而在后续ISP中,只需要减去为了AD转换而认为添加的一个固定偏移即可(我自己使用的Mate30拍摄出来的DNG RAW图给出的这个值四个Bayer通道值都是256,是RAW12 RGGB格式的)。

当然也有的CMOS Sensor这些遮黑区域的值也是可以读出的,这就需要在ISP端同时对这两种黑电平进行处理,处理算法也可以自行设计。

其他的方法参考文末其他优秀的博客,这里 不过多解释。

MATLAB仿真

%raw_image:输入RAW
%Bayer_Pattern:RAW格式
%width:宽度
%height:高度
%BITS:RAW像素深度
%blacklevel:黑电平值
function  raw_out = blc(raw_image, Bayer_Pattern, width, height, BITS, blacklevel)
raw_image = int32(raw_image);   %涉及减法需要转为有符号数
raw_out = zeros(height,width);
% raw_out = raw_image - blacklevel;
for row = 1:height
    for col =1:width
        pix_tmp = raw_image(row,col) - blacklevel;  %对四个通道减去的固定值都相同
        if(pix_tmp<0)
            raw_out(row,col) = 0;    %钳位为0
        else
            raw_out(row,col) = pix_tmp;
        end
    end
end
end  

Verilog设计

/*************************************************************************
    > File Name: isp_blc.v
 ************************************************************************/
`timescale 1 ns / 1 ps
/*
 * ISP - Black Level Correction
 */
module isp_blc
#(
    parameter BITS = 8,
    parameter WIDTH = 1280,
    parameter HEIGHT = 960,
    parameter BAYER = 0 //0:RGGB 1:GRBG 2:GBRG 3:BGGR
)
(
    input pclk,
    input rst_n,
    input [BITS-1:0] black_r,    //黑电平参数
    input [BITS-1:0] black_gr,
    input [BITS-1:0] black_gb,
    input [BITS-1:0] black_b,
    input in_href,
    input in_vsync,
    input [BITS-1:0] in_raw,
    output out_href,
    output out_vsync,
    output [BITS-1:0] out_raw
);
    reg odd_pix;     //奇偶列判断
    always @ (posedge pclk or negedge rst_n) begin
        if (!rst_n)
            odd_pix <= 0;
        else if (!in_href)
            odd_pix <= 0;
        else
            odd_pix <= ~odd_pix; 
    end
    
    reg prev_href;
    always @ (posedge pclk or negedge rst_n) begin
        if (!rst_n) 
            prev_href <= 0;
        else
            prev_href <= in_href;
    end	
    
    reg odd_line;    //奇偶行判断
    always @ (posedge pclk or negedge rst_n) begin
        if (!rst_n) 
            odd_line <= 0;
        else if (in_vsync)
            odd_line <= 0;
        else if (prev_href & (~in_href))
            odd_line <= ~odd_line;
        else
            odd_line <= odd_line;
    end
    wire [1:0] format = BAYER[1:0] ^ {odd_line, odd_pix}; //pixel format 0:[R]GGB 1:R[G]GB 2:RG[G]B 3:RGG[B]
    reg [BITS-1:0] raw_now;
    assign out_raw = raw_now;
    always @ (posedge pclk or negedge rst_n) begin          //该模块仅需一个时钟周期的延时
        if (!rst_n) 
            raw_now <= 0;
        else
            raw_now <= blc_sub(in_raw, format);
    end
    
    //该模块仅占用一个时钟周期,控制信号也打一拍对齐时序
    reg href_now, vsync_now;
    always @(posedge pclk) href_now <= in_href;
    always @(posedge pclk) vsync_now <= in_vsync;
    assign out_href = href_now;
    assign out_vsync = vsync_now;
    //该函数减去黑电平,且保证输出值不小于0(产生负数会回滚)
    function [BITS-1:0] blc_sub;
        input [BITS-1:0] value;
        input [1:0] format;//0:R 1:Gr 2:Gb 3:B
        case (format)
            2'b00: blc_sub = value > black_r ? value - black_r : {BITS{1'b0}};       
            2'b01: blc_sub = value > black_gr ? value - black_gr : {BITS{1'b0}};
            2'b10: blc_sub = value > black_gb ? value - black_gb : {BITS{1'b0}};
            2'b11: blc_sub = value > black_b ? value - black_b : {BITS{1'b0}};
            default: blc_sub = {BITS{1'b0}};
        endcase
    endfunction
endmodule

需要注意的是:

当Black Level值扣除过少时,整体图像画面灰蒙蒙的,整画面对比度没有那么高,画面偏亮偏粉。

当Black Level值扣除过多时,整体画面暗沉沉,动态范围变低细节损失多,黑色部分偏色无法通过白平衡纠正,画面偏绿(黑电平是加性参数,而白平衡增益是乘性参数)。

如有任何问题,欢迎大家批评指正!!!

参考

黑电平校正(BLC-Black Level Correction)-CSDN博客

ISP——BLC(Black Level Correction)_blc为什么在dpc之前-CSDN博客

ISP之黑电平矫正 - 知乎

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号