【问题标题】:How to create Photoshop Stamp filter analog in any pixel shading language?如何以任何像素着色语言创建 Photoshop Stamp 过滤器模拟?
【发布时间】:2023-04-14 02:49:02
【问题描述】:

如何以任何像素着色语言创建 Photoshop Stamp 过滤器模拟? (我至少需要过滤算法……)

【问题讨论】:

    标签: photoshop filter hlsl


    【解决方案1】:

    我查看了 Photoshop 中的图章过滤器,它看起来像是一个阈值和一个强模糊叠加在一起。

    我使用了 Pixel Bender Basics Article on Devnet 找到的 Horizo​​ntalGaussianBlur 内核 并且只是增加了一个便宜的门槛。这是我的内核的样子:

    <languageVersion : 1.0;>
    
    kernel stamp
    <   namespace : "toMaterial";
        vendor : "George Profenza";
        version : 1;
        description : "Attempt to simulate Photoshop Stamp Filter. Original blur code: http://www.adobe.com/devnet/flash/articles/pixel_bender_basics_05.html";
    >
    {
        input image4 src;
        output pixel4 dst;
    
        parameter float threshold<
            minValue: 0.0;
            defaultValue:0.5;
            maxValue:1.0;
        >;
        parameter int radius
        <
            minValue : 1;
            maxValue : 6;
            defaultValue : 6;
        >;
    
        void
        evaluatePixel()
        {
            pixel4 center, band1, band2, band3, band4, band5, band6;
            float2 pos = outCoord();
    
            //Sample image in bands
            if(radius > 5) {
                pixel4 left  = dst;
                pixel4 right = dst;
                left.x -= 6.0;
                right.x += 6.0;
                band6 = left+right;
            }
            if(radius > 4) {
                pixel4 left  = dst;
                pixel4 right = dst;
                left.x -= 5.0;
                right.x += 5.0;
                band5 = left+right;
            }
            if(radius > 3) {
                pixel4 left  = dst;
                pixel4 right = dst;
                left.x -= 4.0;
                right.x += 4.0;
                band4 = left+right;
            }
            if(radius > 2) {
                pixel4 left  = dst;
                pixel4 right = dst;
                left.x -= 3.0;
                right.x += 3.0;
                band3 = left+right;
            }
            if(radius > 1) {
                pixel4 left  = dst;
                pixel4 right = dst;
                left.x -= 2.0;
                right.x += 2.0;
                band2 = left+right;
            }
            pixel4 left  = dst;
            pixel4 right = dst;
            left.x -= 1.0;
            right.x += 1.0;
            band1 = left+right;
    
            dst = sampleNearest(src,pos);
            //quick'n'dirty grayscale
            dst.rgb = float3(dst.r + dst.g + dst.b) * 0.333333333;
            //threshold
            if(dst.r < threshold) dst.r = 0.0; else dst.r = 1.0;
            if(dst.g < threshold) dst.g = 0.0; else dst.g = 1.0;
            if(dst.b < threshold) dst.b = 0.0; else dst.b = 1.0;
    
            center = dst;
    
            //Apply weights and compute resulting pixel
           if( radius == 6 )
           {
                dst = (band6 + (band5 * 12.0) + (band4 * 66.0) + (band3 * 220.0) + (band2 * 495.0) + (band1 * 792.0) + (center * 924.0)) * 0.000244140625;//4096.0;
           }
           if( radius == 5 )
           {
                dst = (band5 + (band4 * 10.0) + (band3 * 45.0) + (band2 * 120.0) + (band1 * 210.0) + (center * 252.0)) * 0.0009765625;//1024.0;
           }       
           if( radius == 4 )
           {
                dst = (band4 + (band3 * 8.0) + (band2 * 28.0) + (band1 * 56.0) + (center * 70.0)) * 0.00390625;//256.0;
           }
           if( radius == 3 )
           {
                dst = (band3 + (band2 * 6.0) + (band1 * 15.0) + (center * 20.0)) * 0.015625;//64.0;
           }
           if( radius == 2 )
           {
                dst = (band2 + (band1 * 4.0) + (center * 6.0)) * 0.0625;//16.0
           }
           if( radius == 1 )
           {
                dst = (band1 + (center * 2.0)) * 0.25;//4.0
           }
    
        }
    }
    

    这远非完美,这是我现在可以快速破解的。这应该 不过给你一些想法。

    更新:

    这是一个使用适当灰度的更新版本,高斯模糊代码主要来自Pixel Bender Guide

    <languageVersion : 1.0;>
    
    kernel Stamp
    <   namespace : "gp";
        vendor : "George Profenza";
        version : 1;
        description : "Attempt to do a filter similar to Photoshop's Stamp Filter, blur code mostly from the guide: http://www.adobe.com/go/pixelbender_devguide";
    >
    {
        input image4 source;
        output pixel4 result;
    
        parameter int blur<
            minValue:1;
            defaultValue:3;
            maxValue:8;
        >;
        parameter float threshold<
            minValue:0.0;
            maxValue:1.0;
            defaultValue:0.5;
        >;
    
        void
        evaluatePixel()
        {
            //blur
            const float sigma = 2.0;
            float c = 1.0 / ( sqrt(2.0 * 3.1415926535 ) * sigma );
            float ec = 2.0 * sigma * sigma;
            float weight0 = exp( -( 0.0 * 0.0 ) / ec ) * c;
            float weight1 = exp( -( 1.0 * 1.0 ) / ec ) * c;
            if(blur > 1) float weight2 = exp( -( 2.0 * 2.0 ) / ec ) * c;
            if(blur > 2) float weight3 = exp( -( 3.0 * 3.0 ) / ec ) * c;
            if(blur > 3) float weight4 = exp( -( 4.0 * 4.0 ) / ec ) * c;
            if(blur > 4) float weight5 = exp( -( 5.0 * 5.0 ) / ec ) * c;
            if(blur > 5) float weight6 = exp( -( 6.0 * 6.0 ) / ec ) * c;
            if(blur > 6) float weight7 = exp( -( 7.0 * 7.0 ) / ec ) * c;
            if(blur > 7) float weight8 = exp( -( 8.0 * 7.0 ) / ec ) * c;
    
            float4 acc = float4( 0.0 );
    
            acc += sampleNearest( source, outCoord() ) * weight0;
            acc += sampleNearest( source, outCoord() + float2( 1.0, 0.0 ) ) * weight1;
            acc += sampleNearest( source, outCoord() + float2( -1.0, 0.0 ) ) * weight1;
            if(blur > 1) {
                acc += sampleNearest( source, outCoord() + float2( 2.0, 0.0 ) ) * weight2;
                acc += sampleNearest( source, outCoord() + float2( -2.0, 0.0 ) ) * weight2;
            }
            if(blur > 2) {
                acc += sampleNearest( source, outCoord() + float2( 3.0, 0.0 ) ) * weight3;
                acc += sampleNearest( source, outCoord() + float2( -3.0, 0.0 ) ) * weight3;
            }
            if(blur > 3) {
                acc += sampleNearest( source, outCoord() + float2( 4.0, 0.0 ) ) * weight4;
                acc += sampleNearest( source, outCoord() + float2( -4.0, 0.0 ) ) * weight4;
            }
            if(blur > 4) {
                acc += sampleNearest( source, outCoord() + float2( 5.0, 0.0 ) ) * weight5;
                acc += sampleNearest( source, outCoord() + float2( -5.0, 0.0 ) ) * weight5;
            }
            if(blur > 5) {
                acc += sampleNearest( source, outCoord() + float2( 6.0, 0.0 ) ) * weight6;
                acc += sampleNearest( source, outCoord() + float2( -6.0, 0.0 ) ) * weight6;
            }
            if(blur > 6) {
                acc += sampleNearest( source, outCoord() + float2( 7.0, 0.0 ) ) * weight7;
                acc += sampleNearest( source, outCoord() + float2( -7.0, 0.0 ) ) * weight7;
            }
            if(blur > 7) {
                acc += sampleNearest( source, outCoord() + float2( 8.0, 0.0 ) ) * weight8;
                acc += sampleNearest( source, outCoord() + float2( -8.0, 0.0 ) ) * weight8;
            }
            //grayscale
            float luma = 0.299 * acc.r + 0.587 * acc.g + 0.114 * acc.b;
            acc = float4(luma,luma,luma,1.0);
            //threshold
            if(acc.r < threshold) acc.r = 0.0; else acc.r = 1.0;
            if(acc.g < threshold) acc.g = 0.0; else acc.g = 1.0;
            if(acc.b < threshold) acc.b = 0.0; else acc.b = 1.0;
    
            result = acc;
        }
    }
    

    注意:我在模糊之后应用了阈值,因此结果不是完全是 Stamp Filter,而是接近。

    HTH, 乔治

    【讨论】: