上次搞的暗通道去霧的算法交給老師就算是交差了泵喘,當(dāng)時(shí)也就是個(gè)調(diào)研而已。前幾天又被老師叫過去說還是需要720p(1280*720)圖像的實(shí)時(shí)處理般妙,看能不能再做一些優(yōu)化纪铺,讓我和一個(gè)職工商量著來,于是又看了兩天的去霧碟渺。還是有一些進(jìn)展鲜锚,總結(jié)一下。
回顧
還是可以回顧一下暗通道去霧的流程,在這里芜繁,其中這個(gè)模型是最重要的:
在這個(gè)模型中攒霹,要獲得的只有兩個(gè),一個(gè)是透射率圖t(x)浆洗,一個(gè)是大氣光值A(chǔ),大氣光值的獲得方法很多,包括暗通道去霧中找最亮的0.5%的最低值集峦,或者是有一個(gè)四叉樹尋找的方法:對(duì)比度暗通道去霧伏社,這片文章可以看做是對(duì)何凱明暗通道去霧的一個(gè)擴(kuò)展,對(duì)天空具有比較好的免疫性塔淤。作者說效果不錯(cuò)摘昌,好不容易調(diào)通給的代碼發(fā)現(xiàn)效果一般,而且算法比暗通道去霧還復(fù)雜一些高蜂,再就沒有細(xì)看聪黎。
透射率這里,何提出的導(dǎo)向?yàn)V波是不錯(cuò)的备恤,效果也還可以稿饰,但是實(shí)測(cè)下來還是這部分花費(fèi)了大部分時(shí)間,后來使用了先下采樣然后導(dǎo)向?yàn)V波之后再插值的快速算法露泊,速度上還是有瓶頸喉镰。
如果在這個(gè)去霧模型上要有所改進(jìn)的話,就只能是對(duì)透射率圖這里改進(jìn)了惭笑。
改進(jìn)
查資料的過程中發(fā)現(xiàn)一篇文章:一種可實(shí)時(shí)處理的圖像去霧算法的實(shí)現(xiàn),文中給出了算法的詳細(xì)步驟:
但說實(shí)話這個(gè)圖里面的公式寫的不太嚴(yán)謹(jǐn)侣姆,比如5式中的Mav應(yīng)該是要進(jìn)行歸一化的,其他的地方倒還容易理解沉噩,特別是5式這個(gè)透射率的求法簡(jiǎn)直不要太簡(jiǎn)潔啊捺宗,看了博客中作者給出的效果圖以及后面作者給的程序進(jìn)行測(cè)試,發(fā)現(xiàn)效果還是不錯(cuò)的,而且從算法復(fù)雜度上來看川蒙,是要比原始的暗通道去霧有些優(yōu)勢(shì)的蚜厉,最起碼沒有麻煩的導(dǎo)向?yàn)V波(導(dǎo)向?yàn)V波里有大量的求均值和濾波操作)。
然后就開始寫代碼派歌,先用python寫了一個(gè)版本弯囊,很快就寫完了斯撮,測(cè)試下來是要比暗通道去霧快一些寡夹,按照C++版本應(yīng)該比python版本提高近一倍的效率來說,是差不多可以到實(shí)時(shí)了勺美,于是就動(dòng)手寫了早抠。
這還是上周四的事情霎烙,周四晚上打球把腳崴了,周五腫了很大,自然是下不了樓就窩在宿舍里寫程序悬垃,雖然說OpenCv已經(jīng)提供了大量的API,寫起來還是沒有python順手游昼,主要是數(shù)據(jù)類型的轉(zhuǎn)換。
比如說如果要做除法的話肯定是要把數(shù)據(jù)轉(zhuǎn)換成float的尝蠕,不能用uchar來做烘豌,因?yàn)楫?dāng)時(shí)用的指針來寫的min_BGR函數(shù),如果要換乘float的話看彼,這里面的指針也都得改廊佩,用uchar類型的指針來訪問float的話肯定是要崩潰的。諸如此類的問題吧靖榕。
大概到晚上吃飯的時(shí)候就已經(jīng)完全調(diào)通了标锄,中間出了一個(gè)莫名其妙的問題卡了很久,貼在下面:
vector<Mat> Img_split_dehaze;
//Mat div_tmp;
for (int i = 0; i < 3; i++)
{
/*cv::divide(Fenzi[i], fenmu, div_tmp);
cout<<div_tmp;
Img_split_dehaze.push_back(div_tmp);*/
//一開始是注釋的這里錯(cuò)了茁计,從最前面一點(diǎn)一點(diǎn)檢查才發(fā)現(xiàn)料皇,不過不知道哪里有問題,改成new對(duì)象就可以了星压,神奇践剂!
Mat *tmp = new Mat;
cv::divide(Fenzi[i], fenmu, *tmp);
Img_split_dehaze.push_back(*tmp);
delete tmp;
}
我一開始使用的注釋掉的那一部分來做這個(gè)除法,然后儲(chǔ)存到vector<Mat>
里租幕,然后三次push_back進(jìn)去的竟然是同一個(gè)東西舷手,導(dǎo)致我最后merge的圖像就是灰度圖,一開始怎么著也沒發(fā)現(xiàn)這里有錯(cuò)誤(現(xiàn)在也不知道為什么錯(cuò)了劲绪,我在循環(huán)里cout出來分明是不一樣的)男窟。
后來對(duì)照著python里的結(jié)果一點(diǎn)點(diǎn)檢查才發(fā)現(xiàn)時(shí)這里的錯(cuò)誤,浪費(fèi)了很長(zhǎng)的時(shí)間贾富,不知道怎么處理就用new一個(gè)對(duì)象來做歉眷,就沒有問題了。
i5_7500cpu上大概可以跑打25fps了颤枪,筆記本上要慢2/5差不多汗捡。
算法的實(shí)現(xiàn)就差不多是這樣了,遍歷像素我還是用的at運(yùn)算符來做畏纲,畢竟最合乎習(xí)慣扇住,而且release模式下速度損失不大。
優(yōu)化
圖像算法層面的優(yōu)化就沒有什么了盗胀,基本上不存在可以優(yōu)化的地方艘蹋,但是還是有一些地方可以進(jìn)行優(yōu)化。主要做了有兩點(diǎn)票灰。
式5求min(Mat1,Mat2)
一開始使用了vector<Mat>
把兩個(gè)式子merge到一張二通道的圖里女阀,然后再調(diào)用函數(shù)MIN_BRG_32F()
(自己寫的)來做這個(gè)工作宅荤,我覺得vector的創(chuàng)建以及調(diào)用merge可能還是花費(fèi)了一些時(shí)間,于是直接來做浸策,于是變成了:
M_minfilter_32f = M_minfilter_32f*m;
int rows = M_minfilter_32f.rows;
int cols = M_minfilter_32f.cols;
Mat res = Mat::zeros(Size(cols,rows), CV_32FC1);
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
res.at<float>(i, j) = std::min(M_minfilter_32f.at<float>(i,j), M_min_32f.at<float>(i, j));
}
}
速度大概提升了10%吧冯键。
式7用查表法來做
這個(gè)改進(jìn)是實(shí)質(zhì)性的,這也是受了那篇博客中作者想法的啟發(fā)庸汗,用查表來做惫确,可以用查表法來做的基礎(chǔ)是:所有對(duì)應(yīng)的操作都是點(diǎn)對(duì)點(diǎn)的操作,而且H和L都是[0-255]
的uchar
類型蚯舱,另外還有一個(gè)參數(shù)A雕薪,是一個(gè)獨(dú)立的大氣光值,也是0-255的晓淀,所以我們可以做一個(gè)二維的查找表,一維是H的取值盏档,一維是L的取值凶掰。這樣的話就不用多次調(diào)用除法,只需要根據(jù)A來建立一個(gè)256*256
大小的查找表就可以了蜈亩。
查找表的建立: 我直接使用vector來做懦窘,索引起來也非常容易。
vector<vector<uchar>> Function7_table(const float &A)
{
vector<vector<uchar>> Table = vector<vector<uchar>>(256, vector<uchar>(256, 0));
//cout << Table.size() << endl;
double Value=0;
for (int Y = 0; Y < 256; Y++)
{
for (int X = 0; X < 256; X++)
{
Value = (Y - X) / (1 - X/A); //function_7
if (Value > 255)
Value = 255;
else if (Value < 0)
Value = 0;
Table[Y][X] = Value;
//printf("%d\t", Table[Y][X]); 這是個(gè)大坑稚配,cout輸出uchar的時(shí)候是按照ascii碼輸出的畅涂,一開始還以為不對(duì)
}
}
return Table;
}
索引的時(shí)候非常方便,對(duì)于一個(gè)H(x)和L(x)的元素來說道川,只需要按照對(duì)應(yīng)的位置來查找這個(gè)表就可以了:
vector<vector<uchar>> Table;
Table = Function7_table(A);
Mat ImgDefog = Img.clone();
int row_Num = ImgDark_32f.rows;
int col_Num = ImgDark_32f.cols;
//獲得行列
for (int i = 0; i < row_Num; i++)
{
for (int j = 0; j < col_Num; j++)
{
ImgDefog.at<Vec3b>(i, j)[0] = Table[Img.at<Vec3b>(i, j)[0]][int(Lx.at<float>(i, j))];
ImgDefog.at<Vec3b>(i, j)[1] = Table[Img.at<Vec3b>(i, j)[1]][int(Lx.at<float>(i, j))];
ImgDefog.at<Vec3b>(i, j)[2] = Table[Img.at<Vec3b>(i, j)[2]][int(Lx.at<float>(i, j))];
//處理三個(gè)通道
}
}
經(jīng)過測(cè)試午衰,速度有40%左右的提升,這樣的話實(shí)時(shí)應(yīng)該是很輕松的就可以達(dá)到了冒萄,查表果然是個(gè)好東西臊岸。
附一張效果圖:效果還可以。
代碼:FastDefog
我的博客即將搬運(yùn)同步至騰訊云+社區(qū)尊流,邀請(qǐng)大家一同入駐:https://cloud.tencent.com/developer/support-plan?invite_code=25kceejka15ww