27 votes

Extraire l'image en noir et blanc du format NV21 de la caméra Android

J'ai fait quelques recherches sur Google et je n'ai pas trouvé suffisamment d'informations sur ce format. Il s'agit du format par défaut pour l'aperçu de l'appareil photo. Quelqu'un peut-il suggérer de bonnes sources d'informations à ce sujet et comment extraire des données d'une photo / image d'aperçu avec ce format? Pour être plus précis, j'ai besoin d'extraire l'image en noir et blanc.

EDIT: On dirait que ce format est également appelé YCbCr 420 Semi Planar

65voto

Derzu Points 2463

J'ai développé le code suivant pour convertir le NV21 RVB, et il est de travail.

/**
 * 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;
}

Cette image permet de comprendre. YUV420 NV21

Si vous voulez juste image en niveaux de gris est flexible. Vous pouvez jeter tous les U et V info, et de prendre un peu l'axe des info. Le code peut être comme ceci:

/**
 * 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;
    }
}

Pour créer votre image Bitmap juste:

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

Où pixels est votre int tableau [].

8voto

Mayank Points 51

NV21 est fondamentalement YUV420 mais au lieu du format planaire où Y, U et V ont des plans indépendants, NV21 a 1 plan pour Luma et 2e plan pour Chroma. Le format ressemble à

YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY. . . .

VUVUVUVUVUVUVUVUVUVUVUVUVUVUVU VUVUVUVUVUVUVUVUVUVUVUVUVUVUVU. . . . .

6voto

Max Points 145

J'ai également eu beaucoup de maux de tête à cause de cet aperçu format.

Le meilleur que j'ai pu trouver sont les suivants:

http://www.fourcc.org/yuv.php#NV21

http://v4l2spec.bytesex.org/spec/r5470.htm

Il semble que la composante Y est la première largeur*hauteur octets int le tableau que vous obtenez.

Certains plus d'information liens:

http://msdn.microsoft.com/en-us/library/ms867704.aspx#yuvformats_yuvsampling

http://msdn.microsoft.com/en-us/library/ff538197(v=vs. 85).aspx

Espérons que cette aide.

3voto

Adi Shavit Points 4470

Les données sont au format YUV420.
Si vous êtes uniquement intéressé par le canal monochrome, c'est-à-dire "noir et blanc", alors ce sont les premiers width x height octets du tampon de données que vous avez déjà.
Le canal Y est le premier plan d'image. C'est exactement le canal gris / intensité / luminosité, etc.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X