You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

528 lines
10 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#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
// 否则优先处理dstImgdstImg——>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;
}
}