Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
197 views
in Technique[技术] by (71.8m points)

Extract black and white image from android camera's NV21 format

I have done some google-ing around and couldn't find enough information about this format. It is the default format for camera preview. Can anyone suggest good sources of information about it and how to extract data from a photo/preview image with that format? To be more specific, I need the black and white image extracted.

EDIT: Seems like that format is also called YCbCr 420 Semi Planar

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I developed the following code to convert the NV21 to RGB, and it is working.

/**
 * Converts YUV420 NV21 to RGB8888
 * 
 * @param data byte array on YUV420 NV21 format.
 * @param width pixels width
 * @param height pixels height
 * @return a RGB8888 pixels int array. Where each int is a pixels ARGB. 
 */
public static int[] convertYUV420_NV21toRGB8888(byte [] data, int width, int height) {
    int size = width*height;
    int offset = size;
    int[] pixels = new int[size];
    int u, v, y1, y2, y3, y4;

    // i percorre os Y and the final pixels
    // k percorre os pixles U e V
    for(int i=0, k=0; i < size; i+=2, k+=2) {
        y1 = data[i  ]&0xff;
        y2 = data[i+1]&0xff;
        y3 = data[width+i  ]&0xff;
        y4 = data[width+i+1]&0xff;

        u = data[offset+k  ]&0xff;
        v = data[offset+k+1]&0xff;
        u = u-128;
        v = v-128;

        pixels[i  ] = convertYUVtoRGB(y1, u, v);
        pixels[i+1] = convertYUVtoRGB(y2, u, v);
        pixels[width+i  ] = convertYUVtoRGB(y3, u, v);
        pixels[width+i+1] = convertYUVtoRGB(y4, u, v);

        if (i!=0 && (i+2)%width==0)
            i+=width;
    }

    return pixels;
}

private static int convertYUVtoRGB(int y, int u, int v) {
    int r,g,b;

    r = y + (int)(1.402f*v);
    g = y - (int)(0.344f*u +0.714f*v);
    b = y + (int)(1.772f*u);
    r = r>255? 255 : r<0 ? 0 : r;
    g = g>255? 255 : g<0 ? 0 : g;
    b = b>255? 255 : b<0 ? 0 : b;
    return 0xff000000 | (b<<16) | (g<<8) | r;
}

This image helps to understand. YUV420 NV21

If you wanna just grayscale image is easer. You can discard all the U and V info, and take just the Y info. The code would can be like this:

/**
 * Converts YUV420 NV21 to Y888 (RGB8888). The grayscale image still holds 3 bytes on the pixel.
 * 
 * @param pixels output array with the converted array o grayscale pixels
 * @param data byte array on YUV420 NV21 format.
 * @param width pixels width
 * @param height pixels height
 */
public static void applyGrayScale(int [] pixels, byte [] data, int width, int height) {
    int p;
    int size = width*height;
    for(int i = 0; i < size; i++) {
        p = data[i] & 0xFF;
        pixels[i] = 0xff000000 | p<<16 | p<<8 | p;
    }
}

To create your Bitmap just:

Bitmap bm = Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888);

Where pixels is your int [] array.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...