OpenCV和Unsharp Masking就像Adobe Photoshop一样

问题描述 投票:2回答:3

我正在尝试实现像在Adobe Photoshop中完成的非锐化掩模。我收集了很多关于互联网的信息,但我不确定我是否遗漏了一些东西。这是代码:

void unsharpMask( cv::Mat* img, double amount, double radius, double threshold ) {

// create blurred img
cv::Mat img32F, imgBlur32F, imgHighContrast32F, imgDiff32F, unsharpMas32F, colDelta32F, compRes, compRes32F, prod;
double r = 1.5;
img->convertTo( img32F, CV_32F );
cv::GaussianBlur( img32F, imgBlur32F, cv::Size(0,0), radius );
cv::subtract( img32F, imgBlur32F, unsharpMas32F );
// increase contrast( original, amount percent ) 
imgHighContrast32F = img32F * amount / 100.0f;
cv::subtract( imgHighContrast32F, img32F, imgDiff32F );
unsharpMas32F /= 255.0f;
cv::multiply( unsharpMas32F, imgDiff32F, colDelta32F );
cv::compare( cv::abs( colDelta32F ), threshold, compRes, cv::CMP_GT );
compRes.convertTo( compRes32F, CV_32F );

cv::multiply( compRes32F, colDelta32F, prod );
cv::add( img32F, prod, img32F );

img32F.convertTo( *img, CV_8U );
}

目前我正在使用灰度图像进行测试。如果我在Photoshop中尝试完全相同的参数,我会得到更好的结果。我自己的代码会导致图像嘈杂。我究竟做错了什么。

第二个问题是,我如何在RGB图像上应用反锐化掩模?我是否需要对3个通道中的每一个进行非锐化遮罩,还是在另一个色彩空间中更好?如何在Photoshop中完成这些工作?

谢谢你的帮助!

c++ opencv image-processing reverse-engineering photoshop
3个回答
2
投票

我也试图复制Photoshop的Unsharp Mask。让我们暂时忽略阈值。

我将向您展示如何使用其高斯模糊复制Photoshop Unsharp Mask。

假设O是原始图像层。

创建一个新的图层GB,它是应用于O的高斯模糊。 创建一个O - GB的新图层(使用应用图像)。 通过反转GB-invGB创建一个新层。 使用Image Apply创建一个O + invGB的新图层。 创建一个新层,它是前一层的反转,即inv(O + invGB)。 创建一个新的层,即O +(O - GB) - inv(O + invGB)。

当您在Photoshop中执行此操作时,您将获得完美再现的锐化蒙版。

如果你做数学回忆inv(L)= 1 - L你会得到USM(O)= 3O - 2B的USM(O)= 3O - 2B。

然而,当我在MATLAB中直接这样做时,我没有得到Photoshop的结果。

希望有人会知道确切的数学。

更新

好, 我想到了。 在Photoshop USM(O)= O +(2 *(金额/ 100)*(O - GB)) 其中GB是O的高斯模糊版本。

然而,为了复制Photoshop的结果,您必须执行上述步骤,并将每个步骤的结果剪辑为[0,1],就像在Photoshop中一样。


1
投票

According to docs:

C ++:void GaussianBlur(InputArray src,OutputArray dst,Size ksize,double sigmaX,double sigmaY = 0,int borderType = BORDER_DEFAULT)

第4个参数不是“半径”,而是“sigma” - 高斯核标准差。半径相当“ksize”。无论如何Photoshop不是开源的,因此我们不能确定它们使用与OpenCV相同的方式来从sigma计算半径。

Channels

是的,您应该对任何或所有渠道应用锐利,这取决于您的目的。当然你可以使用任何空间:如果你想要只有锐利的亮度分量并且不想增加色彩噪声,你可以将它转换为HSL或Lab空间和仅有锐利的L通道(Photoshop也有所有这些选项)。


0
投票

这是我所做的代码。我正在使用此代码来实现USM锐化,它对我来说效果很好。希望它对你有用。

void USM(cv::Mat &O, int d, int amp, int threshold)
{
    cv::Mat GB;
    cv::Mat O_GB;
    cv::subtract(O, GB, O_GB);

    cv::Mat invGB = cv::Scalar(255) - GB;

    cv::add(O, invGB, invGB);

    invGB = cv::Scalar(255) - invGB;

    for (int i = 0; i < O.rows; i++)
    {
        for (int j = 0; j < O.cols; j++)
        {
            unsigned char o_rgb = O.at<unsigned char>(i, j);
            unsigned char d_rgb = O_GB.at<unsigned char>(i, j);
            unsigned char inv_rgb = invGB.at<unsigned char>(i, j);

            int newVal = o_rgb;
            if (d_rgb >= threshold)
            {
                newVal = o_rgb + (d_rgb - inv_rgb) * amp;
                if (newVal < 0)      newVal = 0;
                if (newVal > 255)    newVal = 255;
            }

            O.at<unsigned char>(i, j) = unsigned char(newVal);
        }
    }

}
© www.soinside.com 2019 - 2024. All rights reserved.