I try to find contours and make five cluster with it. I have found the contours with:
Imgproc.findContours(bw.clone(), contours, hierarchy, Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE);
And I would like to use the kmeans algorithm to make the five cluster. But I don't know, the step between the findContours function and the kmeans function.
Core.kmeans(samples32f, 5, labels, criteria, 1, Core.KMEANS_PP_CENTERS, centers);
The first parameter of the kmeans function is a Mat with a float CvType and points.
How can I convert the contours to point or how must I proceed?
P.S. There are 15 contours represents 15 circle.
I solved the problem! Thanks mainactual for your tip.
I don't understood which value the first parameter of the kmeans algorithm need.
With this Tutorial I analyzed the problem and find out the right way.
Imgproc.findContours(bw.clone(), contours, hierarchy, Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE);
Mat samples32final = new Mat(contours.size(), 2, CvType.CV_32F, new Scalar(0));
for (int j = 0 ; j<contours.size(); j++) {
Mat samples32f = new Mat((int) contours.get(j).size().height, 2, CvType.CV_32F, new Scalar(0));
for (int i = 0; i < (int) contours.get(j).size().height; i++) {
samples32f.put(i, 0, contours.get(j).get(i, 0)[0]);
samples32f.put(i, 1, contours.get(j).get(i, 0)[1]);
}
samples32f.reshape((int) contours.get(j).size().height, 2);
Mat labels = new Mat((int) contours.get(j).size().height, 2, CvType.CV_32SC1);
TermCriteria criteria = new TermCriteria(TermCriteria.EPS + TermCriteria.MAX_ITER, 100, 1.0);
Mat centers = new Mat();
Core.kmeans(samples32f, 1, labels, criteria, 10, Core.KMEANS_RANDOM_CENTERS, centers);
samples32final.put(j,0,centers.get(0,0)[0]);
samples32final.put(j,1,centers.get(0,1)[0]);
}
samples32final.reshape(contours.size(), 2);
Mat labels = new Mat(contours.size(), 2, CvType.CV_32SC1);
TermCriteria criteria = new TermCriteria(TermCriteria.EPS + TermCriteria.MAX_ITER, 100, 1.0);
Mat centers = new Mat();
Core.kmeans(samples32final, 5, labels, criteria, 10, Core.KMEANS_PP_CENTERS, centers);
In the first line the contours of the image were found. In the first for loop finds the center of each pip with cluster size 1 and store the center in a new Mat. After the for loop the center position of all pips are stored in the variable samples32final.
With this variable the center of the dice can be found with kmeans.
Sorry for the bad english...
Related
I want to detect yellow colour objects and plot a centroid position on the largest detected yellow object.
I perform my steps in this order:
converted the input rgbaframe to hsv using cvtColor() method
perform color segmentation in HSV using inRange() method, bound it only to yellow color ranges & returns a binary threshold mask.
I perform morphology operation (specifically MORPH_CLOSE) to perform dilation then erosion on the mask to remove any noise.
I perform a gaussian blur to smooth the mask.
I apply canny algorithm to perform edge detection to make edges more obvious to prepare for Contour detection in the next step. (i'm starting to wonder if this step is of beneficial use at all?)
I apply findContour() algorithm to find the Contours in the image as well as find the hierarchy.
HERE I intend to use feature2d.FeatureDetection(SIMPLEBLOB)& pass in the blob area for detection as Params, however there seems to be no implementation supporting for Android, hence I had to work around the limitation and find largest blob using Imgproc.contourArea().
is there a way to do so?
I pass in the contours obtained previously from the findContours() method as parameter to Imgproc.moments to compute the Centroid Position of the objects detected.
HOWEVER, I would like to bring to everyone's attention that this current implementation will compute all centroids in EACH contour (yellow objects) detected. *PLS SEE/REFER to pic 1, 2 to see what is output onto the Frame back to the user.
What I would like to achieve is to find a way to use the contour of the largestblob (via largestContourArea) and pass that info on as a parameter into the ImgprocMoments() so that I will ONLY COMPUTE the centroid of that largest Contour(Object) detected, so I should only see 1 centroid Pos plotted on the screen at any particular point in time.
I have tried a few methods such as passing the contour of the Largest object as param into Imgproc.moments() but it didn't work either due to difference in data Type / if it worked, the output is not as desired, w multiple centroid points being plotted within or along the perimeter of the object, rather than 1 single point at the center of the largest contour object.
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
InputFrame = inputFrame.rgba();
Core.transpose(InputFrame,mat1); //transpose mat1(src) to mat2(dst), sorta like a Clone!
Imgproc.resize(mat1,mat2,InputFrame.size(),0,0,0); // params:(Mat src, Mat dst, Size dsize, fx, fy, interpolation) Extract the dimensions of the new Screen Orientation, obtain the new orientation's surface width & height. Try to resize to fit to screen.
Core.flip(mat2,InputFrame,-1); // mat3 now get updated, no longer is the Origi inputFrame.rgba BUT RATHER the transposed, resized, flipped version of inputFrame.rgba().
int rowWidth = InputFrame.rows();
int colWidth = InputFrame.cols();
Imgproc.cvtColor(InputFrame,InputFrame,Imgproc.COLOR_RGBA2RGB);
Imgproc.cvtColor(InputFrame,InputFrame,Imgproc.COLOR_RGB2HSV);
Lower_Yellow = new Scalar(21,150,150); //HSV color scale H to adjust color, S to control color variation, V is indicator of amt of light required to be shine on object to be seen.
Upper_Yellow = new Scalar(31,255,360); //HSV color scale
Core.inRange(InputFrame,Lower_Yellow, Upper_Yellow, maskForYellow);
final Size kernelSize = new Size(5, 5); //must be odd num size & greater than 1.
final Point anchor = new Point(-1, -1); //default (-1,-1) means that the anchor is at the center of the structuring element.
final int iterations = 1; //number of times dilation is applied. https://docs.opencv.org/3.4/d4/d76/tutorial_js_morphological_ops.html
Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, kernelSize);
Imgproc.morphologyEx(maskForYellow, yellowMaskMorphed, Imgproc.MORPH_CLOSE, kernel, anchor, iterations); //dilate first to remove then erode. White regions becomes more pronounced, erode away black regions
Mat mIntermediateMat = new Mat();
Imgproc.GaussianBlur(yellowMaskMorphed,mIntermediateMat,new Size(9,9),0,0); //better result than kernel size (3,3, maybe cos reference area wider, bigger, can decide better whether inrange / out of range.
Imgproc.Canny(mIntermediateMat, mIntermediateMat, 5, 120); //try adjust threshold //https://stackoverflow.com/questions/25125670/best-value-for-threshold-in-canny
List<MatOfPoint> contours = new ArrayList<>();
Mat hierarchy = new Mat();
Imgproc.findContours(mIntermediateMat, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE, new Point(0, 0));
byte[] arr = new byte[100];
//List<double>hierarchyHolder = new ArrayList<>();
int cols = hierarchy.cols();
int rows = hierarchy.rows();
for (int i=0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
//hierarchyHolder.add(hierarchy.get(i,j));
//hierarchy.get(i,j) is a double[] type, not byte.
Log.d("hierarchy"," " + hierarchy.get(i,j).toString());
}
}
double maxArea1 = 0;
int maxAreaIndex1 = 0;
//MatOfPoint max_contours = new MatOfPoint();
Rect r = null;
ArrayList<Rect> rect_array = new ArrayList<Rect>();
for(int i=0; i < contours.size(); i++) {
//if(Imgproc.contourArea(contours.get(i)) > 300) { //Size of Mat contour # that particular point in ArrayList of Points.
double contourArea1 = Imgproc.contourArea(contours.get(i));
//Size of Mat contour # that particular point in ArrayList of Points.
if (maxArea1 < contourArea1){
maxArea1 = contourArea1;
maxAreaIndex1 = i;
}
//maxArea1 = Imgproc.contourArea(contours.get(i)); //assigned but nvr used
//max_contours = contours.get(i);
r = Imgproc.boundingRect(contours.get(maxAreaIndex1));
rect_array.add(r); //will only have 1 r in the array eventually, cos we will only take the one w largestContourArea.
}
Imgproc.cvtColor(InputFrame, InputFrame, Imgproc.COLOR_HSV2RGB);
if (rect_array.size() > 0) { //if got more than 1 rect found in rect_array, draw them out!
Iterator<Rect> it2 = rect_array.iterator(); //only got 1 though, this method much faster than drawContour, wont lag. =D
while (it2.hasNext()) {
Rect obj = it2.next();
//if
Imgproc.rectangle(InputFrame, obj.br(), obj.tl(),
new Scalar(0, 255, 0), 1);
}
}
//========= Compute CENTROID POS! WHAT WE WANT TO SHOW ON SCREEN EVENTUALLY!======================
List<Moments> mu = new ArrayList<>(contours.size()); //HUMoments
for (int i = 0; i < contours.size(); i++) {
mu.add(Imgproc.moments(contours.get(i)));
}
List<Point> mc = new ArrayList<>(contours.size()); //the Circle centre Point!
for (int i = 0; i < contours.size(); i++) {
//add 1e-5 to avoid division by zero
mc.add(new Point(mu.get(i).m10 / (mu.get(i).m00 + 1e-5), mu.get(i).m01 / (mu.get(i).m00 + 1e-5)));
}
for (int i = 0; i < contours.size(); i++) {
Scalar color = new Scalar(150, 150, 150);
Imgproc.circle(InputFrame, mc.get(i), 20, color, -1); //just to plot the small central point as a dot on the detected ImgObject.
}
Picture of output when view on CameraFrame:
1:
2:
Managed to resolve the issue, instead of looping thru the entire array of Contours for yellow objects detected, and pass each contour as parameter to Imgproc.moments, I now only assign the Contour at the particular index which the LargestContour is detected, so only 1 single contour is being processed now by Imgproc.moments to compute Centroid! The code correction is as shown below
//========= Compute CENTROID POS! WHAT WE WANT TO SHOW ON SCREEN EVENTUALLY!======================
List<Moments> mu = new ArrayList<>(contours.size());
mu.add(Imgproc.moments(contours.get(maxAreaContourIndex1))); //Just adding that 1 Single Largest Contour (largest ContourArea) to arryalist to be computed for MOMENTS to compute CENTROID POS!
List<Point> mc = new ArrayList<>(contours.size()); //the Circle centre Point!
//add 1e-5 to avoid division by zero
mc.add(new Point(mu.get(0).m10 / (mu.get(0).m00 + 1e-5), mu.get(0).m01 / (mu.get(0).m00 + 1e-5))); //index 0 cos there shld only be 1 contour now, the largest one only!
//notice that it only adds 1 point, the centroid point. Hence only 1 point in the mc list<Point>, so ltr reference that point w an index 0!
Scalar color = new Scalar(150, 150, 150);
Imgproc.circle(InputFrame, mc.get(0), 15, color, -1); //just to plot the small central point as a dot on the detected ImgObject.
I use the following code to read through all objects that I segmented from my image which should be ordered in row and columns as semi-circle (because of segmentation and morphological processing for reducing noise):
Imgproc.Canny(srcImg, srcImg, 50, 150);
Imgcodecs.imwrite("/mnt/sdcard/DCIM/cannyImg.jpg", srcImg);//check
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Mat hierarchy = new Mat();
Imgproc.findContours(srcImg, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE, new Point(0,0));
//int index = 0;
//double maximc = Imgproc.contourArea(contours.get(0));
for (int contourIdx = 1; contourIdx < contours.size(); contourIdx++) {
double temp;
temp = Imgproc.contourArea(contours.get(contourIdx));
if (temp > 100) {
// condition to differentiate between noise and objects
Mat drawing = Mat.zeros(srcImg.size(), CvType.CV_8UC1);
Imgproc.drawContours(drawing, contours, contourIdx, new Scalar(255), -1);
Mat resultMat = new Mat();
maskImg.copyTo(resultMat, drawing);
Imgcodecs.imwrite("/mnt/sdcard/DCIM/resultImg" + contourIdx + ".jpg", resultMat);//check
}
}
however, the loop can not read important objects in my image even canny image is correct and can identify all the objects. My questions are: in which order find contours read objects? and also is there another way in Opencv to read through all objects in the image other than find contours? last question i used the size of contours to differentiate between the objects and the noise, so is this Ok or you can suggest other methods.
Any help is appreciated
The following is the code that I run to find the face region
private void detectRegion() {
//get the image from gallery and change it into bitmap
Bitmap bmpTemp = originalImg.copy(Bitmap.Config.ARGB_8888, true);
Utils.bitmapToMat(bmpTemp, mRgbMat);
Imgproc.cvtColor(mRgbMat, mHsvMat, Imgproc.COLOR_RGB2HSV, channelCount);
Scalar lowerThreshold = new Scalar(0, 0.23 * 255, 50); // Blue color – lower hsv values
Scalar upperThreshold = new Scalar(50, 0.68 * 255, 255); // Blue color – higher hsv values
Core.inRange(mHsvMat, lowerThreshold, upperThreshold, mMaskMat);
Imgproc.dilate(mMaskMat, mDilatedMat, new Mat());
Imgproc.findContours(mMaskMat, contours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
Imgproc.drawContours(mRgbMat, contours,counter, colorGreen, iLineThickness);
Log.d(TAG + " contours " , contours.get(counter).toString());
// convert to bitmap:
Bitmap bm = Bitmap.createBitmap(mHsvMat.cols(), mHsvMat.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(mRgbMat, bm);
// find the imageview and draw it!
imageView.setImageBitmap(bm);
}
However, I get so many regions that I did't want.
This is my desired region ( the green one) that I find manually. I add the value when I click the button and draw different region when I press the button.
this is the message of show in logcat.
02-16 00:11:46.413 14234-14234/fyp.hkust.facet D/ColorizeFaceActivity contours: Mat [ 932*1*CV_32SC2, isCont=true, isSubmat=false, nativeObj=0xffffffff96aa78f8, dataAddr=0xffffffff96a57010 ]
I also tried to draw them all but there are so many extra regions that I don't want.
for (int contourIdx = 0; contourIdx < contours.size(); contourIdx++) {
if (contours.size() > 100) // Minimum size allowed for consideration
{
Imgproc.drawContours(mRgbMat, contours, contourIdx, colorGreen, iLineThickness);
Log.d(TAG + " contours " , contours.get(contourIdx).toString());
}
}
This is the whole result
How can I classify them to get the face region and also I need to extract the hsv value in that region. How can I do that? Please give me some help. Thank you very much.
I want to detect paper sheet from image.I applied median Blur, Canny ,dilate,threshold,Etc. algorithms to find.i am able to find sheet but don't know how to crop rectangle and apply transformation
This is my code :-
Mat blurred = new Mat();
Imgproc.medianBlur(src, blurred, 9);
// Set up images to use.
Mat gray0 = new Mat(blurred.size(), CvType.CV_8U);
Mat gray = new Mat();
// For Core.mixChannels.
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
List<MatOfPoint2f> rectangles = new ArrayList<MatOfPoint2f>();
List<Mat> sources = new ArrayList<Mat>();
sources.add(blurred);
List<Mat> destinations = new ArrayList<Mat>();
destinations.add(gray0);
// To filter rectangles by their areas.
int srcArea = src.rows() * src.cols();
// Find squares in every color plane of the image.
for (int c = 0; c < 3; c++) {
int[] ch = {c, 0};
MatOfInt fromTo = new MatOfInt(ch);
Core.mixChannels(sources, destinations, fromTo);
// Try several threshold levels.
for (int l = 0; l < N; l++) {
if (l == 0) {
// HACK: Use Canny instead of zero threshold level.
// Canny helps to catch squares with gradient shading.
// NOTE: No kernel size parameters on Java API.
Imgproc.Canny(gray0, gray, 0, CANNY_THRESHOLD);
// Dilate Canny output to remove potential holes between edge segments.
Imgproc.dilate(gray, gray, Mat.ones(new Size(3, 3), 0));
} else {
int threshold = (l + 1) * 255 / N;
Imgproc.threshold(gray0, gray, threshold, 255, Imgproc.THRESH_BINARY);
}
// Find contours and store them all as a list.
Imgproc.findContours(gray, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
int i=0;
for (MatOfPoint contour : contours) {
MatOfPoint2f contourFloat = GeomUtils.toMatOfPointFloat(contour);
double arcLen = Imgproc.arcLength(contourFloat, true) * 0.02;
// Approximate polygonal curves.
MatOfPoint2f approx = new MatOfPoint2f();
Imgproc.approxPolyDP(contourFloat, approx, arcLen, true);
if (isRectangle(approx, srcArea)) {
Imgproc.drawContours(src, contours, i, new Scalar(255, 0, 0), 3);
//rectangles.add(approx);
/*Rect rect = Imgproc.boundingRect(contour);
Log.e("Rectangle Finder:-" + i, "Height:-" + rect.height + ", Width:-" + rect.width + " and Area:-" + rect.area() + "\nX:-" + rect.x + ",Y:-" + rect.y);*/
}
i++;
}
}
I want to select only white papersheet.please help me
Thanks in advance
I am writing an app using OpenCV 2.4.3.2 for Android.
my app is about license plate recognition.
there are a few ways to do it , I chose to do the following:
1. convert the image to HSV color space
2. threshold image according to license plate HSV (in my country they are yellow...)
3. smooth the image with a Gaussian Blur
4. Detect edges
5. find contours
6. fund houghlines
7. from the houglines, detect curves that match rectangle
I am stuck at 7, I can't find a way to successfully detect the rectangles from the houglines.
I would very much appreciate a code sample in Java, since most of the examples are in C/C++ and converting it is not so straightforward.
here is my code (right now I am just drawing the lines...):
Imgproc.cvtColor(inputFrame, mRGBMat, Imgproc.COLOR_RGBA2BGR);
// convert HSC color space
Imgproc.cvtColor(mRGBMat, mHSVMat, Imgproc.COLOR_BGR2HSV);
// Filter out colors which are out of range (license plate hue ~ 14)
Core.inRange(mHSVMat, new Scalar(9, 70, 80, 0), new Scalar(30, 255,
255, 0), mGrayMat);
// some smoothing of the image
for (int i = 0; i < 10; i++) {
Imgproc.GaussianBlur(mGrayMat, mGrayMat, new Size(9, 9), 2, 2);
}
Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_DILATE,
new Size(3, 3), new Point(1, 1));
Imgproc.Canny(mGrayMat, mGrayMat0, 48, 120);
Imgproc.dilate(mGrayMat0, mGrayMat0, kernel);
kernel.release();
List<MatOfPoint> contours = new Vector<MatOfPoint>();
Imgproc.findContours(mGrayMat0, contours, mHirerchy,
Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
Mat lines = new Mat(); // finds houghlines in the contours
Imgproc.HoughLinesP(mGrayMat0, lines, 1, Math.PI / 180, 1);
for (int x = 0; x < lines.cols(); x++) {
double[] vec = lines.get(0, x);
double x1 = vec[0], y1 = vec[1], x2 = vec[2], y2 = vec[3];
Point start = new Point(x1, y1);
Point end = new Point(x2, y2);
Core.line(mRgba, start, end, RECT_COLOR, 1);
}
I've written such an algorithm before. You classify the lines into two types:
1) vertical
2) horizontal
x) outliers for deletion
Then you classify the lines more into two subtypes each:
1a) vertical, the left border
1b) vertical, the right border
1x) outliers for deletion
2a), 2b), 2x).
Get the average slopes and intercept points of these lines and you have your "rectangle".