索引地址:系列索引
线性变换线性映射( linear mapping)是从一个向量空间V到另一个向量空间W的映射且保持加法运算和数量乘法运算,而线性变换(linear transformation)是线性空间V到其自身的线性映射。
也就是说会改变原图片每个像素的值,像素值最直观的感受就是图像色彩方面的。也就是调整图像亮度和对比度。
g ( i , j ) = α f ( i , j ) + β g(i,j)= \alpha f(i,j) + \beta g ( i , j ) = α f ( i , j ) + β ,其中 α > 0 \alpha>0 α > 0 (对比度),β \beta β 是增益变量(亮度)
测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 #include "opencv2/imgproc/imgproc.hpp" #include <iostream> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> using namespace std;using namespace cv;static void ContrastAndBright (int , void *) ;int g_nContrastValue; int g_nBrightValue; Mat g_srcImage, g_dstImage;int main () { g_srcImage = imread ("1.jpg" ); if (!g_srcImage.data) { printf ("读取g_srcImage图片错误~! \n" ); return false ; } g_dstImage = Mat::zeros (g_srcImage.size (), g_srcImage.type ()); g_nContrastValue = 80 ; g_nBrightValue = 80 ; namedWindow ("Result" , 1 ); createTrackbar ("对比度:" , "Result" , &g_nContrastValue, 300 , ContrastAndBright); createTrackbar ("亮 度:" , "Result" , &g_nBrightValue, 200 , ContrastAndBright); ContrastAndBright (g_nContrastValue, 0 ); ContrastAndBright (g_nBrightValue, 0 ); cout << endl << "\t运行成功,请调整滚动条观察图像效果\n\n" << "\t按下“q”键时,程序退出\n" ; while (char (waitKey (1 )) != 'q' ) { } return 0 ; }static void ContrastAndBright (int , void *) { namedWindow ("Original" , 1 ); for (int y = 0 ; y < g_srcImage.rows; y++) { for (int x = 0 ; x < g_srcImage.cols; x++) { for (int c = 0 ; c < 3 ; c++) { g_dstImage.at <Vec3b>(y, x)[ c ] = saturate_cast <uchar>( (g_nContrastValue * 0.01 ) * (g_srcImage.at <Vec3b>(y, x)[ c ]) + g_nBrightValue); } } } imshow ("Original" , g_srcImage); imshow ("Result" , g_dstImage); }
测试结果:
对比度拉伸变换下面是典型的对比度拉伸变换。点(r1,s1)和(r2,s2)的位置控制变换函数的形状。
如果r1=r2,s1=s2,则变换为一线性函数;
若r1=r2,s1=0且s2=L-1,则是阈值处理函数,产生一幅二值图像;
处理一幅8bit低对比度图像,
( r 1 , s 1 ) = ( r m i n , 0 ) , ( r 2 , s 2 ) = ( r m a x , L − 1 ) ; (r1,s1)=(r_{min},0),(r2,s2)=(r_{max},L-1); ( r 1 , s 1 ) = ( r m i n , 0 ) , ( r 2 , s 2 ) = ( r m a x , L − 1 ) ;
其中r m i n , r m a x r_{min},r_{max} r m i n , r m a x 是图像中最小和最大灰度级;
因此,变换函数把灰度级由原范围线性的拉伸至整个范围[ 0 , L − 1 ] [0,L-1] [ 0 , L − 1 ]
测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 #include <iostream> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> using namespace cv;using namespace std;cv::Mat contrastStretch (cv::Mat srcImage) { cv::Mat resultImage = srcImage.clone (); int nRows = resultImage.rows; int nCols = resultImage.cols; if (resultImage.isContinuous ()) { nCols = nCols * nRows; nRows = 1 ; } uchar *pDataMat; int pixMax = 0 , pixMin = 255 ; for (int j = 0 ; j < nRows; j++) { pDataMat = resultImage.ptr <uchar>(j); for (int i = 0 ; i < nCols; i++) { if (pDataMat[ i ] > pixMax) pixMax = pDataMat[ i ]; if (pDataMat[ i ] < pixMin) pixMin = pDataMat[ i ]; } } for (int j = 0 ; j < nRows; j++) { pDataMat = resultImage.ptr <uchar>(j); for (int i = 0 ; i < nCols; i++) { pDataMat[ i ] = (pDataMat[ i ] - pixMin) * 255 / (pixMax - pixMin); } } return resultImage; }void contrastStretch2 (cv::Mat &srcImage) { if ( srcImage.empty () ){ std::cerr << "image empty" << std::endl; return ; } double pixMin,pixMax; cv::minMaxLoc (srcImage,&pixMin,&pixMax); std::cout << "min_a=" << pixMin << " max_b=" << pixMax << std::endl; cv::Mat lut ( 1 , 256 , CV_8U) ; for ( int i = 0 ; i < 256 ; i++ ){ if (i < pixMin) lut.at <uchar>(i)= 0 ; else if (i > pixMax) lut.at <uchar>(i)= 255 ; else lut.at <uchar>(i)= static_cast <uchar>(255.0 *(i-pixMin)/(pixMax-pixMin)+0.5 ); } LUT ( srcImage, lut, srcImage ); }int main () { cv::Mat srcImage = cv::imread ("lena.jpg" ); if (!srcImage.data) return 0 ; cv::Mat srcGray; cvtColor (srcImage, srcGray, COLOR_BGR2GRAY); imshow ("srcGray" , srcGray); cv::Mat resultImage = contrastStretch (srcGray); cv::imshow ("resultImage" , resultImage); cv::waitKey (0 ); return 0 ; }
测试效果: