首页 > 其他分享 >opencv图像去雾

opencv图像去雾

时间:2024-08-14 20:39:01浏览次数:5  
标签:src Mat int ++ opencv 图像 col row

1、何恺明的暗通道去雾算法           论文原文:Single Image Haze Removal Using Dark Channel Prior | IEEE Journals & Magazine | IEEE Xplore           参考博客:[论文阅读] (11)ACE算法和暗通道先验图像去雾算法(Rizzi | 何恺明老师)_暗通道去雾算法_Eastmount的博客-CSDN博客           参考公众号:GiantPandaCV            将各位大佬的实现代码粘出来,供大家学习!   #include <opencv2/opencv.hpp> #include <iostream> #include <Windows.h> #include <vector>   using namespace std; using namespace cv;   int getMax(Mat src) { int row = src.rows; int col = src.cols; int temp = 0; for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { temp = max((int)src.at<uchar>(i, j), temp); } if (temp == 255) return temp; } return temp; }   Mat dehaze(Mat src) { double eps; int row = src.rows; int col = src.cols; Mat M = Mat::zeros(row, col, CV_8UC1); Mat M_max = Mat::zeros(row, col, CV_8UC1); Mat M_ave = Mat::zeros(row, col, CV_8UC1); Mat L = Mat::zeros(row, col, CV_8UC1); Mat dst = Mat::zeros(row, col, CV_8UC3); double m_av, A;   double sum = 0; for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { uchar r, g, b, temp1, temp2; b = src.at<Vec3b>(i, j)[0]; g = src.at<Vec3b>(i, j)[1]; r = src.at<Vec3b>(i, j)[2]; temp1 = min(min(b, g), r); temp2 = max(max(b, g), r); M.at<uchar>(i, j) = temp1; M_max.at<uchar>(i, j) = temp2; sum += temp1; } } m_av = sum / (row * col * 255); eps = 0.75 / m_av; boxFilter(M, M_ave, CV_8UC1, Size(15, 15));  // 中值滤波 double delta = min(0.9, eps * m_av); for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { L.at<uchar>(i, j) = min((int)(delta * M_ave.at<uchar>(i, j)), (int)M.at<uchar>(i, j)); } } A = (getMax(M_max) + getMax(M_ave)) * 0.5; for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { int temp = L.at<uchar>(i, j); for (int k = 0; k < 3; k++) { int val = A * (src.at<Vec3b>(i, j)[k] - temp) / (A - temp); if (val > 255) val = 255; if (val < 0) val = 0; dst.at<Vec3b>(i, j)[k] = val; } } } return dst; }       // 获取最小值矩阵 int row, col; int** getMinChannel(Mat src) { if (src.channels() != 3) { cout << "input error!" << endl; exit(-1); } int** imgGray; imgGray = new int* [row]; for (int i = 0; i < row; i++) { imgGray[i] = new int[col]; } for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { int localmin = 255; for (int k = 0; k < 3; k++) { if (src.at<Vec3b>(i, j)[k] < localmin) { localmin = src.at<Vec3b>(i, j)[k]; } } imgGray[i][j] = localmin; } } return imgGray; }   // 求暗通道  通过最小矩阵,及poolsize,获取最小矩阵在poolsize范围内的最小值 int** getDarkChannel(int** imgGray, int blocksize = 3) { if (blocksize % 2 == 0 || blocksize < 3) { fprintf(stderr, "blocksize is not odd or too small!"); exit(-1); } int poolsize = (blocksize - 1) / 2; int newheight = row + blocksize - 1; int newwidth = col + blocksize - 1; int** imgMiddle; imgMiddle = new int* [newheight]; for (int i = 0; i < newheight; i++) { imgMiddle[i] = new int[newwidth]; } for (int i = 0; i < newheight; i++) { for (int j = 0; j < newwidth; j++) { if (i < row && j < col) { imgMiddle[i][j] = imgGray[i][j]; } else { imgMiddle[i][j] = 255; } } } int** imgDark; imgDark = new int* [row]; for (int i = 0; i < row; i++) { imgDark[i] = new int[col]; } int localmin = 255; for (int i = poolsize; i < newheight - poolsize; i++) { for (int j = poolsize; j < newwidth - poolsize; j++) { localmin = 255; for (int k = i - poolsize; k < i + poolsize + 1; k++) { for (int l = j - poolsize; l < j + poolsize + 1; l++) { if (imgMiddle[k][l] < localmin) { localmin = imgMiddle[k][l]; } } } imgDark[i - poolsize][j - poolsize] = localmin; } } return imgDark; }   struct node { int x, y, val; node() {} node(int _x,int _y,int _val):x(_x),y(_y),val(_val){} bool operator<(const node& rhs) { return val > rhs.val; } };   // 估算全局大气光值 int getGlobalAtmosphericLightValue(int** imgDark, Mat src, bool meanmodel = false, float percent = 0.001) { int size = row * col; vector<node> nodes; for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { node temp; temp.x = i, temp.y = j, temp.val = imgDark[i][j]; nodes.push_back(temp); } } sort(nodes.begin(), nodes.end());  // 从小到大排序   int atmosphericLight = 0; if (int(percent * size) == 0) { for (int i = 0; i < 3; i++) { if (src.at<Vec3b>(nodes[0].x, nodes[0].y)[i] > atmosphericLight)  // imgDark最小处的原图中像素点中的最大值 { atmosphericLight = src.at<Vec3b>(nodes[0].x, nodes[0].y)[i]; } } } // 开启均值模式 //if (meanmodel == true) //{ //int sum = 0; //for (int i = 0; i < int(percent * size); i++) //{ //for (int j = 0; j < 3; j++) //{ //sum = sum + src.at<Vec3b>(nodes[i].x, nodes[i].y)[j]; //} //} //} // 获取暗通道在前0.1%的位置的像素点在原图像中的最高亮度值 for (int i = 0; i < int(percent * size); i++) { for (int j = 0; j < 3; j++) { if (src.at<Vec3b>(nodes[i].x, nodes[i].y)[j] > atmosphericLight) { atmosphericLight = src.at<Vec3b>(nodes[i].x, nodes[i].y)[j]; } } } return atmosphericLight; } // 恢复原图  omega 去雾比例  t0 最小透射率值 Mat getRecoverScene(Mat src,float omega=0.85,float t0 =0.5,int blocksize=15,bool meanmodel=false,float percent=0.001) { int** imgGray = getMinChannel(src);  // 获取每个像素点b,g,r中的最小值 int** imgDark = getDarkChannel(imgGray, blocksize = blocksize);  // 通过最小矩阵,及poolsize,获取imgGray在poolsize范围内的最小值 int atmosphericLight = getGlobalAtmosphericLightValue(imgDark, src, meanmodel = meanmodel, percent = percent);   // 估算全局大气光值 float** imgDark2, ** transmission; /*imgDark2 = new float* [row]; for (int i = 0; i < row; i++) { imgDark2[i] = new float[col]; }*/ transmission = new float* [row];  // t(x) for (int i = 0; i < row; i++) { transmission[i] = new float[col]; } for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { //imgDark2[i][j] = float(imgDark[i][j]); transmission[i][j] = 1 - omega * imgDark[i][j] / atmosphericLight; if (transmission[i][j] < 0.1) { transmission[i][j] = 0.1; } } } Mat dst(src.rows, src.cols, CV_8UC3);   for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { for (int channel = 0; channel < 3; channel++) { int temp = (src.at<Vec3b>(i, j)[channel] - atmosphericLight) / transmission[i][j] + atmosphericLight;  // J(x) = (I(x) - A)/t(x) + A if (temp > 255) temp = 255; if (temp < 0) temp = 0; dst.at<Vec3b>(i, j)[channel] = temp; } } }   return dst;   }   Mat MedianFilterFogRemove(Mat src, float p = 0.85, int kernelsize = 15, int blocksize = 3, bool meanmodel = false, float percent = 0.001) { int** imgGray = getMinChannel(src);  // 获取每个像素点b,g,r中的最小值 int** imgDark = getDarkChannel(imgGray, blocksize = blocksize);  // 通过最小矩阵,及poolsize,获取imgGray在poolsize范围内的最小值 //int atmosphericLight = getGlobalAtmosphericLightValue(imgDark, src, meanmodel = meanmodel, percent = percent);  // 估算全局大气光值     int Histgram[256] = {0}; for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { Histgram[imgDark[i][j]]++; } } int sum = 0, atmosphericLight = 0; for (int i = 255; i >= 0; i--) { sum += Histgram[i];  // // sum的最大值为row*col if (sum > row * col * 0.01) { atmosphericLight = i;  //  从大到小的前0.1%所在的值作为大气光值   break; } } int sumb = 0, sumg = 0, sumr = 0, amount = 0; for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { if (imgDark[i][j] >= atmosphericLight) { sumb += src.at<Vec3b>(i, j)[0]; sumg += src.at<Vec3b>(i, j)[1]; sumr += src.at<Vec3b>(i, j)[2]; amount++; } } } sumb /= amount; sumg /= amount; sumr /= amount; // 从所有最小值矩阵范围内的最小值矩阵中大于大气光值的,获取原图中的所有b,g,r值,并取均值 Mat filter(row, col, CV_8UC1); for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { filter.at<uchar>(i, j) = imgDark[i][j];   // 将imgDark赋给filter } } Mat A(row, col, CV_8UC1); medianBlur(filter, A, kernelsize);  // 中值滤波,得到A   Mat temp(row, col, CV_8UC1); for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { int diff = filter.at<uchar>(i, j) - A.at<uchar>(i, j);  if (diff < 0) diff = -diff; temp.at<uchar>(i, j) = diff; } } medianBlur(temp, temp, kernelsize);   // 中值滤波 Mat B(row, col, CV_8UC1); for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { int diff = A.at<uchar>(i, j) - temp.at<uchar>(i, j); if (diff < 0) diff = 0; B.at<uchar>(i, j) = diff; } } for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { int minn = B.at<uchar>(i, j) * p; if (imgDark[i][j] > minn) { B.at<uchar>(i,j) = minn; } else { B.at<uchar>(i, j) = imgDark[i][j]; } } } Mat dst(row, col, CV_8UC3); for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { int F = B.at<uchar>(i, j); int value; if (sumb != F) { value = sumb * (src.at<Vec3b>(i, j)[0] - F) / (sumb - F); } else { value = src.at<Vec3b>(i, j)[0]; } if (value < 0) value = 0; else if (value > 255) value = 255; dst.at<Vec3b>(i, j)[0] = value;   if (sumg != F) { value = sumg * (src.at<Vec3b>(i, j)[1] - F) / (sumg - F); } else { value = src.at<Vec3b>(i, j)[1]; } if (value < 0) value = 0; else if (value > 255) value = 255; dst.at<Vec3b>(i, j)[1] = value;   if (sumr != F) { value = sumr * (src.at<Vec3b>(i, j)[2] - F) / (sumr - F); } else { value = src.at<Vec3b>(i, j)[2]; } if (value < 0) value = 0; else if (value > 255) value = 255; dst.at<Vec3b>(i, j)[2] = value; } } return dst; }   int main() {   Mat image = imread("E:/dataset/python_dataset/VOC07+12+test/VOCdevkit/VOC2007/JPEGImages/2008_000084.jpg"); clock_t t0,t1,t2; t0 = clock(); // 方式1 快速去雾 Mat dst = dehaze(image); cout << "the method1 run time is :" << clock() - t0 << "ms" << endl;   // 方式2 暗通道去雾法 row = image.rows; col = image.cols; t1 = clock(); Mat dst1 = getRecoverScene(image); cout << "the method2 run time is :" << clock() - t1 << "ms" << endl;   // 方式3 中值滤波进行去雾 t2 = clock(); Mat dst2 = MedianFilterFogRemove(image); cout << "the method3 run time is :" << clock() - t2 << "ms" << endl;   imshow("origin", image); imshow("result1", dst); imshow("result2", dst1); imshow("result3", dst2); char key = waitKey(); if (key == 'q') { return 0; } system("pause"); return 0; } 输入输出结果:                    

标签:src,Mat,int,++,opencv,图像,col,row
From: https://www.cnblogs.com/kn-zheng/p/18359729

相关文章

  • SenseCraft 部署模型到Grove Vision AI V2图像处理模块
    GroveVisionAIV2图像处理模块开箱测评摘要今天教大家快速上手GroveVisionAIV2图像处理模块,我们将一起探讨如何利用SenseCraft部署AI模型,和如何通过XIAOESP32C3调用这些模型,轻松实现智能视觉功能!原文链接:FreakStudio的博客往期推荐:学嵌入式的你,还不会面向对......
  • OpenCV图像处理——直线拟合并找出拟合直线的起点与端点
    引言对轮廓进行分析,除了可以对轮廓进行椭圆或者圆的拟合之外,还可以对轮廓点集进行直线拟合。在OpenCV中,直线拟合通常是通过cv::fitLine函数实现的,该函数采用最小二乘法对一组2D或3D点进行直线拟合。对于2D点集,拟合结果是一个cv::Vec4f类型的向量,包含了直线的方......
  • 图像识别,训练数据集---GPU篇 3090免费使用
     大家一般都在window上训练yolo等一些深度学习模型,会发现很慢或者说GPU显存不够用而云GPU平台则解决了一系列该问题深度学习目标检测交流群1:985499650yolo2D3D目标检测行为识别交流群2:782537412接下来以该平台为例---有一些免费的3090,4090可以用(24G):https://cloud.lanyun.n......
  • OpenCV(cv::waitKey())
    目录1.函数解析参数返回值2.示例3.说明4.注意事项cv::waitKey()是OpenCV库中的一个函数,用于等待用户的键盘输入。它在处理图像和视频时非常有用,特别是在显示图像窗口时,用于控制图像的显示和响应用户输入。1.函数解析intcv::waitKey(intdelay=0);参数delay:......
  • OpenCV-图片操作
    一.多种形态学形态学变换(MorphologicalTransformations)是一种基于形状的简单变换,它的处理对象通常是二值化图像。形态学变换有两个输入,一个输出:输入为原图像、核(结构化元素),输出为形态学变换后的图像。1.核核(kernel)其实就是一个小区域,通常为3*3、5*5、7*7大小,有着其自己......
  • 掌握图像处理中的颜色识别与形态学变换技术
    形态学变换形态学变换是一种基于形状的图像处理技术,主要应用于二值化图像。它的核心操作包括腐蚀和膨胀,这两者是对立的基本操作。核(结构化元素):核是一个小的矩阵或模板,用于在图像上进行操作。它定义了进行形态学变换时考虑的邻域范围。腐蚀(Erosion):腐蚀操作会缩小图像中目......
  • Debian下使用OpenCV库保存摄相头数据为图片(arm)
    在《移植OpenCV3.1到BBB-Debian》一文件中配置好的环境为前提(后期不特别说明,ARM版的例子均以该环境为基础),编写使用OpenCV库保存WEBCAM的数据为图片的代码,下面是相应的源码和编译配置文件(都保存在SaveCamPic目录下):1.源码scp.cpp#include<stdio.h>#include<sys/stat.h>#in......
  • 人工智能算法,图像识别技术;基于大语言模型的跨境商品识别与问答系统;图像识别
    目录一.研究背景二,大语言模型介绍三,数据采集与预处理 商品识别算法四. 跨境商品问答系统设计五.需要源码联系一.研究背景 在当今全球化的背景下,跨境电商行业迅速发展,为消费者提供了更广泛的购物选择和更便利的购物方式。然而,随着跨境电商平台上商品种类的不断......
  • VisionPro二次开发学习笔记13-使用CogToolBlock进行图像交互
    该程序演示了如何使用CogToolBlock进行图像交互.从vpp文件中加载一个ToolBlock。用户可以通过应用程序窗体上的数字增减控件修改ToolBlock输入端子的值。用户还可以从coins.idb或采集FIFO中选择图像。“运行一次”按钮执行以下操作:获取下一个图像或读取下一个图像......
  • 【图像去噪】论文复现:新手入门必看!DnCNN的Pytorch源码训练测试全流程解析!为源码做详细
    第一次来请先看【专栏介绍文章】:源码只提供了noiselevel为25的DnCNN-S模型文件。本文末尾有完整代码和训练好的σ=15,25,50的DnCNN-S、σ∈[0,55]的DnCNN-B和CDnCNN-B、DnCNN-3共6个模型文件!读者可以自行下载!本文亮点:以官方Pytorch源代码为基础,在DnCNN-S的基础上,增添Dn......