USM锐化之openCV实现,附赠调整对比度函数

源地址:http://www.cnblogs.com/easymind223/archive/2012/07/03/2575277.html

 常用Photoshop的玩家都知道Unsharp Mask(USM)锐化,它是一种增强图像边缘的锐化算法,原理在此处,如果你想使用这个算法,强烈推荐看一下。本文进行一下简单的介绍,USM锐化一共分为三步,第一步生成原始图片src的模糊图片和高对比度图片,记为blur和contrast.第二,把src和blur作差,得到一张差分图片,记为diff,它就是下图的UnsharpMask。然后把src和contras按一定的比例相加,这个比例由diff控制,最终得到锐化图片。USM有一个缺点,锐化后最大和最小的像素值会超过原始图片,如下图红色虚线和白色实线所示。

 
代码如下:
复制代码
void MyTreasureBox::UnsharpMask(const IplImage* src, IplImage* dst, float amount, float radius, uchar threshold, int contrast) { if(!src)return ; int imagewidth = src->width; int imageheight = src->height; int channel = src->nChannels; IplImage* blurimage = cvCreateImage(cvSize(imagewidth,imageheight), src->depth, channel); IplImage* DiffImage = cvCreateImage(cvSize(imagewidth,imageheight), 8, channel); //原图的高对比度图像 IplImage* highcontrast = cvCreateImage(cvSize(imagewidth,imageheight), 8, channel); AdjustContrast(src, highcontrast, contrast); //原图的模糊图像  cvSmooth(src, blurimage, CV_GAUSSIAN, radius); //原图与模糊图作差 for (int y=0; y<imageheight; y++) { for (int x=0; x<imagewidth; x++) { CvScalar ori = cvGet2D(src, y, x); CvScalar blur = cvGet2D(blurimage, y, x); CvScalar val; val.val[0] = abs(ori.val[0] - blur.val[0]); val.val[1] = abs(ori.val[1] - blur.val[1]); val.val[2] = abs(ori.val[2] - blur.val[2]); cvSet2D(DiffImage, y, x, val); } } //锐化 for (int y=0; y<imageheight; y++) { for (int x=0; x<imagewidth; x++) { CvScalar hc = cvGet2D(highcontrast, y, x); CvScalar diff = cvGet2D(DiffImage, y, x); CvScalar ori = cvGet2D(src, y, x); CvScalar val; for (int k=0; k<channel; k++) { if (diff.val[k] > threshold) { //最终图像 = 原始*(1-r) + 高对比*r val.val[k] = ori.val[k] *(100-amount) + hc.val[k] *amount; val.val[k] /= 100; } else { val.val[k] = ori.val[k]; } } cvSet2D(dst, y, x, val); } } cvReleaseImage(&blurimage); cvReleaseImage(&DiffImage); }
复制代码

 

其中用到一个调整图像对比度的函数

复制代码
void MyTreasureBox::AdjustContrast(const IplImage* src, IplImage* dst, int contrast)
{
    if (!src)return ;

    int imagewidth = src->width;
    int imageheight = src->height;
    int channel = src->nChannels;

    //求原图均值
    CvScalar mean = {0,0,0,0};
    for (int y=0; y<imageheight; y++)
    {
        for (int x=0; x<imagewidth; x++)
        {                     
            CvScalar ori = cvGet2D(src, y, x);
            for (int k=0; k<channel; k++)
            {
                mean.val[k] += ori.val[k];
            }         
        }
    }
    for (int k=0; k<channel; k++)
    {
        mean.val[k] /= imagewidth * imageheight;
    }

    //调整对比度
    if (contrast <= -255)    
    {
        //当增量等于-255时,是图像对比度的下端极限,此时,图像RGB各分量都等于阀值,图像呈全灰色,灰度图上只有1条线,即阀值灰度;
        for (int y=0; y<imageheight; y++)
        {
            for (int x=0; x<imagewidth; x++)
            {
                cvSet2D(dst, y, x, mean);
            }
        }
    } 
    else if(contrast > -255 &&  contrast <= 0)
    {
        //(1)nRGB = RGB + (RGB - Threshold) * Contrast / 255
        // 当增量大于-255且小于0时,直接用上面的公式计算图像像素各分量
        //公式中,nRGB表示调整后的R、G、B分量,RGB表示原图R、G、B分量,Threshold为给定的阀值,Contrast为处理过的对比度增量。
        for (int y=0; y<imageheight; y++)
        {
            for (int x=0; x<imagewidth; x++)
            {
                CvScalar nRGB;
                CvScalar ori = cvGet2D(src, y, x);
                for (int k=0; k<channel; k++)
                {
                    nRGB.val[k] = ori.val[k] + (ori.val[k] - mean.val[k]) *contrast /255;
                }
                cvSet2D(dst, y, x, nRGB);
            }
        }
    }
    else if(contrast >0 && contrast <255)
    {
        //当增量大于0且小于255时,则先按下面公式(2)处理增量,然后再按上面公式(1)计算对比度:
        //(2)、nContrast = 255 * 255 / (255 - Contrast) - 255
        //公式中的nContrast为处理后的对比度增量,Contrast为给定的对比度增量。                

        CvScalar nRGB;
        int nContrast = 255 *255 /(255 - contrast) - 255;

        for (int y=0; y<imageheight; y++)
        {
            for (int x=0; x<imagewidth; x++)
            {
                CvScalar ori = cvGet2D(src, y, x);
                for (int k=0; k<channel; k++)
                {
                    nRGB.val[k] = ori.val[k] + (ori.val[k] - mean.val[k]) *nContrast /255;
                }
                cvSet2D(dst, y, x, nRGB);
            }
        }
    }
    else
    {
        //当增量等于 255时,是图像对比度的上端极限,实际等于设置图像阀值,图像由最多八种颜色组成,灰度图上最多8条线,
        //即红、黄、绿、青、蓝、紫及黑与白;        
        for (int y=0; y<imageheight; y++)
        {
            for (int x=0; x<imagewidth; x++)
            {
                CvScalar rgb;
                CvScalar ori = cvGet2D(src, y, x);
                for (int k=0; k<channel; k++)
                {
                    if (ori.val[k] > mean.val[k])
                    {
                        rgb.val[k] = 255;
                    }
                    else
                    {
                        rgb.val[k] = 0;
                    }                    
                }
                cvSet2D(dst, y, x, rgb);
            }
        }
    }
}
复制代码

 

转载于:https://www.cnblogs.com/lanye/p/5363500.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值