簡介
在接觸過的qcom和mtk平台中,camera調試軟件和流程基本都是大同小異。所以查了點資料,然后模仿這些軟件,自己練習寫了下最開始的 兩步:暗電流和len shading補償。
基本原理
產生原因
在camera模組中,會因為sensor本身的暗電流,從而對圖像參數噪聲。同時也會因為模組鏡頭的原因,導致拍攝照片的亮度,中間亮而四周相對較暗。 所以在模組工作中,我們需要對模組做暗電流的校正和len shading相關的補償。對這方面深入的了解,請自己查詢相關資料吧,這里只簡單講解下。
校正補償原理
理解到了暗電流和len shading產生原因之后,就可以通過如下步驟開始進行校正。 暗電流校正:1、用黑膠布遮住攝像頭,然后在全黑環境下拍攝一張全尺寸的照片。 2、軟件讀取並保存住這張圖片的值,這里面非0的值,都是由sensor的暗電流產生的噪點,當對照片處理的時候, 需要減去這些對應的噪聲。 lenshading補償:1、用毛玻璃蓋住模組,在燈箱下拍攝一張照片。正常情況下,可以看到照片是中心亮,而四周相對較暗。 2、將拍攝的照片通過處理,找出照片中最亮位置的亮度,然后用這個亮度為基准,記錄下整個圖片中,每個像素位置亮度和 這個亮度的比值。當對照片處理的時候,對應像素位置乘以這個比值。
具體實現
框架搭建
根據前面一篇提到的《opencv模擬button》,構建出了基本軟件背景界面和三個操作按鍵。分別對應為暗電流、len shading補償、圖片處理。 效果如下:
軟件的運行如下:./XXX darkcurrent.jpg lenshading.jpg tmp.jpg darkcurrent.jpg:拍攝的暗電流照片。 lenshading.jpg:拍攝的len shading照片。 tmp.jpg:需要被處理的照片。
功能實現
所以我們需要關心的就是那三個控件對應的事件處理功能。
void on_button(int buttonNow, Mat img){ if(buttonNow == 0){ doDarkCurrent(img); }else if(buttonNow == 1){ lenrollOff(img); }else if(buttonNow == 2){ pic_process(img); } buttonFlag[buttonNow] = true; }
暗電流
void doDarkCurrent(Mat mat){ IplImage pI = mat; IplImage pI_2 = img3; int width = mat.rows; int height = mat.cols; CvScalar s; int i, j; double b_count = 0, g_count = 0, r_count = 0; for(i=0; i<height; i++){ for(j=0; j<width; j++){ s = cvGet2D(&pI, j, i); cvSet2D(&pI_2, j, i, s); } } }
實現很簡單,就是將darkcurrent.jpg的照片數據保存到img3中,作為暗電流操作的操作數據。
lenshading補償
void lenrollOff(Mat img){ int *address; double maxLight; address = (int *)malloc(2); IplImage pI = img; getMaxLight(img, address, &maxLight); /* 找到圖像中最亮的點位置,address為最亮點所在的坐標 */ lenShading(maxLight, img, img4); }
img對應為傳入的lenshading.jpg。首先通過函數getMaxLight,建立一個8X8的矩陣,然后該圖片中從頭到尾計算出矩陣包圍的圖片區域亮度, 並找出最高的位置和對應平均亮度。 接着使用函數lenShading,計算出圖片所有像素和上一步得到的最大亮度之間比值,對應的保存在img4中。
效果演示
使用步驟:1、運行軟件:./xxx ./res/dark.jpg ./res/lenoff.jpg ./res/1.jpg 2、依次點擊控件:darkcurrent lenrolloff process。 3、最后效果如下:
圖片處理
在第一步和第二步處理完了之后,接着就可以進行第三步的圖片處理。
void pic_process(Mat img){ imshow("poc_process", img); /*process for DarkCurrent*/ proDark(img); /*process for lenrollOff*/ prolenOff(img); imshow("prolenOff", img); }
這一步中,首先顯示出來,需要被處理的照片,也就是之前傳入的tmp.jpg。接着使用proDark來減去暗電流產生的噪點。接着使用函數prolenOff進行 圖片lenshading的補償,最后將處理后的圖片也顯示出來。
void proDark(Mat img){ int width = img.rows; int height = img.cols; IplImage pI = img; int i, j; CvScalar s, s1; IplImage pI_2 = img3; int start_Haddr = img3.cols / 2 - height / 2; int end_Haddr = img3.cols / 2 + height / 2; int start_Waddr = img3.rows / 2 - width / 2; int end_Waddr = img3.rows / 2 + width / 2; if((width > img3.rows) || (height > img3.cols)){ printf("proDark is error!!!!!!\n"); return; } for(i=start_Haddr; i < end_Haddr; i++){ for(j = start_Waddr; j < end_Waddr; j++){ s = cvGet2D(&pI_2, j, i); s1 = cvGet2D(&pI, j - start_Waddr, i - start_Haddr); s1.val[0] = s1.val[0] - s.val[0]; s1.val[1] = s1.val[1] - s.val[1]; s1.val[2] = s1.val[2] - s.val[2]; cvSet2D(&pI, j - start_Waddr, i - start_Haddr, s1); } } }
在傳入的處理圖片中,如果是被sensor裁剪過的話,那就從暗電流保存數據的中心開始,計算出和處理照片同樣大小的數據,然后處理照片再依次 減去對應的暗電流噪聲數據。
void prolenOff(Mat img){ int width = img.rows; int height = img.cols; IplImage pI = img; IplImage pI_2 = img4; int i, j; CvScalar s, s1; cvCvtColor(&pI, &pI, CV_RGB2YCrCb); if((width > img4.rows) || (height > img4.cols)){ printf("prolenOff is error!!!!!!\n"); return; } int start_Haddr = img4.cols / 2 - height / 2; int end_Haddr = img4.cols / 2 + height / 2; int start_Waddr = img4.rows / 2 - width / 2; int end_Waddr = img4.rows / 2 + width / 2; for(i=start_Haddr; i < end_Haddr; i++){ for(j = start_Waddr; j < end_Waddr; j++){ s = cvGet2D(&pI_2, j, i); s1 = cvGet2D(&pI, j - start_Waddr, i - start_Haddr); s1.val[0] = s1.val[0] * s.val[0] / 50; cvSet2D(&pI, j - start_Waddr, i - start_Haddr, s1); } } cvCvtColor(&pI_2, &pI_2, CV_YCrCb2RGB); cvCvtColor(&pI, &pI, CV_YCrCb2RGB); }
len shading補償也是一樣,根據處理圖片大小,從補償數據的中心開始,取出相應大小的數據,然后將圖片對應轉化為YCrCb,根據補償值從新調整 權重,接着將圖像轉換會RGB圖像。
效果演示
使用步驟:1、運行軟件:./xxx ./res/dark.jpg ./res/lenoff.jpg ./res/1.jpg 2、依次點擊控件:darkcurrent lenrolloff process。 3、最后效果如下:
代碼下載:http://download.csdn.net/detail/u011630458/8691453