I am using OpenCV with Android and performing Grabcut on an image for foreground extraction, I am getting the output as expected but the output image has a blue tone and not as the original image that was provided? What is the solution to the problem?
I am attaching the code that I am using currently for the same.
private Mat performGrabCut(Mat image)
{
Mat firstMask = new Mat();
Mat foregroundModel = new Mat();
Mat backgroundModel = new Mat();
Mat mask;
Mat source = new Mat(1, 1, CvType.CV_8U, new Scalar(3.0));
Mat destination = new Mat();
Rect rect = new Rect(topLeft, bottomRight);
Imgproc.grabCut(image, firstMask, rect, backgroundModel, foregroundModel, 1, 0);
Core.compare(firstMask, source, firstMask, Core.CMP_EQ);
Mat foreground = new Mat(image.size(), CvType.CV_8UC3, new Scalar(255,255,255));
image.copyTo(foreground, firstMask);
return foreground;
}
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I had followed this tutorial to apply grab cut algorithm in opencv4android but my output image is not same as described in this tutorial. In fact the image I get is only black.
The output I get is this image Output image. I use same image used toturial
as input but my output was black.
Here is the code for grabcut in android opencv that solves your problem.
public void grabcutAlgo(Bitmap bit){
Bitmap b = bit.copy(Bitmap.Config.ARGB_8888, true);
Point tl=new Point();
Point br=new Point();
//GrabCut part
Mat img = new Mat();
Utils.bitmapToMat(b, img);
Imgproc.cvtColor(img, img, Imgproc.COLOR_RGBA2RGB);
int r = img.rows();
int c = img.cols();
Point p1 = new Point(c / 100, r / 100);
Point p2 = new Point(c - c / 100, r - r / 100);
Rect rect = new Rect(p1, p2);
//Rect rect = new Rect(tl, br);
Mat background = new Mat(img.size(), CvType.CV_8UC3,
new Scalar(255, 255, 255));
Mat firstMask = new Mat();
Mat bgModel = new Mat();
Mat fgModel = new Mat();
Mat mask;
Mat source = new Mat(1, 1, CvType.CV_8U, new Scalar(Imgproc.GC_PR_FGD));
Mat dst = new Mat();
Imgproc.grabCut(img, firstMask, rect, bgModel, fgModel, 5, Imgproc.GC_INIT_WITH_RECT);
Core.compare(firstMask, source, firstMask, Core.CMP_EQ);
Mat foreground = new Mat(img.size(), CvType.CV_8UC3, new Scalar(255, 255, 255));
img.copyTo(foreground, firstMask);
Scalar color = new Scalar(255, 0, 0, 255);
Imgproc.rectangle(img, tl, br, color);
Mat tmp = new Mat();
Imgproc.resize(background, tmp, img.size());
background = tmp;
mask = new Mat(foreground.size(), CvType.CV_8UC1,
new Scalar(255, 255, 255));
Imgproc.cvtColor(foreground, mask, Imgproc.COLOR_BGR2GRAY);
Imgproc.threshold(mask, mask, 254, 255, Imgproc.THRESH_BINARY_INV);
Mat vals = new Mat(1, 1, CvType.CV_8UC3, new Scalar(0.0));
background.copyTo(dst);
background.setTo(vals, mask);
Core.add(background, foreground, dst, mask);
Bitmap grabCutImage = Bitmap.createBitmap(dst.cols(), dst.rows(), Bitmap.Config.ARGB_8888);
Bitmap processedImage = Bitmap.createBitmap(dst.cols(), dst.rows(), Bitmap.Config.RGB_565);
Utils.matToBitmap(dst, grabCutImage);
dst.copyTo(sampleImage);
imageView.setImageBitmap(grabCutImage);
firstMask.release();
source.release();
bgModel.release();
fgModel.release();
}
I want to find the edges of image that I have used in basic image processing methods(blurring,sharpening..etc).I don't get any errors, but it isn't working.The program stops when it comes to on the Imgproc.Canny or Imgproc.findContours method with Debugging.
As a last resort, I wrote native code to find the edges, but I could not run it.
That is my code to call finding contours and execute it:
{
Mat rawImageMatGray = new Mat();
Imgproc.cvtColor(this.rawImageMat, rawImageMatGray, Imgproc.COLOR_BGR2GRAY);
Imgproc.adaptiveThreshold(rawImageMatGray, rawImageMatGray, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY, 55, 15);
Bitmap segmentImage = Bitmap.createBitmap(rawImageMatGray.cols(), rawImageMatGray.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(rawImageMatGray, segmentImage);
segmentImage = Contours(segmentImage);
return segmentImage;
}
private Bitmap Contours(Bitmap cannyImage) {
Mat cannyImageMat = new Mat();
Mat cannyImageMat2 = new Mat();
Utils.bitmapToMat(cannyImage, cannyImageMat);
Mat cannyEdges = new Mat();
Mat hierarchy = new Mat();
List<MatOfPoint> contourList = new ArrayList<MatOfPoint>();
//A list to store all the contours
//Converting the image to grayscale
//Imgproc.cvtColor(originalMat,grayMat,Imgproc.COLOR_BGR2GRAY);
Imgproc.Canny(cannyImageMat, cannyEdges, 80, 100);
//finding contours
Imgproc.findContours(cannyEdges, contourList, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
//Drawing contours on a new image
Mat contours = new Mat();
contours.create(cannyEdges.rows(), cannyEdges.cols(), CvType.CV_8UC3);
Random r = new Random();
for (int i = 0; i < contourList.size(); i++) {
Imgproc.drawContours(contours, contourList, i, new Scalar(r.nextInt(255), r.nextInt(255), r.nextInt(255)), -1);
}
//Converting Mat back to Bitmap
Bitmap cannyImage2 = Bitmap.createBitmap(cannyImageMat2.cols(),cannyImageMat2.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(cannyImageMat2, cannyImage);
Utils.matToBitmap(contours, cannyImage2);
return cannyImage2;
}
I'm writing simple application on android using open cv that will draw red contours on black detected objects.
Here is the processing code
Mat hsv = new Mat();
Mat maskInrange = new Mat();
Mat dilateMat = new Mat();
List<MatOfPoint> contours= new ArrayList<>();
Imgproc.cvtColor(rgbaImage, hsv, Imgproc.COLOR_RGB2HSV);
Scalar lowerThreshold = new Scalar(0, 0, 0);
Scalar upperThreshold = new Scalar(15, 15, 15);
Core.inRange(hsv, lowerThreshold, upperThreshold, maskInrange);
Imgproc.dilate(maskInrange, dilateMat, new Mat());
Mat h=new Mat();
Imgproc.findContours(dilateMat, contours, h, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
Imgproc.drawContours ( rgbaImage, contours, -1, new Scalar(255,0,0), 1);
The problem is that instead of one big contour representing the object there are many little unstable contours.
I guess it's about noise, but what should be the next step in improving the app?
I have searched everywhere for a solution but I haven't found any. I know this is a recurrent question, so I'll try to be precise.
I want to perform color segmentation in HSV using Android and OpenCV. I have an array of HSV samples corresponding to the color I want to segment, from which I obtain mean and std in order to obtain a range of values like:
lowerBoundH = new Scalar(meanSamples[0]-stdSamples[0]);
lowerBoundS = new Scalar(meanSamples[1]-stdSamples[1]);
upperBoundH = new Scalar(meanSamples[0]+stdSamples[0]);
upperBoundS = new Scalar(meanSamples[1]+stdSamples[1]);
Once I obtain these ranges for H, S and V I do the following (I only work with channels H & S):
mH = new Mat();
mS = new Mat();
List<Mat> channels = new ArrayList<Mat>(2);
// convert inputFrame to HSV for segmentation
Mat hsvFrame = new Mat();
convertToHSV(inputFrame, hsvFrame);
Core.split(hsvFrame, channels);
// get H&S channels of the HSVimage
mH = channels.get(0);
mS = channels.get(1);
if(mH!=null & mS!=null){
mHinRange = new Mat();
mSinRange = new Mat();
Core.inRange(mH, lowerBoundH, upperBoundH, mHinRange);
Core.inRange(mS, lowerBoundS, upperBoundS, mSinRange);
Mat filtered = new Mat(hsvFrame.height(), hsvFrame.width(), CvType.CV_8UC1, new Scalar(4));
Core.bitwise_and(mHinRange, mSinRange, filtered);
Mat aux = new Mat();
Mat mRgb = new Mat();
inputFrame.copyTo(mRgb);
Imgproc.cvtColor(filtered, mRgb, Imgproc.COLOR_GRAY2BGR, 0);
Imgproc.cvtColor(mRgb, aux, Imgproc.COLOR_BGR2RGBA, 0);
return aux;
}else{
Log.v("NULL","H OR S CHANNELS ARE NULL");
return null;
}
Then, I convert that segmented Mat to Bitmap in order to display it in an ImageView like so:
Bitmap bmp = null;
Mat tmp = new Mat(result.height(),result.width(), CvType.CV_8UC1, new Scalar(4));
try {
bmp = Bitmap.createBitmap(tmp.cols(), tmp.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(tmp, bmp);
}catch (CvException e){Log.d("Exception",e.getMessage());}
qrImage.setImageBitmap(bmp);
But when I display the resulting image I get a completely black image. I know this is wrong because the camera is facing directly to the colored object I want to segment.
What am I doing wrong?
What a stupid mistake. I was creating the Bitmap from the empty tmp Mat.
Instead, I need to create it using the result Mat:
Bitmap bmp = null;
try {
bmp = Bitmap.createBitmap(result.cols(), result.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(result, bmp);
}catch (CvException e){Log.d("Exception",e.getMessage());}
qrImage.setImageBitmap(bmp);
I'm trying to get the red rectangle region below "C", as image below:
And below is my source code use Opencv4Android:
public void threshold() {
Mat rgbMat = new Mat();
Mat grayMat = new Mat();
Mat edgeMat = new Mat();
Utils.bitmapToMat(bmp, rgbMat);
Mat intermediate = new Mat();
Imgproc.cvtColor(rgbMat, intermediate, Imgproc.COLOR_BGR2GRAY);
Imgproc.GaussianBlur(intermediate, intermediate, new Size(3, 3), 0);
Imgproc.threshold(intermediate, intermediate, 190, 255, Imgproc.THRESH_BINARY | Imgproc.THRESH_OTSU);
Imgproc.Canny(intermediate, intermediate, 60, 140);
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Mat mHierarchy = new Mat();
Imgproc.findContours(intermediate, contours, mHierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
Scalar CONTOUR_COLOR = new Scalar(255,0,0,255);
Log.e(TAG, "Contours count: " + contours.size());
Imgproc.drawContours(intermediate, contours, -1, CONTOUR_COLOR);
Bitmap edgeBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Config.ARGB_8888);
Utils.matToBitmap(intermediate, edgeBmp);
imageView.setImageBitmap(edgeBmp);
}
but the result is not as I expected: as image below:
As log show, Contours count: 372, and the rectangle region is discontinuous, How can I get the contour of the red rectangle region, and filter another useless region. I have referenced some other questions, but the question still not be solved, Could you do me a favor?
[update] change the code by the suggest from Morotspaj,
public void thresholdNew() {
Mat rgbMat = new Mat();
Mat grayMat = new Mat();
Utils.bitmapToMat(bmp, rgbMat);
Imgproc.cvtColor(rgbMat, grayMat, Imgproc.COLOR_BGR2GRAY);
Vector<Mat> bgr_planes = new Vector<Mat>();
Core.split(rgbMat, bgr_planes);
Mat redMat = bgr_planes.get(2);
Mat redness = new Mat();
Core.subtract(redMat, grayMat, redness);
Mat intermediateMat1 = new Mat();
Mat intermediateMat2 = new Mat();
Imgproc.GaussianBlur(redness, intermediateMat1, new Size(15,15), 0);
Imgproc.GaussianBlur(redness, intermediateMat2, new Size(55,55), 0);
Mat red_mask = new Mat();
Core.subtract(intermediateMat1, intermediateMat2, red_mask );
Imgproc.threshold(red_mask , red_mask , 90, 255, Imgproc.THRESH_BINARY | Imgproc.THRESH_OTSU);
Mat masked_image = rgbMat.clone();
masked_image = masked_image.setTo(new Scalar(255,0,0), red_mask );
Bitmap edgeBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Config.ARGB_8888);
Utils.matToBitmap(masked_image, edgeBmp);
imageView.setImageBitmap(edgeBmp);
}
But the result is not as I expected and different with Morotspaj's.
Any error exist in the above code?
[update] Sorry, I am very busy these days, I will be try again later, and If I can not implement with Java, I will use Morotspaj's code through JNI. I will be update soon.
I made a filter to mask out the red rectangle region, just for you ;)
Mat rgbMat = imread("red_rectangle.jpg", -1);
Mat grayMat;
cvtColor(rgbMat, grayMat, COLOR_BGR2GRAY);
// Separate the red channel and compare it to the gray image
Mat channels[3];
split(rgbMat, channels);
Mat redness = Mat_<float>(channels[2]) - Mat_<float>(grayMat);
// Find the sharp red region
Mat red_blur1;
Mat red_blur2;
GaussianBlur(redness, red_blur1, Size(15,15), 0);
GaussianBlur(redness, red_blur2, Size(55,55), 0);
Mat red_mask = (red_blur1-red_blur2) > 2;
// Store result
Mat masked_image = rgbMat.clone();
masked_image.setTo(Scalar(0,0,255), red_mask);
imwrite("red_mask.png", red_mask);
imwrite("masked_image.png", masked_image);
The GaussianBlur method calls can be replaced by boxFilter if you need better performance, and the constants here and there can of course be tweaked. Hope this helps!
EDIT: Taking the difference of two differently blurred images is known as Difference of Gaussians (DoG). It finds changes in a certain scale depending on the size of the kernels. The smaller kernel is used to smooth away small details and noise. The bigger kernel destroys the details we are interested in but not the regions with very smooth changes that we don't want. By taking the difference between them we end up with only the details in the scale we are interested in! A mask can then be created easily by thresholding with the > operator.