I can't get the circle vectors values from the OpenCV Mat in Android. I want to use this function:
HoughCircles(Mat image, Mat circles, int method, double dp, double minDist)
And then I want to show the circles that were found. Where I'm stuck is how to use the circles parameter in this function.
So, the question is: how can I get numbers of 3-element vectors and values of every element in vector from Mat type of OpenCV in Android?
Once you have your circles Mat
for (int i = 0; i < circles.cols(); i++)
{
double vCircle[] = circles.get(0,i);
double x = vCircle[0];
double y = vCircle[1];
double radius = vCircle[2];
}
Ideally you would want to use a vector<Vec3f> list to process the circles like this:
vector<Vec3f> circles;
// do HoughCircles...
for(size_t i = 0; i < circles.size(); i++)
{
Vec3f circle = circles[i];
Point2f center(circle[0] /* x */, circle[1] /* y */);
float radius = circle[2];
// use the circle...
}
EDIT : I tried the code just using a Mat, and it appears that the circle parameters are stored as a 1xN matrix with elements of type CV_32FC3, and where N is the number of circles detected. So, each column contains the (x, y, radius) vector you need.
Here is a sample I wrote in C++ showing this:
Mat circleImage = imread("circle.png", 0);
Mat circleDisp;
cvtColor(circleImage, circleDisp, CV_GRAY2RGB);
Mat circles;
HoughCircles(circleImage, circles, CV_HOUGH_GRADIENT, 2, circleImage.rows >> 2, 200, 100);
for( size_t i = 0; i < circles.cols; i++ )
{
Vec3f vCircle = circles.at<Vec3f>(i);
Point center(cvRound(vCircle[0]), cvRound(vCircle[1]));
int radius = cvRound(vCircle[2]);
// draw the circle center
circle( circleDisp, center, 3, Scalar(0,255,0), -1, 8, 0 );
// draw the circle outline
circle( circleDisp, center, radius, Scalar(0,0,255), 3, 8, 0 );
}
namedWindow( "circles", 1 );
imshow( "circles", circleDisp );
waitKey();
Hope that helps!
Just cast your Mat to vector:
HoughCircles(Mat image, Mat circles, int method, double dp, double minDist);
vector<Vec3f> myCircles = (vector<Vec3f>)circles;
Or, simpler
HoughCircles(Mat image, vector<Vec3f>& circles,
int method, double dp, double minDist);
Note
This is only true for OpenCV 2.3.1.
Related
I'm currently working with libgdx, and am trying to get 4 equal Polygons from a Rectangle:
Rectangle myRect = Rectangle(0, 0, 171, 171);
I am looking to determine the 4 Polygons that represent each side of the Rectangle
This is my first day working with this engine, and I am a bit rusty on my geometry, so I'm looking for any help I can get. Essentialy, I'm going to use these Polygons to determine whether a specified X,Y pair is within them.
Thanks for the help.
You could find the mid point of the rectangle fairly easily, just average the height and width. From there you could manually construct a polygon, jumping from corner to corner to midpoint. You would lose some precision due to rounding, but you can use getX() and getWidth() if you need double precision.
public Polygon[] findTris(Rectangle rectangle){
//Creating a list of the x points of the rectangle, ordered clockwise.
new int[] xpoints = new int[5];
xpoints[0] = rectangle.x;
xpoints[1] = rectangle.x+rectangle.width;
xpoints[2] = rectangle.x+rectangle.width;
xpoints[3] = rectangle.x;
xpoints[4] = rectangle.x;
//Doing the same for y points.
int[] ypoints = new int[5];
ypoints[0] = rectangle.y;
ypoints[1] = rectangle.y;
ypoints[2] = rectangle.y+rectangle.height;
ypoints[3] = rectangle.y+rectangle.height;
ypoints[4] = rectangle.y;
//Finding the midpoint.
int midx = (rectangle.x+rectangle.width)/2;
int midy = (rectangle.y+rectangle.height)/2;
//Creating an array to hold the polygons.
Polygon[] polys = new Polygon[4];
//Creating the polygons.
for(int i = 0; i < 4; i++){
int[] triXPoints = {xpoints[i], xpoints[i+1], midx};
int[] triYPoints = {ypoints[i], ypoints[i+1], midy};
polys[i] = Polygon(xpoints,ypoints,3);
}
return polys;
}
Now that will work fine, but if all you are trying to do is find the mouse position in a square, you can use mouse maps. A mouse map is an image with distinctly different colors in each region that you want to be able to recognize the mouse in. You would store the map as a BufferedImage and whenever you needed to find the region the mouse was in, you can get the color of the buffered image at the appropriate position on the BufferedImage.
Here is the idea:
http://i.stack.imgur.com/iFPsl.png
I have a Java swing application where I can draw hot spots. I am allowing user to draw Rectangle , Polygon and Circle.
For Circle I am using Ellipse2D
Ellipse2D.Double ellipseDouble = new Ellipse2D.Double(x,y,width,height);
g.draw(ellipseDouble);
Above works fine and it does draw an ellipse/circle.
Now the problems when I want the region to be used in HTML Image map.
Html Image map doesn't support Ellipse so I was thinking to use polygon for Ellipse2D but really don't know how would I convert it.
Does anyone know how would I go about it converting an Ellipse2D to Polygon ponits?
Use FlatteningPathIterator.
See e.g. http://java-sl.com/tip_flatteningpathiterator_moving_shape.html where point moves following custom Shape.
You can get list of Points and create Polygon.
Maybe someone will find this one useful: this is pdfbox ellipse or circle (width=height) draw function inside rectangle, it make ellipse as polygon initially to draw.
Code based on math function of ellipse at poin [0 , 0]: x^2/a^2 + y^2/b^2 = 1
private PdfBoxPoligon draw_Ellipse_or_Circle_as_poligon_with_PDFBOX (
PDPageContentStream content, float bottomLeftX, float bottomLeftY,
float width, float height, boolean draw) throws IOException {
PdfBoxPoligon result = new PdfBoxPoligon();
float a = width/2;
float b = height/2;
int points = (int) (a*b/20);
if (DEBUG) {
System.out.println("points=" + points);
}
//top arc
for (float x = -a; x < a; x = x + a / points) {
result.x.add(bottomLeftX + a + x);
float y = (float) Math.sqrt((1-(x*x)/(a*a))*(b*b));
result.y.add(bottomLeftY+b+y);
}
//bottom arc
for (float x = a; x >= -a; x = x - a / points) {
result.x.add(bottomLeftX + a + x);
float y = -(float) Math.sqrt((1-(x*x)/(a*a))*(b*b));
result.y.add(bottomLeftY+b+y);
}
result.x.add(result.x.get(0));
result.y.add(result.y.get(0));
if (draw) {
for (int i=1; i < result.x.size(); i++) {
content.addLine(result.x.get(i-1), result.y.get(i-1), result.x.get(i), result.y.get(i));
}
}
return result;
}
I'm trying to make a useful/generic 2D polygon class for an OpenGL ES renderer.
When I create a polygon, I give it several parameters:
Polygon(Vector3 centerpoint, int numVertices, float inPolySize)
Then, I try to generate the vertices. This is where i'm having a tough time. I need to determine the number of vertices, get an angle, find the x/y position of that angle, someone take the size into account, AND offset by the position.
OpenGL works with big arrays of data. Nothing is nice like Lists of Vector3's. Instead it's float[] arrays, with the first index being X1, second being Y1, third being Z1, fourth being X2, etc...
final int XPOS = 0;
final int YPOS = 1;
final int ZPOS = 2;
int mvSize = 3; // (x, y, z);
float[] vertices = new float[mvSize * mNumVertices];
for (int verticeIndex = 0; verticeIndex < mNumVertices; verticeIndex++)
{
double angle = 2 * verticeIndex * Math.PI / mNumVertices;
vertices[mvSize * verticeIndex + XPOS] = (((float)Math.cos(angle)) * mPolygonSize) + mPosition.GetX();
vertices[mvSize * verticeIndex + YPOS] = (((float)Math.sin(angle)) * mPolygonSize) + mPosition.GetY();
vertices[mvSize * verticeIndex + ZPOS] = mPolygonSize + mPosition.GetZ();
}
Unfortunatley, my triangle is never quite right. It's skewed a lot, the size doesn't seem right...
I figure i'm throwing the size into the wrong formula, can anyone help?
EDIT:
Here's some sample data
Polygon test = new Polygon( new Vector3(0, 1, 0), 3, .5f);
vertices[0] = -0.25
vertices[1] = 1.4330127
vertices[2] = 0.0
vertices[3] = -0.25
vertices[4] = 0.5669873
vertices[5] = 0.0
vertices[6] = 0.5
vertices[7] = 1.0
vertices[8] = 0.0
vertices[9] = -0.25
vertices[10] = 1.4330127
vertices[11] = 0.0
I can't believe I was this stupid. Basically, my render window was smaller than my screen. If my screen is a rectangle, my render window was a square.
This being the case, any triangle I draw that was up was clipped by my render window. To me, it looked like the triangle was skewed. Really, it was just clipped!
The Java math library takes radians as input, not degrees. I didn't see the angles you were using for your calculation, but if you're not converting to radians from degrees, you will get some skewed looking shapes, and would explain that your calculations are correct, but the expected result is off.
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.
I created a program to draw many polygons automatically everytimes user presses a button. The points of the polygon are generated automatically using the random function. The problem is that, since the points of the polygon were randomly generated, some of the polygon are overlap with other polygon. How can I avoid this, so that every polygon shown without being overlapped?
.....
List<Polygon> triangles = new LinkedList<Polygon>();
Random generator = new Random();
public void paintComponent(Graphics g) {
for(int i = 0; i < 10; i++) {
double xWidth = generator.nextDouble() * 40.0 + 10.0;
double yHeight = generator.nextDouble() * 40.0 + 10.0;
xCoord[0] = generator.nextInt(MAX_WIDTH);
yCoord[0] = generator.nextInt(MAX_HEIGHT);
xCoord[1] = (int) (xCoord[0] - xWidth);
xCoord[2] = (int) (xCoord[1] + (xWidth/2));
yCoord[1] = yCoord[0];
yCoord[2] = (int) (yCoord[1] - yHeight);
triangles.add( new Polygon(xCoord,yCoord, 3));
}
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(new BasicStroke(1));
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.00f));
g2.setPaint(Color.black);//set the polygon line
for (Polygon triangle : triangles) g2.drawPolygon(triangle);
Polygon[] triArray = triangles.toArray(new Polygon[triangles.size()]);
for (Polygon p:triArray) triangles.remove (p);
}
Check out the game programming wiki on Polygon Collision:
http://gpwiki.org/index.php/Polygon_Collision
You could break your canvas into 10 regions and constrain your polygons each to their own region. To do this, you could use your i value and a %100 (or other suitable magnitude) of your randomly generated value and apply them to your x coordinates and y coordinates as applicable. The result would be a grid of similarly constrained(no larger than the grid cell), but randomly shaped, Polygons.
EDIT:
Taking another look and fooling around a bit, I took the general concept as I described above and made a stab at an implementation:
public void paintComponent(Graphics g) {
int[] xCoord = new int[3];
int[] yCoord = new int[3];
int colCnt = 5;
int rowCnt = 2;
int maxCellWidth = getWidth() / colCnt;
int maxCellHeight = getHeight() / rowCnt;
for (int i = 0; i < (colCnt * rowCnt); i++) {
int xMultiple = i % colCnt;
int yMultiple = i / colCnt;
for (int j = 0; j < 3; j++) {
xCoord[j] = generator.nextInt(maxCellWidth)
+ (maxCellWidth * xMultiple);
yCoord[j] = generator.nextInt(maxCellHeight)
+ (maxCellHeight * yMultiple);
}
triangles.add(new Polygon(xCoord, yCoord, 3));
}
//... the rest of your method
}
As you can see, all of the Polygons have all points randomly generated, as opposed to your method of generating the first point and then making the rest relative to the first. There is a sense of randomness that is lost, however, as the Polygons are laid out in a grid-like pattern.
Create Area objects from your new polygon as well as for all existing polygons.
Subtract the new polygon's area from the existing ones. If the subtract changed the area, the polygons overlap.
Area newArea = new Area(newPolygon);
Area existingArea = new Area(existingPolygon);
Area existingAreaSub = new Area(existingPolygon); existingAreaSub.subtract(newArea);
boolean intersects = existingAreaSub.equals(existingArea);
You could implement a method Polycon.containsPoint( x, y ) and repeat your random generation until this method returns false for all drawn Polygons.
I have achieved this in Android Using Kotlin (See github project) by using JTS see here
Step-1:
Add JTS library to your project
implementation group: 'org.locationtech.jts', name: 'jts-core', version: '1.15.0'
Step-2:
Create JTS polygon objects for both polygon
// create polygons One
var polygoneOneArray: ArrayList<Coordinate> = ArrayList()
for (points in polygonOnePointsList) {
polygoneOneArray.add(Coordinate(points.latitude(), points.longitude()))
}
val polygonOne: org.locationtech.jts.geom.Polygon = GeometryFactory().createPolygon(
polygoneOneArray.toTypedArray()
)
// create polygons Two
var polygoneTwoArray: ArrayList<Coordinate> = ArrayList()
for (points in polygoneTwoPointsList) {
polygoneTwoArray.add(Coordinate(points.latitude(), points.longitude()))
}
val polygonTwo: org.locationtech.jts.geom.Polygon = GeometryFactory().createPolygon(
polygoneTwo.toTypedArray()
)
Step-3:
Get Common Area of both Polygon
val intersection: org.locationtech.jts.geom.Geometry = polygonOne.intersection(polygonTwo)
Step-4:
Remove common Area from polygonTwo
val difference: org.locationtech.jts.geom.Geometry = polygonTwo.difference(intersection)
Step-5:
Merge Both polygonOne and update polygonTwo
val union: org.locationtech.jts.geom.Geometry = mergePolygonList.get(0).polygons.union(difference)
Step-5:
Now pick points from Geometry and draw a final merged Polygon
val array: ArrayList<Coordinate> = union.coordinates.toList() as ArrayList<Coordinate>
val pointList: ArrayList<Point> = ArrayList()
for (item in array) {
pointList.add(Point.fromLngLat(item.y, item.x))
}
var list: ArrayList<List<Point>> = ArrayList<List<Point>>()
list.add(pointList)
style.addSource(
GeoJsonSource(
"source-id${timeStamp}",
Feature.fromGeometry(Polygon.fromLngLats(list))
)
)