My goal is to take bytearray at onPreviewFrame convert it into openCv MAT for some processing and later display processed frame in imageview.
My implementation of onPreviewFrame is as follows:
#Override
public void onPreviewFrame(byte[] data, Camera camera) {
Mat cvMat=Byte_to_Mat(data);
Imgproc.cvtColor(cvMat, cvMat, Imgproc.COLOR_YUV2BGR_NV12, 4);
Imgproc.cvtColor(cvMat, cvMat, Imgproc.COLOR_BGR2GRAY, 4);
Bitmap bm = Bitmap.createBitmap(cvMat.cols(), cvMat.rows(), Bitmap.Config.ARGB_8888);
public Mat Byte_to_Mat(byte[] data) {
Mat jpegData = new Mat(1, data.length, CvType.CV_8UC1);
jpegData.put(0, 0, data);
Mat bgrMat = new Mat();
bgrMat = Imgcodecs.imdecode(jpegData, Imgcodecs.IMREAD_COLOR);
return bgrMat;
}
However Bitmap.createBitmap throws following exception
java.lang.IllegalArgumentException: width and height must be > 0
Related
Im trying to do some image processing using openCV on the array returned from onPreviewFrame(byte[] rawData), i have converted the byte array into int array.
my question is, how to convert this int array into Iplimage or Mat ?
will converting to the new Camera2 be any good?
i have tried this way to convert the array.
void ProcImage(int Width, int Height, int imageArray[]) {
cv::Mat mat = cv::Mat(Width, Height, CV_32SC1 , imageArray);
}
but mat.data contains values like -14545898.
any solutions ?
thanks in advance
This is most likely due to the Mat type CV_32SC1 that you used.
You don't even have to convert the int array, and use the byte array as is
cv::Mat mat = new cv::Mat(Width, Height, CvType.CV_8UC3, byteArray);
where byteArray is your byte array.
If you still want to use the int array trying changing the type to one of Mat: CV_32SC1,CV_32SC2,CV_32SC3,CV_32SC4 as specified in http://ninghang.blogspot.com/2012/11/list-of-mat-type-in-opencv.html
Directly in Java you could do something like this (it is based on the implementation of JavaCameraView):
...
Mat frameData = new Mat(frameHeight + (frameHeight/2), frameWidth, CvType.CV_8UC1);
#Override
public void onPreviewFrame(byte[] frame, Camera arg1) {
Log.d(TAG, "Preview Frame received. Frame size: " + frame.length);
synchronized (this) {
frameData.put(0, 0, frame);
...
this.notify();
}
}
public Mat getRgbaFrame() {
Mat rgba = new Mat();
Imgproc.cvtColor(frameData, rgba, Imgproc.COLOR_YUV2RGBA_NV21, 4);
return mRgba;
}
public Mat getGrayFrame() {
return frameData.submat(0, frameHeight, 0, frameWidth);
}
In my android app, I am trying to take frames in "onPreviewFrame" and convert them to Mat object so i can do on them some image processing, but i don't know how to convert them back to byte[] type and make them be shown on camera preview.
Does any one know how to do that?
Here is my onPreviewFrame function, i am trying to change frame color to grey:
public void onPreviewFrame(byte[] data, Camera arg1)
{
Mat mRgba = new Mat(PreviewSizeWidth, PreviewSizeHeight, CvType.CV_8UC3);
mRgba.put(0, 0, data);
Imgproc.cvtColor(mRgba, mRgba, Imgproc.COLOR_BGR2GRAY);
mRgba.put(0, 0, data);
mCamera.addCallbackBuffer(data);
}
Thanks in advance!
From an older implementation of the OpenCV camera viewer pipeline:
private Mat mYuv, mGraySubmat;
#Override
public void onPreviewFrame(byte[] data, Camera camera) {
if(mYuv == null) {
mYuv = new Mat(height + height / 2, width, CvType.CV_8UC1);
mGraySubmat = mYuv.submat(0, height, 0, width);
}
mYuv.put(0, 0, data);
Imgproc.cvtColor(mGraySubmat, mRgba, Imgproc.COLOR_GRAY2RGBA, 4);
}
I think you can just call the addCallbackBuffer method in the end and it'd work fine!
I've been trying to process an image as soon as the picture was taken i.e. in the onPictureTaken() callback. As it was to my understanding I should convert the byte array to an OpenCV matrix, but the entire app freezes when I try to do that. Basically all I did was this:
#Override
public void onPictureTaken(byte[] bytes, Camera camera) {
Log.w(TAG, "picture taken!");
if (bytes != null) {
Bitmap image = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
Mat matImage = new Mat();
// This is where my app freezes.
Utils.bitmapToMat(image, matImage);
Log.w(TAG, matImage.dump());
}
mCamera.startPreview();
mCamera.setPreviewCallback(this);
}
Does anyone know why it freezes and how to solve it?
Note: I've used the OpenCV4Android tutorial 3 as a base.
Update 1: I've also tried to parste the bytes (without any success) as follows:
Mat mat = Imgcodecs.imdecode(
new MatOfByte(bytes),
Imgcodecs.CV_LOAD_IMAGE_UNCHANGED
);
Update 2: Supposedly this should work, it did not for me though.
Mat mat = new Mat(1, bytes.length, CvType.CV_8UC3);
mat.put(0, 0, bytes);
Nor did this variant:
Bitmap image = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
Mat mat = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8UC1);
mat.put(0, 0, bytes);
Update 3: This did not work for me either:
Mat mat = new MatOfByte(bytes);
I've got some help of a colleague of mine. He managed to fix the problem by doing the following:
BitmapFactory.Options opts = new BitmapFactory.Options(); // This was missing.
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opts);
Mat mat = new Mat();
Utils.bitmapToMat(bitmap, mat);
// Note: when the matrix is to large mat.dump() might also freeze your app.
Log.w(TAG, mat.size());
Hopefully this'll help all of you who are also struggling with this.
I am not able to convert a byte array to a Bitmap in the preview callback method. I'm using the following code:
public void onPreviewFrame(byte[] data, Camera camera) {
Bitmap bmp = BitmapFactory.decodeByteArray(data , 0, data.length);
Mat orig = new Mat(bmp.getHeight(),bmp.getWidth(),CvType.CV_8UC3);
Bitmap myBitmap32 = bmp.copy(Bitmap.Config.ARGB_8888, true);
Utils.bitmapToMat(myBitmap32, orig);
}
bmp is null. Please justify how to convert bitmap image.
Mat b = new Mat();
Bitmap bmp = getIntent().getExtras().getParcelable("image_send");
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_display_image);
Mat tmp = new Mat (bmp.getWidth(), bmp.getHeight(), CvType.CV_8UC1);
Utils.bitmapToMat(bmp, tmp);
Imgproc.cvtColor(tmp, tmp, Imgproc.COLOR_RGB2GRAY);
//Imgproc.cvtColor(tmp, tmp, Imgproc.COLOR_GRAY2RGB, 4);
Utils.matToBitmap(tmp, bmp);
iv = (ImageView) findViewById(R.id.imageView1);
iv.setImageBitmap(bmp);
}
Can't display the bmp. My app has stopped after taking a picture.
Utils.bitmapToMat converts an Android Bitmap to an OpenCV Mat. It requires a bitmap of type ARGB_8888 or RGB_565.
import org.opencv.android.Utils;
Mat mat = new Mat();
Bitmap bmp32 = bmp.copy(Bitmap.Config.ARGB_8888, true);
Utils.bitmapToMat(bmp32, mat);
Mat tmp = new Mat (bmp.getWidth(), bmp.getHeight(), CvType.CV_8UC1);
OpenCV Mat constructor expects rows, cols pair instead of width, height as its arguments, invert them.
Try:
Mat tmp = new Mat (bmp.getHeight(), bmp.getWidth(), CvType.CV_8UC1);
With Camera2 this task is very fast, only you need config the ImageReader with ImageFormat on YUV_420_888 and then proccess frames with OpenCV like this:
// You can read image with differents patterns for example grayscale:
Mat mGray(height, width, cv::IMREAD_GRAYSCALE, pFrameData);
A complete implementation in the next answer: https://stackoverflow.com/a/49331546/471690
Same problem with my app. In the main activity, I had to render OpenCV utilizable.
(I am assuming your app threw a link error when Mat library was used).
All sample apps do this. Include this your in main activity.
private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
#Override
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS:
{
Log.i("OpenCVManager setup", "OpenCV loaded successfully");
//Use openCV libraries after this
} break;
default:
{
super.onManagerConnected(status);
} break;
}
}
};
#Override
public void onResume()
{
super.onResume();
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_9, this,
mLoaderCallback);
}