> 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);
Related
I am using OpenCV android library thresholding method for image segmentation, but the problem is that the output bitmap contains black background which I do not want please note that original image does not have any black background it is actually white. I am attaching the code for your reference, I am new to opencv and don't have much understanding about it also so kindly help me out.
private void Segmentation() {
Mat srcMat = new Mat();
gray = new Mat();
Utils.bitmapToMat(imageBmp, srcMat);
Imgproc.cvtColor(srcMat, gray, Imgproc.COLOR_RGBA2GRAY);
grayBmp = Bitmap.createBitmap(imageBmp.getWidth(), imageBmp.getHeight(), Bitmap.Config.RGB_565);
Utils.matToBitmap(gray, grayBmp);
grayscaleHistogram();
Mat threshold = new Mat();
Imgproc.threshold(gray, threshold, 0, 255, Imgproc.THRESH_BINARY_INV + Imgproc.THRESH_OTSU);
thresBmp = Bitmap.createBitmap(imageBmp.getWidth(), imageBmp.getHeight(), Bitmap.Config.RGB_565);
Utils.matToBitmap(threshold, thresBmp);
Mat closing = new Mat();
Mat kernel = Mat.ones(5, 5, CvType.CV_8U);
Imgproc.morphologyEx(threshold, closing, Imgproc.MORPH_CLOSE, kernel, new Point(-1, -1), 3);
closingBmp = Bitmap.createBitmap(imageBmp.getWidth(), imageBmp.getHeight(), Bitmap.Config.RGB_565);
Utils.matToBitmap(closing, closingBmp);
result = new Mat();
Core.subtract(closing, gray, result);
Core.subtract(closing, result, result);
resultBmp = Bitmap.createBitmap(imageBmp.getWidth(), imageBmp.getHeight(), Bitmap.Config.RGB_565);
Utils.matToBitmap(result, resultBmp);
Glide.with(ResultActivity.this).asBitmap().load(resultBmp).into(ivAfter);
}
enter image description here
What exactly do you want it to be then? Binary thresholding works like this:
if value < threshold:
value = 0
else:
value = 1
Of course you can convert it to a grayscale / RGB image and adjust the background to your liking. You can also invert your image (white background, black segmentation) by using the ~ operator.
segmented_image = ~ segmented_image
Edit: OpenCV has a dedicated flag to invert the results: CV_THRESH_BINARY_INV You are already using it, maybe try changing it to CV_THRESH_BINARY
So I make a bitmap from a blob with the next code:
byte[] blob = contact.getMP();
ByteArrayInputStream inputStream = new ByteArrayInputStream(blob);
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
Bitmap scalen = Bitmap.createScaledBitmap(bitmap, 320, 240, false);
and it gives back the next output, which is good
Then I do the following to make the bitmap into a Mat, but then my colors just change...
//Mat ImageMat = new Mat();
Mat ImageMat = new Mat(320, 240, CvType.CV_32F);
Utils.bitmapToMat(scalen, ImageMat);
I have no idea why, nor another way to make the bitmap into a Mat. What is wrong?
The format of color channels in Android Bitmap are RGB
But in opencv Mat, the channels are BGR by default.
So when you do Utils.bitmapToMat(), [B,G,R] values are stored in [R,G,B] channels. The red and blue channels are interchanged.
One possible solution is to apply cvtcolor on the opencv Mat you got as below:
Imgproc.cvtColor(ImageMat, ImageMat, Imgproc.COLOR_BGR2RGB);
It worked for me.
I am developing an app for clicked an image and convert the bitmap to binary. Here is some of my code of converting the image to binary:
File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/Watershed/WatershedImages", "Image_"+Save.MyDate+".jpg");
Mat origianlImage = Imgcodecs.imread(file.getAbsolutePath());
Mat image1Mat = new Mat();
Imgproc.cvtColor(origianlImage,image1Mat, Imgproc.COLOR_BGR2HSV);
Mat mat3 = new Mat();
Core.inRange(image1Mat, new Scalar(0, 0, 0), new Scalar(50, 255, 255), mat3);
Mat mat4 = new Mat();
Imgproc.threshold(mat3, mat4, 0, 255, Imgproc.THRESH_BINARY);
Bitmap threshBitmap = Bitmap.createBitmap(mat4.cols(), mat4.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(mat4, threshBitmap);
The image is converted to bitmap. I have checked the color of pixels and found out that black pixel value is -16777216 and white is -1. For further processing, I need to change these values to original java type (0 for black and 255 for white).
How to manipulate the pixel values from -16777216 to 0 and -1 to 255 WITHOUT changing the colors? Is there any way? Please help.
I started with the following image, named rgbaMat4Mask.bmp:
Then I converted it to HSV, and then did inRange() to find contours, and got the following Mat named maskedMat:
Then I went on to draw the first contour (the bigger one), on a newly created empty Mat named newMatWithMask, which has been given the same size as that of the first image I started with:
So far so good, but the problem starts now. I created a new Mat and gave it the same size as that of the first contour (the bigger one), and then set its background color to new Scalar(120, 255, 255). Then I copied the newMat4MaskFinished to it using copyTo function. But neither is the size of the resulting Mat same as that of the contour, nor is its background color set to new Scalar(120, 255, 255) which is blue.
It is rather an image with size same as that of the entire mask, and has a black background. why? What am I doing wrong?
public void doProcessing(View view) {
// READING THE RGBA MAT
Mat rgbaMat4Mask = Highgui.imread("/mnt/sdcard/DCIM/rgbaMat4Mask.bmp");
// CONVERTING TO HSV
Mat hsvMat4Mask = new Mat();
Imgproc.cvtColor(rgbaMat4Mask, hsvMat4Mask, Imgproc.COLOR_BGR2HSV);
Highgui.imwrite("/mnt/sdcard/DCIM/hsvMat4Mask.bmp", hsvMat4Mask);//check
// CREATING A FILTER/MASK FOR RED COLORED BLOB
Mat maskedMat = new Mat();
Core.inRange(hsvMat4Mask, new Scalar(0, 100, 100), new Scalar(10, 255, 255), maskedMat);
Highgui.imwrite("/mnt/sdcard/DCIM/maskedMat.bmp", maskedMat);// check
// COPYING THE MASK TO AN EMPTY MAT
// STEP 1:
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Imgproc.findContours(maskedMat, contours, new Mat(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_NONE);
//STEP 2:
Mat newMat4Mask = new Mat(rgbaMat4Mask.rows(), rgbaMat4Mask.cols(), CvType.CV_8UC1);
newMat4Mask.setTo(new Scalar(0));
Imgproc.drawContours(newMat4Mask, contours, 0, new Scalar(255), -1);//TODO Using -1 instead of CV_FILLED.
Highgui.imwrite("/mnt/sdcard/DCIM/newMatWithMask.bmp", newMat4Mask);// check
//STEP 3
Log.i(TAG, "HAPPY rows:"+contours.get(0).rows()+" columns:"+contours.get(0).cols());
Mat newMatwithMaskFinished = new Mat(contours.get(0).rows(), contours.get(0).cols(), CvType.CV_8UC3);
newMatwithMaskFinished.setTo(new Scalar(120, 255, 255));
rgbaMat4Mask.copyTo(newMatwithMaskFinished, newMat4Mask);
Highgui.imwrite("/mnt/sdcard/DCIM/newMatwithMaskFinished.bmp", newMatwithMaskFinished);//check*/
}
Your newMatwithMaskFinished should have the same size as rgbaMat4Mask and newMat4Mask.
Mat newMatwithMaskFinished = new Mat(rgbaMat4Mask.rows(), rgbaMat4Mask.cols(), CvType.CV_8UC3);
If you want to have a Mat of the bigger circle only, with transparent background, then you need to:
1) create newMatwithMaskFinished with type CV_8UC4
Mat newMatwithMaskFinished = new Mat(rgbaMat4Mask.rows(), rgbaMat4Mask.cols(), CvType.CV_8UC4);
2) set a transparent background:
newMatwithMaskFinished.setTo(new Scalar(0, 0, 0, 0));
3) Compute the bounding box box of the contour you're interested in, with boundingRect.
4) Convert rgbaMat4Mask to 4 channels (unless it's already), with cvtColor(..., COLOR_BGR2BGRA), let's call this rgba
5) Copy rgba to newMatwithMaskFinished, with mask newMat4Mask.
6) Crop newMatwithMaskFinished on box, using submat method
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)