繁体   English   中英

在Android上逐像素更改png颜色的最佳方法是什么?

[英]What is the best way to change png color pixel by pixel on Android?

我需要更改SDCard中存储的PNG的特定颜色。 我不能在位图或任何其他对象上使用tintcolor,因为这将为所有图像着色而不是特定的像素颜色。

为什么我需要这样做?
我正在尝试开发头像应用程序,我希望能够使用从调色板中选择的任何颜色来更改头像的头发。 该头发有两种颜色,一种用于边界,另一种用于其余的头发。 我只想更改空气颜色并保持边框为一。

这是一种简单的情况,但是图像中可能有多种颜色。

我正在寻找解决方案。 这是我发现的唯一内容(方法可能更多,但我并不幸运):

Android位图:将透明像素转换为颜色

这是它在此处公开的内容:

Bitmap b = ...;
for(int x = 0; x<b.getWidth(); x++){
    for(int y = 0; y<b.getHeight(); y++){
        if(b.getPixel(x, y) == Color.TRANSPARENT){
            b.setPixel(x, y, Color.WHITE);
        }
     }
}

我想知道是否有更好的方法可以做到这一点。 像这样的东西:

bipmapImage.changeColor(originalColor, newColor);

我不知道使用循环检查像素是否是一个好的性能。 想象一下1080 x 1080的图像。

提前致谢。

getPixel()setPixel()相比,您可以通过调用copyPixelsToBuffer()将像素复制到缓冲区中,然后修改缓冲区中的像素值,最后调用copyPixelsFromBuffer()将缓冲区中的像素复制回到位图:

boolean changeColor(Bitmap bitmap, int originalColor, int newColor)
{
    // bitmap must be mutable and 32 bits per pixel:
    if((bitmap.getConfig() != Bitmap.Config.ARGB_8888) || !bitmap.isMutable())
        return false;

    int pixelCount = bitmap.getWidth() * bitmap.getHeight();
    IntBuffer buffer = IntBuffer.allocate(pixelCount);
    bitmap.copyPixelsToBuffer(buffer);
    int[] array = buffer.array();
    for(int i = 0; i < pixelCount; i++)
    {
        if(array[i] == originalColor)
            array[i] = newColor;
    }
    bitmap.copyPixelsFromBuffer(buffer);

    return true;    
}

但是,还有一些额外的复杂性:位图必须使用ARGB_8888像素格式(如果不同,则需要编写额外的代码来处理),并且您需要捕获分配IntBuffer时可能发生的内存异常。 您应该首先使用setPixels()分析代码,然后查看速度是否不能接受。

这也可能不是最快的解决方案,可能是在库中使用本机函数调用。 但是它仍然比setPixel()更快,并且您不需要在项目中添加库。

您最好使用OpenCV Matrix API,特别是为了提高性能(和紧凑性)。

此处查看OpenCV Android教程。

假设您已经安装了OpenCV功能,则可以更改图像中某些特定区域的颜色。

(您应该首先了解Mat功能。)

实际上,我还没有在Android上使用OpenCV。
这是一些示例代码,用于在C ++中将头发颜色更改为红色:

// 1. Loading
Mat src = imread("yourImagePath/yourOriginalImage.jpg");  // This code will automatically loads image to Mat with 3-channel(BGR) format
Mat mask = imread("yourImagePath/yourHairMaskImage.png", CV_GRAYSCALE);  // This code will automatically loads mask image to Mat with 1-channel(grayscale) format

// 2. Splitting RGB channel into 3 separate channels
vector<Mat> channels;   // C++ version of ArrayList<Mat>
split(src, channels);   // Automatically splits channels and adds them to channels. The size of channels = 3

// 3-1. Adjusting red color
Mat adjustRed = channels[0]*1.5;

// 3-2. Copy the adjusted pixels into org Mat with mask
channels[2] = adjustRed & mask + channels[0] & ~mask;

// 4. Merging channels
Mat dst;
merge(channels, dst);   // dst is re-created with 3-channel(BGR).
// Note that OpenCV applies BGR by default if your array size is 3,
// even if actual order is different. In this case this makes sense.

// 5. Saving
imwrite("yourImagePath/yourDstImage.jpg", dst);


我认为Android版本代码不会有太大不同。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM