This is my code. I am using FFmpegFrameGrabber to grab frames one by one from a video stored in my android file system. I need some way to convert a IplImage or a Frame to a Mat so that I can perform some functions on it.
FFmpegFrameGrabber grabber=new FFmpegFrameGrabber("/data/data/some.path.name/files/images/1.mp4");
grabber.start();
while(true){
IplImage image=grabber.grab();
// or Frame image=grabber.grabFrame();
/*
some code to convert Frame/IplImage to Mat.
*/
}
grabber.stop();
grabber.release();
In C++ cv::Mat has a constructor that takes an IplImage
C++: Mat::Mat(const IplImage* img, bool copyData=false)
There should also be one in your JavaCV.
On the other hand you should be able to use your IplImage directly with OpenCV without the need to convert to cv::Mat.
EDIT: Have a look at this Question on SO: Convert IplImage to Mat in javacv
Related
I have a bitmap in ARGB format in android
Bitmap bitmapRGB=Bitmap.createBitmap(capturedImageMat.cols(),capturedImageMat.rows(),Bitmap.Config.ARGB_8888);
I send this image into Android NDK part to process the image using Opencv libaray in C++. Now i want to change the ARGB format into RGB format and then change it to BGR because Opencv uses BGR format. At first i want to change using cvtColor method in opencv but there is no ARGB2RGB conversion. I also tried to see how opencv team change BGRA2BGR in github and based on that to write a code to change ARGB2RGB but am unable to find the function in opencv source code.
Thanks to Alexander i swapped the image channels using mixChannels method in opencv. When we use bitmapToMat method the ARGB image format of android is changed into RGBA image format in opencv mat. The code i used to separate the RGBA image format into two different images i.e RGB and A
cv::Mat inputImage = *(cv::Mat *) inputImageAddress_;
cv::Mat inputImageBGR(inputImage.rows, inputImage.cols,CV_8UC3);
cv::Mat inputImageALPHA(inputImage.rows, inputImage.cols,CV_8UC1);
int from_to[]={0,2, 1,1, 2,0, 3,3};
Mat out[]={inputImageBGR,inputImageALPHA};
cv::mixChannels(&inputImage,1,out,2,from_to,4);
As #Yirga pointed out, OpenCV's Utils.bitmapToMat() converts the ARGB8888 Bitmap to RGBA Mat by default.
So a complete Java solution to convert ARGB8888 Android Bitmap to RGB OpenCV Mat would be:
Bitmap imageFromAndroid = ... ; // Whatever you have
Mat cvMatRGB = new Mat();
Utils.bitmapToMat(imageFromAndroid, cvMatRGB);
Imgproc.cvtColor(cvMatRGB, cvMatRGB, Imgproc.COLOR_RGBA2RGB);
Imports:
import android.graphics.Bitmap;
import org.opencv.core.Mat;
import org.opencv.android.Utils;
import org.opencv.imgproc.Imgproc;
I'm trying to create an app that processes camera images in real time and displays them on screen. I'm using the camera2 API. I have created a native library to process the images using OpenCV.
So far I have managed to set up an ImageReader that receives images in YUV_420_888 format like this.
mImageReader = ImageReader.newInstance(
mPreviewSize.getWidth(),
mPreviewSize.getHeight(),
ImageFormat.YUV_420_888,
4);
mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mImageReaderHandler);
From there I'm able to get the image planes (Y, U and V), get their ByteBuffer objects and pass them to my native function. This happens in the mOnImageAvailableListener:
Image image = reader.acquireLatestImage();
Image.Plane[] planes = image.getPlanes();
Image.Plane YPlane = planes[0];
Image.Plane UPlane = planes[1];
Image.Plane VPlane = planes[2];
ByteBuffer YPlaneBuffer = YPlane.getBuffer();
ByteBuffer UPlaneBuffer = UPlane.getBuffer();
ByteBuffer VPlaneBuffer = VPlane.getBuffer();
myNativeMethod(YPlaneBuffer, UPlaneBuffer, VPlaneBuffer, w, h);
image.close();
On the native side I'm able to get the data pointers from the buffers, create a cv::Mat from the data and perform the image processing.
Now the next step would be to show my processed output, but I'm unsure how to show my processed image. Any help would be greatly appreciated.
Generally speaking, you need to send the processed image data to an Android view.
The most performant option is to get an android.view.Surface object to draw into - you can get one from a SurfaceView (via SurfaceHolder) or a TextureView (via SurfaceTexture). Then you can pass that Surface through JNI to your native code, and there use the NDK methods:
ANativeWindow_fromSurface to get an ANativeWindow
The various ANativeWindow methods to set the output buffer size and format, and then draw your processed data into it.
Use setBuffersGeometry() to configure the output size, then lock() to get an ANativeWindow_Buffer. Write your image data to ANativeWindow_Buffer.bits, and then send the buffer off with unlockAndPost().
Generally, you should probably stick to RGBA_8888 as the most compatible format; technically only it and two other RGB variants are officially supported. So if your processed image is in YUV, you'd need to convert it to RGBA first.
You'll also need to ensure that the aspect ratio of your output view matches that of the dimensions you set; by default, Android's Views will just scale those internal buffers to the size of the output View, possibly stretching it in the process.
You can also set the format to one of Android's internal YUV formats, but this is not guaranteed to work!
I've tried the ANativeWindow approach, but it's a pain to set up and I haven't managed to do it correctly. In the end I just gave up and imported OpenCV4Android library which simplifies things by converting camera data to a RGBA Mat behind the scenes.
I am trying to make a gaussian blur with opencv in ios. I have already included opencv into my app, but I don't know how to call it so that it makes a gaussian blur.
In Android I call it like this:
Mat source = Highgui.imread(filepath, Highgui.CV_LOAD_IMAGE_COLOR);
Mat destination = new Mat(source.rows(),source.cols(),source.type());
Imgproc.GaussianBlur(source, destination, new Size(45, 45), 0);
Highgui.imwrite(getDir().getPath() + File.separator +"Gaussian45.jpg", destination);
Is there something similar in iOS too?
Thanks for your answers.
By the looks of things, You have to convert it to a cv::Mat, then you can use the normal guassian blur c++ method and then convert it back to ULLImage
The above link demonstrates how to convert from and to the two image types. Once you have converted it to cv::Mat you simply use this method:
void GaussianBlur(InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY=0, int
From an Android camera, I take YUV array and decode it to RGB. (JNI NDK) Then, I using black-white filter for RGB matrix, and show on CameraPrewiev in format YCbCr_420_SP
lParameters.setPreviewFormat(PixelFormat.YCbCr_420_SP);
Now I need to take a photo. But when I takePhoto, i have this error:
CAMERA-JNI Manually set buffer was too small! Expected 1138126 bytes, but got 165888!
Because from Surface you are not give the image. You must give bitmap from layout and than save on SdCsrd in some folder as Compress JPG. Thanks for all. This question is closed.
I have an array of bytes that correspond to a "grayscaled bitmap" (one byte->one pixel), and I need to create a PNG file for this image.
The method below works, but the png created is HUGE, as the Bitmap I am using is an ARGB_8888 bitmap, which takes 4 bytes per pixel instead of 1 byte.
I haven't been able to make it work with other Bitmap.Config different than ARGB_8888. Maybe ALPHA_8 is what I need, but I have not been able to make it work.
I have also tried the toGrayScale method which is included in some other posts (Convert a Bitmap to GrayScale in Android), but I have the same issue with the size.
public static boolean createPNGFromGrayScaledBytes(ByteBuffer grayBytes, int width,
int height,File pngFile) throws IOException{
if (grayBytes.remaining()!=width*height){
Logger.error(Tag, "Unexpected error: size mismatch [remaining:"+grayBytes.remaining()+"][width:"+width+"][height:"+height+"]", null);
return false;
}
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
// for each byte, I set it in three color channels.
int gray,color;
int x=0,y=0;
while(grayBytes.remaining()>0){
gray = grayBytes.get();
// integer may be negative as byte is signed. make them positive.
if (gray<0){gray+=256;}
// for each byte, I set it in three color channels.
color= Color.argb(-1, gray, gray, gray);
bitmap.setPixel(x, y, color);
x++;
if (x==width){
x=0;
y++;
}
}
FileOutputStream fos=null;
fos = new FileOutputStream(pngFile);
boolean result= bitmap.compress(Bitmap.CompressFormat.PNG,100,fos);
fos.close();
return result;
}
EDIT: Link to the generated file (it may look nonsense, but is just created with randon data).
http://www.tempfiles.net/download/201208/256402/huge_png.html
Any help will be greatly appreciated.
As you've noticed, saving a grayscale image as RGB is expensive. If you have luminance data then it would be better to save as a Grayscale PNG rather than an RGB PNG.
The bitmap and image functionality available in the Android Framework is really geared towards reading and writing image formats that are supported by the framework and UI components. Grayscale PNG is not included here.
If you want to save out a Grayscale PNG on Android then you'll need to use a library like http://code.google.com/p/pngj/
If you use OPENCV for Android library, you can use the library to save a binary data to a png file.
My way is:
in jni part,
set Mat whose data begin with the byte array:
jbyte* _ByteArray_BrightnessImgForOCR = env->GetByteArrayElements(ByteArray_BrightnessImgForOCR, 0);
Mat img(ByteArray_BrightnessImgForOCR_h, ByteArray_BrightnessImgForOCR_w, CV_8UC1, (unsigned char *) _ByteArray_BrightnessImgForOCR);
And then write it to a png file.
imwrite("/mnt/sdcard/binaryImg_forOCR.png", img);
Of course, you need to take some time to get yourself familiar with OpenCV and Java native coding. Following OpenCV for Android examples, it is fast to learn.