Question

I have an injective function that moves around some pixels in an image:

pixel (x, y) ===func===> pixel (X, Y)
X = funcX(x, y)
Y = funcY(y, x)

I want to use this function to transform the whole image in RGB, I420 and NV12 mode.

* RGB *: If the image is in RGB mode, it's pretty obvious:

strideR = strideG = strideB = width;

//Temporary table for the destination
for (j = 0; j < height; j++)
    for (i = 0; i < width; i++) {
        toR[i][j] = j * strideR + i;
        toG[i][j] = j * strideG + i;
        toB[i][j] = j * strideB + i;
    }

//Temporary table for the source
for (j = 0; j < height; j++)
    for (i = 0; i < width; i++) {
        fromR[i][j] = funcY(i, j) * strideR + funcX(i, j);
        fromG[i][j] = funcY(i, j) * strideG + funcX(i, j);
        fromB[i][j] = funcY(i, j) * strideB + funcX(i, j);
    }

for (j = 0; j < height; j++)
    for (i = 0; i < width; i++) {
        destR[ toR[i][j] ] = srcR[ fromR[i][j] ];
        destG[ toG[i][j] ] = srcG[ fromG[i][j] ];
        destb[ toB[i][j] ] = srcB[ fromB[i][j] ];
    }

* I420 *: If the image is in I420 mode (YYYYYYYY UU VV), the following is working:

strideY = width;
strideU = strideV = width / 2;

//Temporary table for the destination
for (j = 0; j < height; j++)
    for (i = 0; i < width; i++) {
        toY[i][j] = j * strideY + i;
        toU[i][j] = j / 2 * strideU + i / 2;
        toV[i][j] = j / 2 * strideV + i / 2;
    }

//Temporary table for the source
for (j = 0; j < height; j++)
    for (i = 0; i < width; i++) {
        fromY[i][j] = funcY(i, j) * strideY + funcX(i, j);
        fromU[i][j] = funcY(i, j) / 2 * strideU + funcX(i, j) / 2;
        fromV[i][j] = funcY(i, j) / 2 * strideV + funcX(i, j) / 2;
    }

    for (j = 0; j < height; j++)
        for (i = 0; i < width; i++) {
            destY[ toY[i][j] ] = srcY[ fromY[i][j] ];
            if ((i % 2 == 0) && (j % 2 == 0)) {
                destU[ toU[i][j] ] = srcU[ fromU[i][j] ];
                destV[ toV[i][j] ] = srcV[ fromV[i][j] ];
            }
        }

* NV12 *: If the image is in NV12 mode (YYYYYYYY UVUV), the following is NOT working:

strideY = strideUV = width;

//Temporary table for the destination
for (j = 0; j < height; j++)
    for (i = 0; i < width; i++) {
        toY[i][j] = j * strideY + i;
        toUV[i][j] = j / 2 * strideUV + i;
    }

//Temporary table for the source
for (j = 0; j < height; j++)
    for (i = 0; i < width; i++) {
        fromY[i][j] = funcY(i, j) * strideY + funcX(i, j);
        fromUV[i][j] = funcY(i, j) / 2 * strideUV + funcX(i, j);
    }

for (j = 0; j < height; j++)
    for (i = 0; i < width; i++) {
        destY[ toY[i][j] ] = srcY[ fromY[i][j] ];
        if ((i % 2 == 0) && (j % 2 == 0)) {
            destUV[ toUV[i][j] ] = srcUV[ fromUV[i][j] ];
            destUV[ toUV[i][j] + 1 ] = srcUV[ fromUV[i][j] + 1 ];
        }
    }

I got the image but with wrong colors. The black and white portion (aka the Y portion) is correct but the color portion (aka the UV portion) is altered. What am I doing wrong?

Was it helpful?

Solution

Found the problem! Solution is:

fromUV[i][j] = funcY(i, j) / 2 * strideUV + ((int)(funcX(i, j) / 2)) * 2;

I needed to floor X/2 to get the start of the UV byte.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top