安卓实时黑白阈值图像



我有一个代码,可以使用以下代码将具有灰色的位图转换为黑白颜色的位图:

// scan through all pixels
for (int x = 0; x < width; ++x) {                                                                                                                                                                                               
  for (int y = 0; y < height; ++y) {                                                                                                                                                                                            
    // get pixel color
    pixel = bitmap.getPixel(x, y);                                                                                                                                                                                              
    A = Color.alpha(pixel);                                                                                                                                                                                                     
    R = Color.red(pixel);                                                                                                                                                                                                       
    G = Color.green(pixel);                                                                                                                                                                                                     
    B = Color.blue(pixel);                                                                                                                                                                                                      
    int gray = (int) (0.2989 * R + 0.5870 * G + 0.1140 * B);                                                                                                                                                                    
    // use 128 as threshold, above -> white, below -> black
    if (gray > 128)
    gray = 255;                                                                                                                                                                                                                 
    else
    gray = 0;                                                                                                                                                                                                                   
    // set new pixel color to output bitmap
    bmOut.setPixel(x, y, Color.argb(A, gray, gray, gray));                                                                                                                                                                      
  }
}   

如您所见,我遍历原始位图的所有像素点,然后将颜色的分量与给定阈值进行比较,在本例中为 128,然后如果上面我说它的白色,否则它将是一个黑色像素。

我现在要做的是一个可以更改该阈值的微调器,然后BW图像将有所不同。

为此,我需要再次绘制所有图像,这是非常耗时的CPU,再次移动所有像素需要时间。

有没有办法使用不同的 BW 阈值实时更改图像?

有人告诉我使用 GIF,然后我要做的,只是更改 GIF 的查找表值,有人在 Android 上对此有所了解吗?

自从提出这个问题以来已经过去了一段时间,但我遇到了这个问题,寻找其他东西,碰巧有解决方案。您可以在没有OpenCV或任何其他第三方库的情况下实现这一点,仅使用自API级别1以来可用的ColorMatrixColorFilter。

以下是您可以使用的矩阵:

//matrix that changes picture into gray scale
public static ColorMatrix createGreyMatrix() {
    ColorMatrix matrix = new ColorMatrix(new float[] {
            0.2989f, 0.5870f, 0.1140f, 0, 0,
            0.2989f, 0.5870f, 0.1140f, 0, 0,
            0.2989f, 0.5870f, 0.1140f, 0, 0,
            0, 0, 0, 1, 0
    });
    return matrix;
}
// matrix that changes gray scale picture into black and white at given threshold.
// It works this way:
// The matrix after multiplying returns negative values for colors darker than threshold
// and values bigger than 255 for the ones higher. 
// Because the final result is always trimed to bounds (0..255) it will result in bitmap made of black and white pixels only
public static ColorMatrix createThresholdMatrix(int threshold) {
    ColorMatrix matrix = new ColorMatrix(new float[] {
            85.f, 85.f, 85.f, 0.f, -255.f * threshold,
            85.f, 85.f, 85.f, 0.f, -255.f * threshold,
            85.f, 85.f, 85.f, 0.f, -255.f * threshold,
            0f, 0f, 0f, 1f, 0f
    });
    return matrix;
}

以下是使用它们的方法:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
//load source bitmap and prepare destination bitmap
Bitmap pic = BitmapFactory.decodeResource(getResources(), R.drawable.thePicture, options);
Bitmap result = Bitmap.createBitmap(pic.getWidth(), pic.getHeight(),  Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(result);
//first convert bitmap to grey scale:
bitmapPaint.setColorFilter(new ColorMatrixColorFilter(createGreyMatrix()));
c.drawBitmap(pic, 0, 0, bitmapPaint);
//then convert the resulting bitmap to black and white using threshold matrix 
bitmapPaint.setColorFilter(new ColorMatrixColorFilter(createThresholdMatrix(128)));
c.drawBitmap(result, 0, 0, bitmapPaint);
//voilà! You can now draw the result bitmap anywhere You want:
bitmapPaint.setColorFilter(null);
otherCanvas.drawBitmap(result, null, new Rect(x, y, x + size, y + size), bitmapPaint);

希望这会帮助某人。

我建议你看看使用适用于Android的OpenCV库。安装后,您可以使用它对图像进行许多其他常用操作中的快速阈值。以下代码片段将把您的彩色位放大器转换为灰度图像和灰度级别 128 的阈值。

// first convert bitmap into OpenCV mat object
Mat imageMat = new Mat (bitmap.getHeight(), bitmap.getWidth(),
                CvType.CV_8U, new Scalar(4));
Bitmap myBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
Utils.bitmapToMat(myBitmap, imageMat);
// now convert to gray
Mat grayMat = new Mat ( bitmap.getHeight(), bitmap.getWidth(),
            CvType.CV_8U, new Scalar(1));
Imgproc.cvtColor(imageMat, grayMat, Imgproc.COLOR_RGB2GRAY, 1);
// get the thresholded image
Mat thresholdMat = new Mat ( bitmap.getHeight(), bitmap.getWidth(),
            CvType.CV_8U, new Scalar(1));
Imgproc.threshold(grayMat, thresholdMat , 128, 255, Imgproc.THRESH_BINARY);
// convert back to bitmap for displaying
Bitmap resultBitmap = Bitmap.createBitmap(bitmap.cols(), bitmap.rows(),
                Bitmap.Config.ARGB_8888);
thresholdMat.convertTo(thresholdMat, CvType.CV_8UC1);
Utils.matToBitmap(thresholdMat, resultBitmap);

GIF 的标题中有一个调色板,为每个"值"关联与它相关的颜色(维基百科条目)。问题在于:过去,他们认为 256 种颜色就足够了,而调色板条目的数量就足够了。您可以使用类 GifDecoder.java其中包含 256 个条目和两个值的本地颜色表:您的两个输出 0 和 255。但归根结底,有一个循环可以检查每个字节,通过调色板查找关联哪个值(这是行)。不比你的代码快一点。

加快速度的另一种方法是使用 OpenGL 生成阈值(假设无论如何您都要在屏幕上绘制位图,对吧?这需要一堆额外的代码,幸运的是,本教程完全可以执行您想要执行的操作,减去阈值部分。

对于阈值,需要编译 OpenGL 程序(在 GlRenderer::onSurfaceChanged 上)并且每次(在 GlRenderer::onDrawFrame 上)使用。该程序有两个着色器,它们将以光速对每个像素进行阈值设置!(好吧,也许有点慢,但非常快!

着色器如下所示。让我知道我是否可以帮助您将它们插入示例代码中。

private static final String mVertexShader =
    "attribute vec4 aPosition;n" +
    "attribute vec4 aTextureCoord;n" +
    "varying vec2 vTextureCoord;n" +
    "void main() {n" +
    "  gl_Position = aPosition;n" +
    "  vTextureCoord = aTextureCoord;n" +
    "}n";
private static final String mFragmentShader =
    "precision mediump float;n" +
    "varying vec2 vTextureCoord;n" +
    "uniform float threshold_in_range_0_to_1;n" +
    "const vec4 coeff_y = vec4(0.256, 0.504, 0.097, 0.0625);n" +
    "float y;n" +
    "void main() {n" +
    "  y = dot(coeff_y, texture2D(sTexture, vTextureCoord));n" +
    "  if ( y > threshold_in_range_0_to_1)" +
    "    gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0)n" +
    "  else" +
    "    gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0)n" +
    "}n";

最新更新