在 Android 中将位图转换为灰度

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3373860/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 09:56:46  来源:igfitidea点击:

Convert a Bitmap to GrayScale in Android

androidimage-processingbitmapgrayscale

提问by leparlon

I am new to this site, and I come with a question about Android.

我是这个网站的新手,我有一个关于 Android 的问题。

Is there any way to convert a Bitmap to grayscale? I know how to draw a grayscale bitmap (using canvas operations: http://www.mail-archive.com/[email protected]/msg38890.html) but I really need The actual bitmap in gray colors (or at least something that could be converted to a bitmap later on). Do I have to implement it by hand (pixel by pixel operations)?

有没有办法将位图转换为灰度?我知道如何绘制灰度位图(使用画布操作:http: //www.mail-archive.com/[email protected]/msg38890.html)但我真的需要灰色的实际位图(或在至少可以稍后转换为位图的东西)。我是否必须手动实现它(逐像素操作)?

I've searched a lot, and still could not find. Anyone knows a easy/efficient way to do it?

我已经搜索了很多,仍然找不到。任何人都知道一种简单/有效的方法吗?

Thanks a lot!

非常感谢!

采纳答案by EboMike

Isn't that exactly what the code you're linking to does? It takes a color bitmap ("bmp"), creates a duplicate bitmap ("bm"), and then draws the color bitmap into "bm" using the filter to turn it into grayscale. From that point on, you can use "bm" as an actual grayscale bitmap and do whatever you want to do with it.

这不正是您链接到的代码所做的吗?它需要一个颜色位图(“bmp”),创建一个重复的位图(“bm”),然后使用过滤器将颜色位图绘制到“bm”中,将其转换为灰度。从那时起,您可以使用“bm”作为实际的灰度位图,并使用它做任何您想做的事情。

You'd need to tweak the sample a bit (it's using hard-coded sizes, you may want to just clone the size of the original bitmap), but other than that, this seems to be as ready-to-use as it gets, depending on what you want.

您需要稍微调整样本(它使用硬编码大小,您可能只想克隆原始位图的大小),但除此之外,这似乎是随时可用的,取决于你想要什么。

回答by leparlon

OH, yes, it does. I was using it wrong, thanks for pointing it out to me. (Sorry for the useless question) Here is the end code (heavily based on the one linked) since it may help someone:

哦,是的,确实如此。我用错了,谢谢你给我指出来。(抱歉没用的问题)这是最终代码(主要基于链接的代码),因为它可能对某人有所帮助:

public Bitmap toGrayscale(Bitmap bmpOriginal)
{        
    int width, height;
    height = bmpOriginal.getHeight();
    width = bmpOriginal.getWidth();    

    Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    Canvas c = new Canvas(bmpGrayscale);
    Paint paint = new Paint();
    ColorMatrix cm = new ColorMatrix();
    cm.setSaturation(0);
    ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
    paint.setColorFilter(f);
    c.drawBitmap(bmpOriginal, 0, 0, paint);
    return bmpGrayscale;
}

Any remarks or comments on it are very welcome.

非常欢迎任何评论或评论。

Thanks

谢谢

回答by E Player Plus

If you are going to show that Bitmap on ImageView. Then Instead of converting Bitmap to Gray Scale, you can try below code:

如果您要在ImageView. 然后,您可以尝试以下代码,而不是将位图转换为灰度:

ColorMatrix matrix = new ColorMatrix();
matrix.setSaturation(0);

ColorMatrixColorFilter filter = new ColorMatrixColorFilter(matrix);
imageview.setColorFilter(filter);

For reference

以供参考

回答by Code-Monkey

I'd like to mention that with this approach one important aspect must be taken in account. BitMap's on Android are stored in the NativeHeap. By just "creating bitmaps", you'll eventually clog the memory, getting an OutOfMemoryException(OOM).

我想提一下,使用这种方法必须考虑一个重要方面。Android 上的 BitMap 存储在 NativeHeap 中。仅仅通过“创建位图”,你最终会阻塞内存,得到一个OutOfMemoryException(OOM)。

Therefor, the bitmap must always be .recycled().

因此,位图必须始终为.recycled().

回答by android developer

Here's a more efficient way, which I've made to support all versions of Android:

这是一种更有效的方法,我已经用它来支持所有版本的 Android:

    //    https://xjaphx.wordpress.com/2011/06/21/image-processing-grayscale-image-on-the-fly/
    @JvmStatic
    fun getGrayscaledBitmapFallback(src: Bitmap, redVal: Float = 0.299f, greenVal: Float = 0.587f, blueVal: Float = 0.114f): Bitmap {
        // create output bitmap
        val bmOut = Bitmap.createBitmap(src.width, src.height, src.config)
        // pixel information
        var A: Int
        var R: Int
        var G: Int
        var B: Int
        var pixel: Int
        // get image size
        val width = src.width
        val height = src.height
        // scan through every single pixel
        for (x in 0 until width) {
            for (y in 0 until height) {
                // get one pixel color
                pixel = src.getPixel(x, y)
                // retrieve color of all channels
                A = Color.alpha(pixel)
                R = Color.red(pixel)
                G = Color.green(pixel)
                B = Color.blue(pixel)
                // take conversion up to one single value
                B = (redVal * R + greenVal * G + blueVal * B).toInt()
                G = B
                R = G
                // set new pixel color to output bitmap
                bmOut.setPixel(x, y, Color.argb(A, R, G, B))
            }
        }
        // return final image
        return bmOut
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    @JvmStatic
    fun getGrayscaledBitmap(context: Context, src: Bitmap): Bitmap {
//        https://gist.github.com/imminent/cf4ab750104aa286fa08
//        https://en.wikipedia.org/wiki/Grayscale
        val redVal = 0.299f
        val greenVal = 0.587f
        val blueVal = 0.114f
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1)
            return getGrayscaledBitmapFallback(src, redVal, greenVal, blueVal)
        val render = RenderScript.create(context)
        val matrix = Matrix4f(floatArrayOf(-redVal, -redVal, -redVal, 1.0f, -greenVal, -greenVal, -greenVal, 1.0f, -blueVal, -blueVal, -blueVal, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f))
        val result = src.copy(src.config, true)
        val input = Allocation.createFromBitmap(render, src, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT)
        val output = Allocation.createTyped(render, input.type)
        // Inverts and do grayscale to the image
        @Suppress("DEPRECATION")
        val inverter =
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
                    ScriptIntrinsicColorMatrix.create(render)
                else
                    ScriptIntrinsicColorMatrix.create(render, Element.U8_4(render))
        inverter.setColorMatrix(matrix)
        inverter.forEach(input, output)
        output.copyTo(result)
        src.recycle()
        render.destroy()
        return result
    }