【圖像處理】暗通道去霧c++

【圖像處理】暗通道去霧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;
}

效果還沒不錯的,有時間再改進下。

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