数字图像处理10--图像增强之对比度拉伸,OpenCV C++

下图是典型的对比度拉伸变换。点(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 <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>

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<uchar>(j);
        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<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);
    }
    //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 <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>

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<uchar>(j);
        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<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);
    }
    //apply lut
    LUT( srcImage, lut, srcImage );
}

int main(int argc, char *argv[])
{
    if( argc != 2 ){
        std::cerr << "Usage: " << argv[0] << "<image_name>" << std::endl;
        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<cv::Mat> bgr;
    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;
}

结果:

最小,最大灰度值:

猜你喜欢

转载自blog.csdn.net/cyf15238622067/article/details/87717092