数字图像处理9--图像增强之伽马变换,OpenCV C++

幂次变换又称伽马变换:

✓    c和 γ是正常数

✓    γ < 1 提高灰度级,在正比函数上方,使图像变亮

✓    γ  > 1 降低灰度级,在正比函数下方,使图像变暗

创建滑动条改变Gama值

•    例:人体胸上部脊椎骨折的核磁共振图像

代码如下:

/*
 *伽马变换--s=cr^γ
 * 滑动条改变Gama值,γ<1时将较窄范围的暗色输入转换为较宽范围的输出值;γ>1时将较窄范围的亮色输入转换为较宽范围的输出值。
 * OpenCV代码实现,注意此代码使用与灰度图像
 */

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;

#define WINDOW_NAME "【滑动条改变Gama值】"        //为窗口标题定义的宏

const int g_nMaxGamaValue = 25;//Alpha值的最大值
int  g_nGamaValueSlider;//滑动条对应的变量
double g_spiderValue;


//声明存储图像的变量
Mat g_srcImage1;
Mat g_dstImage;

void gammaTransformation(cv::Mat& matInput, cv::Mat& matOutput, float fGamma, float fC /*= 1.0f*/)
{
    assert(matInput.elemSize() == 1);
    //构造输出图像
    matOutput = cv::Mat::zeros(matInput.rows, matInput.cols, matInput.type());

    //循环中尽量避免除法
    float fNormalFactor = 1.0f / 255.0f;
    for (size_t r = 0; r < (size_t)matInput.rows; r++)
    {
        unsigned char* pInput = matInput.data + r * matInput.step[0];
        unsigned char* pOutput = matOutput.data + r * matOutput.step[0];
        for (size_t c = 0; c < (size_t)matInput.cols; c++)
        {
            //gamma变换
            float fOutput = std::pow(pInput[c] * fNormalFactor, fGamma) * fC;
            //数值溢出判断
            fOutput = fOutput > 1.0f ? 1.0f : fOutput;
            //输出
            pOutput[c] = static_cast<unsigned char>(fOutput * 255.0f);
        }
    }
}

void gammaTransformation_lut(cv::Mat& matInput, cv::Mat& matOutput, float fGamma, float fC /*= 1.0f*/)
{
    assert(matInput.elemSize() == 1);
    //构造输出图像
    matOutput = cv::Mat::zeros(matInput.rows, matInput.cols, matInput.type());

    //循环中尽量避免除法
    float fNormalFactor = 1.0f / 255.0f;
    //构造查询表
    std::vector<unsigned char> lookUp(256);
    for (size_t m = 0; m < lookUp.size(); m++)
    {
        //gamma变换
        float fOutput = std::pow(m * fNormalFactor, fGamma) * fC;
        //数值溢出判断
        fOutput = fOutput > 1.0f ? 1.0f : fOutput;
        //输出
        lookUp[m] = static_cast<unsigned char>(fOutput * 255.0f);
    }

    for (size_t r = 0; r < (size_t)matInput.rows; r++)
    {
        unsigned char* pInput = matInput.data + r * matInput.step[0];
        unsigned char* pOutput = matOutput.data + r * matOutput.step[0];
        for (size_t c = 0; c < (size_t)matInput.cols; c++)
        {
            //查表gamma变换
            pOutput[c] = lookUp[pInput[c]];
        }
    }
}

void MyGammaCorrection(Mat& src, Mat& dst, float fGamma)
{
    CV_Assert(src.data);

    // accept only char type matrices
    CV_Assert(src.depth() != sizeof(uchar));

    // build look up table
    unsigned char lut[256];
    for( int i = 0; i < 256; i++ )
    {
        lut[i] = saturate_cast<uchar>(pow((float)(i/255.0), fGamma) * 255.0f);
    }

    dst = src.clone();
    const int channels = dst.channels();
    switch(channels)
    {
        case 1:
            {

                MatIterator_<uchar> it, end;
                for( it = dst.begin<uchar>(), end = dst.end<uchar>(); it != end; it++ )
                    //*it = pow((float)(((*it))/255.0), fGamma) * 255.0;
                    *it = lut[(*it)];

                break;
            }
        case 3:
            {

                MatIterator_<Vec3b> it, end;
                for( it = dst.begin<Vec3b>(), end = dst.end<Vec3b>(); it != end; it++ )
                {
                    //(*it)[0] = pow((float)(((*it)[0])/255.0), fGamma) * 255.0;
                    //(*it)[1] = pow((float)(((*it)[1])/255.0), fGamma) * 255.0;
                    //(*it)[2] = pow((float)(((*it)[2])/255.0), fGamma) * 255.0;
                    (*it)[0] = lut[((*it)[0])];
                    (*it)[1] = lut[((*it)[1])];
                    (*it)[2] = lut[((*it)[2])];
                }

                break;

            }
    }
}

void on_Trackbar( int, void* )
{
    float coef = 5;
    //求出当前alpha值相对于最大值的比例
    g_spiderValue = (float) g_nGamaValueSlider/(float)g_nMaxGamaValue ;
    std::cout <<  coef * g_spiderValue << std::endl;
//    gammaTransformation(g_srcImage1,g_dstImage, coef * g_spiderValue, 1 );
    gammaTransformation_lut(g_srcImage1,g_dstImage, coef * g_spiderValue, 1 );
//    MyGammaCorrection(g_srcImage1,g_dstImage, coef * g_spiderValue);
    imshow( WINDOW_NAME, g_dstImage );
}

int main( int argc, char** argv )
{

    g_srcImage1 = imread("10.tif", IMREAD_GRAYSCALE);

    if( !g_srcImage1.data ) {
        printf("读取第一幅图片错误,请确定目录下是否有imread函数指定图片存在~! \n");
        return -1;
    }

    //设置滑动条初值为15
    g_nGamaValueSlider = 15;

    namedWindow(WINDOW_NAME, 1);

    //在创建的窗体中创建一个滑动条控件
    char TrackbarName[50];
    sprintf( TrackbarName, "Gama值 %d", g_nMaxGamaValue );

    createTrackbar( TrackbarName, WINDOW_NAME, &g_nGamaValueSlider, g_nMaxGamaValue, on_Trackbar );

    //结果在回调函数中显示
    on_Trackbar( g_nGamaValueSlider, 0 );
    waitKey(0);

    return 0;
}
 

原始图像,γ  = 2.5校正图像:

原图像、γ  = 0.4校正图像:

原图像、γ  =5校正图像:

猜你喜欢

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