下图是典型的对比度拉伸变换。点(r1,s1)和(r2,s2)的位置控制变换函数的形状。
如果r1=r2,s1=s2,则变换为一线性函数;
若r1=r2,s1=0且s2=L-1,则是阈值处理函数,产生一幅二值图像;
处理一幅8bit低对比度图像,(r1,s1)=(r_min,0),(r2,s2)=(r_max,L-1);其中r_min,r_max是图像中最小和最大灰度级;
因此,变换函数把灰度级由原范围线性的拉伸至整个范围[0,L-1]
代码实现:
/*
* 对比度拉伸
*/
#include
#include
#include
#include
cv::Mat contrastStretch1(cv::Mat srcImage)
{
cv::Mat resultImage = srcImage.clone();
int nRows = resultImage.rows;
int nCols = resultImage.cols;
// 图像连续性判断
if(resultImage.isContinuous()){
nCols = nCols * nRows;
nRows = 1;
}
// 计算图像的最大最小值
double pixMin,pixMax;
cv::minMaxLoc(resultImage,&pixMin,&pixMax);
std::cout << "min_a=" << pixMin << " max_b=" << pixMax << std::endl;
// 对比度拉伸映射
for(int j = 0; j < nRows; j ++){
uchar *pDataMat = resultImage.ptr
for(int i = 0; i < nCols; i ++){
pDataMat[i] = (pDataMat[i] - pixMin) *
255 / (pixMax - pixMin); //255/(pixMax - pixMin)是斜率 y=k(x-a)
}
}
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;
//create lut table
cv::Mat lut( 1, 256, CV_8U);
for( int i = 0; i < 256; i++ ){
if (i < pixMin) lut.at
else if (i > pixMax) lut.at
else lut.at
}
//apply lut
LUT( srcImage, lut, srcImage );
}
int main()
{
cv::Mat srcImage = cv::imread("123.tif");
if(!srcImage.data)
return 0;
cv::Mat srcGray;
cvtColor(srcImage, srcGray, CV_BGR2GRAY);
cv::resize(srcGray, srcGray, cv::Size(), 0.5, 0.5);
// srcGray = srcGray +150;
imshow("srcGray", srcGray);
// cv::Mat resultImage = contrastStretch1(srcGray);
contrastStretch2(srcGray);
cv::imshow("resultImage", srcGray);
cv::waitKey(0);
return 0;
}
结果:
这清晰度提高太多。。。。。。。
处理彩色图片,先分层BGR,再单独拉伸,在合并;
代码:
// stretch.cpp
/*
* 对比度拉伸,deal color or gray
*/
#include
#include
#include
#include
cv::Mat contrastStretch1(cv::Mat srcImage)
{
cv::Mat resultImage = srcImage.clone();
int nRows = resultImage.rows;
int nCols = resultImage.cols;
// 图像连续性判断
if(resultImage.isContinuous()){
nCols = nCols * nRows;
nRows = 1;
}
// 计算图像的最大最小值
double pixMin,pixMax;
cv::minMaxLoc(resultImage,&pixMin,&pixMax);
std::cout << "min_a=" << pixMin << " max_b=" << pixMax << std::endl;
// 对比度拉伸映射
for(int j = 0; j < nRows; j ++){
uchar *pDataMat = resultImage.ptr
for(int i = 0; i < nCols; i ++){
pDataMat[i] = (pDataMat[i] - pixMin) *
255 / (pixMax - pixMin); //255/(pixMax - pixMin)是斜率 y=k(x-a)
}
}
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;
//create lut table
cv::Mat lut( 1, 256, CV_8U);
for( int i = 0; i < 256; i++ ){
if (i < pixMin) lut.at
else if (i > pixMax) lut.at
else lut.at
}
//apply lut
LUT( srcImage, lut, srcImage );
}
int main(int argc, char *argv[])
{
if( argc != 2 ){
std::cerr << "Usage: " << argv[0] << "
return 0;
}
std::string img_name = argv[1];
cv::Mat srcImage = cv::imread(img_name, cv::IMREAD_COLOR);
if(!srcImage.data)
return 0;
cv::Mat srcGray;
// cvtColor(srcImage, srcGray, CV_BGR2GRAY);
std::vector
split( srcImage, bgr );
contrastStretch2(bgr[0]);
contrastStretch2(bgr[1]);
contrastStretch2(bgr[2]);
//merge result
merge(bgr, srcGray);
// cv::Mat resultImage = contrastStretch1(srcGray);
// cv::resize(srcImage, srcImage, cv::Size(), 0.25, 0.25);
imshow("srcGray", srcImage);
// cv::resize(srcGray, srcGray, cv::Size(), 0.25, 0.25);
cv::imshow("resultImage", srcGray);
cv::waitKey(0);
return 0;
}
结果:
最小,最大灰度值: