1 ////////https://blog.csdn.net/uestc_c2_403/article/details/72814206 2 #include "opencv2/highgui/highgui.hpp" 3 #include "opencv2/imgproc/imgproc.hpp" 4 #include "opencv2/opencv.hpp" 5 #include "opencv2/core/core.hpp" 6 #include <iostream> 7 using namespace std; 8 using namespace cv; 9 //图像线性变换操作 10 cv::Mat linearTransform(cv::Mat srcImage, float a, int b) 11 { 12 if (srcImage.empty()) 13 { 14 std::cout << "No data!" << std::endl; 15 } 16 const int nRows = srcImage.rows; 17 const int nCols = srcImage.cols; 18 cv:; Mat resultImage = 19 cv::Mat::zeros(srcImage.size(), srcImage.type()); 20 //图像元素遍历 21 for (int i = 0; i < nRows; i++) 22 { 23 for (int j = 0; j < nCols; j++) 24 { 25 for (int c = 0; c < 3; c++) 26 { 27 //矩阵at操作,检查下标防止越界 28 resultImage.at<Vec3b>(i, j)[c] = saturate_cast<uchar>(a * (srcImage.at<Vec3b>(i, j)[c]) + b); 29 } 30 } 31 } 32 return resultImage; 33 } 34 int main() 35 { 36 cv::Mat srcImage = cv::imread("D:\大海.jpg"); 37 if (srcImage.empty()) 38 { 39 return -1; 40 } 41 42 cv::imshow("源图像", srcImage); 43 //线性变换 44 float a = 1.2; 45 int b = 50; 46 cv::Mat new_image = linearTransform(srcImage, a, b); 47 cv::imshow("dst", new_image); 48 cv::waitKey(0); 49 return 0; 50 }
3.5.2 对数变换
对数变换的公式为:
其中c为常数,r>=0
对数变换目前我知道的有两个作用:
①因为对数曲线在像素值较低的区域斜率较大,像素值较高的区域斜率比较低,所以图像经过对数变换之后,在较暗的区域对比度将得到提升,因而能增强图像暗部的细节。
②图像的傅里叶频谱其动态范围可能宽达0~10^6。直接显示频谱的话显示设备的动态范围往往不能满足要求,这个时候就需要使用对数变换,使得傅里叶频谱的动态范围被合理地非线性压缩。
在OpenCV中,图像对数变换的实现可以直接通过对图像中每个元素运算上述公式完成,也可以通过矩阵整体操作来完成。下面的代码中给了三种方法,其中方法一和方法三都是通过矩阵整体操作来完成,第二种方法是对图像中每个元素操作来完成。方法一和方法三的区别是前者是对源图像作对数运算,后者是对目标图像作对数运算!
1 //////https://blog.csdn.net/gone_huilin/article/details/53223118 2 //////https://blog.csdn.net/spw_1201/article/details/53482877 3 #include <opencv2/core/core.hpp> 4 #include <opencv2/highgui/highgui.hpp> 5 #include <opencv2/imgproc/imgproc.hpp> 6 #include <iostream> 7 using namespace cv; 8 using namespace std; 9 //基于源图像的方法1 10 Mat logTransform1(Mat srcImage, int c) 11 { 12 if (srcImage.empty()) 13 cout << "No data" << endl; 14 Mat resultImage = Mat::zeros(srcImage.size(), srcImage.type()); 15 add(srcImage, Scalar(1.0), srcImage); //计算 r+1 16 srcImage.convertTo(srcImage, CV_32F); //转化为32位浮点型 17 log(srcImage, resultImage); //计算log(1+r) 18 resultImage = c*resultImage; 19 //归一化处理 20 normalize(resultImage, resultImage, 0, 255, NORM_MINMAX); 21 convertScaleAbs(resultImage, resultImage); 22 return resultImage; 23 24 } 25 //方法2 26 Mat logTransform2(Mat srcImage, float c) 27 { 28 if (srcImage.empty()) 29 cout << "No data" << endl; 30 Mat resultImage = Mat::zeros(srcImage.size(), srcImage.type()); 31 double gray = 0; 32 for (int i = 0; i < srcImage.rows; i++) 33 { 34 for (int j = 0; j < srcImage.cols; j++) 35 { 36 gray = (double)srcImage.at<uchar>(i, j); 37 gray = c*log((double)(1 + gray)); 38 resultImage.at<uchar>(i, j) = saturate_cast<uchar>(gray); 39 } 40 } 41 //归一化处理 42 normalize(resultImage, resultImage, 0, 255, NORM_MINMAX); 43 convertScaleAbs(resultImage, resultImage); 44 return resultImage; 45 } 46 //方法3 47 Mat logTransform3(Mat srcImage, float c) 48 { 49 if (srcImage.empty()) 50 cout << "No data" << endl; 51 Mat resultImage = Mat::zeros(srcImage.size(), srcImage.type()); 52 srcImage.convertTo(resultImage, CV_32F); //图像类型转换 53 resultImage = resultImage + 1; //图像矩阵元素加1 54 log(resultImage, resultImage); 55 resultImage = c*resultImage; 56 //归一化处理 57 normalize(resultImage, resultImage, 0, 255, NORM_MINMAX); 58 convertScaleAbs(resultImage, resultImage); 59 return resultImage; 60 } 61 int main() 62 { 63 Mat srcImage = imread("D:\大海.jpg"); 64 if (!srcImage.data) 65 return -1; 66 cvtColor(srcImage, srcImage, CV_BGR2GRAY); 67 imshow("srcImage", srcImage); 68 float c = 1.2; 69 Mat resultImage; 70 double tTime; 71 tTime = (double)getTickCount(); 72 const int nTimes = 100; 73 for (int i = 0; i < nTimes; i++) 74 { 75 resultImage = logTransform3(srcImage, c); 76 } 77 tTime = 1000 * ((double)getTickCount() - tTime) / getTickFrequency(); 78 tTime /= nTimes; 79 cout << tTime << endl; 80 imshow("resultImage", resultImage); 81 waitKey(0); 82 return 0; 83 }
参考:
https://blog.csdn.net/gone_huilin/article/details/53223118
https://blog.csdn.net/spw_1201/article/details/53482877
https://blog.csdn.net/wenhao_ir/article/details/51658086
https://blog.csdn.net/eric_e/article/details/79440089
https://blog.csdn.net/dcrmg/article/details/53677739
3.5.3 对比度拉伸
1 //////https://blog.csdn.net/spw_1201/article/details/53486594 2 #include <opencv2/imgproc/imgproc.hpp> 3 #include <opencv2/core/core.hpp> 4 #include <opencv2/highgui/highgui.hpp> 5 #include <iostream> 6 using namespace cv; 7 using namespace std; 8 Mat contrastStretch(Mat srcImage) 9 { 10 Mat resultImage = srcImage.clone();//"=";"clone()";"copyTo"三种拷贝方式,前者是浅拷贝,后两者是深拷贝。 11 int nRows = resultImage.rows; 12 int nCols = resultImage.cols; 13 //判断图像的连续性 14 if (resultImage.isContinuous()) 15 { 16 nCols = nCols*nRows; 17 nRows = 1; 18 } 19 //图像指针操作 20 uchar *pDataMat; 21 int pixMax = 0, pixMin = 255; 22 //计算图像的最大最小值 23 for (int j = 0; j < nRows; j++) 24 { 25 pDataMat = resultImage.ptr<uchar>(j);//ptr<>()得到的是一行指针 26 for (int i = 0; i < nCols; i++) 27 { 28 if (pDataMat[i] > pixMax) 29 pixMax = pDataMat[i]; 30 if (pDataMat[i] < pixMin) 31 pixMin = pDataMat[i]; 32 } 33 } 34 //对比度拉伸映射 35 for (int j = 0; j < nRows; j++) 36 { 37 pDataMat = resultImage.ptr<uchar>(j); 38 for (int i = 0; i < nCols; i++) 39 { 40 pDataMat[i] = (pDataMat[i] - pixMin) * 255 / (pixMax - pixMin); 41 } 42 } 43 return resultImage; 44 } 45 int main() 46 { 47 Mat srcImage = imread("D:\小女孩与熊.jpg"); 48 if (!srcImage.data) 49 return -1; 50 Mat srcGray; 51 cvtColor(srcImage, srcGray, CV_RGB2GRAY); 52 imshow("srcGray", srcGray); 53 Mat resultImage = contrastStretch(srcGray); 54 imshow("resultImage", resultImage); 55 waitKey(0); 56 return 0; 57 }
https://blog.csdn.net/spw_1201/article/details/53486594
https://blog.csdn.net/abcd1992719g/article/details/25483395
3.5.4 灰度级分层
1 //////https://blog.csdn.net/spw_1201/article/details/53487746 2 #include <opencv2/imgproc/imgproc.hpp> 3 #include <opencv2/core/core.hpp> 4 #include <opencv2/highgui/highgui.hpp> 5 #include <iostream> 6 using namespace cv; 7 using namespace std; 8 Mat grayLayered(Mat srcImage) 9 { 10 Mat resultImage = srcImage.clone(); 11 int nRows = resultImage.rows; 12 int nCols = resultImage.cols; 13 if (resultImage.isContinuous()) 14 { 15 nCols = nRows*nCols; 16 nRows = 1; 17 } 18 uchar *pDataMat; 19 int controlMin = 150; 20 int controlMax = 200; 21 for (int j = 0; j < nRows; j++) 22 { 23 pDataMat = resultImage.ptr<uchar>(j); 24 for (int i = 0; i < nCols; i++) 25 { 26 //第一种方法:二值映射 27 if (pDataMat[i] > controlMin) 28 pDataMat[i] = 255; 29 else 30 pDataMat[i] = 0; 31 //第二种方法:区域映射 32 /*if (pDataMat[i] > controlMin && pDataMat[i] < controlMax) 33 pDataMat[i] = controlMax;*/ 34 } 35 } 36 return resultImage; 37 } 38 int main() 39 { 40 Mat srcImage = imread("D:\大海.jpg"); 41 if (!srcImage.data) 42 return -1; 43 Mat srcGray; 44 cvtColor(srcImage, srcGray, CV_BGR2GRAY); 45 imshow("srcGray", srcGray); 46 Mat resultImage = grayLayered(srcGray); 47 imshow("resultImage", resultImage); 48 waitKey(0); 49 return 0; 50 }
3.5.5 灰度比特平面
1 //////https://blog.csdn.net/gone_huilin/article/details/53223151 2 #include <opencv2/imgproc/imgproc.hpp> 3 #include <opencv2/core/core.hpp> 4 #include <opencv2/highgui/highgui.hpp> 5 #include <iostream> 6 #include <stdio.h> 7 using namespace cv; 8 using namespace std; 9 void showMBitPlan(cv::Mat srcImage) 10 { 11 int nRows = srcImage.rows; 12 int nCols = srcImage.cols; 13 // 图像连续性判断 14 if (srcImage.isContinuous()) 15 { 16 nCols = nCols * nRows; 17 nRows = 1; 18 } 19 // 图像指针操作 20 uchar *pSrcMat; 21 uchar *pResultMat; 22 cv::Mat resultImage = srcImage.clone(); 23 int pixMax = 0, pixMin = 0; 24 for (int n = 1; n <= 8; n++) 25 { 26 // 比特平面分层像素构成 27 pixMin = pow(2, n - 1); 28 pixMax = pow(2, n); 29 for (int j = 0; j < nRows; j++) 30 { 31 // 获取图像数据指针 32 pSrcMat = srcImage.ptr<uchar>(j); 33 pResultMat = resultImage.ptr<uchar>(j); 34 for (int i = 0; i < nCols; i++) 35 { 36 // 相应比特平面层二值化 37 if (pSrcMat[i] >= pixMin && pSrcMat[i] < pixMax) 38 pResultMat[i] = 255; 39 else 40 pResultMat[i] = 0; 41 } 42 } 43 // 比特平面层输出 44 char windowsName[20]; 45 sprintf_s(windowsName, "BitPlane %d", n); 46 imshow(windowsName, resultImage); 47 } 48 } 49 int main() 50 { 51 cv::Mat srcImage = cv::imread("D:\大海.jpg"); 52 if (!srcImage.data) 53 return 0; 54 cv::Mat srcGray; 55 cvtColor(srcImage, srcGray, CV_BGR2GRAY); 56 imshow("srcGray", srcGray); 57 showMBitPlan(srcGray); 58 cv::waitKey(0); 59 return 0; 60 }