I am trying to convert the YUV frames to JPEG for Mavic 2 Pro. This is done using the newSaveYuvDataToJPEG420P or newSaveYuvDataToJPEG functions in repo.
However, I observe that the incoming data is not complete, yuvFrame.length < width * height the data size is not equal to the product of width and height. So the data is not processed.
What may be the reason for this discrepancy?
There are multiple YUV formats
See https://developer.android.com/reference/android/graphics/ImageFormat#YUV_420_888
Mostly likely the format used is YUV_420_888 as this is more common for cameras which representation, 8 bits for Y and 4 bits for UV (interleaved).
Thus yuvFrame.length = width * height * 12 bits or (6 bytes per 4 pixels)
The frame will have all 3 colour channels in it's length so it's length would never equal width times height in bytes.
Where as YUV444 is 3 bytes per pixel
So that test in the code is logically wrong as would not detect some incomplete YUV frames. The correct test would be yuvFrame.length < width * height * 1.5f
The only reason I can think of why it is failing this incorrect test is that the image format is not YUV, a lot of cameras can output jpeg natively as a jpg frame could fail this test.
Note that you can use the Android YuvImage class to convert YUV images to jpeg
Related
I am using com.otaliastudios.cameraview.CameraView component from otaliastudios Library. I need to convert some of the frames to Mat objects to process using OpenCV. How can I convert Otaliastudios Frame object into OpenCV Mat object?
Edit: The frame class I am using is located here: github.com/natario1/CameraView/blob/master/cameraview/src/main/java/com/otaliastudios/cameraview/Frame.java
How can I know which Image format this is? Does it make a difference?
You need to know the source format of your phone camera frame.
The Frame object contains a byte[] data field.This field is probably in the same ImageFormat of your camera. The two most common formats are NV21 and YUV_420_888.
The YUV format is composed by a component that is the luminance Y and another component that is called chrominance (U-V).
Typically the relation (and consequently the real bit/byte size) of these two components is defined by methods that reduce the chrominance component because human eyes are more sensible to luminance variations than color variations (see Chroma Subsampling). The reduction is expressed by a set of numbers like 4:2:0.
In this case the part related to chrominance is half the size of luminance.
So the byte size of a Frame has probably a part for the luminance that is equal to width X height bytes and a part of chrominance that is width X (height/2) bytes. This means that the byte size is heavily dependent on the image format that you are acquiring and you have to modify the mat size and choose the CvType according to this.
You have to allocate a mat that has the same size of your frame and put the data into it(from this answer):
mYuv = new Mat(getFrameHeight() + getFrameHeight() / 2,
getFrameWidth(), CvType.CV_8UC1);
....
mYuv.put(0, 0, data);
And then you have your Mat. If you need also to convert to an RGB format check the bottom of this page.
Hope this will help you.
Does anybody know how to modify the picture size using OpenCV for Android ?
It seems that sizes are set to a maximum that I didn't managed to change.
Using the tutorial ImageManipulations which is based on JavaCameraView, here are the maximum resolutions that I can get:
camera Preview Size. Width: 960 Height : 720
camera Picture Size. Width: 640 Height : 480
The problem is that I need a much higher resolution for the picture (I don't care about the preview size).
Maybe there's an answer in the opencv forum but I can't access to this answer since it seems there are works over there (OpenCVForum)
You can resize a Mat as follows:
Size szSource = new Size(640,480);
Size szResized = new Size(2592,1944);
Mat mSource= new Mat(szSource, CvType.CV_8U);// Read or Fill Something in your mSource
Mat mResised = new Mat();
Imgproc.resize( mSource, mResised, szResized,0,0,INTER_NEAREST);//mSource-> Your Source image
interpolation – interpolation method can be any of the above
INTER_NEAREST - a nearest-neighbor interpolation
INTER_LINEAR - a bilinear interpolation (used by default)
INTER_AREA - resampling using pixel area relation. It may be a preferred method for image decimation, as it gives moire’-free results. But when the image is zoomed, it is similar to the INTER_NEAREST method.
INTER_CUBIC - a bicubic interpolation over 4x4 pixel neighborhood
INTER_LANCZOS4 - a Lanczos interpolation over 8x8 pixel neighborhood
For further reference please see this.
I have camera preview callback. On onPreviewFrame I will get YUV data. By default my image format is NV21. If I am not wrong data[] is YUV format.
Let I have a preview of 640*480.How can I crop this YUV to get a byte[] containing 480*480 YUV image.
How can I rotate a YUV Image.
If this is difficult to archive how can I crop a IplImage.I am using Javacv to encode a video. Bad luck its greenish.
Is there any other way to archive that?
Thanks in Advance
Amlan.
Assuming you want a left most 480 pixels of a column while cropping, you could loop over the the image height (480 rows) and just copy the first 480 pixels for the Y plane. For the UV plane, just copy the first 480 pixels from the original UV plane (this would consist of 240 U and 240 V values), looped over half of image height (240 rows).
Generate a rotational transformation matrix for the given rotation angle. It will be something like
[cos(theta) -sin(theta)
sin(theta) cos(theta)]
Check wiki for more info on that. Take it's inverse matrix and for every (x, y) pair of the resultant rotated empty image, apply that transformation to get the corresponding (x, y) coordinated in the original image. Use nearest-neighbor or bi-linear interpolation to get the final pixel value.
I was reading an article about how to load bitmaps efficiently here. it had suggested using some techniques to load bitmap with a size that is needed not the real size. the only thing is that I didn't get what inSampleSize variable does(which must be a power of 2). if I choose number 1 for that, does it mean that this would be like if i normally loaded a bitmap with its real size?
Rajesh has quoted the explanation from the documentation of what inSampleSize does; that explanation can be expanded on with diagrams.
The important part is:
The sample size is the number of pixels in either dimension that correspond to a single pixel in the decoded bitmap.
So, if we had this image (where each letter denotes a pixel):
AAAABBBB
AAAABBBB
AAAABBBB
AAAABBBB
CCCCDDDD
CCCCDDDD
CCCCDDDD
CCCCDDDD
And we set inSampleSize = 2, we would get a decoded bitmap that looks like this:
AABB
AABB
CCDD
CCDD
That is, 2 pixels in the original image (AA) correspond to 1 pixel (A) in the decoded image.
If we set inSampleSize = 4, we would get a decoded bitmap that looks like this:
AB
CD
That is, 4 pixels in the original image correspond to 1 pixel in the decoded image.
Notice than an inSampleSize of 2 effectively halves the vertical and horizontal resolutions, but uses 1/4 of the pixels - and therefore only 1/4 of the memory.
Please read the documentation for inSampleSize
If set to a value > 1, requests the decoder to subsample the original image, returning a smaller image to save memory. The sample size is the number of pixels in either dimension that correspond to a single pixel in the decoded bitmap. For example, inSampleSize == 4 returns an image that is 1/4 the width/height of the original, and 1/16 the number of pixels. Any value <= 1 is treated the same as 1. Note: the decoder uses a final value based on powers of 2, any other value will be rounded down to the nearest power of 2.
if I choose number 1 for that, does it mean that this would be like if i normally loaded a bitmap with its real size?
Yes, 1 denotes no subsampling.
I try to visualize the gradiants and angles of an image which computed by the HOGDescriptor of the OpenCV Lib for Android. At the begin i have an 3 channel image Mat() with 8 bit unsigned int (CV_8UC3). The result of the computation is a MAT() (CV_32FC2) of the gradiants and a Mat() (CV_8UC2) of the angles. How can i visualize this results? What represent the values? Why have the angle Mat() 2 channels? Are the 2 channels of the gradiant Mat() the x and y component of the gradiant? I cant find documentation of the computeGradiant-Method.
HOG descriptor is an histogram of oriented gradient: it is an histogram where each bin reprezent the vote for gradient in corresponding orientation.
In order to compute this descriptor, you should first convert you 3 channels color image into a grayscale image
cv::cvtColor(CV_BGR2GRAY);
The result of "ComputeGradient" method is for exemple two images (same size as the original): x-component and y-component.
You should then be able to compute for each pixel the gradient magnitude and orientation.
mag=sqrt(x*x+y*y)
alpha=atan(y/x)
Then you can fill you histogram. Note that HOG descritpor is computed by blocks and cells. See this for more detail.