Rotate YUV420Sp image 90 degrees counterclockwise

I want to rotate the YUV420SP image 90 counterclockwise. The image size is 640 * 480, so the size of the rotated image becomes 480 * 640, which I don't need. So I want to extract 480 * 480 data (or any other square size) and rotate that data.

I saw: Rotating YUV byte array on Android

But this answer rotates 90 clockwise.

Can someone suggest some function that rotates the YUV420Sp data 90 (counterclockwise) or 270 degrees (clockwise) without resizing the image.

+3


source to share


1 answer


OK, here is my native code that evolved after a big headbutt.

My difficulty was that I didn't understand flat image formats until I saw this and this:

YUV420SP NV21 aspect ratio

Here are two functions that I ended up writing:

// rotate luma image plane 90*
//
//             (dst direction)
//                 ------>
//      dst -> +-------------+
//             |^            |
//             |^ (base dir) |
//             |^            |
//     base -> +-------------+ <- endp
//
//////////////////////////////////////////////////////////
void rotateLumaPlane90(const unsigned char *src, unsigned char *dst,
                       size_t size, size_t width, size_t height)
{
    const unsigned char *endp;
    const unsigned char *base;
    int j;

    endp = src + size;
    for (base = endp - width; base < endp; base++) {
        src = base;
        for (j = 0; j < height; j++, src -= width)
        {
            *dst++ = *src;
        }

    }
}


//
// nv12 chroma plane is interleaved chroma values that map
// from one pair of chroma to 4 pixels:
//
// Y1 Y2 Y3 Y4
// Y5 Y6 Y7 Y8   U1,V1 -> chroma values for block  Y1 Y2
// Y9 Ya Yb Yc                                     Y5 Y6
// Yd Ye Yf Yg
// -----------   U2,V2 -> chroma values for block  Y3 Y4
// U1 V1 U2 V2                                     Y7 Y8
// U3 V3 U4 V4
//
//////////////////////////////////////////////////////////
void rotateChromaPlane90(const unsigned char *src, unsigned char *dst,
                         size_t size, size_t width, size_t height)
{
    // src will start at upper right, moving down to bottom
    // then left 1 col and down...
    //
    // dest will start at end and go to 0

    int row = 0;
    int col = (int) width;
    int src_offset = col - 1;
    int dst_offset = (int) size - 2;

    while (src_offset >= 0)
    {
        dst[dst_offset] = src[src_offset];
        dst[dst_offset+1] = src[src_offset+1];
        dst_offset -= 2;

        src_offset += width;
        row++;

        if (row >= height) {
            col -= 2;
            src_offset = col;
            row = 0;
        }
    }
}

      



And here is an example of how I am calling these funcs from native android:

  // first rotate the Y plane
  rotateLumaPlane90((unsigned char *) encode_buffer, 
                     rotate_buffer, 
                     yPlaneSize,
                     gInputWidth, 
                     gInputHeight);


  // now rotate the U and V planes
  rotateChromaPlane90((unsigned char *) encode_buffer + yPlaneSize,
                       rotate_buffer + yPlaneSize,
                       yPlaneSize / 2,
                       gInputWidth,
                       gInputHeight/2);

      

Note that the last parameter for rotateChromaPlane90

is the height of the original image / 2. I should probably just change the chroma rotation function to make this less error prone.

When I flipped to the reverse camera I found that I needed to rotate 90 * in the opposite direction (or 270 *), so I also have a 270 * change as:

// rotate luma image plane 270*
//
//             +-------------+
//             |^            |
//             |^ (base dir) |
//             |^            |
//     base -> +-------------+ <- endp
//                          ^
//             <----------  |
//              (dst dir)  dst
//
//////////////////////////////////////////////////////////
void rotateLumaPlane270(unsigned char *src,
                        register unsigned char *dst,
                        int size, int width, int height)
{
    unsigned char *endp;
    register unsigned char *base;
    int j;

    endp = src + size;
    dst = dst + size - 1;
    for (base = endp - width; base < endp; base++) {
        src = base;
        for (j = 0; j < height; j++, src -= width)
        {
            *dst-- = *src;
        }

    }
}

//
// nv21 chroma plane is interleaved chroma values that map
// from one pair of chroma to 4 pixels:
//
// Y1 Y2 Y3 Y4
// Y5 Y6 Y7 Y8   U1,V1 -> chroma values for block  Y1 Y2
// Y9 Ya Yb Yc                                     Y5 Y6
// Yd Ye Yf Yg
// -----------   U2,V2 -> chroma values for block  Y3 Y4
// U1 V1 U2 V2                                     Y7 Y8
// U3 V3 U4 V4
//
//////////////////////////////////////////////////////////
void rotateChromaPlane270(unsigned char *src,
                          register unsigned char *dst,
                          int size, int width, int height)
{
    // src will start at upper right, moving down to bottom
    // then left 1 col and down...
    //
    // dest will start at 0 and go til end

    int row = 0;
    int col = width;
    int src_offset = col - 1;
    int dst_offset = 0;

    while (src_offset > 0)
    {
      dst[dst_offset++] = src[src_offset];
      dst[dst_offset++] = src[src_offset+1];

      src_offset += width;
      row++;

      if (row >= height) {
        col -= 2;
        src_offset = col;
        row = 0;
      }
    }
}

      

+4


source







All Articles