我想在我的安卓应用程序中使用Sobel操作员。但我不明白怎么用一个像素。
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。但是非常慢。
发布于 2015-05-08 10:09:39
好消息和坏消息。下面的方法很有效但是..。
Android,由于一些特殊的原因,不允许你创建一个8位的灰度图像。这意味着您必须创建一个ARGB_8888格式的灰度。这可能是您上一个版本中出错的地方,当数据不是字节时,我们就将它读取为字节。
下面的代码可以工作,我只在一个仿真器上运行它,在您的图像上运行它的速度非常慢(11秒)。当然,你的形象是很大的,但这仍然是,我想,方式缓慢。
我强烈建议考虑使用OpenCV Java库,因为它们与Android类不同,它们既快速又节省内存!
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));
}
}发布于 2015-05-08 01:01:36
单独的像素访问绝对不是正确的方法!
我假设您已经将源转换为灰度,因此它本质上是一个字节数组。我建议您使用以下方法提取数据:
int w = source.getWidth();
int h = source.getHeight();
ByteBuffer buffer = ByteBuffer.allocate( w * h );
source.copyPixelsToBuffer( buffer );
final byte[] bitmapData = buffer.array()这将给出源数据。你现在可以把你的Sobel过滤器应用到上面了。请注意,您希望将结果输出字节写入新的byte数组,然后将其转换回图像。
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到字节的输出类型
https://stackoverflow.com/questions/30107271
复制相似问题