about detecting iris and pupil circles using hough circle in java opencv - java

I'm using opencv in Java to try to detect circles (iris, and pupil) in images with eyes, but I didn't get the expected results.
Here is my code
// convert source image to gray
org.opencv.imgproc.Imgproc.cvtColor(mRgba, imgCny, Imgproc.COLOR_BGR2GRAY);
//fliter
org.opencv.imgproc.Imgproc.blur(imgCny, imgCny, new Size(3, 3));
//apply canny
org.opencv.imgproc.Imgproc.Canny(imgCny, imgCny, 10, 30);
//apply Hough circle
Mat circles = new Mat();
Point pt;
org.opencv.imgproc.Imgproc.HoughCircles(imgCny, circles, Imgproc.CV_HOUGH_GRADIENT, imgCny.rows() / 4, 2, 200, 100, 0, 0);
//draw the found circles
for (int i = 0; i < circles.cols(); i++) {
double vCircle[] = circles.get(0, i);
pt = new Point((int) Math.round((vCircle[0])), (int) Math.round((vCircle[1])));
int radius = (int) Math.round(vCircle[2]);
Core.circle(mRgba, pt, radius, new Scalar(0, 0, 255), 3);
}
the original image
canny result
I don't know what is the problem. Whether the problem is in the parameters of the found circle function or something else.
Has anyone faced such problem or knows how to fix it?

There is no way that the Hough transform will detect THE circle you want in this canny result! There are too many edges. You must clean the image first.
Start with black (the pupil, iris inner part) and white detection. These two zones will delimitate the ROI.
Moreover, I would also try to perform a skin detection (simple threshold into HSV color space. It will eliminate 90% of the research area.

Related

how to count non-zero pixels inside a contour opencv

I am developing OMR scanner android application using opencv library.
I have detected my circles inside the sheet as contours and now I want to get filled circle contours from all the obtains contours
Since java support for opencv is very less I couldnt figure out anything,
please suggest some method for the same.
//paramview is my image
Utils.bitmapToMat(paramView, localMat1);
Mat localMat2 = new Mat();
double[] lo;
Imgproc.GaussianBlur(localMat1, localMat2, new Size(5.0D, 5.0D), 7.0D, 6.5D);
Object localObject = new Mat();
Imgproc.cvtColor(localMat2, (Mat)localObject, COLOR_RGB2GRAY);
Mat cloneMat= ((Mat) localObject).clone();
localMat2 = localMat1.clone();
bitwise_not(cloneMat,cloneMat);
Imgproc.threshold(cloneMat,localMat2,127,255,Imgproc.THRESH_OTSU);
Mat thresh=localMat2.clone();
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
List<MatOfPoint> questions = new ArrayList<MatOfPoint>();
List<MatOfPoint> sorted = new ArrayList<MatOfPoint>();
//All contours detected
Mat hierarchy = new Mat();
Imgproc.findContours(localMat2, contours, hierarchy,
Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
Image of Detected circles here
I reworked my own code and found this solution. Hope it might help.
for (int contourIdx = 0; contourIdx < questionSortedR.size(); contourIdx++) {
//creating rectangle around identified contour
Rect rectCrop = boundingRect(questionSortedR.get(contourIdx));
//creating crop of that contour from actual image
Mat imageROI= thresh.submat(rectCrop);
//apply countnonzero method to that crop
int total = countNonZero(imageROI);
double pixel =total/contourArea(questionSortedR.get(contourIdx))*100;
//pixel is in percentage of area that is filled
if(pixel>=100 && pixel<=130){
//counting filled circles
count++;
}
}
I propose an alternative to the accepted answer: instead of counting pixels inside a bounding rectangle, paint the contour into a mask, then mask the original image and count the pixels inside it. I was counting black pixels on a white background, where the contour kept several pixels on the edge, so your mileage may vary. Here is my code in Python:
mask = np.zeros(bw_image.shape, np.uint8)
cv.drawContours(mask, [contour], 0, 255, -1)
inverted = cv.bitwise_not(bw_image)
masked = cv.bitwise_not(cv.bitwise_and(inverted, inverted, mask = mask))
# Grab masked image inside contour
x, y, w, h = cv.boundingRect(contour)
pixels = masked[y:y+h, x:x+w]
# Check if black is only a line, in which case whiteness is 1
kernel = np.ones((3, 3), np.uint8)
dilated = cv.dilate(pixels, kernel, iterations = 1)
whiteness = np.sum(dilated) / (255 * w * h)

Want to find the Focal length first then distance of face detected in real time using opencv android

Formula for focal length is given below:
F = (P x D) / W
But I am unable to find pixel value (P) of the rectangle that appears on the detected face in real time:
Want to find the width of rectangle drawn around the mobile phone in the image:
It was done using Python and OpenCV but I am confused as to how to implement it in Java OpenCV.
http://www.pyimagesearch.com/2015/01/19/find-distance-camera-objectmarker-using-python-opencv/
In the image you added you have drawn a square around the phone so you already have the width of the square. What I understand from your question is that you want to get the real rectangle around the phone.
For this to be achieved there can be several solutions but one done through working with contours is like the following code:
// localImage would be the cropped image of the square you have drawn,
// the global image is the original image and phoneSquare is the Rect you
// have drawn
localImage = new Mat(globalImage, phoneSqure).clone();
// make the phone black and surroundings white
Imgproc.threshold(localImage, localImage, 127, 255, Imgproc.THRESH_OTSU + Imgproc.THRESH_BINARY_INV);
// get contours
ArrayList<MatOfPoint> contours = new ArrayList<>();
Mat hierarchy = new Mat();
Imgproc.findContours(canny, contours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_NONE);
// sort contours by size and get the biggest which is assumed to be the outer contour of the phone
contours.sort(new Comparator<MatOfPoint>() {
#Override
public int compare(MatOfPoint o1, MatOfPoint o2) {
return (int) Math.signum(o2.size().area() - o1.size().area());
}
});
MatOfPoints biggestContour = contours.get(contours.size() - 1);
// get the bounding rectangle of the phone, the you can get the width
Rect whatYouWant = Imgproc.boundingRect(biggestContour);

Detect three nested objects of similar shape in an image

I want to detect an archery target by its colors and made it that far:
Original image and analyzed colors:
I'm getting the circles using color range on a RGB image. As you can see, there are also many other blobs on the images which I want to get rid of.
I tried to compare all shapes in all three images with each other to find the best match by matchShape, but it doesn't result in those three circles I want.
Any ideas how I can find out which contours/shapes/objects on the image are actually the three circles?
The input image might have an angle/perspective, so I can't use hough to find circles.
What I need as a result is a contour of the three circles (outer and inner contour), as I need to do further processing with that data.
This is actually a follow-up of that question: find archery target in image of different perspectives
As it is a more specific question, I created a new one. I'm new here
A follow-up to Miki's answer.
One of the results looks like this:
Contour of blue circle and fitting ellipse
The contour in the binary image and the resulting ellipse in the original image are different.
I would still like to solve that problem. I'm thinking of an algorithm that goes along the contour of the binary image and wherever the contour is broken the algorithm keeps going using the last known radius until it finds the next pixel of the contour. Is there such an algorithm? Or maybe a method to stretch the fitting ellipse at specific points until all parts of the contour are covered?
You can look a Circle Hough Transform algorithm to find all circular objects in Red, Green and Blue channels and then match them.
You can find implementation here or use OpenCV realization.
Finding directly the ellipses in that image can be quite tricky. You can, however, have a look here for a few info and references to code.
In this case, it's much easier to segment the 3 color: blue, red and yellow, find the outer contours, and fit an ellipse to them.
So, on this input image:
So, you first convert your image to HSV, and then apply some thresholds to recover the masks. Using morphological close operations will get rid of some holes, and link nearby blobs.
blue mask:
red mask:
yellow mask:
Then, you can retrieve the external contours from this masks, and keep only the largest (in case you find some smaller blob not belonging to the target).
Now you just need to fit an ellipse to these contours:
Please note that I tried also on the image in your other question. Blue target is deformed and so it's not an ellipse, so fitting an ellipse is not a good choice here:
In this case may be better to use the convex hull of the contours, which will be more robust than the contour itself, if the mask is not perfect (code is given below):
Code:
#include <opencv2/opencv.hpp>
#include <vector>
#include <string>
using namespace std;
using namespace cv;
int main()
{
// Load image
Mat3b img = imread("path_to_image");
// Convert to hsv
Mat3b hsv;
cvtColor(img, hsv, COLOR_BGR2HSV);
// Find masks for different colors
Mat1b blue_mask;
inRange(hsv, Scalar(90, 150, 150), Scalar(110, 255, 255), blue_mask);
Mat1b red_mask;
inRange(hsv, Scalar(160, 150, 100), Scalar(180, 255, 255), red_mask);
Mat1b yellow_mask;
inRange(hsv, Scalar(20, 150, 100), Scalar(30, 255, 255), yellow_mask);
// Apply morphological close
Mat1b kernel = getStructuringElement(MORPH_ELLIPSE, Size(11,11));
morphologyEx(blue_mask, blue_mask, MORPH_CLOSE, kernel);
morphologyEx(red_mask, red_mask, MORPH_CLOSE, kernel);
morphologyEx(yellow_mask, yellow_mask, MORPH_CLOSE, kernel);
// Find largest blob and draw it
vector<Point> blue_contour, red_contour, yellow_contour;
{
vector<vector<Point>> contours;
findContours(blue_mask.clone(), contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
blue_contour = *max_element(contours.begin(), contours.end(), [](const vector<Point>& lhs, const vector<Point>& rhs){
return contourArea(lhs) < contourArea(rhs); });
}
{
vector<vector<Point>> contours;
findContours(red_mask.clone(), contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
red_contour = *max_element(contours.begin(), contours.end(), [](const vector<Point>& lhs, const vector<Point>& rhs){
return contourArea(lhs) < contourArea(rhs); });
}
{
vector<vector<Point>> contours;
findContours(yellow_mask.clone(), contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
yellow_contour = *max_element(contours.begin(), contours.end(), [](const vector<Point>& lhs, const vector<Point>& rhs){
return contourArea(lhs) < contourArea(rhs); });
}
// Fit ellipse
RotatedRect blue_ellipse = fitEllipse(blue_contour);
RotatedRect red_ellipse = fitEllipse(red_contour);
RotatedRect yellow_ellipse = fitEllipse(yellow_contour);
// Draw ellipses
ellipse(img, blue_ellipse, Scalar(255, 0, 0), 3);
ellipse(img, red_ellipse, Scalar(0, 0, 255), 3);
ellipse(img, yellow_ellipse, Scalar(0, 255, 255), 3);
imshow("Result", img);
waitKey();
return 0;
}
Code for convex hull:
// Get convex hulls
vector<Point> blue_hull, red_hull, yellow_hull;
convexHull(blue_contour, blue_hull);
convexHull(red_contour, red_hull);
convexHull(yellow_contour, yellow_hull);
// Draw convex hulls
drawContours(img, vector < vector<Point> > {blue_hull}, 0, Scalar(255,0,0), 3);
drawContours(img, vector < vector<Point> > {red_hull}, 0, Scalar(0, 0, 255), 3);
drawContours(img, vector < vector<Point> > {yellow_hull}, 0, Scalar(0, 255, 255), 3);

JavaCV Warning sign detection?

I've looked at JavaCV wrapper for OpenCV library and I saw that it is possible to use that library in Java for face detection on an image, but I was wondering is it possible to use that library for detecting traffic warning signs on an image and how?
I have pictures taken from the road that look like this: http://www.4shared.com/photo/5QxoVDwd/041.html
and the result of detection should look sometning like this or similar: http://www.4shared.com/photo/z_pL0lSK/overlay-0.html
EDIT:
After I detect red color I get this image:
And I have a problem detecting just the warning sign triangle shape and ignore all other shapes. I tried changing the cvApproxPoly parameters but with no result. This is my code:
public void myFindContour(IplImage image)
{
IplImage grayImage = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1);
cvCvtColor(image, grayImage, CV_BGR2GRAY);
CvMemStorage mem;
CvSeq contours = new CvSeq();
CvSeq ptr = new CvSeq();
cvThreshold(grayImage, grayImage, 150, 255, CV_THRESH_BINARY);
mem = cvCreateMemStorage(0);
cvFindContours(grayImage, mem, contours, Loader.sizeof(CvContour.class) , CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0));
Random rand = new Random();
while (contours != null && !contours.isNull()) {
if (contours.elem_size() > 0) {
CvSeq points = cvApproxPoly(contours, Loader.sizeof(CvContour.class),
mem, CV_POLY_APPROX_DP, cvContourPerimeter(contours)*0.02, 0);
Color randomColor = new Color(rand.nextFloat(), rand.nextFloat(), rand.nextFloat());
CvScalar color = CV_RGB( randomColor.getRed(), randomColor.getGreen(), randomColor.getBlue());
cvDrawContours(image, points, color, CV_RGB(0,0,0), -1, CV_FILLED, 8, cvPoint(0,0));
}
contours = contours.h_next();
}
cvSaveImage("myfindcontour.png", image);
}
This is the output that i get (I used different colors for every shape, but in the final output i will use only white for detected warning sign and everything other left black):
You have to do the following:
Detect red color on image - you will get 1bit image where: 0=non-red, 1=red.
Detect triangles on created in previous step image. You can do that using approxPoly function.
see ,the first find the contour area.
compare it with the precalculated value and keep it with in a range
like
if(area>Mincontourarea && area<maxcontourare)
{
thats it now we have the signboard do
}
the value if calculated wouldnot be bigger than the car conotur,
to get the contoutr
up to my knowledge u need
Moments operator
code for the momnts operator:
Moments moment = moments((cv::Mat)contours[index]);
area = moment.m00; //m00 gives the area of the detected contour
put the above code before the if block discussed above
if you want the x and y coordinates put a post again..
take a look of my answer, it is in c++ but using opencv it is able to detect road signs, you can take it as a good example.
https://stackoverflow.com/a/52651521/8035924

Trying to get the centre of a circle with opencv

I'm trying to detect the center of a circle. I try to do this with cvHoughCircle. But I can't seem to get it working properly .
The only thing that can vary is the size of the circle.
I try detecting the circle by doing :
circle = cvHoughCircles(imgThreshold, storage, CV_HOUGH_GRADIENT, 1,
(double)imgThreshold.height()/20, 200, 20, 0, 0);
imgThreshold is the b/w image you can see here. The resolution of the image is in fact 1280*1024.
Can anyone tell me what I am doing wrong.
Instead of using cvHoughCircle it is possible to solve this problem with a bit of math:
CvMoments moments = new CvMoments();
cvMoments(imgThreshold, moments, 1);
double moment10 = cvGetSpatialMoment(moments, 1, 0);
double moment01 = cvGetSpatialMoment(moments,0,1);
double area = cvGetCentralMoment(moments, 0, 0);
int posX = 0;
int posY = 0;
int lastX = posX;
int lastY = posY;
posX = (int) (moment10/area);
posY = (int) (moment01/area);
cvCircle(iplRgbImage, new CvPoint(posX,posY), 3, CvScalar.GREEN, -1, 8, 0);
source = http://aishack.in/tutorials/tracking-colored-objects-in-opencv/
If the circle is complete and filled and not occluded by other shapes, you can use findContours() and then find the center of the contour.
use cvBlob
https://code.google.com/p/cvblob/
Concerning Hough transform it can detect circles by identifying pixels that belongs to a circle periphery. More precisely given a binary (thresholded) image containing ie white pixels along a cyclic path, the hough circle transform will detect the circle. So the image to feed the algorithm should be binary and thresholded but in your example must be the thresholded example of an edge filter (ex Sobel) rather than a solid filled circle.
I can not tell a right way of "fitting" a circle on the above image, but the centroid of the blob extracted with connected components is a good and fast way to go.

Categories

Resources