开发者

camera pixels rotated

I want to do some image processing to the pixels gotten from the camera.

The problem is that the pixels from the cam开发者_JS百科era are rotated 90 degrees.

Im getting the pixels inside the method onPreviewFrame(byte[] data, Camera camera)

I tried camera.setDisplayOrientation(90); and it displays the video in the correct orientation but I am still receiving the rotated pixels as stated in the documentation:

This does not affect the order of byte array passed in Android.Hardware.Camera.IPreviewCallback.OnPreviewFrame(Byte[], Android.Hardware.Camera), JPEG pictures, or recorded videos.

I also tried:

parameters.setRotation(90);
camera.setParameters(parameters);

but that did not work.

I'm using android 2.2

camera pixels rotated

Top image shows the SurfaceView when using camera.setDisplayOrientation(90);

The second image is gotten inside onPreviewFrame(byte[] data, Camera camera) from the data array. As you can see the data array comes rotated.


While I'm a bit late to the party, here's a method I wrote that others might find useful to rotate a YUV420sp (NV21) image. None of the other methods I saw on SO seemed to actually do it.

public static byte[] rotateNV21(final byte[] yuv,
                                final int width,
                                final int height,
                                final int rotation)
{
  if (rotation == 0) return yuv;
  if (rotation % 90 != 0 || rotation < 0 || rotation > 270) {
    throw new IllegalArgumentException("0 <= rotation < 360, rotation % 90 == 0");
  }

  final byte[]  output    = new byte[yuv.length];
  final int     frameSize = width * height;
  final boolean swap      = rotation % 180 != 0;
  final boolean xflip     = rotation % 270 != 0;
  final boolean yflip     = rotation >= 180;

  for (int j = 0; j < height; j++) {
    for (int i = 0; i < width; i++) {
      final int yIn = j * width + i;
      final int uIn = frameSize + (j >> 1) * width + (i & ~1);
      final int vIn = uIn       + 1;

      final int wOut     = swap  ? height              : width;
      final int hOut     = swap  ? width               : height;
      final int iSwapped = swap  ? j                   : i;
      final int jSwapped = swap  ? i                   : j;
      final int iOut     = xflip ? wOut - iSwapped - 1 : iSwapped;
      final int jOut     = yflip ? hOut - jSwapped - 1 : jSwapped;

      final int yOut = jOut * wOut + iOut;
      final int uOut = frameSize + (jOut >> 1) * wOut + (iOut & ~1);
      final int vOut = uOut + 1;

      output[yOut] = (byte)(0xff & yuv[yIn]);
      output[uOut] = (byte)(0xff & yuv[uIn]);
      output[vOut] = (byte)(0xff & yuv[vIn]);
    }
  }
  return output;
}


Maybe you can perform your image processing on the sideways frame, and only worry about rotation when you display it (which you have already done). If not, you need to rotate the frame the old fashioned way. I found some code somewhere (with a little modification) that might help:

// load the origial bitmap
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
       R.drawable.android);

int width = bitmap.width();
int height = bitmap.height();

// create a matrix for the manipulation
Matrix matrix = new Matrix();
// rotate the Bitmap 90 degrees (counterclockwise)
matrix.postRotate(90);

// recreate the new Bitmap, swap width and height and apply transform
Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0,
                  width, height, matrix, true);

This is easy because the createBitmap method supports a matrix transform: http://developer.android.com/reference/android/graphics/Bitmap.html#createBitmap(android.graphics.Bitmap, int, int, int, int, android.graphics.Matrix, boolean)


If you are receiving a YUV420 byte array then the following method can rotate this by 90 degree.

private byte[] rotateYUV420Degree90(byte[] data, int imageWidth, int imageHeight) 
{
    byte [] yuv = new byte[imageWidth*imageHeight*3/2];
    // Rotate the Y luma
    int i = 0;
    for(int x = 0;x < imageWidth;x++)
    {
        for(int y = imageHeight-1;y >= 0;y--)                               
        {
            yuv[i] = data[y*imageWidth+x];
            i++;
        }
    }
    // Rotate the U and V color components 
    i = imageWidth*imageHeight*3/2-1;
    for(int x = imageWidth-1;x > 0;x=x-2)
    {
        for(int y = 0;y < imageHeight/2;y++)                                
        {
            yuv[i] = data[(imageWidth*imageHeight)+(y*imageWidth)+x];
            i--;
            yuv[i] = data[(imageWidth*imageHeight)+(y*imageWidth)+(x-1)];
            i--;
        }
    }
    return yuv;
}

(Note that this might only work if the width and height is a factor of 4)


You can rotate the raw data as follows:

// Rotate the data for Portait Mode
byte[] rotatedData = new byte[data.length];
for (int y = 0; y < height; y++) {
    for (int x = 0; x < width; x++)
        rotatedData[x * height + height - y - 1] = data[x + y * width];
}

Where 'width' and 'height' are the pre-set sizes for your preview image using:

Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(width, height);
camera.setParameters(parameters);

You can then use your rotated data accordingly.

I've only used this method for QR Code scanning and it appears to work perfectly. Not sure how it might effect other applications.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜