首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用单像素Sobel矩阵

如何使用单像素Sobel矩阵
EN

Stack Overflow用户
提问于 2015-05-07 16:52:18
回答 2查看 317关注 0票数 1

我想在我的安卓应用程序中使用Sobel操作员。但我不明白怎么用一个像素。

代码语言:javascript
复制
int sobel_x[][] = {{-1, 0, 1},
        {-2, 0, 2},
        {-1, 0, 1}};
int sobel_y[][] = {{-1, -2, -1},
        {0, 0, 0},
        {1, 2, 1}};
Bitmap source = ImageHelper.GetBitmapGromUri(Path);
    int w = source.getWidth();
    int h = source.getHeight();
    int[] pixels;
    pixels = new int[h * w];
    source.getPixels(pixels, 0, w, 1, 1, w - 1, h - 1);
    for(int i = 0;i < pixels.length;i++){
          ...
    }

我尝试使用get/setPixel。但是非常慢。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-05-08 10:09:39

好消息和坏消息。下面的方法很有效但是..。

Android,由于一些特殊的原因,不允许你创建一个8位的灰度图像。这意味着您必须创建一个ARGB_8888格式的灰度。这可能是您上一个版本中出错的地方,当数据不是字节时,我们就将它读取为字节。

下面的代码可以工作,我只在一个仿真器上运行它,在您的图像上运行它的速度非常慢(11秒)。当然,你的形象是很大的,但这仍然是,我想,方式缓慢。

我强烈建议考虑使用OpenCV Java库,因为它们与Android类不同,它们既快速又节省内存!

代码语言:javascript
复制
public class Sobel {
    private static Bitmap toGreyScale( Bitmap source ) {
        Bitmap greyScaleBitmap = Bitmap.createBitmap(
                source.getWidth(), source.getHeight(),
                Bitmap.Config.ARGB_8888);

        Canvas c = new Canvas(greyScaleBitmap);
        Paint p = new Paint();
        ColorMatrix cm = new ColorMatrix();

        cm.setSaturation(0);
        ColorMatrixColorFilter filter = new ColorMatrixColorFilter(cm);
        p.setColorFilter(filter);
        c.drawBitmap(source, 0, 0, p);
        return greyScaleBitmap;
    }

    public static void doSobel( Bitmap source) {

        Bitmap grey = toGreyScale(source);

        int w = grey.getWidth();
        int h = grey.getHeight();
        // Allocate 4 times as much data as is necessary because Android.
        int sz = w * h;

        IntBuffer buffer = IntBuffer.allocate( sz );
        grey.copyPixelsToBuffer( buffer );
        final int[] bitmapData = buffer.array();

        int[] output = new int[ w * h ];
        for( int y=1; y<h-1; y++ ) {
            for( int x=1; x<w-1; x++ ) {
                int idx = (y * w + x );

                // Apply Sobel filter
                int tl = (bitmapData[idx - w - 1]) & 0xFF;
                int tr = (bitmapData[idx - w + 1]) & 0xFF;
                int l = (bitmapData[idx - 1]) & 0xFF;
                int r = (bitmapData[idx + 1]) & 0xFF;
                int bl = (bitmapData[idx + w - 1]) & 0xFF;
                int br = (bitmapData[idx + w + 1]) & 0xFF;

                int sx = (int) ( tr - tl + 2 * ( r - l ) + br - bl );
                sx = sx & 0xFF;

                // Put back into ARG and B bytes
                output[toIdx] = (sx << 24) | ( sx << 16) | (sx << 8) | sx;
            }
        }

        source.copyPixelsFromBuffer( IntBuffer.wrap(output));
    }
}
票数 2
EN

Stack Overflow用户

发布于 2015-05-08 01:01:36

单独的像素访问绝对不是正确的方法!

我假设您已经将源转换为灰度,因此它本质上是一个字节数组。我建议您使用以下方法提取数据:

代码语言:javascript
复制
int w = source.getWidth();
int h = source.getHeight();
ByteBuffer buffer = ByteBuffer.allocate( w * h );
source.copyPixelsToBuffer( buffer );
final byte[] bitmapData = buffer.array()

这将给出源数据。你现在可以把你的Sobel过滤器应用到上面了。请注意,您希望将结果输出字节写入新的byte数组,然后将其转换回图像。

代码语言:javascript
复制
byte[] output = new byte[ w * h ];
for( int y=1; y<h-1; y++ ) {
    for( int x=1; x<w-1; x++ ) {
        int idx = y * w + x;

        // Apply Sobel filter
        byte sx = (byte) ((-1 * bitmapData[idx-w-1]) + ( 1 * bitmapData[idx-w+1] ) + (-2 * bitmapData[idx-1]) + ( 2 * bitmapData[idx+1] ) + (-1 * bitmapData[idx+w-1]) + ( 1 * bitmapData[idx+w+1] ) );

        output[idx] = sx;
    }
}

对于水平过滤器,您也可以这样做。

编辑以纠正从int到字节的输出类型

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30107271

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档