日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【camera】【ISP】Lens Shading Correction镜头阴影校正

發布時間:2023/12/14 编程问答 73 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【camera】【ISP】Lens Shading Correction镜头阴影校正 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

ISP-LSC 鏡頭陰影校正

參考:

  • https://zhuanlan.zhihu.com/p/389334269
  • https://blog.csdn.net/xiaoyouck/article/details/77206505
  • https://www.cnblogs.com/wnwin/p/11805901.html
  • http://kb.colorspace.com.cn/kb/2022/09/05/isp-%E9%95%9C%E5%A4%B4%E9%98%B4%E5%BD%B1%E6%A0%A1%E6%AD%A3%EF%BC%88lsc%EF%BC%89/

  • LSC(Lens Shading Correction)鏡頭陰影校正。

    Shading細分為Lens Shading(Luma Shaing)和Color Shading(chrom Shading)。

    1. Shading產生原因及影響

    由于Lens的光學特性,sensor影像區的邊緣區域接收的光強比中心小,造成中心和四角亮度不一致的現象,并且鏡頭本身是一個凸透鏡,由于凸透鏡的原理,中心的感光必然比周邊多。

    如下圖,綠色和藍色的光強在進入鏡頭前是一致的,由于Lens的特性,在邊緣的綠色光線會有一部分被遮擋,sensor邊緣部分能捕捉到的光信號就比較少;

    另外由于綠色部分光線經過的距離比較長,光的衰減也要比藍色部分的衰減大,也導致了到達邊緣部分的光信號的強度弱;

    以上來自:https://zhuanlan.zhihu.com/p/389334269

    Lens Shading會造成圖像邊角偏暗,即暗角。

    color Shading

    各種顏色的波長不同,經過透鏡折射后,折射的角度也不一樣,就會造成color Shading的現象,另外由于CRA的原因也會導致shading現象,如下:

    Color Shading 中心和四周顏色不一致,表現出來一般是中心或者四周偏色。

    2. Shading校正-LSC

    在ISP Pipeline中,Shading一般在OB和DPC后面。另外需要注意,如果3A的統計數據是在shading校正之后獲取的,那么shading校正結果會影響3A的統計數據。

    2.1 校正方法

    LSC校正目前主流的方法有兩種:同心圓法和網格法。

    同心圓法:

  • 找到RGB三通道的圓心;

  • 以同心圓的形狀將畫面的中心和畫面的邊緣的三通道乘以不同的增益。

    如下圖,一般考慮shading漸變的曲率從中心到邊緣逐漸增大,所以等增益曲線中心稀疏,邊緣密集。一般lens shading增益最好不要超過2倍,因為這會引入噪聲。

  • 網格法:

    也叫做mesh shading correction,把整幅圖像分成m*n個網格,然后針對網格頂點求出校正的增益,然后把這些頂點的增益儲存到內存中,其它點的增益通過插值的方式求出。

    比如圖像分成如下的網格:

    如下圖是每個網格的亮度分布,這里有一個cos4θcos^{4}\thetacos4θ的關系。

    針對上面的亮度求出的增益圖如下:

    cos4θcos^{4}\thetacos4θ的函數如下:

    同心圓校正方法的優點是計算量小,缺點是鏡頭若裝配時稍有不對稱則校正失敗–這個方法可以通過先找到圖像的實際中心,然后以實際中心為圓點去校正。

    網格法的優點是能夠應對各種shading情況,缺點是運算量大。

    網格法校正代碼流程:

  • 整張raw圖像分為四通道;
  • 對四通道圖像劃分為m*n個網格,并求出每個網格的均值;
  • 根據每個網格均值求出該網格對應的增益;
  • 根據得到的增益再利用插值算法得到每個像素校正后的值;
  • template <typename T> bool lsc(const T *src, T *dst, int width, int height) {// 拆分為四通道int sub_width = width / 2;int sub_height = height / 2;T *pr, *pb, *pgr, *pgb;pr = new T[sub_width * sub_height];pb = new T[sub_width * sub_height];pgr = new T[sub_width * sub_height];pgb = new T[sub_width * sub_height];if (!pr || !pb || !pgr || !pgb){printf("allocate channel buf failed!\n");return false;}memset(pr, 0, sizeof(pr[0]) * sub_width * sub_height);memset(pb, 0, sizeof(pb[0]) * sub_width * sub_height);memset(pgr, 0, sizeof(pgr[0]) * sub_width * sub_height);memset(pgb, 0, sizeof(pgb[0]) * sub_width * sub_height);general::raw_split_to_4channel(src, pr, pgr, pgb, pb, width, height);// 整張圖像劃分為17*13 block,并獲取平均值int grid_width, grid_height; //每個網格的像素個數const int Nx = 17; // 網格個數 Nx*Nyconst int Ny = 13;const int nx = Nx + 1;const int ny = Ny + 1;grid_width = floor(sub_width * 1.0 / (Nx));grid_height = floor(sub_height * 1.0 / (Ny));float rave[Ny + 1][Nx + 1],grave[Ny + 1][Nx + 1],gbave[Ny + 1][Nx + 1],bave[Ny + 1][Nx + 1];memset(rave, 0, sizeof(rave));memset(grave, 0, sizeof(grave));memset(gbave, 0, sizeof(gbave));memset(bave, 0, sizeof(bave));int sx, sy, ex, ey;sx = sy = ex = ey = 0;for (int i = 0; i <= Ny; i++){for (int j = 0; j <= Nx; j++){sx = j * grid_width - grid_width / 2;ex = j * grid_width + grid_width / 2;sy = i * grid_height - grid_height / 2;ey = i * grid_height + grid_height / 2;if (i == Ny && ey != sub_height)ey = sub_height;if (j == Nx && ex != sub_width)ex = sub_width;sx = sx < 0 ? 0 : sx;sy = sy < 0 ? 0 : sy;rave[i][j] = general::get_average_roi(pr, sub_width, sx, sy, ex, ey);grave[i][j] = general::get_average_roi(pgr, sub_width, sx, sy, ex, ey);gbave[i][j] = general::get_average_roi(pgb, sub_width, sx, sy, ex, ey);bave[i][j] = general::get_average_roi(pb, sub_width, sx, sy, ex, ey);}}// 獲取每個通道的均值最大值float max[4] = {0, 0, 0, 0};for (int i = 0; i <= Ny; i++){for (int j = 0; j <= Nx; j++){max[0] = (max[0] < rave[i][j] ? rave[i][j] : max[0]);max[1] = (max[1] < grave[i][j] ? grave[i][j] : max[1]);max[2] = (max[2] < gbave[i][j] ? gbave[i][j] : max[2]);max[3] = (max[3] < bave[i][j] ? bave[i][j] : max[3]);}}// 計算每個通道的增益float rgain[ny][nx], grgain[ny][nx],gbgain[ny][nx], bgain[ny][nx];memset(rgain, 0, sizeof(rgain));memset(grgain, 0, sizeof(grgain));memset(gbgain, 0, sizeof(gbgain));memset(bgain, 0, sizeof(bgain));for (int i = 0; i <= Ny; i++){for (int j = 0; j <= Nx; j++){rgain[i][j] = max[0] / float(rave[i][j]);grgain[i][j] = max[1] / float(grave[i][j]);gbgain[i][j] = max[2] / float(gbave[i][j]);bgain[i][j] = max[3] / float(bave[i][j]);}}// 計算最終值float gaintmp = 0;int gainx, gainy;gainx = gainy = 0;int tmp_grid_width, tmp_grid_height;int tmp_x, tmp_y;float tmp = 0;int curgain = 0;T *prdst, *pbdst, *pgrdst, *pgbdst;prdst = new T[sub_width * sub_height];pbdst = new T[sub_width * sub_height];pgrdst = new T[sub_width * sub_height];pgbdst = new T[sub_width * sub_height];if (!prdst || !pbdst || !pgrdst || !pgbdst){printf("allocate channel buf failed!\n");return false;}memset(prdst, 0, sizeof(prdst[0]) * sub_width * sub_height);memset(pbdst, 0, sizeof(pbdst[0]) * sub_width * sub_height);memset(pgrdst, 0, sizeof(pgrdst[0]) * sub_width * sub_height);memset(pgbdst, 0, sizeof(pgbdst[0]) * sub_width * sub_height);tmp = 0;for (int y = 0; y < sub_height; y++){for (int x = 0; x < sub_width; x++){gainy = floor(float(y) / grid_height);gainy = (gainy > Ny - 1) ? (Ny - 1) : gainy;gainx = floor(float(x) / grid_width);gainx = (gainx > Nx - 1) ? (Nx - 1) : gainx;// if (x == 2103 && y == 1557)// tmp = 1;// 插值得到每個像素校正后的值// f(x,y) = [f(1,0)-f(0,0)]*x +// [f(0,1) - f(0,0)]*y +// [f(1,1)+f(0,0)-f(0,1)-f(1,0)]*xy +// f(0,0)gaintmp = (rgain[gainy][gainx + 1] - rgain[gainy][gainx]) * (x - gainx * grid_width) / grid_width +(rgain[gainy + 1][gainx] - rgain[gainy][gainx]) * (y - gainy * grid_height) / grid_height +(rgain[gainy + 1][gainx + 1] + rgain[gainy][gainx] - rgain[gainy + 1][gainx] - rgain[gainy][gainx + 1]) * (x - gainx * grid_width) / grid_width * (y - gainy * grid_height) / grid_height +rgain[gainy][gainx];prdst[x + y * sub_width] = T(float(pr[x + sub_width * y]) * gaintmp);gaintmp = (grgain[gainy][gainx + 1] - grgain[gainy][gainx]) * (x - gainx * grid_width) / grid_width +(grgain[gainy + 1][gainx] - grgain[gainy][gainx]) * (y - gainy * grid_height) / grid_height +(grgain[gainy + 1][gainx + 1] + grgain[gainy][gainx] - grgain[gainy + 1][gainx] - grgain[gainy][gainx + 1]) * ((x - gainx * grid_width) / grid_width) * ((y - gainy * grid_height) / grid_height) +grgain[gainy][gainx];pgrdst[x + y * sub_width] = T(float(pgr[x + sub_width * y]) * gaintmp);gaintmp = (gbgain[gainy][gainx + 1] - gbgain[gainy][gainx]) * (x - gainx * grid_width) / grid_width +(gbgain[gainy + 1][gainx] - gbgain[gainy][gainx]) * (y - gainy * grid_height) / grid_height +(gbgain[gainy + 1][gainx + 1] + gbgain[gainy][gainx] - gbgain[gainy + 1][gainx] - gbgain[gainy][gainx + 1]) * ((x - gainx * grid_width) / grid_width) * ((y - gainy * grid_height) / grid_height) +gbgain[gainy][gainx];pgbdst[x + y * sub_width] = T(float(pgb[x + sub_width * y]) * gaintmp);gaintmp = (bgain[gainy][gainx + 1] - bgain[gainy][gainx]) * (x - gainx * grid_width) / grid_width +(bgain[gainy + 1][gainx] - bgain[gainy][gainx]) * (y - gainy * grid_height) / grid_height +(bgain[gainy + 1][gainx + 1] + bgain[gainy][gainx] - bgain[gainy + 1][gainx] - bgain[gainy][gainx + 1]) * ((x - gainx * grid_width) / grid_width) * ((y - gainy * grid_height) / grid_height) +bgain[gainy][gainx];pbdst[x + y * sub_width] = T(float(pb[x + sub_width * y]) * gaintmp);}}// 合并rawgeneral::channels4_to_raw(dst, prdst, pgrdst, pgbdst, pbdst, width, height);return true; }

    校正后效果:

    總結

    以上是生活随笔為你收集整理的【camera】【ISP】Lens Shading Correction镜头阴影校正的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。