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;
}
Related
I'm working on Android and OpenCV 3.2, I want to apply the perspective transform but I have some trouble
I referenced to this official document OpenCV (go to perspective transform example ) http://docs.opencv.org/trunk/da/d6e/tutorial_py_geometric_transformations.html
but i get a rotated image result 90° or 180°
intput img = [input img ][2] output img output image 90 ° output 2 [output image 180 °][4]
this is my code
public void prespective(Bitmap img){
Mat imgSrc = new Mat();
Bitmap bmp32 = img.copy(Bitmap.Config.ARGB_8888, true);
Utils.bitmapToMat(bmp32, imgSrc);
Mat gray = new Mat();
cvtColor( imgSrc, gray, COLOR_RGBA2GRAY ); //Convert to gray
Mat thr = new Mat();
threshold( gray, thr, 125, 255, THRESH_BINARY ); //Threshold the gray
List<MatOfPoint> contours = new LinkedList<>(); // Vector for storing contours
findContours( thr, contours,new Mat(), RETR_CCOMP, CHAIN_APPROX_SIMPLE ); // Find the contours in the image
MatOfPoint m = biggestCountousMatOfPoint(contours);
RotatedRect box = Imgproc.minAreaRect(new MatOfPoint2f(m.toArray()));
Rect destImageRect = box.boundingRect();
Mat destImage = new Mat(destImageRect.size(),imgSrc.type());
final Point[] pts = new Point[4];
box.points(pts);
Mat _src = new MatOfPoint2f(pts[0], pts[1], pts[2], pts[3]);
Mat _dst = new MatOfPoint2f(new Point(0, 0), new Point(destImage.width() - 1, 0), new Point(destImage.width() - 1, destImage.height() - 1), new Point(0, destImage.height() - 1));
Mat perspectiveTransform=Imgproc.getPerspectiveTransform(_src, _dst);
Imgproc.warpPerspective(imgSrc, destImage, perspectiveTransform, destImage.size());
if(destImage.height() > 0 && destImage.width() > 0) {
Bitmap cinBitmapRotated = Bitmap.createBitmap(destImage.width(), destImage.height(), Bitmap.Config.ARGB_8888);
if (cinBitmapRotated != null) {
Utils.matToBitmap(destImage, cinBitmapRotated);
prenom2Cin.setImageBitmap(cinBitmapRotated);
}
}
}
what's the problem in my code ?
I am new to image processing and I cant get fillPoly() working. Also, drawContours() is leaving some spaces while drawing contours. I am working on Android and most of the references that are given on internet are of Python, Matlab or C++
sSize5 = new Size(5, 5);
mIntermediateMat = new Mat();
Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.contours_in_contours_red);
Mat rgba = new Mat(bmp.getHeight(), bmp.getWidth(), CvType.CV_8UC1);
Utils.bitmapToMat(bmp, rgba);
Mat greyInnerWindow;
greyInnerWindow = new Mat();
Mat mRgba = new Mat();
Imgproc.cvtColor(rgba, greyInnerWindow, Imgproc.COLOR_RGBA2GRAY);
Imgproc.GaussianBlur(greyInnerWindow, greyInnerWindow, sSize5, 2, 2);
Imgproc.Canny(greyInnerWindow, mIntermediateMat, 5, 35);
Imgproc.cvtColor(mIntermediateMat, mRgba, Imgproc.COLOR_GRAY2BGRA, 4);
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Imgproc.findContours(mIntermediateMat, contours, mHierarchy, Imgproc.RETR_EXTERNAL,
Imgproc.CHAIN_APPROX_SIMPLE);
for( int i = 0; i< contours.size(); i++ )
{
Imgproc.drawContours(rgba, contours, i, new Scalar(0, 255, 0), -1);
Imgproc.fillPoly(rgba, contours, new Scalar(0,255,0));
}
Bitmap resultBitmap = Bitmap.createBitmap(rgba.cols(), rgba.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(rgba, resultBitmap);
imageView.setImageBitmap(resultBitmap);
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;
}
I am new to OpenCV and trying to track a circular object using find contours on Android using 3.1.0. I am following the sample color blob detector to write the code, but the drawContours() function never draws anything when I run the application. Here is the onCameraFrame() function, which is doing all the processing. Can you tell me what I am doing wrong?
EDIT: New version of the code: Still does not work as expected. drawContours() draws around any black objects, and the function produces a very noisy result. Here is what it now looks like.
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
Mat rgba = inputFrame.rgba();
Mat grayMat = new Mat();
Imgproc.cvtColor(rgba, grayMat, Imgproc.COLOR_RGBA2GRAY);
Mat processedMat = new Mat();
Imgproc.threshold(grayMat, processedMat, 0, 255, Imgproc.THRESH_BINARY);
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
List<MatOfPoint> matchedContours = new ArrayList<MatOfPoint>();
Mat hierarchy = new Mat();
Imgproc.findContours(processedMat, contours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
for(MatOfPoint contour : contours){
double actualArea = Imgproc.contourArea(contour);
double width = contour.width();
double radius = width/2;
double calculatedArea = Math.PI * Math.pow(radius, 2);
if((actualArea - calculatedArea) < 10000) { //chose some arbitrary threshold because I am not sure what to make this
matchedContours.add(contour);
}
}
Imgproc.drawContours(rgba, matchedContours, -1, new Scalar(0,255,0));
return rgba;
}
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.