【问题标题】:Sobel Edge Detection in AndroidAndroid中的Sobel边缘检测
【发布时间】:2011-02-25 16:15:13
【问题描述】:

作为我正在为 Android 开发的应用程序的一部分,我想向用户展示他们拍摄的图像的边缘检测版本(类似于下面的示例)。

为了实现这一点,我一直在研究 Sobel 运算符以及如何在 Java 中实现它。但是,我发现的许多示例都使用了不属于 Android 的 AWT (like this example) 中的对象和方法。

那么我的问题是,Android 是否提供了上述示例中使用的 AWT 功能的替代方案?如果我们仅使用 Android 内置的库来重写该示例,我们将如何进行呢?

【问题讨论】:

  • 关于您链接到的源代码,AWT 并没有什么特别之处:-/
  • 难道 BufferedImage 不是 AWT 中的一个类吗?

标签: android image-processing edge-detection


【解决方案1】:

由于Android中没有BufferedImage,所有基本操作都可以自己完成:

Bitmap b = ...
width = b.getWidth();
height = b.getHeight();
stride = b.getRowBytes();
for(int x=0;x<b.getWidth();x++)
  for(int y=0;y<b.getHeight();y++)
    {
       int pixel = b.getPixel(x, y);
       // you have the source pixel, now transform it and write to destination 
    }

如您所见,这几乎涵盖了移植该 AWT 示例所需的所有内容。 (只需更改 'convolvePixel' 函数)

【讨论】:

  • 这很好,但是当我逐个像素地做这件事时,Bitmap.getPixel() 和 Bitmap.setPixel() 对我来说似乎真的很慢。我认为最好在开始时使用 Bitmap.getPixels() 将位图的值作为整数复制到 int[]。我将如何对 RGB int 值数组而不是位图执行卷积?
  • 你是对的,获取整个数组更快。要对数组执行卷积,您只需使用相同类型的 for 循环进行迭代,并通过使用分离的 R、G 和 B 通道或使用Color.rgb(r1,g1,b1) 函数从 RGB 数组组合像素来获取像素值。
【解决方案2】:

在此处检查 java 实现:

http://code.google.com/p/kanzi/source/browse/java/src/kanzi/filter/SobelFilter.java

不依赖于 Swing/AWT 或任何其他库。它直接对图像像素进行操作,速度很快。

结果可以在这里看到(向下滚动):

http://code.google.com/p/kanzi/wiki/Overview

【讨论】:

    【解决方案3】:

    问题和答案已有 3 年历史了...@reflog 的解决方案适用于边缘检测等简单任务,但速度很慢。

    我在 iOS 上使用 GPUImage 进行边缘检测任务。 Android上有一个等效的库: https://github.com/CyberAgent/android-gpuimage/tree/master

    它是硬件加速的,所以它应该非常快。这是sobel边缘检测滤波器: https://github.com/CyberAgent/android-gpuimage/blob/master/library/src/jp/co/cyberagent/android/gpuimage/GPUImageSobelEdgeDetection.java

    根据文档,您可以这样做:

    Uri imageUri = ...;
    mGPUImage = new GPUImage(this);
    mGPUImage.setGLSurfaceView((GLSurfaceView) findViewById(R.id.surfaceView));
    mGPUImage.setImage(imageUri); // this loads image on the current thread, should be run in a thread
    mGPUImage.setFilter(new GPUImageSobelEdgeDetection());
    
    // Later when image should be saved saved:
    mGPUImage.saveToPictures("GPUImage", "ImageWithFilter.jpg", null);
    

    另一个选项是使用 RenderScript,您可以并行访问每个像素并使用它做任何您想做的事情。我还没有看到任何用它构建的图像处理库。

    【讨论】:

      【解决方案4】:

      另一种选择是使用 OpenCV,它对 Android 有很好的实现。

      Imgproc.Sobel() 方法采用“Mat”类型形式的图像,可以轻松地从资源或位图中加载。输入的Mat应该是灰度图,也可以用opencv创建。 Mat src = Highgui.imread(getClass().getResource( "/SomeGrayScaleImage.jpg").getPath());

      然后在其上运行 sobel 边缘检测器,将结果保存在新的 Mat 中。如果你想保持相同的图像深度,那么这将做到...... Mat dst; int ddepth = -1; // destination depth. -1 maintains existing depth from source int dx = 1; int dy = 1; Imgproc.Sobel(src, dst, ddepth, dx, dy);

      这里有一些参考文档: http://docs.opencv.org/java/org/opencv/imgproc/Imgproc.html#Sobel(org.opencv.core.Mat,%20org.opencv.core.Mat,%20int,%20int,%20int)

      对于 Android Studio 中的 gradle 构建,您可以从不同的地方拉入为 Java 构建的 opencv 库,但我也托管了一个最近的构建。在您的 build.gradle 文件中,您可以像这样添加依赖项......否则,这有点棘手。 dependencies { compile 'com.iparse.android:opencv:2.4.8' } 如果您使用的是 Eclipse,您可以查看 Opencv 网站了解在 Android 上使用 Opencv 的详细信息:http://opencv.org/platforms/android.html

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-02
        • 2020-04-06
        • 2016-11-07
        • 2018-12-12
        相关资源
        最近更新 更多