HoughLinesP not detecting lines OpenCV android - java

I am working with OpenCV 3.0 for Android. I have an image in which i want to detect angle of hands inside circular dials. for that i am working on HoughLinesP to detect hands.
Here is the code.
Mat imgSource = new Mat(), imgCirclesOut = new Mat(),imgLinesOut=new Mat();
//grey opencv
Imgproc.cvtColor(Image, imgSource, Imgproc.COLOR_BGR2GRAY);
Imgproc.GaussianBlur( imgSource, imgSource, new Size(9, 9), 2, 2 );
int threshold = 0;
int minLineSize = 0;
int lineGap = 0;
Imgproc.HoughLinesP(imgSource, imgLinesOut, 1, Math.PI/180, threshold, minLineSize, lineGap);
for( int j = 0; i < imgLinesOut.cols(); i++ )
{
double[] vec=imgLinesOut.get(0,j);
Point pt1, pt2;
pt1=new Point(vec[0],vec[1]);
pt2=new Point(vec[2],vec[3]);
Imgproc.line( Image, pt1, pt2, new Scalar(0,0,255), 3, Core.LINE_AA,0);
}
But result is
What i need is the angle of hands in these circles. Any help regarding this issue is highly appreciated. Thanks in ADvance
Edit
I have updated my code with this
Mat imgSource = new Mat(), imgCirclesOut = new Mat(),imgLinesOut=new Mat();
Imgproc.GaussianBlur( Image, imgSource, new Size(5, 5), 2, 2 );
int threshold = 20;
int minLineSize = 0;
int lineGap = 10;
Imgproc.Canny(imgSource, imgSource, 70, 100);
Imgproc.HoughLinesP(imgSource, imgLinesOut, 1, Math.PI/180, threshold, minLineSize, lineGap);
for( int j = 0; j < imgLinesOut.cols(); j++ )
{
double[] vec=imgLinesOut.get(0,j);
Point pt1, pt2;
pt1=new Point(vec[0],vec[1]);
pt2=new Point(vec[2],vec[3]);
Imgproc.line( imgSource, pt1, pt2, new Scalar(0,0,255), 3, Core.LINE_AA,0);
}
as suggested by #Micka, there is no need of Graying image(I removed cvtcolor). I also decreased value of GuassianBlur Size to 5. I have added Canny on image too for edges.
Resulting blur image is

Detecting lines can be a problem in such small images, since you have to few points to fill the Hough accumulator properly.
I propose to use a different approach:
Segment each circle (dial)
Extract the largest dark blob (hand)
Below is a simple implementation of this idea. The code is in C++, but you can easily port to Java, or at least use as a reference.
#include "opencv2/opencv.hpp"
using namespace cv;
int main(int, char**)
{
Mat1b img = imread("path_to_image", IMREAD_GRAYSCALE);
Mat3b res;
cvtColor(img, res, COLOR_GRAY2BGR);
// Find dials
vector<Vec3f> circles;
HoughCircles(img, circles, CV_HOUGH_GRADIENT, 1, img.cols/10, 400, 40);
// For each dial
for (int i = 0; i < circles.size(); ++i)
{
// Segment the dial
Mat1b dial(img.size(), uchar(255));
Mat1b mask(img.size(), uchar(0));
circle(mask, Point(circles[i][0], circles[i][1]), circles[i][2], Scalar(255), CV_FILLED);
img.copyTo(dial, mask);
// Apply threshold and open
Mat1b bin;
threshold(dial, bin, 127, 255, THRESH_BINARY_INV);
Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(5,5));
morphologyEx(bin, bin, MORPH_OPEN, kernel);
// Get min area rect
vector<Point> points;
findNonZero(bin, points);
RotatedRect r = minAreaRect(points);
// Draw min area rect
Point2f pts[4];
r.points(pts);
for (int j = 0; j < 4; ++j) {
line(res, pts[j], pts[(j + 1) % 4], Scalar(0, 255, 0), 1);
}
}
imshow("Result", res);
waitKey();
return 0;
}
Starting from this image:
I find hands here:

for( int j = 0; j < imgLinesOut.size(); j++ )
This will give the size of the vector.To iterate through that vector

Related

Detection of red circle-alike | openCV | Java

I am writing a program which need to detect red circle-alikes from this picture.
I have tried canny edge detection and find contours but none of them find this red "circles". I also tried to convert this to hsv and detect this by color but I couldn't determine good range for this color, maybe background color confuses it?
I put here a piece of my code with my final attempt..
Mat image = new Mat();
image = Imgcodecs.imread("image.jpg");
Mat hsvImage = new Mat();
Mat grayscaleImage = new Mat();
Mat binaryImage = new Mat();
Imgproc.blur(image, image, new Size(1, 1));
Imgproc.cvtColor(image, hsvImage, Imgproc.COLOR_BGR2HSV);
Imgproc.cvtColor(image, grayscaleImage, Imgproc.COLOR_BGR2GRAY);
Imgproc.equalizeHist(grayscaleImage, grayscaleImage);
Imgproc.Canny(grayscaleImage, grayscaleImage, 50, 150, 3,false);
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Imgproc.findContours(grayscaleImage.clone(), contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
for (int id=0;id<contours.size();id++){
MatOfPoint2f mop2f = new MatOfPoint2f();
contours.get(id).convertTo(mop2f,CvType.CV_32F);
RotatedRect rectangle = Imgproc.minAreaRect(mop2f);
if (rectangle.boundingRect().width>80)
Imgproc.drawContours(image,contours,id,new Scalar(0,255,0));
}
If you want to process that marked image, you really might want to detect colors. Typically this is done in HSV color-space.
Here is some C++ code to detect "red" color. The result isn't good enough to use findContours yet, but maybe after some dilation. Maybe you can convert the code to Java.
If you want to detect different color, change the line redMask = thresholdHue(hsv, 0, 20, 50, 50); to mask = thresholdHue(hsv, yourWantedHueColorValue, 20, 50, 50);`
// for example to shift a circluar hue-channel
cv::Mat shiftChannel(cv::Mat H, int shift, int maxVal = 180)
{
// CV_8UC1 only!
cv::Mat shiftedH = H.clone();
//int shift = 25; // in openCV hue values go from 0 to 180 (so have to be doubled to get to 0 .. 360) because of byte range from 0 to 255
for (int j = 0; j < shiftedH.rows; ++j)
for (int i = 0; i < shiftedH.cols; ++i)
{
shiftedH.at<unsigned char>(j, i) = (shiftedH.at<unsigned char>(j, i) + shift) % maxVal;
}
return shiftedH;
}
cv::Mat thresholdHue(cv::Mat hsvImage, int hueVal, int range = 30, int minSat = 50, int minValue = 50)
{
// hsvImage must be CV_8UC3 HSV image.
// hue val and range are in openCV's hue range (0 .. 180)
// range shouldnt be bigger than 90, because that's max (all colors), after shifting the hue channel.
// this function will
// 1. shift the hue channel, so that even colors near the border (red color!) will be detectable with same code.
// 2. threshold the hue channel around the value 90 +/- range
cv::Mat mask; // return-value
std::vector<cv::Mat> channels;
cv::split(hsvImage, channels);
int targetHueVal = 180 / 2; // we'll shift the hue-space so that the target val will always be 90 afterwards, no matter which hue value was chosen. This can be important if
int shift = targetHueVal - hueVal;
if (shift < 0) shift += 180;
cv::Mat shiftedHue = shiftChannel(channels[0], shift, 180);
// merge the channels back to hsv image
std::vector<cv::Mat> newChannels;
newChannels.push_back(shiftedHue);
newChannels.push_back(channels[1]);
newChannels.push_back(channels[2]);
cv::Mat shiftedHSV;
cv::merge(newChannels, shiftedHSV);
// threshold
cv::inRange(shiftedHSV, cv::Vec3b(targetHueVal - range, minSat, minValue), cv::Vec3b(targetHueVal + range, 255, 255), mask);
return mask;
}
int main(int argc, char* argv[])
{
cv::Mat input = cv::imread("C:/StackOverflow/Input/redCircleLikeContours.jpg");
cv::Mat redMask;
cv::Mat hsv;
cv::cvtColor(input, hsv, CV_BGR2HSV);
redMask = thresholdHue(hsv, 0, 20, 50, 50);
cv::imshow("red", redMask);
cv::imshow("input", input);
cv::imwrite("C:/StackOverflow/Output/redCircleLikeContoursMask.png", redMask);
cv::waitKey(0);
return 0;
}
Here's the result:
Here is my code if somebody would want to look :)
public static void main (String args[]){
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
Mat image = new Mat();
image = Imgcodecs.imread("imageorg.jpg");
if ( image == null) System.out.println("Image is fine");
else System.out.println("Wrong path to image");
Mat hsvImage = new Mat();
Imgproc.blur(image, image, new Size(3,3));
Imgproc.cvtColor(image, hsvImage, Imgproc.COLOR_BGR2HSV);
Mat redMask = new Mat();
redMask = thresholdHue(hsvImage,0,20,50,50);
Mat kernel = new Mat();
kernel = Imgproc.getStructuringElement(Imgproc.MORPH_DILATE, new Size(2,2));
Mat dilateMat = new Mat();
Imgproc.dilate(redMask, dilateMat, kernel);
Imgcodecs.imwrite("redCircleLikeContours.png", redMask);
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Imgproc.findContours(dilateMat.clone(), contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
List<MatOfPoint> removedContoursList = new ArrayList<MatOfPoint>();
for (int id=0;id<contours.size();id++){
MatOfPoint2f mop2f = new MatOfPoint2f();
contours.get(id).convertTo(mop2f,CvType.CV_32F);
RotatedRect rectangle = Imgproc.minAreaRect(mop2f);
if (rectangle.boundingRect().height<10){
removedContoursList.add(contours.get(id));
System.out.println("removing: "+rectangle.boundingRect());
contours.remove(id);
id--;
}
}
}
public static Mat thresholdHue(Mat hsvImage, int hueVal, int range, int minSat, int minValue)
{
Mat mask = new Mat();
List<Mat> channels = new ArrayList<Mat>();
Core.split(hsvImage, channels);
int targetHueVal = 180 / 2;
int shift = targetHueVal - hueVal;
if (shift < 0) shift += 180;
Mat shiftedHue = shiftChannel(channels.get(0), shift, 180);
List<Mat> newChannels = new ArrayList<Mat>();
newChannels.add(shiftedHue);
newChannels.add(channels.get(1));
newChannels.add(channels.get(2));
Mat shiftedHSV = new Mat();
Core.merge(newChannels, shiftedHSV);
Core.inRange(shiftedHSV, new Scalar(targetHueVal - range, minSat, minValue), new Scalar(targetHueVal + range, 255, 255), mask);
return mask;
}
private static Mat shiftChannel(Mat H, int shift, int maxVal)
{
Mat shiftedH = H.clone();
for (int j = 0; j < shiftedH.rows(); ++j)
for (int i = 0; i < shiftedH.cols(); ++i)
{
shiftedH.put(j, i,(shiftedH.get(j,i)[0] + shift) % maxVal);
}
return shiftedH;
}

OpenCV Java Harris Corner Detection

I am developing an Android application and I want to make use of Harris corner detection. I want to draw the corners detected but I cannot seem to find the documentation for the Java code.
My code so far:
Mat inputImage = inputFrame.rgba();
Imgproc.cornerHarris(inputImage, inputImage, 7, 5, 0.05, Imgproc.BORDER_DEFAULT);
How can I detect and display the corners?
For Java you can try this piece of code.
private void Harris(Mat Scene, Mat Object, int thresh) {
// This function implements the Harris Corner detection. The corners at intensity > thresh
// are drawn.
Mat Harris_scene = new Mat();
Mat Harris_object = new Mat();
Mat harris_scene_norm = new Mat(), harris_object_norm = new Mat(), harris_scene_scaled = new Mat(), harris_object_scaled = new Mat();
int blockSize = 9;
int apertureSize = 5;
double k = 0.1;
Imgproc.cornerHarris(Scene, Harris_scene,blockSize, apertureSize,k);
Imgproc.cornerHarris(Object, Harris_object, blockSize,apertureSize,k);
Core.normalize(Harris_scene, harris_scene_norm, 0, 255, Core.NORM_MINMAX, CvType.CV_32FC1, new Mat());
Core.normalize(Harris_object, harris_object_norm, 0, 255, Core.NORM_MINMAX, CvType.CV_32FC1, new Mat());
Core.convertScaleAbs(harris_scene_norm, harris_scene_scaled);
Core.convertScaleAbs(harris_object_norm, harris_object_scaled);
for( int j = 0; j < harris_scene_norm.rows() ; j++){
for( int i = 0; i < harris_scene_norm.cols(); i++){
if ((int) harris_scene_norm.get(j,i)[0] > thresh){
Imgproc.circle(harris_scene_scaled, new Point(i,j), 5 , new Scalar(0), 2 ,8 , 0);
}
}
}
for( int j = 0; j < harris_object_norm.rows() ; j++){
for( int i = 0; i < harris_object_norm.cols(); i++){
if ((int) harris_object_norm.get(j,i)[0] > thresh){
Imgproc.circle(harris_object_scaled, new Point(i,j), 5 , new Scalar(0), 2 ,8 , 0);
}
}
}
}
I just wrote this following code here
I know this is not ideal, but it is also not so bad - you can look at the c++ documentation and examples, the translation to Java is usually straight forward:
One example: Harris corner detector. (you did not mention your version, this is from v2.4).
If anyone is still looking for OpenCV Java Samples, you can find it here in the following links.
Complete Java Samples
https://github.com/opencv/opencv/tree/master/samples/java/tutorial_code
Motion Tracking
https://github.com/opencv/opencv/tree/master/samples/java/tutorial_code/TrackingMotion
Harris Corner Detection
https://github.com/opencv/opencv/blob/master/samples/java/tutorial_code/TrackingMotion/harris_detector/CornerHarrisDemo.java

Find circles image processing in OpenCV/JaVa

I'm using opencv and java to find circles on an image, I have the image below so far. I'm using Hough to find the circles with the code like this :
public static Vector<Mat> circles(Mat img){
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
long start_time = System.nanoTime();
Imgproc.resize(img, img, new Size(450,250));
Mat gray = new Mat();
Imgproc.cvtColor(img, gray, Imgproc.COLOR_BGR2GRAY);
Imgproc.blur(gray, gray, new Size(3, 3));
Mat edges = new Mat();
int lowThreshold = 40;
int ratio = 3;
Imgproc.Canny(gray, edges, lowThreshold, lowThreshold * ratio);
Mat circles = new Mat();
Vector<Mat> circlesList = new Vector<Mat>();
Imgproc.HoughCircles(edges, circles, Imgproc.CV_HOUGH_GRADIENT, 1, 60, 200, 20, 30, 0 );
System.out.println("#rows " + circles.rows() + " #cols " + circles.cols());
double x = 0.0;
double y = 0.0;
int r = 0;
for( int i = 0; i < circles.rows(); i++ )
{
double[] data = circles.get(i, 0);
for(int j = 0 ; j < data.length ; j++){
x = data[0];
y = data[1];
r = (int) data[2];
}
Point center = new Point(x,y);
// circle center
Core.circle( img, center, 3, new Scalar(0,255,0), -1);
// circle outline
Core.circle( img, center, r, new Scalar(0,0,255), 1);
Imshow im1 = new Imshow("Hough");
im1.showImage(img);
Rect bbox = new Rect((int)Math.abs(x-r), (int)Math.abs(y-r), (int)2*r, (int)2*r);
Mat croped_image = new Mat(img, bbox);
Imgproc.resize(croped_image, croped_image, new Size(160,160));
circlesList.add(croped_image);
Imshow m2 = new Imshow("cropedImage");
m2.showImage(croped_image);
}
long end_time = System.nanoTime();
long duration = (end_time - start_time)/1000000; //divide by 1000000 to get milliseconds.
System.out.println("duration : " + duration * 0.001 + " s");
return circlesList;
}
BUT it always detects only one circle.
My Question is how I can detect all the circles in an image using java/OpenCV ?
Note:-
1- I'm using Mat called circles in HoughCircles function parameters , because the function requires a Mat in Java.
2- I'm using openCV 2.4.11 version.
The circles are saved in columns of the mat circles
try replacing for loop as:
for( int i = 0; i < circles.cols(); i++)
{
double[] data = circles.get(0,i);
...

Android OpenCV Find contours

I need to extract the largest contour of an image.
This is the code i'm currently using. gathered of a few snippets online
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Imgproc.findContours(outerBox, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
double maxArea = -1;
int maxAreaIdx = -1;
for (int idx = 0; idx < contours.size(); idx++) {
Mat contour = contours.get(idx);
double contourarea = Imgproc.contourArea(contour);
if (contourarea > maxArea) {
maxArea = contourarea;
maxAreaIdx = idx;
}
}
and it seems to work. however, I'm not quite sure how to go about from here.
I tried using Imgproc.floodFill, but I'm not quite sure how.
this function requires a mast Mat of the same size as the original Mat +2 horizontal and +2 vertical.
When I ran this on the contour contours.get(maxAreaIdx), it gave me an error.
The code:
Mat mask = Mat.zeros(contour.rows() + 2, contour.cols() + 2, CvType.CV_8UC1);
int area = Imgproc.floodFill(contour, mask, new Point(0,0), new Scalar(255, 255, 255));
The error:
11-18 19:07:49.406: E/cv::error()(3117): OpenCV Error: Unsupported format or combination of formats () in void cvFloodFill(CvArr*, CvPoint, CvScalar, CvScalar, CvScalar, CvConnectedComp*, int, CvArr*), file /home/oleg/sources/opencv/modules/imgproc/src/floodfill.cpp, line 621
So basically my question is, how can I, after finding the contour with the largest area, to "highlight" it? I want everything else to be black, and the contour to be white
Thanks!
You can use the DrawContours function in OpenCV : http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=drawcontours#drawcontours
Or you can use this implementation in C++ (you can find the equivalent in Java in the OpenCV doc, just type OpenCV + the name of the function on google)
Mat src = imread("your image"); int row = src.rows; int col = src.cols;
//Create contour
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
Mat src_copy = src.clone();
findContours( src_copy, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);
// Create Mask
Mat_<uchar> mask(row,col);
for (int j=0; j<row; j++)
for (int i=0; i<col; i++)
{
if ( pointPolygonTest( contours[0], Point2f(i,j),false) =0)
{mask(j,i)=255;}
else
{mask(j,i)=0;}
};
try contours[1], contours[2]... to find the biggest one
This is for displaying your contour:
namedWindow("Contour",CV_WINDOW_AUTOSIZE);
imshow("Contour", mask);

Detecting Hough circles android

I am trying to detect circles using android. I succeeded to implement the detect lines algorithm but nothing gets displayed when trying the draw hough circles algoritm.
Here is my code:
Mat thresholdImage = new Mat(getFrameHeight() + getFrameHeight() / 2, getFrameWidth(), CvType.CV_8UC1);
mYuv.put(0, 0, data);
Imgproc.cvtColor(mYuv, destination, Imgproc.COLOR_YUV420sp2RGB, 4);
Imgproc.cvtColor(destination, thresholdImage, Imgproc.COLOR_RGB2GRAY, 4);
Imgproc.GaussianBlur(thresholdImage, thresholdImage, new Size(9, 9), 2, 2 );
Mat circles = new Mat();
Imgproc.HoughCircles(thresholdImage, circles, Imgproc.CV_HOUGH_GRADIENT, 1d, (double)thresholdImage.height()/70, 200d, 100d);
Log.w("circles", circles.cols()+"");
for (int x = 0; x < circles.cols(); x++)
{
double vCircle[]=circles.get(0,x);
Point center=new Point(Math.round(vCircle[0]), Math.round(vCircle[1]));
int radius = (int)Math.round(vCircle[2]);
// draw the circle center
Core.circle(destination, center, 3,new Scalar(0,255,0), -1, 8, 0 );
// draw the circle outline
Core.circle( destination, center, radius, new Scalar(0,0,255), 3, 8, 0 );
}
You may have got this sorted by now, but a few things. I'd check your circles mat actually has some results; sometimes vCircle seems to come back null; try one of the other versions of HoughCircles:
iCannyUpperThreshold = 100;
iMinRadius = 20;
iMaxRadius = 400;
iAccumulator = 300;
Imgproc.HoughCircles(thresholdImage, circles, Imgproc.CV_HOUGH_GRADIENT,
2.0, thresholdImage.rows() / 8, iCannyUpperThreshold, iAccumulator,
iMinRadius, iMaxRadius);
if (circles.cols() > 0)
for (int x = 0; x < circles.cols(); x++)
{
double vCircle[] = circles.get(0,x);
if (vCircle == null)
break;
Point pt = new Point(Math.round(vCircle[0]), Math.round(vCircle[1]));
int radius = (int)Math.round(vCircle[2]);
// draw the found circle
Core.circle(destination, pt, radius, new Scalar(0,255,0), iLineThickness);
Core.circle(destination, pt, 3, new Scalar(0,0,255), iLineThickness);
}
(I swapped your code into mine, renamed some stuff and swapped it back, I think I've got it back so it works...)
B.

Categories