本文是isp算法学习的第二篇章,主要是讲述BLC原理和算法。

1产生原因

通常使用的CMOS或者CCD的Sensor。而CMOS就是MOS管,学过模拟电路的应该知道,MOS管(光电管)本质就是PN结。

1.1暗电流

左边的图是二极管的图,CMOS的PN结工作范围是反向,即UB到O的这段。在反向截止的区域里面,没有光照,依然存在电压,虽然电压的值非常小。这段区域就会产生暗电流,暗电流一般跟载流子的扩散和制造工艺相关。

理论上应该是0,0,0的输出,但是由于暗电流的存在,经过光电转换之后就会存在类似5,5,6的输出。

1.2AD前增加一个固定值

另外,由于AD模数转换前,会在模拟信号前加上一个固定的电压值,保证AD转换在精度范围内。

2校正方法

当前的主流方法有两种,sensor端和isp段。

2.1Sensor端

sensor端主要跟芯片相关

上图可以看到,有效的像素区域是3280*2464,底下灰色的区域为OB区域(Sensor预留了一些完全没有曝光的像素)。当整个Sensor处理完全黑暗环境,OB区域每个像素也会有一个值。

最简单的方法,就是对OB区取个平均值,然后让所有有效像素区减去这个值(模拟信号的值)即可。

其他算法可以查看这个专利。

2.2isp端

2.2.1固定值

本身有四个通道GR,GB,R,B通道。由于开始会在AD前增加一个固定值,这个时候把这个减掉即可。相当于区域往下平移C(C指的是固定值的偏移量),但是发现区域往下移动,整个区域就为0~(255-C)。我们这个时候会对两个G通道进行运算处理 $$ G_{in} = \frac{255}{255 - \Delta{C}} $$ 校正完成后,就能恢复到0~255的范围。

这里不对R和B通道处理,后面pipeline的AWB内容,会对其进行RGain和BGain的操作。

2.2.2ISO联动

黑电平直接和曝光增益相关联。(RK目前用的也是这个方式)

本身曝光增益跟曝光时间有关,曝光时间会影响温度,而温度也会间接影响到暗电流。通过曝光的倍数来减去对应的数值取平均也可以对其进行校正。

2.2.3曲线拟合

到isp端的RAW图,每个像素点的值都不是相同的值,选取一定数量的样本点,每个样本点需要包含四个通道GR,GB,R,B,然后对样本点的周围进行拟合。

2.3总结

目前固定值的方式是最普遍的,代价也是最小的。

其余两种方式或是存表或是联动,都需要一定的内存开销。

3方法实现

盖上镜头盖或者处于全黑的环境下,抓取Raw图,四个通道的值因为存在暗电流和固定值,所以必定存在一个值。

1)分成四个通道

2)每个通道求mean值(或者中位值),求得△R,△GR,△GB,△B

3)RAW图上的每个像素点所在的通道,减去对应通道的平均值即可,就能大致恢复到RGB(0,0,0)

上面的左边那张图,显示有一定的值,经过BLC之后,就是最右的图,显示的值都趋于为0,且图片颜色会更加黑。

3.1效果展示

3.2Raw图信息

1% ------------Raw Format----------------
2filePath = 'images/HisiRAW_4208x3120_8bits_RGGB.raw';
3bayerFormat = 'RGGB';
4row = 4208;
5col = 3120;
6bits = 8;
7% --------------------------------------

3.3 读取Raw矩阵

1%  I(1:2:end, 1:2:end) = R(1:1:end, 1:1:end);
2
3data = readRaw(filePath, bits, row, col);

readRaw

 1function rawData = readRaw(fileName, bitsNum, row, col)
 2% readRaw.m    get rawData from HiRawImage
 3%   Input:
 4%       fileName    the path of HiRawImage 
 5%       bitsNum      the number of bits of raw image
 6%       row         the row of the raw image
 7%       col         the column of the raw image
 8%   Output:
 9%       rawData     the matrix of raw image data
10%   Instructions:
11%       author:     wtzhu
12%       e-mail:     wtzhu_13@163.com
13% Last Modified by wtzhu v1.0 2021-06-29
14% Note: 
15
16% get fileID
17fin = fopen(fileName, 'r');
18% format precision
19switch bitsNum
20    case 8
21        disp('bits: 8');
22        format = sprintf('uint8=>uint8');
23    case 10
24        disp('bits: 10');
25        format = sprintf('uint16=>uint16');
26    case 12
27        disp('bits: 12');
28        format = sprintf('uint16=>uint16');
29    case 16
30        disp('bits: 16');
31        format = sprintf('uint16=>uint16');
32end
33% 转换成列向量
34I = fread(fin, row*col, format);
35%转换成1维矩阵
36% plot(I, '.');
37z = reshape(I, row, col);
38z = z';
39rawData = z;
40% imshow(z);
41end
  • 判断是8bit,10bit,12bit还是16bit的值
  • 转换成列向量
  • 转换成一维矩阵

3.4分成四个通道

根据R|GR|GB|B的排布方式,分成四个通道

 1% get the four channels by bayerFormat
 2switch bayerFormat
 3    case 'RGGB'
 4        disp('bayerFormat: RGGB');
 5        R = data(1:2:end, 1:2:end);
 6        Gr = data(1:2:end, 2:2:end);
 7        Gb = data(2:2:end, 1:2:end);
 8        B = data(2:2:end, 2:2:end);
 9    case 'GRBG'
10        disp('bayerFormat: GRBG');
11        Gr = data(1:2:end, 1:2:end);
12        R = data(1:2:end, 2:2:end);
13        B = data(2:2:end, 1:2:end);
14        Gb = data(2:2:end, 2:2:end);
15    case 'GBRG'
16        disp('bayerFormat: GBRG');
17        Gb = data(1:2:end, 1:2:end);
18        B = data(1:2:end, 2:2:end);
19        R = data(2:2:end, 1:2:end);
20        Gr = data(2:2:end, 2:2:end);
21    case 'BGGR'
22        disp('bayerFormat: BGGR');
23        B = data(1:2:end, 1:2:end);
24        Gb = data(1:2:end, 2:2:end);
25        Gr = data(2:2:end, 1:2:end);
26        R = data(2:2:end, 2:2:end);
27end

3.5计算每个通道均值

 1% calculate the Correction coefficient of every channel
 2R_mean = round(mean(mean(R)));
 3Gr_mean = round(mean(mean(Gr)));
 4Gb_mean = round(mean(mean(Gb)));
 5B_mean = round(mean(mean(B)));
 6
 7% Correct each channel separately
 8cR = R-R_mean;
 9cGr = Gr-Gr_mean;
10cGb = Gb-Gb_mean;
11cB = B-B_mean;
12fprintf('R:%d Gr:%d Gb:%d B:%d\n', R_mean, Gr_mean, Gb_mean, B_mean);
13
14cData = zeros(size(data));

3.6四个通道还原到Raw图

 1% Restore the image with four channels
 2switch bayerFormat
 3    case 'RGGB'
 4        disp('bayerFormat: RGGB');
 5        cData(1:2:end, 1:2:end) = cR(1:1:end, 1:1:end);
 6        cData(1:2:end, 2:2:end) = cGr(1:1:end, 1:1:end);
 7        cData(2:2:end, 1:2:end) = cGb(1:1:end, 1:1:end);
 8        cData(2:2:end, 2:2:end) = cB(1:1:end, 1:1:end);
 9    case 'GRBG'
10        disp('bayerFormat: GRBG');
11        cData(1:2:end, 1:2:end) = cGr(1:1:end, 1:1:end);
12        cData(1:2:end, 2:2:end) = cR(1:1:end, 1:1:end);
13        cData(2:2:end, 1:2:end) = cB(1:1:end, 1:1:end);
14        data(2:2:end, 2:2:end) = cGb(1:1:end, 1:1:end);
15    case 'GBRG'
16        disp('bayerFormat: GBRG');
17        cData(1:2:end, 1:2:end) = cGb(1:1:end, 1:1:end);
18        cData(1:2:end, 2:2:end) = cB(1:1:end, 1:1:end);
19        cData(2:2:end, 1:2:end) = cR(1:1:end, 1:1:end);
20        cData(2:2:end, 2:2:end) = cGr(1:1:end, 1:1:end);
21    case 'BGGR'
22        disp('bayerFormat: BGGR');
23        cData(1:2:end, 1:2:end) = cB(1:1:end, 1:1:end);
24        cData(1:2:end, 2:2:end) = cGb(1:1:end, 1:1:end);
25        cData(2:2:end, 1:2:end) = cGr(1:1:end, 1:1:end);
26        cData(2:2:end, 2:2:end) = cR(1:1:end, 1:1:end);
27end

3.7展示效果

 1function show(orgData, corData, bitsNum, mean)
 2% show.m    Data visualization
 3%   Input:
 4%       orgData     the org img data 	 
 5%       corData     the corrected data of img
 6%       bitsNum      the count of bits
 7%   Output:
 8%   Instructions:
 9%       author:     wtzhu
10%       e-mail:     wtzhu_13@163.com
11% Last Modified by wtzhu v1.0 2021-06-30
12% Note: 
13    yMax = 2^bitsNum;
14    listOrgData = orgData(:);
15    listCorData = corData(:);
16    figure;
17    subplot(221);
18    
19    imshow(orgData);
20    title('orgDta');
21    subplot(222);
22    
23    imshow(uint8(corData));
24    title('corData');
25    subplot(223)
26    
27    plot(listOrgData(listOrgData<(mean+10)))
28    title('org pixel value');
29    ylim([-10 yMax]);
30    subplot(224);
31    
32    plot(listCorData(listCorData<(yMax*10/255)));
33    title('cor pixel value');
34    ylim([-10 yMax]);
35end

源码查看

可以点击这里