OpenCV和Unsharp Masking就像Adobe Photoshop一样

时间:2012-11-08 19:50:40

标签: c++ opencv image-processing reverse-engineering photoshop

我正在尝试实现像在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中完成这些工作?

感谢您的帮助!

4 个答案:

答案 0 :(得分:2)

我也试图复制Photoshop的钝化面膜。 让我们暂时忽略阈值。

我将向您展示如何使用高斯模糊复制Photoshop的钝化蒙版。

假设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。

然而,当我在MATLAB中直接这样做时,我无法获得Photoshop的结果。

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

更新

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

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

答案 1 :(得分:1)

根据文件:

  

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

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

频道

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

答案 2 :(得分:0)

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

using PROJECT;
using PROJECT.UWP;
using System.Collections.Generic;
using Windows.Devices.Geolocation;
using Windows.UI.Xaml.Controls.Maps;
using Xamarin.Forms.Maps;
using Xamarin.Forms.Maps.UWP;
using Xamarin.Forms.Platform.UWP;

[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace PROJECT.UWP
{
    public class CustomMapRenderer : MapRenderer
    {
        MapControl nativeMap;
        CustomMap formsMap;

        protected override void OnElementChanged(ElementChangedEventArgs<Map> e)
        {
            base.OnElementChanged(e);

            if (e.OldElement != null)
            {
                nativeMap = Control as MapControl;
            }

            if (e.NewElement != null)
            {
                formsMap = (CustomMap)e.NewElement;
                nativeMap = Control as MapControl;
                UpdatePolyLine();
            }
        }

        protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);
            if (this.Element == null || this.Control == null)
                return;

            if (e.PropertyName == CustomMap.RouteCoordinatesProperty.PropertyName)
            {
                UpdatePolyLine();
            }
        }

        private void UpdatePolyLine()
        {
            if (formsMap != null && formsMap.RouteCoordinates.Count > 0)
            {
                List<BasicGeoposition> coordinates = new List<BasicGeoposition>();

                foreach (var position in formsMap.RouteCoordinates)
                {
                    coordinates.Add(new BasicGeoposition() { Latitude = position.Latitude, Longitude = position.Longitude });
                }

                Geopath path = new Geopath(coordinates);
                MapPolyline polyline = new MapPolyline();
                polyline.StrokeColor = Windows.UI.Color.FromArgb(128, 255, 0, 0);
                polyline.StrokeThickness = 5;
                polyline.Path = path;
                nativeMap.MapElements.Add(polyline);
            }
        }
    }
}

答案 3 :(得分:0)

作为对@Royi 的回应,2x 乘数源于假设此公式中没有钳位:

USM(Original) = Original + Amount / 100 * ((Original - GB) - (1 - (Original + (1 - GB))))

忽略不正确的钳位会导致:

USM(Original) = Original + 2 * Amount / 100 * (Original - GB) 

但是,正如您还指出的,(Original - GB)(Original + inv(GB)) 被限制为 [0, 1]:

USM(Original) = Original + Amount / 100 *
   (Max(0, Min(1, Original - GB)) - (1 - (Max(0, Min(1, Original + (1 - GB))))))

这正确地简化为:

USM(Original) = Original + Amount / 100 * (Original - GB)

这是一个说明原因的示例:

https://legacy.imagemagick.org/discourse-server/viewtopic.php?p=133597#p133597