黑电平校正原理及长曝光校正方案浅析

黑电平产生的原因

传感器受到材质、热量和外部干扰等因素的影响,即使没有光照射,像素单元也会产生电荷,形成暗电流。暗电流很难与光照产生的电荷区分开来。

黑电平是指图像数据为“0”时对应的信号电平。由于暗电流的影响,传感器实际输出的原始数据并不是我们想要的黑平衡(数据不为“0”)。

黑电平校正原理

为了减少暗电流对图像信号的影响,可以采用一种有效的方法,即从已获得的图像信号中减去参考暗电流信号。通常情况下,在传感器中,实际像素比有效像素多,像素区的前几行被用作不感光区(实际上,这部分区域也使用了RGB的彩色滤波器),用于自动黑电平校正。校正值的平均值被用作参考值,然后下面区域的像素都减去这个校正值,从而实现黑电平校正。

没有进行黑电平校正的图像通常整体或局部会偏紫色(品红),过度校正的图像整体或局部会偏绿色。黑电平校正的缺失也会影响图像的对比度。

关于黑电平(Black Level)的概念

Black Level Subtraction(BLS)黑电平减法

Black Level Clamping(BLC)黑电平箝位

Linearization(LZ)线性化

Off Bit(OB)在数字电子系统中,通常使用二进制编码来表示数据,其中"1"表示高电平或开启状态,而"0"表示低电平或关闭状态。因此,当电信号处于低电平时,人们也称之为"OB"或"黑电平"。

以上概念所代表的含义和处理流程不完全相同,一般提到时都属于黑电平校正的概念和范畴。

黑电平校正方法

以高通平台为例,在ISP流程中,sensor output后,进行黑电平校正,工具根据导入的raw图,分别将R,Gr,Gb,B 四个通道减去计算出的校正值(4个通道的校正值可能略有不同,总体比较接近),然后再进行AWB校正。

通常,经过这样的校正后,会得到比较理想的效果。如图:

在特定条件下,以上方案存在缺陷。例如:

①当需要较大的gain值(如512x gain以上)时,A gain和D gain不能满足,需要叠加ISP gain,高gain区间校正值敏感度过高,可调性变差,很难平衡正常光和全黑环境的效果。

如图,正常光效果趋于平衡,但全黑偏紫;此时如果再增加扣除黑电平强度,全黑效果会更好,但正常光环境暗区会偏绿。

②当需要长曝光时,此时由于长曝光期间由暗电流累积引起的暗电压(OB)上升没有被OB箝位补偿,并且OB没有被足够地扣除,导致整体偏紫,品红色浮动。

长曝光方案浅析

上面我们简析了高通平台黑电平校正的机制,即在AWB校正前,先进行黑电平的校正,将R,Gr,Gb,B 四个通道减去校正值。这样的方案不能满足长曝光时黑电平的校正需求。我们不妨再来分析一下信号处理流程。

通过流程的组合和拆解可以看出,在WB校正的前或后,可以获取动态的OB钳制值,将其写入处理的流程中,这样即便是长曝光,既可以保留部分暗信号,理论上又可以实现正常的颜色和白平衡效果。

动态调整方案的实现

在开篇的时候我们提到,黑电平校正使用到了非有效像素的区域,即Optical Black,我们将这个控制分成3个步骤:

任务(1):计算传感器Optical Black区域(8行)中R、Gr、Gb和B的平均值

① 获取图像数据:从传感器读取原始图像数据(RAW数据)。

② 定义OB区域:确定传感器图像中光学黑区域的位置和大小。通常,光学黑区域位于图像的顶部或底部。例如,假设OB区域是图像顶部的8行。

③ 提取OB区域数据:从图像数据中提取前8行的OB区域数据。

④ 分离颜色通道:根据Bayer阵列将OB区域的数据按颜色通道(R、Gr、Gb、B)分离。Bayer阵列中颜色通道排列如下:

                                       R  Gr

                                       Gb B

每4个像素组成一个Bayer单元,依次提取每个颜色通道的数据。

⑤ 计算平均值:分别计算R、Gr、Gb和B通道的平均值。

python代码示例:

import numpy as np

def calculate_ob_averages(image, ob_lines=8):

ob_region = image[:ob_lines, :]  # 提取前8行的OB区域

height, width = ob_region.shape

# 分离颜色通道

R_channel = ob_region[0:height:2, 0:width:2]

Gr_channel = ob_region[0:height:2, 1:width:2]

Gb_channel = ob_region[1:height:2, 0:width:2]

B_channel = ob_region[1:height:2, 1:width:2]

# 计算各通道的平均值

R_avg = np.mean(R_channel)

Gr_avg = np.mean(Gr_channel)

Gb_avg = np.mean(Gb_channel)

B_avg = np.mean(B_channel)

return R_avg, Gr_avg, Gb_avg, B_avg

# 示例用法

# 假设 raw_image 是从传感器获取的RAW图像数据

# R_avg, Gr_avg, Gb_avg, B_avg = calculate_ob_averages(raw_image)

任务(2):为(1)中的值计算多个帧的平均值(例如,32帧、LiveView、Movie only)

① 初始化存储器:创建一个存储器来保存每个帧的OB平均值。

② 累积帧数据:循环处理每一帧,计算并存储每一帧的OB平均值。

③ 计算多帧平均值:在累积了一定数量(例如32帧)的数据后,计算每个通道的多帧平均值。

python代码示例:

def calculate_multi_frame_averages(frames, num_frames=32):

R_avgs = []

Gr_avgs = []

Gb_avgs = []

B_avgs = []

for frame in frames[:num_frames]:

R_avg, Gr_avg, Gb_avg, B_avg = calculate_ob_averages(frame)

R_avgs.append(R_avg)

Gr_avgs.append(Gr_avg)

Gb_avgs.append(Gb_avg)

B_avgs.append(B_avg)

# 计算多个帧的平均值

R_multi_avg = np.mean(R_avgs)

Gr_multi_avg = np.mean(Gr_avgs)

Gb_multi_avg = np.mean(Gb_avgs)

B_multi_avg = np.mean(B_avgs)

return R_multi_avg, Gr_multi_avg, Gb_multi_avg, B_multi_avg

# 示例用法

# 假设 frames是一个包含32帧RAW图像数据的列表

# R_multi_avg,Gr_multi_avg,Gb_multi_avg, B_multi_avg = calculate_multi_frame_averages(frames)

任务(3):实时校正传感器钳制值与(2)的差值

① 获取实时帧数据:从传感器获取实时帧。

② 计算当前帧的OB平均值:使用(1)中的方法计算当前帧的R、Gr、Gb和B通道的OB平均值。

③ 计算差值:将当前帧的OB平均值与(2)中计算的多帧平均值进行比较,计算差值。

④ 应用校正:根据差值调整当前帧的钳制值。

python代码示例:

def correct_frame_with_ob_diff(current_frame, multi_frame_avgs):

R_avg, Gr_avg, Gb_avg, B_avg = calculate_ob_averages(current_frame)

R_multi_avg, Gr_multi_avg, Gb_multi_avg, B_multi_avg = multi_frame_avgs

# 计算差值

R_diff = R_avg - R_multi_avg

Gr_diff = Gr_avg - Gr_multi_avg

Gb_diff = Gb_avg - Gb_multi_avg

B_diff = B_avg - B_multi_avg

# 钳制值校正(根据实际需要调整校正公式)

corrected_frame = current_frame.copy()

corrected_frame[:, :] -= (R_diff + Gr_diff + Gb_diff + B_diff) / 4

return corrected_frame

# 示例用法

# 假设 current_frame 是当前实时帧,multi_frame_avgs 是多帧平均值

# corrected_frame = correct_frame_with_ob_diff(current_frame, (R_multi_avg, Gr_multi_avg, Gb_multi_avg, B_multi_avg))

以上步骤完成了计算OB区域平均值、多帧平均值和实时校正传感器钳制值的过程。具体的实现可能需要根据传感器和系统的具体情况进行调整和优化。

  • 11
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
电平校正可以通过FPGA实现,以下是一个基于Verilog的电平校正程序的实现流程: 1. 读取图像数据: 将传感器采集到的图像数据存储在内存中,通过FPGA读取内存中的图像数据。 2. 计算电平: 通过计算图像像素点的灰度值,找到图像中的点区域,将点区域的像素灰度值加起来,求出这些像素的平均灰度值,即为电平。 3. 校正图像数据: 将图像数据中的每个像素值减去电平值,得到校正后的图像数据。可以通过一次遍历校正完整个图像。 4. 存储校正后的数据: 将校正后的图像数据存储在内存中,或者输出到显示器等外设上。 需要注意的是,在FPGA实现电平校正时,需要考虑算法的复杂度和FPGA资源的限制。同时,需要对算法进行优化,使其在FPGA上实现的速度和效率更高。以下是一个基于Verilog的电平校正的代码示例: ```verilog module black_level_correction(clk, rst, data_in, data_out); input clk, rst; input [11:0] data_in; // 输入的原始图像数据 output [11:0] data_out; // 输出的校正后的图像数据 reg [11:0] black_level; reg [11:0] corrected_data; reg [11:0] data_in_reg; reg correction_done; always @(posedge clk or negedge rst) begin if (rst == 0) begin black_level <= 0; data_in_reg <= 0; corrected_data <= 0; correction_done <= 0; end else begin data_in_reg <= data_in; if (correction_done == 0) begin // 如果还没完成校正 if (black_level == 0) begin // 如果还没计算电平,计算电平 if (/* 判断当前像素是否为点 */) begin black_level <= black_level + data_in_reg; // 累加像素值 end else if (/* 判断点区域是否计算完成 */) begin black_level <= black_level / /* 点像素数量 */; // 计算平均像素值 end end else begin // 如果已经计算电平,进行校正 corrected_data <= data_in_reg - black_level; // 校正像素值 correction_done <= 1; // 标记校正完成 end end else begin // 如果已经完成校正 corrected_data <= data_in_reg - black_level; // 直接输出校正后的像素值 end end end assign data_out = corrected_data; endmodule ``` 在实际应用中,需要根据具体的传感器和图像数据格式进行适当的修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值