灰度图像归一化到0~255(对比度拉伸)原理如下:
g' = g * Mult + Add
其中:
怎么理解这个原理?
上面的原理把简单的事情搞复杂了,我们对上式进行化简,用Python-sympy进行化简,代码如下:
from sympy import *
g, Gmax, Gmin = symbols('g Gmax Gmin')
Mult = 255/(Gmax-Gmin)
Add = -Mult*Gmin
g_ = simplify(g*Mult+Add)
print(g_)
化简结果如下:
上面这个式子就很好理解了,上面的式子相当于把介于[Gmin,Gmax]区间的灰度值按比例拉伸到0~255的区间。
原理就这么简单,接下来上代码,这个代码其实我之前就已经写过基于OpenCV1.x的版本了,详情可参见我写的另一篇博文,链接如下
https://blog.csdn.net/wenhao_ir/article/details/51142979
这篇博文提供的代码是基于OpenCV2.x的,并且没有使用OpenCV的函数cvMinMaxLoc()求阵列的最大值、最小值,有兴趣的同学可以参考我之前写过的代码,将下面代码中的求最大值、最小值的代码用OpenCV的cvMinMaxLoc()函数实现。
当然,以下代码最大的作用还是为大家学习图像处理基本原理之用。因为下面的代码完全可以被OpenCV的函数normalize()代替,即下面这条语句:
normalize(srcGray, resultImage, 0, 255, NORM_MINMAX);
我在之前的代码中也用到过这个归一化函数,比如下面这篇博文中的代码:
https://blog.csdn.net/wenhao_ir/article/details/51655055
关于OpenCV的函数normalize()的详细讲解,可参考博文https://blog.csdn.net/wenhao_ir/article/details/125619073
说回来,本文要提供给大家的源码如下:
源码中用到的图像的下载链接:
https://pan.baidu.com/s/1i4Dvm2h
//原文链接:https://blog.csdn.net/wenhao_ir/article/details/51658765
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
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;
}
int main()
{
cv::Mat srcImage = cv::imread("lakeWater.jpg");
if(!srcImage.data)
return 0;
cv::Mat srcGray;
cvtColor(srcImage, srcGray, CV_BGR2GRAY);
imshow("srcGray", srcGray);
cv::Mat resultImage = contrastStretch(srcGray);
cv::imshow("resultImage", resultImage);
cv::waitKey(0);
return 0;
}
运行结果如下图所示:
这篇博文中我们是把对比度拉伸到了0~255的区间,也可以拉伸到自己指定的区间,详情见博文 https://blog.csdn.net/wenhao_ir/article/details/51604520