Canvas 绘画 - 红色和绿色颠倒

Canvas Paint - Reds and Greens Inverted

我有一个应用程序可以从使用 ImageAvailableListener 录制的视频中捕获帧并在帧的顶部绘制水印。水印保存为 PNG 文件并为蓝色。但是,当我在捕获的帧上绘制水印时,它显示为红色。同样,我使用蓝色绘制到 canvas 的任何矩形或线条都显示为红色,但捕获的图像很好地保留了它的颜色。这是代码:

//Capture the image
final Image img = reader.acquireLatestImage();
if (img == null)
{
   totalImages--;
   return;
}

//Convert from Bytes into bitmap
byte[] data = getBytesFromYuv(img);
Bitmap.Config conf = Bitmap.Config.ARGB_8888;
Bitmap bitmap = Bitmap.createBitmap(imgWidth,imgHeight,conf);
ByteArrayOutputStream out = new ByteArrayOutputStream();
YuvImage yuvImage = new YuvImage(data, ImageFormat.NV21, imgWidth, imgHeight, null);
data = null;
yuvImage.compressToJpeg(new Rect(0, 0, imgWidth, imgHeight), JPEG_QUALITY, out);
byte[] imageBytes = out.toByteArray();
bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);

//Release the image
img.close();

//Create mutable bitmap and initiate canvas & paint
Bitmap mutableBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
Canvas canvas = new Canvas(mutableBitmap);
Paint p = new Paint();

//Set color to blue
p.setColor(Color.argb(255,0,0,255)); //Set color to BLUE

//...draw watermark, lines or rectangles here...
//Anything drawn using canvas/paint appears with blues/reds inverted
//but underlying frame captured retains its colors just fine.

在这段代码之后,我使用一些其他函数将带水印的帧编码为 YUV420 用于其他目的 - 我认为问题可能出在这个函数中,但考虑到捕获的视频帧很好地保留了它的颜色(只有覆盖水印),我断定这不是问题,没有包含此代码。

解决我的问题的一个明显的快速修复方法是将我的水印 PNG 设为红色并将任何 lines/rectangles 绘制为红色(以便它们在绘制时显示为蓝色)- 但我更愿意理解为什么会这样。我是否漏掉了一些明显的东西?

我通过捕获帧、应用水印然后将其保存为 JPEG 图像(在将其发送到视频编码器之前)发现了问题所在。图像中的颜色看起来还不错,所以我知道视频编码过程后出现了奇怪的颜色。

最后,我的问题是由于缺乏关于颜色格式的知识而发生的。用于视频的颜色格式与用于位图的颜色格式不同。我的视频编解码器使用 YUV420 格式,而我的位图使用 ARGB_8888。我的问题的解决方案是将 ColorMatrix 应用于我的 Paint 对象,以考虑在编码过程中发生的颜色变化(即反转红色和绿色)。在我开始在捕获的帧之上绘图之前插入此代码。

//Initiate color filter
ColorMatrix cm = new ColorMatrix();
float[] matrix = {
    0, 0, 1, 0, 0, //Red (Grabbing blue values)
    0, 1, 0, 0, 0, //Green 
    1, 0, 0, 0, 0, //Blue (Grabbing red values)
    0, 0, 0, 1, 0 //Alpha 
};
cm.set(matrix);
ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);

//Set color filter
p.setColorFilter(f);

关于ColorMatrix的更多信息,请参考: Android: ColorMatrix