opencv暗通道圖像去霧(Mat風格代碼)

最近《數字圖像處理》課需要做圖像去霧的工作,然後我們百度了一下,找到下面的鏈接(主要的方法有圖像增強和圖像復原兩大類):

http://www.cspmag.cn/jscx/spjk/201406/1336.html

最終,我和隊友選擇了使用暗通道先驗的方法,我們參考的是下面的代碼:

http://blog.sina.com.cn/s/blog_4d8730df0100m8lz.html

上面的代碼是對何愷明博士Single Image Haze Removal Using Dark Channel Prior》 一文的實現,但是沒有使用soft matting,在最小值濾波以及求A的時候也有一些出入,我們直接跑了一下,大致的效果還行,但是代碼的風格是OpenCV1.0的風格,使用的是IplImage,我們決定將它改成OpenCV2.0風格的代碼,我們修改的代碼如下,具體的思路沒有改變:

我們使用的環境是VS2013+OpenCV3.1

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

#include<iostream>
#include<opencv2\opencv.hpp>


using namespace std;
using namespace cv;


string tbarname1 = "block:";
//定義兩個滑動條,用於調節參數
string tbarname2 = "w:";
//w是爲了保留一部分的霧
int block = 5;
int w1 = 95;
double w = (double)w1/100;
Mat src;
Mat dst;


//定義去霧函數如下
Mat haze_removal(Mat src, int block, double w)
{
//圖像分別有三個顏色通道
vector<cv::Mat>dst(src.channels());
Mat imgROI1;
//dst[0]的ROI
Mat imgROI2;
//dst[1]的ROI
Mat imgROI3;
//dst[2]的ROI
Mat darkROI;
//dark channel的ROI
Mat darkChannel;
//暗原色先驗
Mat imgTransmissivity;
//透射率


//去霧算法運算後的三個通道
Mat removalDst1;
Mat removalDst2;
Mat removalDst3;
//去霧後的圖像,三通道合併成
Mat dst3D;
//源圖像ROI位置以及大小
Rect ROI_rect;


//爲各個ROI分配內存
imgROI1 = Mat(block, block, CV_8UC1);
imgROI2 = Mat(block, block, CV_8UC1);
imgROI3 = Mat(block, block, CV_8UC1);
darkROI = Mat(block, block, CV_8UC1);


//爲removalDst1 removalDst2 removalDst3分配大小
removalDst1 = Mat(src.rows, src.cols, CV_8UC1);
removalDst2 = Mat(src.rows, src.cols, CV_8UC1);
removalDst3 = Mat(src.rows, src.cols, CV_8UC1);


//爲暗原色先驗分配大小
darkChannel = Mat(src.rows, src.cols, CV_8UC1);
//爲透射率分配大小
imgTransmissivity = Mat(src.rows, src.cols, CV_8UC1);
//dst3D分配大小
dst3D = Mat(src.rows, src.cols, CV_8UC3);
//將原彩色圖像分離成三通道
split(src, dst);
//求暗原色
ROI_rect.width = block;
ROI_rect.height = block;
ROI_rect.x = 0;
ROI_rect.y = 0;




int i;
int j;
double min1 = 0;
double max1 = 0;
double min2 = 0;
double max2 = 0;
double min3 = 0;
double max3 = 0;
double min = 0;
for (i = 0; i<src.cols / block; i++)
{
for (j = 0; j<src.rows / block; j++)
{
//分別計算三個通道內ROI的最小值
imgROI1 = dst[0](ROI_rect);
minMaxIdx(imgROI1, &min1, &max1);
imgROI2 = dst[1](ROI_rect);
minMaxIdx(imgROI2, &min2, &max2);
imgROI3 = dst[2](ROI_rect);
minMaxIdx(imgROI3, &min3, &max3);
//求三個通道內最小值的最小值
if (min1<min2)
min = min1;
else
min = min2;
if (min>min3)
min = min3;//min爲這個ROI中暗原色
//min賦予darkChannel中相應的ROI
darkROI = darkChannel(ROI_rect);
Mat tmp = Mat(block, block, CV_8UC1, Scalar(min));
tmp.copyTo(darkROI);
//轉入下一個ROI
ROI_rect.x = block*i;
ROI_rect.y = block*j;
}
}
//保存暗原色先驗的圖像
imwrite("F:\\My_Desktop\\Haze_Removal\\darkChannel.jpg", darkChannel);
//利用得到的暗原色先驗dark_channel_prior.jpg求大氣光強
double minDark;
double maxDark;
int minLoc[2] = { 255, 255 };
int maxLoc[2] = { 255, 255 };//maxLoc是暗原色先驗最亮一小塊的原座標
minMaxIdx(darkChannel, &minDark, &maxDark, minLoc, maxLoc);
cout << maxLoc[1] << " " << maxLoc[0] << endl;
ROI_rect.x = maxLoc[1];
ROI_rect.y = maxLoc[0];
double dst1A;//定義大氣光成分的估計值
double minDst1;
double dst2A;
double minDst2;
double dst3A;
double minDst3;

//按照論文方法求大氣光強估計值
imgROI1 = dst[0](ROI_rect);
minMaxIdx(imgROI1, &minDst1, &dst1A);
imgROI2 = dst[1](ROI_rect);
minMaxIdx(imgROI2, &minDst2, &dst2A);
imgROI3 = dst[2](ROI_rect);
minMaxIdx(imgROI3, &minDst3, &dst3A);
cout << dst1A << " " << dst2A << " " << dst3A << endl;//這三值爲大氣光強度估計值
//求透射率
int k;
int l;
uchar m;
uchar n;//暗原色先驗各元素值


for (k = 0; k<src.rows; k++)
{
for (l = 0; l<src.cols; l++)
{
m = darkChannel.at<uchar>(k, l);
n = 255 - w * m;
//w目的是保留一部分的霧,使圖像看起來真實些
imgTransmissivity.at<uchar>(k, l) = n;
}
}
imwrite("F:\\My_Desktop\\Haze_Removal\\imgTransmissivity.jpg", imgTransmissivity);


//求無霧圖像
int p, q;
double tx;
uchar srcB, srcG, srcR;
CvScalar ix, jx;
for (p = 0; p<src.rows; p++)
{
for (q = 0; q<src.cols; q++)
{
tx = imgTransmissivity.at<uchar>(p, q);
tx = tx / 255;
if (tx<0.1)
tx = 0.1;
srcB = (src.at<Vec3b>(p, q)[0] - dst1A) / tx + dst1A;//根據霧產生模型運算,還原出無霧圖像
srcG = (src.at<Vec3b>(p, q)[1] - dst2A) / tx + dst2A;
srcR = (src.at<Vec3b>(p, q)[2] - dst3A) / tx + dst3A;
dst3D.at<Vec3b>(p, q)[0] = srcB;
dst3D.at<Vec3b>(p, q)[1] = srcG;
dst3D.at<Vec3b>(p, q)[2] = srcR;
}
}
imwrite("F:\\My_Desktop\\Haze_Removal\\removed_haze.jpg", dst3D);
return dst3D;
}


void on_trackbar1(int h,void *pt)
{
dst = haze_removal(src, block, w);
imshow("目的圖像", dst);
}
void on_trackbar2(int h,void *pt)
{
w = (double)w1 / 100;
dst = haze_removal(src, block, w);
imshow("目的圖像", dst);
}
//主函數如下
void main()
{
//打開圖像
src = imread("F:\\My_Desktop\\Haze_Removal\\wu-035.jpg");
//創造窗口
namedWindow("有霧圖像", CV_WINDOW_AUTOSIZE);
imshow("有霧圖像", src);
namedWindow("目的圖像", CV_WINDOW_AUTOSIZE);
createTrackbar(tbarname1, "目的圖像", &block, 15, on_trackbar1);
createTrackbar(tbarname2, "目的圖像", &w1, 100, on_trackbar2);
waitKey(0);
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章