如何在iPhone上通过颜色查找图像的边缘?

3

我正在开发一个与更改图像颜色效果相关的应用程序。我已经完成了几乎所有的工作。现在的问题是,在其中一种效果中,我必须像Photoshop中的辉光边缘滤镜一样给出效果。这个滤镜会用它的颜色流过图像的边缘,而图像的其余颜色则为黑色。通过使用BradLarson GPU Image GPUImageSobelEdgeDetectionFilter或GPUImageCannyEdgeDetectionFilter,我可以找到边缘,但是边缘是白色的,我需要找到彩色边缘。是否有其他方法可以使用GPUImage或openCV找到彩色边缘。 对我来说,任何帮助都将非常有用。 谢谢


当然可以。您可以基于GPUImage中的边缘检测滤镜创建自定义滤镜,将白色替换为您自己可控制的颜色。已经有几个人这样做了,只需要对着色器代码进行一些微调即可。 - Brad Larson
@BradLarson:感谢您的回复,但我需要更多帮助。如何获取图像中边缘的原始颜色,请解释一下。这将非常有帮助。 - Surjeet Singh
1个回答

7
你真的应该尝试使用自定义着色器。它非常容易上手,如果你投入足够的精力,就能很快地变得强大。
话虽如此,我认为你是想要达到以下结果: Edge Detection on a pile of Lego's 有很多可行的方法可以实现这一点,但编写一个GPUImageTwoInputFilter子类的自定义着色器,并将其定位于原始图像和边缘检测图像,是我实现这个图片的方法。
这个子类看起来应该像这样:
#import "OriginalColorEdgeMixer.h"


//Assumes you have targeted this filter with the original image first, then with an edge detection filter that returns white pixels on edges
//We are setting the threshold manually here, but could just as easily be a GLint which is dynamically fed at runtime

#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
NSString *const kOriginalColorEdgeMixer = SHADER_STRING
(
 varying highp vec2 textureCoordinate;
 varying highp vec2 textureCoordinate2;

 uniform sampler2D inputImageTexture;
 uniform sampler2D inputImageTexture2;

 lowp float threshold;
 mediump float resultingRed;
 mediump float resultingGreen;
 mediump float resultingBlue;

 void main()
 {
     mediump vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
     mediump vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);
     threshold = step(0.3, textureColor2.r);

     resultingRed = threshold * textureColor.r;
     resultingGreen = threshold * textureColor.g;
     resultingBlue = threshold *textureColor.b;

     gl_FragColor = vec4(resultingRed, resultingGreen, resultingBlue, textureColor.a);
 }
 );
#else
NSString *const kGPUImageDifferenceBlendFragmentShaderString = SHADER_STRING
(
 varying vec2 textureCoordinate;
 varying vec2 textureCoordinate2;

 uniform sampler2D inputImageTexture;
 uniform sampler2D inputImageTexture2;

 float threshold;
 float resultingRed;
 float resultingGreen;
 float resultingBlue;

 void main()
 {
     vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
     vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);
     threshold = step(0.3,textureColor2.r);

     resultingRed = threshold * textureColor.r;
     resultingGreen = threshold * textureColor.g;
     resultingBlue = threshold *textureColor.b;

     gl_FragColor = vec4(resultingRed, resultingGreen, resultingBlue, textureColor.a);
 }
 );
#endif

@implementation OriginalColorEdgeMixer

- (id)init;
{
    if (!(self = [super initWithFragmentShaderFromString:kOriginalColorEdgeMixer]))
    {
        return nil;
    }

    return self;
}

@end

在我写作的时候,我们期望边缘检测滤镜的输出是这个自定义滤镜的第二个输入。

我任意选择了一个阈值为0.3的数值来控制边缘检测图像上的强度,以便原始颜色可以显示出来。通过将它与从应用程序的 UISlider 获取到的 GLint 相关联(Brad 的示例代码中有很多这样的例子),这很容易实现动态调整。

为了让那些刚开始使用 GPUImage 的人更加清晰易懂,使用你编写的自定义滤镜非常容易。我像这样做:

[self configureCamera];

edgeDetection = [[GPUImageSobelEdgeDetectionFilter alloc] init];
edgeMixer = [[OriginalColorEdgeMixer alloc] init];

[camera addTarget:edgeDetection];
[camera addTarget:edgeMixer];
[edgeDetection addTarget:edgeMixer];
[edgeMixer addTarget:_previewLayer];

[camera startCameraCapture];

总之,不要害怕开始编写自定义着色器!学习曲线很短,调试器抛出的错误非常有帮助,可以让您准确地知道语法出了什么问题。最后,这是一个关于OpenGL特定函数的语法和用法的文档资源

它对我有效,完全符合我的要求。我尝试创建自定义过滤器但未成功。你解决了我的问题。所以非常感谢Ryan Cumley。 - Surjeet Singh
非常愉快!编程对于反复尝试/失败的周期非常宽容,所以当你的前几次尝试不成功时不要灰心。调整并再次尝试直到成功,这就是我们所有人的做法... - ryan cumley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接