#include "stdafx.h"
#include "DecreaseHazeControl.h"
#include "omp.h" // 多核编程

#include "histProject.h"
//#include "DarkChannelDehaze.h"

// 计算暗通道最大值:A_MAX
double GetDarkChannelMaxVal(const cv::Mat &img)
{
	try
	{
		// 输入有效性验证
		if (img.empty() == true || img.type() != 16 || img.cols <= 0 || img.rows <= 0)
		{
			return 0;
		}


		const int patch = 8;

		// 图像尺寸
		int imgWidth = img.cols;
		int imgHeight = img.rows;

		//  边界扩展图像
		cv::Mat Mid(imgHeight + 2 * patch, imgWidth + 2 * patch, CV_8UC3); 
		cv::copyMakeBorder(img, Mid, patch, patch, patch, patch, IPL_BORDER_REFLECT);

		// 暗通道图像
		cv::Mat DarkChannel(imgHeight, imgWidth, CV_8UC1);
		for (int i = 0; i < imgHeight; ++i)
		{
			for (int j = 0; j < imgWidth; ++j)
			{
				// 局部区域
				cv::Mat patchRegion = Mid(cv::Rect(j, i, 2 * patch, 2 * patch));

				// 通道分离
				std::vector<cv::Mat> planes;
				cv::split(patchRegion, planes);

				// 求取三个通道的最小值
				double minB = 0, minG = 0, minR = 0; 
				cv::minMaxLoc(planes[0], &minB);
				cv::minMaxLoc(planes[1], &minG);
				cv::minMaxLoc(planes[2], &minR);

				// 给暗通道复制
				double minVal = min(min(minB, minG), minR);
				DarkChannel.at<unsigned char>(i,j) = static_cast<unsigned char>(minVal);

				// 内存释放
				planes.clear();
			}
		}

		// 计算暗通道最大值
		double minDarkChannel = 0.0;
		double maxDarkChannel = 0.0;
		cv::minMaxLoc(DarkChannel, &minDarkChannel, &maxDarkChannel);

		// 释放暗通道图像
		DarkChannel.release();

		return maxDarkChannel;
	}
	catch(cv::Exception &e)
	{
		e.msg;
		return 0;
	}
	catch(...)
	{
		return 0;
	}
}


//求取三个通道中最小值,然后以最小值组成一幅灰度图
bool GetMinChannel(const cv::Mat &img, cv::Mat& dark)
{
	try
	{
		// 输入有效性判断
		if (img.empty() == true || img.type() != CV_8UC3)
		{
			return false;
		}

		std::vector<cv::Mat> planes;
		cv::split(img, planes);

		cv::min(planes[0], planes[1], dark);
		cv::min(planes[2], dark, dark);

		planes.clear();

		return true;
	}
	catch(cv::Exception &e)
	{
		e.msg;
		return false;
	}
	catch(...)
	{
		return false;
	}
}



// 计算图像V
bool GetImgV(const cv::Mat &MinChannel,const cv::Mat &Diff, const cv::Mat &Smooth, cv::Mat & DstV, double degree = 0.78)
{
	try
	{
		// 输入有效性判断

		// 1空值判断
		if (MinChannel.empty() == true || Diff.empty() == true || Smooth.empty() == true)
		{
			return false;
		}

		// 2图像类型判断
		if (MinChannel.type() != CV_8UC1 || Diff.type() != CV_8UC1 || Smooth.type() != CV_8UC1)
		{
			return false;
		}

		// 3图像尺寸判断
		if (MinChannel.cols <= 0 || MinChannel.cols != Diff.cols || Diff.cols != Smooth.cols || 
			MinChannel.rows <= 0 || MinChannel.rows != Diff.rows || Diff.rows != Smooth.rows)
		{
			return false;
		}

		if (degree < 0)
		{
			degree = 0;
		}
		else if (degree > 1)
		{
			degree = 1;
		}

		// 图像属性
		int ImgWidth = MinChannel.cols;
		int ImgHeight = MinChannel.rows;

		// 创建:DstV
		DstV.create(cv::Size(ImgWidth, ImgHeight), CV_8UC1);

		// DstV 检查
		if (DstV.empty() == true)
		{
			return false;
		}

		// 连续性判断以提高速度
		if (DstV.isContinuous())
		{
			ImgWidth *= ImgHeight;
			ImgHeight = 1;
		}

		// 计算DstV值
		for(int i = 0; i < ImgHeight; ++i)
		{
			const uchar* pMinChannel = MinChannel.ptr<uchar>(i);
			const uchar* pDiff = Diff.ptr<uchar>(i);
			const uchar* pSmooth = Smooth.ptr<uchar>(i);
			uchar* pDstV = DstV.ptr<uchar>(i);

			for(int j = 0; j < ImgWidth; ++j)   
			{ 
				double val = degree * max(uchar(min(uchar((*pMinChannel++) - (*pDiff++)), (*pSmooth++))), uchar(0));
				(*pDstV++) = static_cast<uchar>(val); 
			}
		}

		return true;
	}
	catch(cv::Exception &e)
	{
		e.msg;
		return false;
	}
	catch(...)
	{
		return false;
	}
}


// 获取无雾图像
bool GetHazeFreeImg(const cv::Mat& img, const cv::Mat &ImgV, double A_MAX, cv::Mat &HazeFree)
{
	try
	{
		// 输入有效性判断
		if (img.empty() == true || img.type() != CV_8UC3 || img.cols <= 0 || img.rows <= 0
			|| ImgV.empty() == true || ImgV.type() != CV_8UC1 || ImgV.cols <= 0 || ImgV.rows <= 0
			|| A_MAX < 0 || A_MAX > 255 || img.cols != ImgV.cols || img.rows != ImgV.rows)
		{
			return false;
		}

		// 图像尺寸
		int imgWidth = img.cols;
		int imgHeight = img.rows;

		// 创建输出图像
		HazeFree.create(imgHeight, imgWidth, CV_8UC3);
		if (HazeFree.empty() == true)
		{
			return false;
		}

#pragma omp parallel for
		for (int j = 0; j < imgWidth; ++j)
		{
			for (int i = 0; i < imgHeight; i++)
			{
				double V = ImgV.at<unsigned char>(i, j);
				cv::Vec3b vec = img.at<cv::Vec3b>(i, j);

				for (int k = 0; k < 3; k++)
				{
					double VAB = 0;
					if (V != A_MAX)
					{
						VAB = fabs(vec[k] - V)/(fabs(1 - V/A_MAX));
					}

					if (VAB > 255)
					{
						vec[k] = 255;
					}
					else
					{
						vec[k] = static_cast<unsigned char>(VAB);
					}
				}

				HazeFree.at<cv::Vec3b>(i, j) = vec;	
			}		
		}

		return true;
	}
	catch(cv::Exception &e)
	{
		e.msg;
		return false;
	}
	catch(...)
	{
		return false;
	}
}




//功能:图像去雾控制
//输入:	1. img 输入图像
//		    2. A_MAX  控制去雾效果, A_MAX < 0 时,自适应计算(特别耗时); 有效范围【0,255】,异常值自适应
//		    3. degree 控制去雾效果, 有效范围【0,1】,异常值自适应

//输出:	1. HazeFree 输出图像
//          2. 返回值:处理成功返回true,失败返回false
bool DeHazeImg(const cv::Mat &img, cv::Mat &HazeFree, double A_MAX, double degree)
{
	try
	{
		// 单通道 红外图像细节增强  作者:王家星
		if (img.type() == CV_8UC1)
		{
			if (A_MAX != 0)
			{
				// 高斯无约束
				return GNRHP(HazeFree,img, false);
			} 
			else
			{
				// 高斯约束
				return GRHP(HazeFree, img, true);
			}
		}
		else
		{
			// 王家星算法
			      // 三通道
			if (A_MAX < 0)
			{
				A_MAX = GetDarkChannelMaxVal(img);
			}
			
			if (A_MAX > 255)
			{
				A_MAX = 255;
			}
			
			cv::Mat Dark;
			cv::Mat Smooth;
			cv::Mat Diff;
			cv::Mat V;
			
			// 获取暗通道
			if (GetMinChannel(img, Dark) == false)
			{
				return false;
			}
			
			// 高斯模糊
			cv::GaussianBlur(Dark, Smooth, cv::Size(5, 5), 1.667);
			
			// 计算Diff
			cv::absdiff(Dark, Smooth, Diff);
			
			// 计算V
			if (GetImgV(Dark, Diff, Smooth, V, degree) == false)
			{
				return false;
			}  
			
			// 计算HazeFree
			if (GetHazeFreeImg(img, V, A_MAX, HazeFree) == false)
			{
				return false;
			}
			
			return true;
		}
	}
	catch(cv::Exception &e)
	{
		e.msg;
		return false;
	}
	catch(...)
	{
		return false;
	}
}

// ImgStru结构下的图像去雾控制

//功能:图像去雾控制
//输入:	1. src 输入图像结构体
//		    2. A_MAX  控制去雾效果, A_MAX < 0 时,自适应计算(特别耗时); 有效范围【0,255】,异常值自适应
//		    3. degree 控制去雾效果, 有效范围【0,1】,异常值自适应

//输出:	1. dst 输出图像结构体
//          2. 返回值:处理成功返回true,失败返回false
bool ImgStruDeHazeControl(ImgStru* src, ImgStru* dst, int A_MAX, double degree)
{
	try
	{
		// src dst 有效性验证
		if (src == NULL || dst == NULL || 
			src->ImgWidth <=0   ||
			src->ImgHeight <= 0 ||
			src->buff == NULL)
		{
			return false;
		}


		// 属性复制
		dst->ImgWidth = src->ImgWidth;
		dst->ImgHeight = src->ImgHeight;
		dst->bitcount = src->bitcount;
		dst->BoundingBox = src->BoundingBox;

		// 构建输入、输出图像
		cv::Mat src_Img; // 

		if (src->bitcount == 8)
		{
			src_Img = cv::Mat(src->ImgHeight, src->ImgWidth, CV_8UC1);
		}
		else if (src->bitcount == 24)
		{
			src_Img = cv::Mat(src->ImgHeight, src->ImgWidth, CV_8UC3);
		}
		else
		{
			return false;
		}


		// 步长:每行像素所占字节数
		int lineByte = (src->ImgWidth * src->bitcount / 8);

		// 位图数据缓冲区的大小,即图像大小
		unsigned int imgBufSize = static_cast<unsigned int>(src->ImgHeight * lineByte);

		if (!src_Img.empty())
		{
			// 图像数据复制
			memcpy(src_Img.data, src->buff, imgBufSize);  
		}
		else
		{
			return false;
		}

		//  构建输出图像
		cv::Mat dst_Img;

		// 调用DeHazeImg算法,实现去雾控制
		if (DeHazeImg(src_Img, dst_Img, A_MAX, degree) == true)
		{
			if (src == dst)
			{
				memcpy(dst->buff, dst_Img.data, imgBufSize);
			}
			else
			{
				SAFE_DELETE_ARRAY(dst->buff);
				dst->buff = new unsigned char[imgBufSize];
				memcpy(dst->buff, dst_Img.data, imgBufSize);
			}
		}
		else
		{
			return false;
		}

		return true;
	}
	catch(cv::Exception &e)
	{
		e.msg;
		return false;
	}
	catch(...)
	{
		return false;
	}
}

//功能:图像去雾控制
//输入:	1. qbData 通用情报数据结构体
//		    2. A_MAX  控制去雾效果, A_MAX < 0 时,自适应计算(特别耗时); 有效范围【0,255】
//		    3. degree 控制去雾效果, 有效范围【0,1】
//          3. bSrcFirst 默认时,优先处理srcImg, srcImg-->dstImg
//                         否则,优先处理dstImg,dstImg——>dstImg                         

//输出:	1. qbData 含图像去雾后图像的情报数据结构体
//          2. 返回值:处理成功返回true,失败返回false
//说明: 首先判断图像数据有效性标识位,无效时直接返回,不做任何处理;
bool QBStruDeHazeControl(QBStru *qbData, int A_MAX, double degree, bool bSrcFirst)
{
	try
	{
		// 空值判断
		if (qbData == NULL)
		{
			return false;
		}

		// 图像数据无效,直接返回false
		if (qbData->image.bValid == false) 
		{
			return false;
		}

		// 优先处理srcImg
		if (bSrcFirst == true)
		{
			if (qbData->image.srcImg.buff != NULL &&
				qbData->image.srcImg.ImgWidth  > 0 && // srcImg 宽度验证
				qbData->image.srcImg.ImgHeight > 0 )  // srcImg 高度验证
			{
				return ImgStruDeHazeControl(&qbData->image.srcImg, &qbData->image.dstImg, A_MAX, degree);
			}
			else
				if (qbData->image.dstImg.buff != NULL &&
					qbData->image.dstImg.ImgWidth  > 0 && // dstImg 宽度验证
					qbData->image.dstImg.ImgHeight > 0 )   // dstImg 高度验证
					
				{
					// 输入dstImg,输出dstImg
					return ImgStruDeHazeControl(&qbData->image.dstImg, &qbData->image.dstImg, A_MAX, degree);
				}
				else // srcImg dstImg均无效
				{
					return false;
				}
		}
		else 
		{
			// 先看dstImg是否有效
			if (qbData->image.dstImg.buff != NULL &&
				qbData->image.dstImg.ImgWidth  > 0 && // dstImg 宽度验证
				qbData->image.dstImg.ImgHeight > 0 )  // dstImg 高度验证
			{
				return ImgStruDeHazeControl(&qbData->image.dstImg, &qbData->image.dstImg, A_MAX, degree);
			}else 
				if (qbData->image.srcImg.buff != NULL &&
					qbData->image.srcImg.ImgWidth  > 0 && // srcImg 宽度验证
					qbData->image.srcImg.ImgHeight > 0 ) // srcImg 高度验证
				{
					return ImgStruDeHazeControl(&qbData->image.srcImg, &qbData->image.dstImg, A_MAX, degree);
				} 
				else // 情报结构体srcImg 和 dstImg 均无效
				{
					return false;
				}
		}

		return true;
	}
	catch(cv::Exception &e)
	{
		e.msg;
		return false;
	}
	catch(...)
	{
		return false;
	}
}