what is the LSC?

lens shading 分为:Y-shading , color shading。

在讲LSC之前,我们先来理解一个重要的术语--CRA(Chief ray angle)。

CRA:分为lens cra , sensor cra两种。

1.1什么是lens CRA?

定义:最大像高处的主光线与光轴的倾角。备注:最大像高定义为 像素响应降低为零度角像素响应的80%的像素点。

因为Lens CRA 的存在,所以就出现了FOV (filed of view) 所谓的视角的概念。视角大小=2*CRA。

下图为lens CRA示意图。

1.2 什么是sensor的CRA

               sensor的CRA 说白了是sensor与之配对的micro lens的CRA.

圈1 表示lens折射过来的光,圈2表示micro lens再次折射的光。可以看出,sensor的光电转换二极管接收到的光并不是                 lens直接折射过来的,而是经过microlens再次折射过来的。所以你明白了什么呢?! 这也就是为什么图像边缘会变暗                   的原因,光电转换二极管并不会全部接收到光能。这是LensShading中Y-shading的主要原因。

一般情况下,当lens_cra < micro_cra的时候,在sensor传感器的边缘只会出现Y-shading。

倘若,lens_cra > micro_cra, sensor传感器可能会因为无法有效捕捉某频率的光,就会出现偏色的情况,即Color-                          shading。比如microlens 对R ,G,B的折射率不同,在R_pixel上接收了很小的能量,而在B_pixel上接受了相对较多的能                  量。

如何处理或者叫减轻shading带来的图像不均问题呢?

              1.lens cra要小于micro cra,这样既可以减缓y-shading,又可以大大避免color-shading.

              2.因为镜头是圆的,画面的对角线是最接近镜头成像直径的,所以sensor有效区域最大尺寸是对角线尺寸

3.硬件矫正

4.软件矫正(下面会细讲)

how to LSC with software?

一般模组厂会根据矫正工具将图像划分为17*13(qualcomm),15*15(MTK),33*25(Samsung)等区间,计算每一块的四通道平均值,然后对每个通道与中心块的四通道平均值做除法,得到每个点的增益倍数,整个lut存储在otp中,手机端就可以根据lut进行插值计算每个pixel的增益。

一般用双线性差值或者多项式拟合的方法,确定每个pixel的增益。

原始图片的rgb通道(节选自网络):

y-shading 增益之后,基本与中心数值在同一个平面(节选自网络):

color-shading 增益之后,各区域的r/g,b/g均值相同(节选自网络):

上面三张图片为了让大家理解,节选自网络。本人也模拟了shading矫正过程,但由于colorshading不严重所以矫正效果不明显。下面是我的矫正过程:

1.原始图:

2.三通道三维图

3.(17*13block)r,g,b平均

4.colorgain

5、lensgain=ygain+colorgain

6. 还原后三通道值

7.还原后图片

附上我的代码:

clc
clear all;
close all;
BLOCK_H = 17
BLOCK_V = 13
img = imread('1.bmp');
r= medfilt2(img(:,:,1));%中值滤波抑制边缘凸起噪声
g= medfilt2(img(:,:,2));
b= medfilt2(img(:,:,3));
figure(1)
[rows,cols,channels] = size(img);
width = 1:cols; height = 1:rows; [X1,Y1] = meshgrid(width,height);
mesh(X1,Y1,im2double(r)); hold on; mesh(X1,Y1,im2double(g)); hold on; mesh(X1,Y1,im2double(b));

subSampleRGB=ones(BLOCK_V+1,BLOCK_H+1,3);%6*6*3 gainlut

strideX=floor(cols/BLOCK_H)
strideY=floor(rows/BLOCK_V)
for i=1:BLOCK_H+1%cols
    for j=1:BLOCK_V+1%rows
        for k=1:3%channels
            if i==1
                if j==1%left_top
                   subSampleRGB(j,i,k)=mean2( img(1:floor(strideY*0.5),                                1:floor(strideX*0.5),k) );
                elseif j==BLOCK_V+1 %left_bottom
                   subSampleRGB(j,i,k)=mean2( img(floor((BLOCK_V-0.5)*strideY):BLOCK_V*strideY,        1:floor(strideX*0.5),k) );
                else %left_middle
                   subSampleRGB(j,i,k)=mean2( img(floor((j-1-0.5)*strideY):floor((j-1+0.5)*strideY),   1:floor(strideX*0.5),k) );
                end
            elseif i==BLOCK_H+1
                if j==1%right_top
                   subSampleRGB(j,i,k)=mean2( img(1:floor(strideY*0.5),                                floor(strideX*(BLOCK_H-0.5)):BLOCK_H*strideX,k) );
                elseif j==BLOCK_V+1 %right_bottom
                   subSampleRGB(j,i,k)=mean2( img(floor((BLOCK_V-0.5)*strideY):BLOCK_V*strideY,        floor(strideX*(BLOCK_H-0.5)):BLOCK_H*strideX,k) );
                else %right_middle
                   subSampleRGB(j,i,k)=mean2( img(floor((j-1-0.5)*strideY):floor((j-1+0.5)*strideY),        floor(strideX*(BLOCK_H-0.5)):BLOCK_H*strideX,k) );
                end
            elseif j==1%top without corner
                if i~=1&&i~=BLOCK_H+1
                    subSampleRGB(j,i,k)=mean2( img(1:floor(0.5*strideY),                               floor(strideX*(i-1-0.5)):floor(strideX*(i-1+0.5)),k) );
                end
            elseif j==BLOCK_V+1%bottom without corner
                if i~=1&&i~=BLOCK_H+1
                    subSampleRGB(j,i,k)=mean2( img(floor((BLOCK_V-0.5)*strideY):BLOCK_V*strideY,       floor(strideX*(i-1-0.5)):floor(strideX*(i-1+0.5)),k));
                end
            else
                if i~=1&&i~=BLOCK_H+1&&j~=1&&j~=BLOCK_V+1 %center area
                    subSampleRGB(j,i,k)=mean2( img(floor((j-1-0.5)*strideY):floor((j-1+0.5)*strideY),  floor(strideX*(i-1-0.5)):floor(strideX*(i-1+0.5)),k));
                end
            end
        end
    end
end

figure(2)
[A,B] = meshgrid(1:BLOCK_H+1,1:BLOCK_V+1);
mesh(A,B,subSampleRGB(:,:,1));
hold on
mesh(A,B,subSampleRGB(:,:,2));
hold on
mesh(A,B,subSampleRGB(:,:,3));

%Gainlut luma gain (Y-shading gain)
gainlut=zeros(BLOCK_V+1,BLOCK_H+1,3);% gainlut
for i = 1:BLOCK_H+1
    for j =1:BLOCK_V+1
        for k = 1:3
           gainlut(j,i,k)=mean2( subSampleRGB(floor(BLOCK_V/2+1) : floor(BLOCK_V/2+1)+1,  floor(BLOCK_H/2+1) : floor(BLOCK_H/2+1)+1,k)) / subSampleRGB(j,i,k);
        end
    end
end

%Gainlut chroma gain (colorshading gain)
gainlut_c = zeros(BLOCK_V+1,BLOCK_H+1,2);
center_RoverG = mean2( subSampleRGB(floor(BLOCK_V/2+1) : floor(BLOCK_V/2+1)+1,  floor(BLOCK_H/2+1) : floor(BLOCK_H/2+1)+1,1)) / mean2( subSampleRGB(floor(BLOCK_V/2+1) : floor(BLOCK_V/2+1)+1,  floor(BLOCK_H/2+1) : floor(BLOCK_H/2+1)+1,2));
center_BoverG = mean2( subSampleRGB(floor(BLOCK_V/2+1) : floor(BLOCK_V/2+1)+1,  floor(BLOCK_H/2+1) : floor(BLOCK_H/2+1)+1,3)) / mean2( subSampleRGB(floor(BLOCK_V/2+1) : floor(BLOCK_V/2+1)+1,  floor(BLOCK_H/2+1) : floor(BLOCK_H/2+1)+1,2));
for i = 1:BLOCK_H+1
    for j =1:BLOCK_V+1
           RoverG = subSampleRGB(j,i,1)/subSampleRGB(j,i,2);
           BoverG = subSampleRGB(j,i,3)/subSampleRGB(j,i,2);
           gainlut_c(j,i,1) = center_RoverG/RoverG-1;
           gainlut_c(j,i,2) = center_BoverG/BoverG-1;
    end
end

%chroma+luma gain
gainlut_full = zeros(BLOCK_V+1,BLOCK_H+1,2);
for i = 1:BLOCK_H+1
    for j =1:BLOCK_V+1
           gainlut_full(:,:,1) = gainlut(:,:,1) + gainlut_c(j,i,1);
           gainlut_full(:,:,2) = gainlut(:,:,2) + gainlut_c(j,i,2);
    end
end

%(BLOCK_H+1)*(BLOCK_V+1) colorgain
figure(3)
[C,D] = meshgrid(1:BLOCK_H+1,1:BLOCK_V+1);
mesh(C,D,gainlut_c(:,:,1))
hold on
mesh(C,D,gainlut_c(:,:,2))

figure(4)
mesh(C,D,gainlut_full(:,:,1))
hold on
mesh(C,D,gainlut_full(:,:,2))
hold on
mesh(C,D,gainlut(:,:,2))

%双线性插值FullGainLut
x = 1:strideX:cols+1;
x(end) = cols;
y = 1:strideY:rows+1;
y(end) = rows;

xitp = 1:cols;
yitp = 1:rows;
[Xitp,Yitp]=meshgrid(xitp,yitp);
rgain=interp2(x,y,gainlut(:,:,1),Xitp,Yitp);
ggain=interp2(x,y,gainlut(:,:,2),Xitp,Yitp);
bgain=interp2(x,y,gainlut(:,:,3),Xitp,Yitp);

%shading r,b,g gain
figure(5)
r=im2uint8( (im2double(r).*rgain) );
mesh(X1,Y1,im2double(r));
b=im2uint8( (im2double(b).*bgain) );
hold on
mesh(X1,Y1,im2double(b));
g=im2uint8( (im2double(g).*ggain) );
hold on
mesh(X1,Y1,im2double(g));

%shading corrected img
figure(6)
lscgain = cat(3,rgain,ggain,bgain);%merge三通道gain
imgDoubleType = im2double(img);
imgDoubleType = imgDoubleType.*lscgain;
imgUint = im2uint8(imgDoubleType);
imshow(imgUint)

ISP PIPLINE (二) LensShading Correct的更多相关文章

  1. ISP PIPLINE (六) 3A 综述

    前言: 上一篇文章: ISP PIPLINE (五) Denoise 下一篇文章: (1)3A定义包括什么 Iris:自动光圈,根据环境自动调节光圈. 既然讲到光圈,就先看一下光圈是什么,以及它如何影 ...

  2. ISP PIPLINE (十四) AE(自动曝光)

    自动曝光可以可以通过调节 模拟增益,数字增益,曝光时间,光圈大小来调剂曝光. 曝光在ISP PIPLINE的位置. (先介绍一个额外的知识点: ) gamma compression(也就是de-ga ...

  3. ISP PIPLINE(零) 知识综述预热

    本文为camera isp pipline概述 ISP,即image signal processing.为图像成型做的处理工作.适应不同光学环境下图像的还原. pipline流程如下: 光通过LEN ...

  4. ISP PIPLINE (十二) Sharpening

    什么是sharpening? 不解释,从左到右为sharpen , 从右到左为blur. 简单理解为边缘增强,使得轮廓清晰.增强对比度. 如何进行sharpening? 下面是实际sharpen的过程 ...

  5. ISP PIPLINE (七) gamma

    what is the gamma? CCD.CMOS成像方式是通过像点中的"硅"感受光线的强弱而获得画面.而硅感光是物理成像,它真实地反应光线强度的变化,来多少就输出多少,因此它 ...

  6. ISP PIPLINE (一) BLC 以及 线性化

    what is the BlackLevel? 暗电流来源1.raw8为例,单个pixel的有效值是0~255,但是实际AD芯片的精度可能无法将电压值很小的一部分转换出来,芯片厂会刻意添加一个固定的偏 ...

  7. ISP PIPLINE (十五) AF

    主流的AF: CDAF, PDAF, laser assist AF(这个只是辅助,在微距或者拍摄纹理不明显的场景下好用). AF的大致原理就是检测图像锐度或者等价于锐度的参数,推动马达实现合焦或者对 ...

  8. ISP PIPLINE (九_2) Denoise 之 time domain denoise

    时域噪声是空域噪声在时间上波动的一种描述. 1.多帧平均去噪法 1.1 理论: 1.2 帧数增加,噪声减小: 1.3 IIR滤波器的效果 2.1中的两种方法在拍摄视频的时候,如果有运动物体,则会出现拖 ...

  9. ISP PIPLINE (九_1) Denoise 之 space domain denoise

    1.空间域噪声类型 1.gauss+possion 2.椒盐噪声(dpc处理已经处理了) 去除空域噪声有哪些方法? 空域噪声一般的思想是对某pixel邻域的pixels进行加权平均. 比如 1.高斯降 ...

随机推荐

  1. Help Me Escape ZOJ - 3640

    Background     If thou doest well, shalt thou not be accepted? and if thou doest not well, sin lieth ...

  2. GWAS分析基本流程及分析思路

    数据预处理(DNA genotyping.Quality control.Imputation) QC的工作可以做PLINK上完成Imputation的工作用IMPUTE2完成 2. 表型数据统计分析 ...

  3. 批量ping 检测linux主机是否可以通

    批量ping 检测linux主机是否可以通 # 1.配置列表 [root@db137 liweiwie]# cat /home/dbatlbb/script/liweiwie/ping_ip.txt ...

  4. jmeter将上一个接口返回值作为下一个接口的请求参数

    在jmeter中有时候会用到,将上一个接口的返回值作为下一个接口的请求参数 具体操作如下: 1.首先新建一个http请求(右键线程组--添加Sampler--http请求),同时添加好接口相应的请求参 ...

  5. pkuseg:一个多领域中文分词工具包

    pkuseg简单易用,支持细分领域分词,有效提升了分词准确度. 目录 主要亮点 编译和安装 各类分词工具包的性能对比 使用方式 相关论文 作者 常见问题及解答 主要亮点 pkuseg具有如下几个特点: ...

  6. .net异步委托

    委托Delegate是一个类,定义了方法的类型, 使得可以将方法当做另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大佬使用If-Else(Switch)语句,同时使得程序 ...

  7. 用vim打开.py和.sh文件自动添加头

    在~/.vimrc文件最后一行添加 "auto add pyhton header --start autocmd BufNewFile *.py 0r ~/.vim/template/py ...

  8. Elasticsearch 6.4基本操作 - Java版

    1. Elasticsearch Java API有四类client连接方式 TransportClient RestClient Jest Spring Data Elasticsearch 其中T ...

  9. 一个QQ旋风的BUG

    本人喜欢用QQ旋风下载工具,很不幸的是这个工具BUG太多了. 下载不同COOKIE,相同文件名.URL的文件时候会QQ旋风崩溃. 感兴趣可以试下.

  10. Entity Framework查询

    Entity Framework是个好东西,虽然没有Hibernate功能强大,但使用更简便.今天整理一下常见SQL如何用EF来表达,Func形式和Linq形式都会列出来(本人更喜欢Func形式). ...