【圖像處理】暗通道去霧c++
轉載請說明出處!
#include <string.h>
#include <memory>
#include <iostream>
#include <assert.h>
#include <opencv2/opencv.hpp>
class dark_del_fog{
public:
cv::Mat process(const cv::Mat& src, float w = 0.95)
{
cv::Mat dark = get_dark_channel_image(src);
float Ac = get_atmospheric_light(dark, 0.001);
cv::Mat min = get_Transmittance_image(src, Ac);
cv::Mat tx = cv::Mat::zeros(min.size(), CV_32FC1);
for(int r = 0; r < tx.rows; r++){
float* ptr = (float*)tx.data + r * tx.cols;
float* m_ptr = (float*)min.data + r * tx.cols;
for(int c = 0; c < tx.cols; c++){
float v = 1 - w*m_ptr[c];
if(v < 0.1) v = 0.1;
ptr[c] = v;
}
}
cv::Mat final_image = get_finals(src, Ac, tx);
return final_image;
}
protected:
cv::Mat get_dark_channel_image(const cv::Mat& src, int ksize = 30)
{
cv::Mat dark = cv::Mat::zeros(src.size(), CV_8UC1);
for(int r = 0; r < src.rows; r++)
for(int c = 0; c < src.cols; c++)
{
int min = 300;
auto iter = src.at<cv::Vec3b>(r,c);
for(int i = 0; i < 3; i++){
if(iter[i] < min)
min = iter[i];
}
dark.at<uchar>(r,c) = min;
}
cv::Mat structErode = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(ksize, ksize), cv::Point(-1,-1));
cv::erode(dark, dark, structErode);
return dark;
}
float get_atmospheric_light(const cv::Mat& dark, float coeff)
{
assert(dark.channels() == 1);
std::shared_ptr<int> histmaps(new int[256]);
int* hist = histmaps.get();
memset(hist, 0, sizeof(int)*256);
for(int r = 0; r < dark.rows; r++)
{
uchar* ptr = dark.data + r * dark.cols;
for(int c = 0; c < dark.cols; c++){
hist[ptr[c]]++;
}
}
int sum = 0;
int thr = coeff * dark.rows * dark.cols;
int sum2 = 0, nums;
for(int i = 255; sum < thr; i--){
nums = hist[i];
sum += nums;
if(sum >= thr){
nums = thr - (sum - nums);
sum = thr;
}
sum2 += i * nums;
}
return (float)sum2/sum;
}
cv::Mat get_Transmittance_image(const cv::Mat& src, float Ac)
{
cv::Mat dark = cv::Mat::zeros(src.size(), CV_32FC1);
for(int r = 0; r < src.rows; r++)
for(int c = 0; c < src.cols; c++)
{
float min = FLT_MAX;
auto iter = src.at<cv::Vec3b>(r,c);
for(int i = 0; i < 3; i++){
float val = iter[i] / Ac;
if(val < min) min = val;
}
dark.at<float>(r,c) = min;
}
cv::Mat structErode = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5), cv::Point(-1,-1));
cv::erode(dark, dark, structErode);
}
cv::Mat get_finals(const cv::Mat& src, float Ac, const cv::Mat& tx)
{
cv::Mat bgr[3];
bgr[0] = cv::Mat::zeros(src.size(), CV_8UC1);
bgr[1] = cv::Mat::zeros(src.size(), CV_8UC1);
bgr[2] = cv::Mat::zeros(src.size(), CV_8UC1);
uchar* bgr_ptr[3];
for(int r = 0; r < src.rows; r++){
float* ptr = (float*)tx.data + r * src.cols;
bgr_ptr[0] = (uchar*)bgr[0].data + r * src.cols;
bgr_ptr[1] = (uchar*)bgr[1].data + r * src.cols;
bgr_ptr[2] = (uchar*)bgr[2].data + r * src.cols;
for(int c = 0; c < src.cols; c++){
float v;
auto iter = src.at<cv::Vec3b>(r,c);
for(int i = 0; i < 3; i++)
{
v = (iter[i] - Ac) / ptr[c] + Ac;
bgr_ptr[i] = limit(v);
}
}
}
cv::Mat dst;
cv::merge(bgr, 3, dst);
return dst;
}
uchar limit(float val)
{
val = val < 0 ? 0 : val;
val = val > 255 ? 255 : val;
return (uchar)val;
}
}
int main()
{
cv::Mat src = cv::irmead("haze.jpg");
dark_del_fog delfog;
cv::Mat dst = delfog.process(src);
cv::imshow("fog.jpg", src);
cv::imshow("delfog.jpg", dst);
cv::waitKey(0);
return 0;
}
效果還沒不錯的,有時間再改進下。