How to get X and Y of detected circles? - android

I want to extract circles in and Image, So I extract them with below code:
Mat circles = new Mat();
Imgproc.HoughCircles(adaptiveThresh, circles, Imgproc.HOUGH_GRADIENT, 1.0, (double) adaptiveThresh.rows() / 40, 100.0, 30.0, 20, 30);
And then I iterate through them with below code:
for (int x = 0; x < circles.cols(); x++) {
double[] c = circles.get(0, x);
Point center = new Point(Math.round(c[0]), Math.round(c[1]));
int radius = (int) Math.round(c[2]);
Imgproc.circle(source, center, radius, new Scalar(0, 0, 255), 3);
}
But I want to sort them from topleft to bottom right, And the problem is I can not access the x and y of the circles!
How may I sort them based on row from top left to bottom right?

Your question is can be confusing. As it can be (1) sort distance to the circle to the top left of the image. (2)sort the distance from top left of each circle to top left of the image corner?
I assume you want to find the circle which is most close to top left case (1).
Here is my response.
From the C++ sample( i guess you are using android, not very familiar). You can convert using my sample code below.
for( size_t i = 0; i < circles.size(); i++ )
{
Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
int radius = cvRound(circles[i][2]);
// circle center
circle( src, center, 3, Scalar(0,255,0), -1, 8, 0 );
// circle outline
circle( src, center, radius, Scalar(0,0,255), 3, 8, 0 );
}
the center should be the point you want.
To sort them from top left to bottom right using city block distance you just have to
void sort_points (std::vector<Vec3f> &array)
{
std::cout<<"Elements in the array: "<<array.size()<<std::endl;
//comparisons will be done n times
for (int i = 0; i < array.size(); i++)
{
//compare elemet to the next element, and swap if condition is true
for(int j = 0; j < array.size() - 1; j++)
{
if ((array[j][0]+array[j][1]) > (array[j+1][0]+ array[j+1][1])
Swap(&array[j], &array[j+1]);
}
}
}
int main(argc,argv)
// ...................//do your stuff
vector<Vec3f> circles; //detected circle
// ... //do the detection
sort_points(circles);
//circles here is fully sorted from city block distance
std::cout<<circles<<std::endl; // print out all sorted circile
// ...................//do your stuff
}
if it is 2nd case just change if by
if ((array[j][0]+array[j][1]-2*array[j][2]) > (array[j+1][0]+ array[j+1][1]-2*array[j+1][2])

Here is what you need to do:
First, declare a Circle class (for encapsulation the circle properties for sorting purpose)
class Circle {
int cX;
int cY;
int radius;
double distance;
}
Now iterate over the HoughCircles result, and create a Circle instance and then add it to the List
List<Circle> circleList = new ArrayList<>();
//start point, it is used to calculate the distance
Point p1 = new Point(0, 0);
for (int x = 0; x < circles.cols(); x++) {
double[] c = circles.get(0, x);
Point center = new Point(Math.round(c[0]), Math.round(c[1]));
int radius = (int) Math.round(c[2]);
Imgproc.circle(source, center, radius, new Scalar(0, 0, 255), 3);
// here create the Circle instance
Circle circle = new Circle();
cricle.cX = center.x;
circle.cY = center.y;
circle.radius= radius;
double D = Math.sqrt(Math.pow(abs(p1.x - circles.x), 2) + Math.pow(abs(p1.y - circles.y), 2));
circle.distance = D;
// add the circle instance to the list
circleList.add(circle);
}
Now sort the circles in the list, use distance from small to bigger
circleList.sort(new Comparator<File>() {
#Override
public int compare(Circle c1, Circle c2) {
return Double.compare(c1.distance, c2.distance);
}
});
Now you can do what you want with circles list.
Hope it helps!!

Related

How to find average color of area in an Image?

I have a Mat of detected circles using HoughCircles and I iterate through them and add them to a List
Now I want to get the average color of detected circles to check if that circle is marked or not (for example the image below)
Mat circles = new Mat();
Imgproc.HoughCircles(adaptiveThresh, circles, Imgproc.HOUGH_GRADIENT, 1.0, (double) adaptiveThresh.rows() / 40, 100.0, 30.0, 20, 30);
List<Circle> circleList = new ArrayList<>();
Point p1 = new Point(0, 0);
for (int x = 0; x < circles.cols(); x++) {
double[] c = circles.get(0, x);
Point center = new Point(Math.round(c[0]), Math.round(c[1]));
int radius = (int) Math.round(c[2]);
Imgproc.circle(source, center, radius, new Scalar(255,0,255), 3, 8, 0 );
Circle circle = new Circle();
circle.centerY = (int) center.y;
circle.centerY = (int) center.y;
circle.radius= radius;
circle.x = circle.centerX - circle.radius;
circle.y = circle.centerY - circle.radius;
circle.distance = Math.sqrt(Math.pow(Math.abs(p1.x - circle.centerX), 2) + Math.pow(Math.abs(p1.y - circle.centerY), 2));
circleList.add(circle);
Log.d(TAG, "scan2: x->" + circle.x + "\ty->" + circle.y);
}
Hopefully I get all 200 circles from this image but I want to detect which circles are marked (for example the first row and the second circle is marked!)
How can I detect which circle is marked and also know which row and column it is!
There are 2 columns that in each column is 25 rows that each row has 4 circles, overall there is 200 circles
what you want is
static Scalar mean(Mat src)
Calculates an average (mean) of array elements.
The circle detected, draw a closed circle as a mask, input
Mat maskimg=new Mat(); //this image changes for every different circle
Imgproc.circle(maskimg, center, radius, new Scalar(255,255,255), **-1**, 8, 0 );
//draw filled circle on a image
Scalar averagecolor=core.mean(inputimage,masking);
double averageintensity=(averagecolor[0]+averagecolor[1]
+averagecolor[2])/3
if(averageintensity> your preset)
check position to see if answer is correct based on the official answer position
My java is bad. I wrote it without compiling. So there could be grammar mistake use it with caution

LibGDX - Issue with FrameBuffer, Scene2D Table and clipping

I have a custom ImageTextButton in which I render the button to a FrameBuffer first and then draw with frameBuffer.getColorBufferTexture(). I don't really want to do this but I use a custom shader with this button that creates some visual effects and the only way I have been able to achieve it is with a FrameBuffer. I was surprised to find this actually works very smooth and fast though, the whole process takes 1-2ms on slow devices and having several instances doesn't cause any kind of framerate drop, so I am happy with this bit.
The issue I am having though is when I enable clipping on the ImageTextButton (with setClip(true)). The reason for this is the button can change in width, and I would like it to clip the text within the bounds of the button. If I disable the FrameBuffer and render normally, this part also works very well. If I combine the 2, it seems the clipping process gets confused and the result is either no text or very small parts of the text.
So here is the relevant code. I assumed it was because I set the FrameBuffer and SpriteBatch size/projection matrix just to deal with the active area (for efficiency) however if I don't modify any of this and use the same batch/projection matrix, so the FrameBuffer manages the whole screen, it is still the same result.
public void initFrameBuffer(){
xCache = (int) super.getX(); yCache = (int) super.getY();
widthCache = (int) super.getWidth(); heightCache = (int) super.getHeight();
frameBuffer = new FrameBuffer(Pixmap.Format.RGBA8888, widthCache, heightCache, false);
fboProjectionMatrix.setToOrtho2D(xCache, yCache+heightCache, widthCache, -heightCache);
this.fbBatch = new SpriteBatch();
this.fbBatch.setProjectionMatrix(fboProjectionMatrix);
this.frameBufferReady = true;
}
public void doFrameBuffer(Batch batch, float parentAlpha){
batch.end();
frameBuffer.begin();
fbBatch.begin();
Gdx.gl20.glClearColor(0f, 0.0f, 0.0f, 0.0f);
Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
super.draw(fbBatch, parentAlpha);
fbBatch.end();
frameBuffer.end();
batch.begin();
}
public void drawFrameBufferObject(Batch batch, float parentAlpha){
batchColorCache = batch.getColor();
batch.setColor(1.0f, 1.0f, 1.0f, parentAlpha);
batch.draw(frameBuffer.getColorBufferTexture(), getX(), getY());
batch.setColor(batchColorCache);
}
#Override
public void draw(Batch batch, float parentAlpha) {
if (!this.frameBufferReady) initFrameBuffer();
doFrameBuffer(batch, parentAlpha);
drawFrameBufferObject(batch, parentAlpha);
}
Sorry for the long code, it's actually heavily trimmed down for the necessary parts..
Help hugely appreciated as always!
After much playing, the solution I have found is one that could probably be useful in other situations, and that is true clipping of the BitmapFontCache by vertex modification, no scissors involved! So if anyone would find this useful, the code is;
float xStart = ...start position of clip
float xEnd = ...end position of clip
//vertex offset numbers
int x_1 = 0, x_2 = 5, x2_1 = 10, x2_2 = 15;
int u_1 = 3, u_2 = 8, u2_1 = 13, u2_2 = 18;
for (int j = 0, n = pageCount; j < n; j++) {
int c = cache.getVertexCount(j);
int newIdx = 0;
if (c > 0) { // ignore if this texture has no glyphs
float[] vertices = cache.getVertices(j);
for(int i = 0; i < vertices.length; i+=20){
//if any of the vertices are outside the label, don't put them in the new cache
if(vertices[i+x2_1] > xStart && vertices[i+x_1] < xEnd){
for(int k = 0; k < 20; k++){
clippedVerts[j][newIdx+k] = vertices[i+k];
}
//case on major left glyph
if(vertices[i+x_1] < xStart){
float xDiff = vertices[i+x2_1]-xStart; //difference between right of glyph and clip
float xRatio = xDiff / (vertices[i+x2_1]-vertices[i+x_1]);
float uDiff = vertices[i+u2_1] - vertices[i+u_1];
float newU = vertices[i+u2_1] - uDiff*xRatio;
clippedVerts[j][newIdx+x_1] = xStart;
clippedVerts[j][newIdx+x_2] = xStart;
clippedVerts[j][newIdx+u_1] = newU;
clippedVerts[j][newIdx+u_2] = newU;
}
//case on major right glyph
if(vertices[i+x2_1] > xEnd){
float xDiff = xEnd-vertices[i+x_1]; //difference between left of glyph and clip
float xRatio = xDiff / (vertices[i+x2_1]-vertices[i+x_1]);
float uDiff = vertices[i+u2_1] - vertices[i+u_1];
float newU_2 = vertices[i+u_1] + uDiff*xRatio;
clippedVerts[j][newIdx+x2_1] = xEnd;
clippedVerts[j][newIdx+x2_2] = xEnd;
clippedVerts[j][newIdx+u2_1] = newU_2;
clippedVerts[j][newIdx+u2_2] = newU_2;
}
newIdx += 20;
}
}
}
clippedIdx[j] = newIdx;
}
for (int j = 0, n = pageCount; j < n; j++) {
int idx = clippedIdx[j];
if (idx > 0) { // ignore if this texture has no glyphs
float[] vertices = clippedVerts[j];
batch.draw(regions.get(j).getTexture(), vertices, 0, idx);
}
}

Getting the overlapping area of two circles

I'm in a tremendous bind with a last minute request on a consulting project I'm working on.
Essentially here is what I am trying to accomplish:
I have a surfaceview that draws a series of randomly sized circles. Each circle can have a radius from 50-100.
The x,y values are randomly generated along with a random radius
Each circle is created as an object representing that circle (x, y coord's and radius) and it is added to a list.
Once they are all created they are drawn.
The problem is I want to make sure none of these circles overlap.
I'm struggling a bit. This seems like it's shouldn't be all that difficult but it is for me unfortunately.
Here's my code so far (I know it's not close...be kind):
x = 100 + (int) (Math.random() * (mCanvasWidth - 200));
y = 100 + (int) (Math.random() * (mCanvasHeight - 200));
radius = 50 + (int) (Math.random() * 99);
color[0] = (float) (Math.random() * 360);
color[1] = 1;
color[2] = 1;
String radVal = String.valueOf(radius);
circle circ = new circle(x, y, radius, Color.HSVToColor(128, color), radVal);
boolean addit = true;
for (dot d : Dots) {
int leftSide = d.get_x() - radius;
int rightSide = d.get_x() + radius;
int xBoundary = x + radius;
int yBoundary = y + radius;
int exist_xLeft = d.get_x() - d.get_radius();
int exist_xRight = d.get_x() + d.get_radius();
int exist_yTop = d.get_y() - d.get_radius();
int exist_yBottom = d.get_y() + d.get_radius();
if ((xBoundary > exist_xLeft) && (xBoundary < exist_xRight))
{
if (yBoundary > (exist_yTop) && (yBoundary < exist_yBottom)) {
addit = false;
break;
}
}
}
if (addit)
circles.add(mdot);
if (circles.size() >= 5)
running = false;
Then it iterates the circles list and draws them to the canvas.
Any suggestions on where I'm failing in the collision detection?
You can detect if 2 circles are colliding like this:
Given:
centerpoints cx1,cy1 & cx2,cy2
and given radii r1 & r2,
Then you can determine if the 2 circles are colliding:
areColliding=((cx2-cx1)*(cx2-cx1)+(cy2-cy1)*(cy2-cy1))<((r1+r2)*(r1+r2));

Issues with drawArc

I'm having some issues with drawArc. When I have 4 wedges, it seems to be fine, but when I don't ahve 4 wedges (like 10), then the wedges don't align properly. You can see in the pictures, there is a slight mis-alignment. Any thoughts?
int wedgeNum = 10;
for (int i = 0; i < wedgeNum; i++) {
canvas.drawArc(bounds, 0, 360.0f / wedgeNum,
true, paints[i % 2]);
canvas.rotate(360.0f / wedgeNum, bounds.centerX(), bounds.centerY());
}
In this case of two colors, to fix the problem we can draw a whole circle of a first color, and then draw wedges of the second color on it. Like this:
int wedgeNum = 10;
float wedgeSweepAngle = 360f / wedgeNum;
// draw a round gray background
canvas.drawCircle(bounds.centerX(), bounds.centerY(), bounds.width() / 2f, paints[1]);
// draw only green wedges
for (int i = 0; i < wedgeNum; i += 2) {
canvas.drawArc(bounds, i * wedgeSweepAngle, wedgeSweepAngle, true, paints[0]);
}
In general, we can draw wedges in reverse order. Besides, start angle of all wedges will be 0, and end angle will have old value. First, we draw the last sector from 0 to 360 degrees, i.e. whole circle. Then draw wedge with number (n - 1) from 0 to (360 - sweep angle of the last wedge) degrees. And so on.
int wedgeNum = 10;
float wedgeSweepAngle = 360f / wedgeNum;
// end angle, we will decrease this value on each iteration
float endAngle = 360f;
// start angle, always 0
final float startAngle = 0f;
// reverse order
for (int i = wedgeNum - 1; i >= 0; i--) {
// draw wedge from 0 to endAngle
canvas.drawArc(bounds, startAngle, endAngle, true, paints[i % 2]);
// calculate the next wedge's end angle
endAngle -= wedgeSweepAngle;
}
Hope it will help.

how can we define dynamic(in parabola curve) Path of ViewObject(Bitmap)

I am Currently working on One 2D Android Game,
In this game One ViewObject(Bitmap) is moving Across Screen On Parabola Path Like in this Image, But this Path is Static, the Static path is getting throught the Drawing with Fingure on canvas,
As Same as signature Drawing.
The Bitmap Move code On this Static Path is
//animation step
private static int iMaxAnimationStep = 900;
private int iCurStep = 0;
private Path ptCurve = new Path(); //curve
private PathMeasure pm; //curve measure
private float fSegmentLen; //curve segment length
//init smooth curve
PointF point = aPoints.get(0);
ptCurve.moveTo(point.x, point.y);
for(int i = 0; i < aPoints.size() - 1; i++){
point = aPoints.get(i);
PointF next = aPoints.get(i+1);
ptCurve.quadTo(point.x, point.y, (next.x + point.x) / 2, (point.y + next.y) / 2);
}
pm = new PathMeasure(ptCurve, false);
fSegmentLen = pm.getLength() / iMaxAnimationStep;//20 animation steps
//animate the Bitmap
Matrix mxTransform = new Matrix();
if (iCurStep <= iMaxAnimationStep)
{
pm.getMatrix(fSegmentLen * iCurStep, mxTransform,
PathMeasure.POSITION_MATRIX_FLAG);
mxTransform.preTranslate(-Bitmap.getWidth(), -Bitmap.getHeight());
canvas.drawBitmap(Bitmap, mxTransform, null);
iCurStep++; //advance to the next step
mPauseViewHandler.post(mPauseViewRunnable);
} else {
iCurStep = 0;
}
But My Problem is I want to Move This ViewObject(Bitmap) On Dynamic Path(in parabola curve)
& that Dynamic curved path will work in Any Device.
I have searched Lot but i can't Find Solution How to get Dynamic Path (in parabola curve).
help! If you have Any Solution,Suggestion, idea ,tutorial regarding this post is Mostly Appreciated.
It's simple enough to fill aPoints array based on your screen size, and get a parabolic path based on those points. I've removed all your bitmap/animation code, this code below will calculate the path and draw it on the screen.
We need a new variable to set how many curves we want in the screen. If you prefer it's easy to change the math and define the size of the curve instead.
private int numberOfCurves = 5;
With that it's simple to calculate 3 points for each parabola:
public void calculatePoints(){
float w = v.getWidth(); //Screen width
float h = v.getHeight(); //Screen height
float curveSize = w/numberOfCurves; // Curve size
float curveHeight = (h/100) * 20; //80% of the screen size
Log.d(TAG,"h:"+h +" - w:" + w);
float lastX = 0; //last used X coordinate
for (int i=0;i<numberOfCurves;i++){ //for each curve we'll need 3 points
float newX = lastX + curveSize;
PointF p = new PointF(lastX, h); //first point is the last point
PointF p1 = new PointF((lastX + newX)/2, curveHeight); //the middle point is halfway between the last and the new point
PointF p2 = new PointF(newX,h); // the new point is last point + the size of our curve
aPoints.add(p); //fill in the array
aPoints.add(p1);
aPoints.add(p2);
lastX = newX; //update last point
}
//log our points
for (PointF p : aPoints){
Log.d(TAG,p.x +"-"+p.y);
}
}
Now we have a set of points defining each parabola, we need to draw it. Instead of using quadTo, use cubicTo. It takes 3 points and draws a curve connecting them. Put it onDraw, and you have your parabolas drawn on the screen.
private Path ptCurve = new Path(); //curve
#Override
public void onDraw(Canvas canvas) {
calculatePoints();
Log.d(TAG,"DRAWING");
PointF point = aPoints.get(0);
ptCurve.moveTo(point.x, point.y);
for(int i = 0; i < aPoints.size() - 1; i+=3){
point = aPoints.get(i);
PointF middle = aPoints.get(i+1);
PointF next = aPoints.get(i+2);
ptCurve.cubicTo(point.x, point.y, middle.x,middle.y, next.x , next.y);
}
canvas.drawPath(ptCurve, paint);
}
So your ptCurve variable is now filled with a parabolic path, with as many curves as you've defined earlier, and it will work on any screen size.

Categories

Resources