Why my application is crushing when i use openCv Mat - android

I am new in openCV android image Processing. but i am facing some problem. when i use openCV in android and i use Mat then my apps will crushed.... what is the problem with this.....
My code is here..:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView img=(ImageView) findViewById(R.id.imageView);
Bitmap b = BitmapFactory.decodeResource(getResources(), R.drawable.in);
Mat tmp = new Mat (b.getWidth(), b.getHeight(), CvType.CV_8UC1);
Utils.bitmapToMat(b, tmp);
Imgproc.cvtColor(tmp, tmp, Imgproc.COLOR_RGB2GRAY);
//there could be some processing
Imgproc.cvtColor(tmp, tmp, Imgproc.COLOR_GRAY2RGB, 4);
Utils.matToBitmap(tmp, b);
img.setImageBitmap(b);
}

There are multiple problems:
Mat constructor is Mat(height, width, type), you inverted height and width.
CV_8UC1 is a single channel (grayscale). So if it IS necessary to create the Mat in advance, you should create a Mat with appropriate number of channels. I assume you want to use a RGB image, so use CV_8UC3. But typically, functions re-allocate the Mat if the size doesn't fit. If that's the case with bitmapToMat too, then there is another problem.
Afaik, android uses RGBA as standard color-space. So PROBABLY after Utils.bitmapToMat(b, tmp); tmp is a 4 channel RGBA matrix. So please try Imgproc.cvtColor(tmp, tmp, Imgproc.COLOR_RGBA2GRAY); and later Imgproc.cvtColor(tmp, tmp, Imgproc.COLOR_GRAY2RGBA, 4); if you aren't sure you should add some checks like if Mat.channels isn't 3, don't try to convert RGB2GRAY if the check fails you can try to find out what the real number of channels is and why.

Related

Android OpenCV copy ROI to part of bigger image

I get a mat (320x480) from the camera of the phone. Then I need to process a part of that frame. I use ROI for that:
mat2 = new Mat(width, 175, CvType.CV_8SC3);
Rect roi = new Rect(75, 0, 175, 320);
mat2 = new Mat(mat1, roi);
Now I want to create a new mat with dimensions 320x480 with a black background. How do I do that?
Then I want to copy the processed ROI to the new mat at the same place it was on the first mat. How do I do that?
I am using OpenCV 3.4.6 and android studio.
Thank you in advance
You just need to submat() an ROI from the original Mat (your camera frame), and then process the submat as a normal Mat, but be careful to do not clone the sumbmat if you want the original get the effect.
Update according to the comment:
Mat originalMat = someMat;
Mat blackMat = Mat.zeros(size, CvType.CV_8UC1); // it is your black mat
// create a submat from the original mat, and clone it
Mat roiMat = originalMat.submat(rect).clone();
..... // do what you want with roiMat
// now copy the result to the original mat
Mat dst = originalMat.submat(rect); // do not clone this submat
roiMat.copyTo(dst);
// done!

How to set transparent background to grabcut output image with open cv?

> Hi, I am using OpenCV android library grabcut() method to extract an image from background, but the problem is that the output bitmap contains background Same as original image and object become white .I need Object as its same as original image and background transparent
I am using this code
private static Bitmap makeBlackTransparent(Bitmap image) {
// convert image to matrix
Mat src = new Mat(image.getWidth(), image.getHeight(), CvType.CV_8UC4);
Utils.bitmapToMat(image, src);
// init new matrices
Mat dst = new Mat(image.getWidth(), image.getHeight(), CvType.CV_8UC4);
Mat tmp = new Mat(image.getWidth(), image.getHeight(), CvType.CV_8UC4);
Mat alpha = new Mat(image.getWidth(), image.getHeight(), CvType.CV_8UC4);
// convert image to grayscale
Imgproc.cvtColor(src, tmp, Imgproc.COLOR_BGR2GRAY);
// threshold the image to create alpha channel with complete transparency in black background region and zero transparency in foreground object region.
Imgproc.threshold(tmp, alpha, 100, 255, Imgproc.THRESH_BINARY);
// split the original image into three single channel.
List<Mat> rgb = new ArrayList<Mat>(3);
Core.split(src, rgb);
// Create the final result by merging three single channel and alpha(BGRA order)
List<Mat> rgba = new ArrayList<Mat>(4);
rgba.add(rgb.get(0));
rgba.add(rgb.get(1));
rgba.add(rgb.get(2));
rgba.add(alpha);
Core.merge(rgba, dst);
// convert matrix to output bitmap
Bitmap output = Bitmap.createBitmap(image.getWidth(), image.getHeight(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(dst, output);
return output;
}
There are 2 problems in your code:
Firstly you need to segment out the white background, so adjust your thresh to be near 220 - 240 and also use THRESH_BINARY_INV instead of THRESH_BINARY :
Imgproc.threshold(tmp, alpha, 230, 255, Imgproc.THRESH_BINARY_INV);
Secondly, you must pre-multiply the ARGB layers, as Android ImageView behaves weird without premultiplication, for that you need to use cvtColor with COLOR_RGBA2mRGBA flag:
// Create the final result by merging three single channel and alpha(BGRA order)
List<Mat> rgba = new ArrayList<Mat>(4);
rgba.add(rgb.get(0));
rgba.add(rgb.get(1));
rgba.add(rgb.get(2));
rgba.add(alpha);
Core.merge(rgba, dst);
Imgproc.cvtColor(dst, dst, Imgproc.COLOR_RGBA2mRGBA);

Convert Mat to Bitmap by opencv

I'm trying to convert Mat rectangle from onCameraFrame to bitmap then send the bitmap to ocr function because i need to make the ocr works on real-time on ROI according to rectangle. I tried these lines:
Mat mgray= inputFrame.gray();
Mat grayInnerWindow = mgray.submat(100, 100 +500, 150, 200 + 50);
Imgproc.cvtColor(mIntermediateMat, rgbaInnerWindow, Imgproc.COLOR_GRAY2BGRA, 4);
rgbaInnerWindow.release();
Size sizeGray = grayInnerWindow.size();
int rowss = (int) sizeGray.height;
int colss = (int) sizeGray.width;
Mat tmp = new Mat(colss, rowss, CvType.CV_8UC4);
Imgproc.cvtColor(rgbaInnerWindow, tmp, Imgproc.COLOR_RGBA2BGRA, 4);
Bitmap bmp = Bitmap.createBitmap(tmp.cols(), tmp.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(tmp, bmp);
ImageView Img = (ImageView)findViewById(R.id.image_manipulations_activity_surface_view);
Img.setImageBitmap(bmp);
but when i run it terminated.
you are releasing rgbaInnerWindow, then you re-use it as input to cvtColor.
yep, that will burn, rgbaInnerWindow is invalid/empty now..
also, why all those cvtColor calls ? can't you just pass an 8bit grayscale image to your ocr?
(converting a 4channel, all grayscale image from rgba to bgra is utterly useless)

Android OpenCV Highgui.imread wrong color

i have code to load image from sdcard and post it to ImageView.
Mat mRgba = Highgui.imread(dir);
Bitmap bmp = Bitmap.createBitmap(mRgba.cols(), mRgba.rows(),Bitmap.Config.ARGB_8888);
Utils.matToBitmap(mRgba, bmp);
mImage.setImageBitmap(bmp, true, null, 5.0f);
the image is loaded but it's wrong color. Color seem to be inverted (but not inverted).
Here is image comparison
I tried to load image by
Bitmap bmp = BitmapFactory.decodeFile(dir);
It worked correctly. But i have to use Highgui.imread.
What wrong with my code?
You will have to use something like this:
Mat inputImage = Highgui.imread(pathToFile);
Mat tmp = new Mat();
Imgproc.cvtColor(inputImage, tmp, Imgproc.COLOR_BGR2RGB);
Bitmap imageToShow = Bitmap.createBitmap(tmp.cols(), tmp.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(tmp, imageToShow);
You're trying to load a bitmap supposing that the image is 8-bit/color RGBA: are you sure of that?
Also note that ARGB is not RGBA. You may need to re-arrange the bytes of each pixel. Something like
int pixel = get_the_pixel();
int alpha = 0xff & pixel;
pixel = pixel<<8 | alpha;
set_the_pixel(pixel);
You'll want to do something more efficient than accessor methods shown here, but you get the idea.

ANDROID - color detection using openCV - how to?

my goal is to display a threshed image using the HSV color space in a way that only yellow objects will be shown. i use this code (based on a code given by the openCV 2.3.1 android samples):
protected Bitmap processFrame(VideoCapture capture) {
//capture.retrieve(mGray, Highgui.CV_CAP_ANDROID_GREY_FRAME);
//Imgproc.cvtColor(mGray, mRgba, Imgproc.COLOR_GRAY2RGBA, 4);
capture.retrieve(mHSV, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA);
Imgproc.cvtColor(mHSV, mRgba, Imgproc.COLOR_RGB2HSV, 4);
//Core.inRange(mRgba, new Scalar(20, 100, 100), new Scalar(30, 255, 255), mRgba);
Bitmap bmp = Bitmap.createBitmap(mRgba.cols(), mRgba.rows(), Bitmap.Config.ARGB_8888);
if (Utils.matToBitmap(mRgba, bmp))
return bmp;
bmp.recycle();
return null;
}
the base (Abstract)class contains the "run" method:
protected abstract Bitmap processFrame(VideoCapture capture);
public void run() {
...
bmp = processFrame(mCamera);
...
canvas.drawBitmap(bmp, (canvas.getWidth() - bmp.getWidth()) / 2, (canvas.getHeight() - bmp.getHeight()) / 2, null);
...
}
i get this distorted preview which i think i can understand (HSV format) but why is it repeating itself (i`v draw a green line to emphasize it) 4 time? and what is the black horizontal line?
what am i doing wrong?
one last thing, what is the logic behind:
Imgproc.cvtColor(mHSV, mRgba, Imgproc.COLOR_RGB2HSV, 4);
why is it COLOR_RGB2HSV? shouldnt it be COLOR_HSV2RGB?
Let's say i'v passed this problem, how can i make a gray level image with the yellow objects in their native color? i thought using the Core.inRange() method but when i do this i get black screen.
yes, i guess i look like a total jerk but i need to start from somewhere, don't i?
10x!
Update 1:
i tried to do RGB->HSV->RGB this way:
#Override
protected Bitmap processFrame(VideoCapture capture) {
//capture.retrieve(mGray, Highgui.CV_CAP_ANDROID_GREY_FRAME);
//Imgproc.cvtColor(mGray, mRgba, Imgproc.COLOR_GRAY2RGBA, 4);
capture.retrieve(mRgba, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGB);
Imgproc.cvtColor(mRgba, mHSV, Imgproc.COLOR_RGB2HSV,0);
//Imgproc.cvtColor(mRgba, mRgba, Imgproc.COLOR_BGR2RGB, 4);
//Core.inRange(mRgba, new Scalar(20, 100, 100), new Scalar(30, 255, 255), mRgba);
Imgproc.cvtColor(mHSV,mRgba , Imgproc.COLOR_HSV2RGB,0);
Bitmap bmp = Bitmap.createBitmap(mRgba.cols(), mRgba.rows(), Bitmap.Config.ARGB_8888);
if (Utils.matToBitmap(mRgba, bmp))
return bmp;
bmp.recycle();
return null;
}
and i got:
?
Update 2:
i finally understand that before setting a frame, it must be converted into RGBA space.
so i now tried the threshold with the code as follow:
capture.retrieve(mRgba, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA);
Imgproc.cvtColor(mRgba, mHSV, Imgproc.COLOR_RGB2HSV,0);
Core.inRange(mHSV, new Scalar(20, 100, 100), new Scalar(30, 255, 255), mHSVThreshed);
Imgproc.cvtColor(mHSVThreshed, mRgba, Imgproc.COLOR_HSV2RGB, 0);
Imgproc.cvtColor(mRgba, mRgba, Imgproc.COLOR_RGB2RGBA, 0);
Bitmap bmp = Bitmap.createBitmap(mRgba.cols(), mRgba.rows(), Bitmap.Config.ARGB_8888);
but now it gives me force shutdown... any ideas?
friends. i give you the result of 1 month of hard work and help from friends across the ocean:
Ethan was right. but the code needed some fixing.
the code:
capture.retrieve(mRgba, Highgui.CV_CAP_ANDROID_COLOR_FRAME_BGRA);
Imgproc.cvtColor(mRgba, mHSV, Imgproc.COLOR_BGR2HSV,3);
Core.inRange(mHSV, new Scalar(0, 100, 30), new Scalar(5, 255, 255), mHSVThreshed);
Imgproc.cvtColor(mHSVThreshed, mRgba, Imgproc.COLOR_GRAY2BGR, 0);
Imgproc.cvtColor(mRgba, mRgba2, Imgproc.COLOR_BGR2RGBA, 0);
Bitmap bmp = Bitmap.createBitmap(mRgba2.cols(), mRgba2.rows(), Bitmap.Config.ARGB_8888);
if (Utils.matToBitmap(mRgba2, bmp))...
first, the mat is binary 0 or 255 so the transform to gray level is more "natural". second, the conversion from HSVto RGBis in fact HSV-BGR!!. and last thing is that the preview is expecting RGBA Bitmap.
thats it. hope other can benefit from this post. SHALOM!
I think mHSVThreshed is a binary mat
so maybe this line :
Imgproc.cvtColor(mHSVThreshed, mRgba, Imgproc.COLOR_HSV2RGB, 0);
should change to :
Imgproc.cvtColor(mHSVThreshed, mRgba, Imgproc.COLOR_GRAY2RGB, 0);
I spent a lot of time dealing with the "showing" problem too...
hope this help...
Well as far as I see it you fetch the image frame in RGBA and save it under the name "mHSV"
capture.retrieve(mHSV, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA);
so you should there store it as mRgba
in the cvtColor you need to transform it to HSV via COLOR_RGBA2HSV. Assuming you have changed the names this would be:
Imgproc.cvtColor(mRgba, mRSV, Imgproc.COLOR_RGB2HSV, 0);
And I assume this repetition of the images comes from the "4" in you cvtColor function since your HSV picture will only have 3 channels. Put in a 0 there and it should be detected automatically...
I hope it helps...
why is it COLOR_RGB2HSV? shouldnt it be COLOR_HSV2RGB?
I would say that it should :).
Looks like a problem on how opencv grabs the pixels. Check that both your input and output images have the same size and numberof channels.
This
capture.retrieve(mHSV, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA);
looks also weird to me, Are you storing the RGBA image that you get into an image at HSV format?
That would explain the problem.
Try to do something like that : RGB(capture retrieve) => HSV(cvt color) => color detection => RGB (cvt color again)

Categories

Resources