Ad

Canvas Paint - Reds And Greens Inverted

- 1 answer

I have an app that captures a frame from video that is being recorded using ImageAvailableListener and draws a watermark on the top of the frame. The watermark is saved as a PNG file and is blue. However, when I draw on the watermark on the captured frame it is appearing as red. Similarly, any rectangles or lines I draw to the canvas using a blue color are appearing red, but the captured image is retaining its colors just fine. Here is the code:

//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.

After this code, I use some other functions to encode the watermarked frame into YUV420 for other purposes - I thought the problem could lie within this function, but given the captured video frame is retaining its color just fine (only the overlaid watermark is effected), I concluded that this is not the problem and have not included this code.

An obvious quick-fix for my problem is to make my watermark PNG red and draw any lines/rectangles as red (so that they appear blue when drawn) - but I would rather understand why this is happening. Am I missing something obvious?

Ad

Answer

I discovered what the issue was by capturing a frame, applying the watermark and then saving it as a JPEG image (before sending it to the video encoder). The colors in the image seemed just fine, so I knew the strange colors were happening after the video encoding process.

In the end, my issue was happening because of lack of knowledge about color formats. Different color formats are used for video than are used for Bitmaps. My Video codec uses a YUV420 format, where as my bitmap is using ARGB_8888. The solution to my problem was to apply a ColorMatrix to my Paint object to take into account the changes in color that will occur during the encoding process (i.e. inverting reds and greens). This code is inserted before I begin drawing on top of the captured frame.

//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);

For more information on ColorMatrix, refer to: Android: ColorMatrix

Ad
source: stackoverflow.com
Ad