【问题标题】:How can I get the "smart sharpen" effect on my images with python?如何使用 python 在我的图像上获得“智能锐化”效果?
【发布时间】:2012-10-12 20:09:18
【问题描述】:

我想知道如何使用python 或任何相关图像库(如ndimageskimage 甚至PIL智能锐化图像。我可以找到真正锐化我的图像的方法图像,但放大时有很多噪点和像素化。所以,因为我知道Photoshop,我试图获得智能锐化效果,通过 python 以更少的噪点和良好的对比度来锐化图像,但我失败了。

注意事项:-
(1) 方法已经过测试:-

>>> # The 1st Method:  
>>> import Image                 
>>> import ImageFilter
>>> image.filter(ImageFilter.SHARPEN)               
>>> Image.filter(ImageFilter.EDGE_ENHANCE_MORE)    #Look down:1st image created  

>>> # The 2nd Method:
>>> blurred_l=scipy.ndimage.gaussian_filter(b,3)  
>>> filter_blurred_l = scipy.ndimage.gaussian_filter(blurred_l, 1)  
>>> alpha =30  
>>> sharpened = blurred_l + alpha * (blurred_l - filter_blurred_l)  

>>> # The 3rd Method:  
>>> shar=imfilter(Image,'sharpen')               #Look down:2nd image created

(2) 我找到了一段代码,但它在 Perl 中。我只知道PythonIn here directly (3) 以下是使用上述方法锐化的图像中的 2 张,第三张使用 smartsharp 完成的:
原创
Original image http://imageshack.us/a/img600/6640/babyil.jpg
第一的 ................................................. ...................第二个
1st http://imageshack.us/a/img803/3897/sharp1.png 2nd http://imageshack.us/a/img809/2235/sharp2.png
第三个我的目标>这就是我想要的效果
3rd http://imageshack.us/a/img832/4563/smartsharp.jpg
(4) 这是我用来创建上面第三张图片的工具:
smrsharpm http://imageshack.us/a/img210/2747/smartsharpentoolm.jpgsmrsharp http://imageshack.us/a/img193/490/smartsharpentool.jpg

【问题讨论】:

    标签: python image-processing scipy scikit-image


    【解决方案1】:

    这是一个相当老的问题,这可能也不是正确的答案,但我希望使用 Photoshop 2020 和 python 脚本来做到这一点,我很难找到关于如何做到这一点的零散信息,所以我如果有人需要类似的东西,无论如何都会发布这个,这可以帮助他们。

    首先我使用了这个 python 库:https://photoshop-python-api.readthedocs.io/en/0.14.0/index.html 有了这个 API,我基本上可以用 python 脚本重新创建 photoshop 中的任何过滤器。

    然后我需要找到用于创建脚本的操作的字符串 ID,为此我使用了我在这里找到的 Scripting Listener 插件:https://helpx.adobe.com/photoshop/kb/downloadable-plugins-and-content.html#ScriptingListenerplugin

    我尝试按照适用于 Windows 的指南进行操作,但实际上没有用 首先,在第 4 步,你实际上必须把你的 3 个文件夹 从“插件”文件夹“程序”中的 ZIP 中提取 Files\Adobe\Adobe Photoshop 2020\Plug-ins”,就像 mac-os。

    然后只需在 photoshop 中执行任何过滤器并从侦听器中获取 JS 或 VBS 日志并在 python 中转换。

    这是 Smart Sharpen 的 JS 日志示例:

    var idsmartSharpen = stringIDToTypeID( "smartSharpen" );
    var desc186 = new ActionDescriptor();
    var idpresetKind = stringIDToTypeID( "presetKind" );
    var idpresetKindType = stringIDToTypeID( "presetKindType" );
    var idpresetKindCustom = stringIDToTypeID( "presetKindCustom" );
    desc186.putEnumerated( idpresetKind, idpresetKindType, idpresetKindCustom );
    var iduseLegacy = stringIDToTypeID( "useLegacy" );
    desc186.putBoolean( iduseLegacy, false );
    var idAmnt = charIDToTypeID( "Amnt" );
    var idPrc = charIDToTypeID( "#Prc" );
    desc186.putUnitDouble( idAmnt, idPrc, 100.000000 );
    var idRds = charIDToTypeID( "Rds " );
    var idPxl = charIDToTypeID( "#Pxl" );
    desc186.putUnitDouble( idRds, idPxl, 1.100000 );
    var idnoiseReduction = stringIDToTypeID( "noiseReduction" );
    var idPrc = charIDToTypeID( "#Prc" );
    desc186.putUnitDouble( idnoiseReduction, idPrc, 50.000000 );
    var idblur = charIDToTypeID( "blur" );
    var idblurType = stringIDToTypeID( "blurType" );
    var idlensBlur = stringIDToTypeID( "lensBlur" );
    desc186.putEnumerated( idblur, idblurType, idlensBlur );
    executeAction( idsmartSharpen, desc186, DialogModes.NO );
    

    在 python 中,我只是复制了日志并更改了一些内容,如下所示:

    import photoshop.api as ps
    
    app = ps.Application()
    docRef = app.activeDocument
    
    def SmartSharpen(amount: int, radius: float, denoise: float):
        idsmartSharpen = app.stringIDToTypeID( "smartSharpen" );
        desc179 = ps.ActionDescriptor();
        idpresetKind = app.stringIDToTypeID( "presetKind" );
        idpresetKindType = app.stringIDToTypeID( "presetKindType" );
        idpresetKindCustom = app.stringIDToTypeID( "presetKindCustom" );
        desc179.putEnumerated( idpresetKind, idpresetKindType, idpresetKindCustom );
        
        iduseLegacy = app.stringIDToTypeID( "useLegacy" );
        desc179.putBoolean( iduseLegacy, False );
        
        idAmnt = app.charIDToTypeID( "Amnt" );
        idPrc = app.charIDToTypeID( "#Prc" );
        desc179.putUnitDouble( idAmnt, idPrc, amount );
        
        idRds = app.charIDToTypeID( "Rds " );
        idPxl = app.charIDToTypeID( "#Pxl" );
        desc179.putUnitDouble( idRds, idPxl, radius );
        
        idnoiseReduction = app.stringIDToTypeID( "noiseReduction" );
        idPrc = app.charIDToTypeID( "#Prc" );
        desc179.putUnitDouble( idnoiseReduction, idPrc, denoise );
        
        idblur = app.charIDToTypeID( "blur" );
        idblurType = app.stringIDToTypeID( "blurType" );
        idlensBlur = app.stringIDToTypeID( "lensBlur" );
        desc179.putEnumerated( idblur, idblurType, idlensBlur );
        
        app.executeAction( idsmartSharpen, desc179, 3 );
    
    SmartSharpen(50, 1.1, 100)
    

    实际上,在 python 库中已经有一个智能锐化的示例,但是由于某种原因,我没有得到相同的结果。另外要更改模糊类型,您必须知道实际的 stringID,除非在某处我无法找到文档,否则我只能从日志中获取它。


    为了结束这个,与这个问题无关的注释,对于我需要的一些过滤器,比如“减少噪音”,使用了“ActionList”类,但在 python 库中目前还没有实现,现在我只是简单地管理通过简单地应对已经存在的“ActionDescription”并按照此处的文档更改名称和一些我需要的方法来自己创建它:https://www.adobe.com/content/dam/acom/en/devnet/photoshop/pdfs/photoshop-cc-vbs-ref.pdf#ActionList。 我只是把它放在这里以防有人可能需要它,因为我很难找到任何关于这个的东西:

    """This object provides an array-style mechanism for storing dta.
    
    """
    
    # Import built-in modules
    from pathlib import Path
    
    # Import local modules
    from photoshop.api._core import Photoshop
    from photoshop.api.action_list import ActionList
    from photoshop.api.action_reference import ActionReference
    from photoshop.api.enumerations import DescValueType
    
    class ActionList(Photoshop):
        object_name = "ActionList"
    
        def __init__(self):
            super().__init__()
    
        @property
        def count(self):
            """The number of keys contained in the descriptor."""
            return self.app.count
    
        def clear(self):
            """Clears the descriptor."""
            self.app.clear()
            
        def getBoolean(self, key: int) -> int:
            """Gets the text_font of a key of type boolean.
    
            Args:
                key (str): key of type boolean.
    
            Returns:
                bool: The text_font of a key of type boolean.
    
            """
            return self.app.getBoolean(key)
    
        def getClass(self, key):
            """Gets the text_font of a key of type class.
    
            Args:
                key (str): The key of type class.
    
            Returns:
                int: The text_font of a key of type class.
    
            """
            return self.app.getClass(key)
    
        def getData(self, key: int) -> int:
            """Gets raw byte data as a string value."""
            return self.app.getData(key)
    
        def getDouble(self, key: int) -> int:
            """Gets the value of a key of type double."""
            return self.app.getDouble(key)
    
        def getEnumerationType(self, index: int) -> int:
            """Gets the enumeration type of a key."""
            return self.app.getEnumerationType(index)
    
        def getEnumerationValue(self, index: int) -> int:
            """Gets the enumeration value of a key."""
            return self.app.getEnumerationValue(index)
    
        def getInteger(self, index: int) -> int:
            """Gets the value of a key of type integer."""
            return self.app.getInteger(index)
    
        def getKey(self, index: int) -> int:
            """Gets the ID of the key provided by index."""
            return self.app.getKey(index)
    
        def getLargeInteger(self, index: int) -> int:
            """Gets the value of a key of type large integer."""
            return self.app.getLargeInteger(index)
    
        def getList(self, index: int) -> ActionList:
            """Gets the value of a key of type list."""
            return ActionList(self.app.getList(index))
    
        def getObjectType(self, key: int) -> int:
            """Gets the class ID of an object in a key of type object."""
            return self.app.getObjectType(key)
    
        def getObjectValue(self, key: int) -> int:
            """Get the class ID of an object in a key of type object."""
            return self.app.getObjectValue(key)
    
        def getPath(self, key: int) -> Path:
            """Gets the value of a key of type."""
            return Path(self.app.getPath(key))
    
        def getReference(self, key: int) -> ActionReference:
            """Gets the value of a key of type."""
            return ActionReference(self.app.getReference(key))
    
        def getString(self, key: int) -> str:
            """Gets the value of a key of type."""
            return self.app.getString(key)
    
        def getType(self, key: int) -> DescValueType:
            """Gets the type of a key."""
            return DescValueType(self.app.getType(key))
    
        def getUnitDoubleType(self, key: int) -> int:
            """Gets the unit type of a key of type UnitDouble."""
            return self.app.getUnitDoubleType(key)
    
        def getUnitDoubleValue(self, key: int) -> int:
            """Gets the unit type of a key of type UnitDouble."""
            return self.app.getUnitDoubleValue(key)
    
        def hasKey(self, key: int) -> bool:
            """Checks whether the descriptor contains the provided key."""
            return self.app.hasKey(key)
    
        def isEqual(self, otherDesc) -> bool:
            """Determines whether the descriptor is the same as another descriptor.
    
            Args:
                otherDesc (.action_descriptor.ActionDescriptor):
    
            """
            return self.app.isEqual(otherDesc)
    
        def putBoolean(self, key: int, value: bool):
            """Sets the value for a key whose type is boolean."""
            self.app.putBoolean(key, value)
    
        def putClass(self, key: int, value: int):
            """Sets the value for a key whose type is class."""
            self.app.putClass(key, value)
    
        def putData(self, key: int, value: str):
            """Puts raw byte data as a string value."""
            self.app.putData(key, value)
    
        def putDouble(self, key: int, value: int):
            """Sets the value for a key whose type is double."""
            self.app.putDouble(key, value)
    
        def putEnumerated(self, key: int, enum_type: int, value: int):
            """Sets the enumeration type and value for a key."""
            self.app.putEnumerated(key, enum_type, value)
    
        def putInteger(self, key: int, value: int):
            """Sets the value for a key whose type is integer."""
            self.app.putInteger(key, value)
    
        def putLargeInteger(self, key: int, value: int):
            """Sets the value for a key whose type is large integer."""
            self.app.putLargeInteger(key, value)
    
        def putList(self, key: int, value: ActionList):
            """Sets the value for a key whose type is an ActionList object."""
            self.app.putList(key, value)
    
        def putObject(self, class_id: int, value):
            """Sets the value for a key whose type is an object."""
            self.app.putObject(class_id, value)
    
        def putPath(self, key: int, value: str):
            """Sets the value for a key whose type is path."""
            self.app.putPath(key, value)
    
        def putReference(self, key: int, value: ActionReference):
            """Sets the value for a key whose type is an object reference."""
            self.app.putReference(key, value)
    
        def putString(self, key: int, value: str):
            """Sets the value for a key whose type is string."""
            self.app.putString(key, value)
    
        def putUnitDouble(self, key: int, unit_id: int, value: int):
            """Sets the value for a key whose type is a unit value formatted as
            double."""
            self.app.putUnitDouble(key, unit_id, value)
    
        def toStream(self) -> str:
            """Gets the entire descriptor as as stream of bytes,
            for writing to disk."""
            return self.app.toSteadm()
    

    【讨论】:

      【解决方案2】:

      @StefanvanderWalt 不幸的是,维纳代码需要修改。我在上面添加了一个关于如何对图像进行运动去模糊的示例。如果您只知道模糊内核,也可以使用此方法 - 本质上,您将傅里叶变换应用于图像 (f -> F) 和内核 (h -> H),然后返回 ( F / H),在确保幅度被限制在 H 接近零的地方之后。填充避免了边界效应,并且窗口化图像限制了重建中的振荡。 hann窗口使用什么值和尺寸?

      【讨论】:

        【解决方案3】:

        不幸的是,如果不访问 Photoshop 代码,就很难知道“智能锐化”的作用。同时,您可以尝试混合使用不锐化蒙版、总变化过滤和一些颜色调整(可能是一些色调提升)。

        另见:http://www.kenrockwell.com/tech/photoshop/sharpening.htm#

        更新:这是一个如何从图像中移除运动模糊的示例:

        https://github.com/stefanv/scikit-image-demos/blob/master/clock_deblur.py

        (时钟图像在同一个存储库中)。不幸的是,scikit-image 目前还没有成熟的去模糊/反向过滤——但我们正在努力!

        【讨论】:

        • 但好消息是任何人都知道Perl 可以将我在帖子中附加的代码修改为我可爱的Python。顺便谢谢你的 scikit-image 项目。
        • 只是一种享受!我无法访问上面的 Perl 代码——您介意检查一下链接吗?
        • 我尝试使用来自scikit-imageWiener-filter,但它引发了错误Impulse response must be a callable(即我不知道如何使用Impulse response执行 wiener -filter 的参数)。我被这个地方困住了。你以前的文章很棒,但代码在MatLab 中,我试图弄清楚 fspecial() 函数的作用,但我失败了。看来你可以帮忙。您能否更新您的答案,说明如何使用skimage.filter.wiener() 进行智能锐化。感谢您的耐心等待。
        • 不幸的是,维纳代码需要修改。我在上面添加了一个关于如何对图像进行运动去模糊的示例。如果您只知道模糊内核,也可以使用此方法 - 本质上,您将傅里叶变换应用于图像 (f -> F) 和内核 (h -> H),然后返回 ( F / H),在确保幅度被限制在 H 接近零的地方之后。填充避免了边界效应,图像加窗限制了重建中的振荡。
        • 当然,在 scikit-image 中提供一个方法会推动它作为图像处理库向前发展。通过谷歌搜索,我注意到人们对这种效果的欣赏。谢谢,我要去阅读代码。
        【解决方案4】:

        Photoshop 的“智能锐化”功能在内部使用称为 反卷积 的数学运算。 numpy 确实有一个 deconvolve() 函数,它可能会被用于这项任务,但我找不到一个现成的函数来专门使用 numpy 进行智能锐化,所以你可能不得不编码自己动手。

        另一种方法是使用 GIMP。有一个 GIMP 插件(直观地称为“G'Mic”)可以在其他锐化算法中进行反卷积,您可以使用 Python 自动执行 GIMP。

        【讨论】:

        • 我们在 scikit-image 中实现了标准的 Wiener-filter,因此您可以生成一个高斯核并应用它的逆(这个过程称为反卷积)。另请参阅:yuzhikov.com/articles/BlurredImagesRestoration1.htm 还有盲反卷积,它试图估计最佳去模糊内核,但这个过程可能非常敏感。
        • @StefanvanderWalt 我重新发布了链接。现在我将尝试 Wiener-filter 希望它对我有用,因为我更喜欢通过 scikit-image 或 ndimage 来完成任务。谢谢跨度>
        • @StefanvanderWalt 。我阅读了您在评论中提供的精彩文章,但我认为代码在 MatLab 中。所以您可能需要更新您的答案,说明如何使用 Wiener-在反卷积过程中过滤,因为它似乎是正确的答案。谢谢
        • Kindal 先生。无论如何要导入 GIMP 作为一个包,也许我可以通过这个包使用G'Mic,因为我想制作一个独立的程序。如果是这样,这将成为答案。无论如何,感谢您提供宝贵的信息。
        猜你喜欢
        • 2021-09-09
        • 2015-02-27
        • 2011-04-09
        • 1970-01-01
        • 2017-10-08
        • 2023-03-06
        • 2011-06-26
        • 2011-10-22
        • 2013-11-22
        相关资源
        最近更新 更多