get the points from image - image

I want to extract the points from given image. the image is shown below..
The points I want are the green upper point and the red point. I tried pixel by pixel comparison but it is too slow. I need a better algorithm. What are your suggestions ?

If the points are always going to be at a known radius from the center then you can just check the points that lie on the circumference.

Pixel by pixel comparison is going to be hard to beat. You can improve your search speed on the green line considerably by using a divide-and-conquer method.
If the image width is x and its height is y, search all of the pixels located at x={0...x},y={y/4,3*y/4} for a green pixel. If none is found, search all the pixels along x={x/4,3*x/4},y={0...y}. As soon as you find a green pixel p at coordinates px,py, search that pixel's two-pixel neighborhood which is farther from the center of the image (that is, {px,py+1},{px+1,py} if p is in the upper right, {px,py-1},{px-1,py} if p is in the lower left, {px,py+1},{px-1,py} if p is in the upper left, or {px,py-1},{px+1,py} if p is in the lower right quadrant. Update p to be the first green neighbor you find. Iterate until p has no more green neighbors. Worst-case this algorithm is ~O(2*(x+y)+(1/2)*max(x,y)) ~= O(2.5*max(x,y)) ~= O(x), which is a lot better than O(x*y) if you simply check the color value of every {x,y} pair.
Finding the red dot is going to be expensive, though, no less expensive than O(x*y) since the only way to improve the cost of searching for a single red pixel will be by subsampling the image (O(x*y)) and then searching the whole image (now O(sqrt(x*y))) for the red pixel.
I like par's idea, though, if the two dots are always the same distance from the center of the image then you can just search the pixels that fall along the circumference of that radius!

Related

Footprint finding algorithm

I'm trying to come up with an algorithm to optimize the shape of a polygon (or multiple polygons) to maximize the value contained within that shape.
I have data with 3 columns:
X: the location on the x axis
Y: the location on the y axis
Value: Value of the block which can have positive and negative values.
This data is from a regular grid so the spacing between each x and y value is consistent.
I want to create a bounding polygon that maximizes the contained value with the added condition.
There needs to be a minimum radius maintained at all points of the polygon. This means that we will either lose some positive value blocks or gain some negative value blocks.
The current algorithm I'm using does the following
Finds the maximum block value as a starting point (or user defined)
Finds all blocks within the minimum radius and determines if it is a viable point by checking the overall value is positive
Removes all blocks in the minimum search radius from further value calculations and flags them as part of the final shape
Moves onto the next point determined by a spiraling around the original point. (center is always a grid point so moves by deltaX or deltaY)
This appears to be picking up some cells that aren't needed. I'm sure there are shape algorithms out there but I don't have any idea what to look up to find help.
Below is a picture that hopefully helps outline the question. Positive cells are shown in red (negative cells are not shown). The black outline shows the shape my current routine is returning. I believe the left side should be brought in more. The minimum radius is 100m the bottom left black circle is approximately this.
Right now the code is running in R but I will probably move to something else if I can get the algorithm correct.
In response to the unclear vote the problem I am trying to solve without the background or attempted solution is:
"Create a bounding polygon (or polygons) around a series of points to maximize the contained value, while maintaining a minimum radius of curvature along the polygon"
Edit:
Data
I should have included some data it can be found here.
The file is a csv. 4 columns (X,Y,Z [not used], Value), length is ~25k size is 800kb.
Graphical approach
I would approach this graphically. My intuition tells me that the inside points are fully inside the casted circles with min radius r from all of the footprint points nearby. That means if you cast circle from each footprint point with radius r then all points that are inside at least half of all neighboring circles are inside your polygon. To be less vague if you are deeply inside polygon then you got Pi*r^2 such overlapping circles at any pixel. if you are on edge that you got half of them. This is easily computable.
First I need the dataset. As you did provide just jpg file I do not have the vales just the plot. So I handle this problem like a binary image. First I needed to recolor the image to remove jpg color distortions. After that this is my input:
I choose black background to easily apply additive math on image and also I like it more then white and leave the footprint red (maximally saturated). Now the algorithm:
create temp image
It should be the same size and cleared to black (color=0). Handle its pixels like integer counters of overlapping circles.
cast circles
for each red pixel in source image add +1 to each pixel inside the circle with minimal radius r around the same pixel but in the temp image. The result is like this (Blue are the lower bits of my pixelformat):
As r I used r=24 as that is the bottom left circle radius in your example +/-pixel.
select inside pixels only
so recolor temp image. All the pixels with color < 0.5*pi*r^2 recolor to black and the rest to red. The result is like this:
select polygon circumference points only
Just recolor all red pixels near black pixels to some neutral color blue and the rest to black. Result:
Now just polygonize the result. To compare with the input image you can combine them both (I OR them together):
[Notes]
You can play with the min radius or the area treshold property to achieve different behavior. But I think this is pretty close match to your problem.
Here some C++ source code for this:
//picture pic0,pic1;
// pic0 - source
// pic1 - output/temp
int x,y,xx,yy;
const int r=24; // min radius
const int s=float(1.570796*float(r*r)); // half of min radius area
const DWORD c_foot=0x00FF0000; // red
const DWORD c_poly=0x000000FF; // blue
// resize and clear temp image
pic1=pic0;
pic1.clear(0);
// add min radius circle to temp around any footprint pixel found in input image
for (y=r;y<pic1.ys-r;y++)
for (x=r;x<pic1.xs-r;x++)
if (pic0.p[y][x].dd==c_foot)
for (yy=-r;yy<=r;yy++)
for (xx=-r;xx<=r;xx++)
if ((xx*xx)+(yy*yy)<=r*r)
pic1.p[y+yy][x+xx].dd++;
pic1.save("out0.png");
// select only pixels which are inside footprint with min radius (half of area circles are around)
for (y=0;y<pic1.ys;y++)
for (x=0;x<pic1.xs;x++)
if (pic1.p[y][x].dd>=s) pic1.p[y][x].dd=c_foot;
else pic1.p[y][x].dd=0;
pic1.save("out1.png");
// slect only outside pixels
pic1.growfill(c_foot,0,c_poly);
for (y=0;y<pic1.ys;y++)
for (x=0;x<pic1.xs;x++)
if (pic1.p[y][x].dd==c_foot) pic1.p[y][x].dd=0;
pic1.save("out2.png");
pic1|=pic0; // combine in and out images to compare
pic1.save("out3.png");
I use my own picture class for images so some members are:
xs,ys size of image in pixels
p[y][x].dd is pixel at (x,y) position as 32 bit integer type
clear(color) - clears entire image
resize(xs,ys) - resizes image to new resolution
[Edit1] I got a small bug in source code
I noticed some edges were too sharp so I check the code and I forgot to add the circle condition while filling so it filled squares instead. I repaired the source code above. I really just added line if ((xx*xx)+(yy*yy)<=r*r). The results are slightly changed so I also updated the images with new results
I played with the inside area coefficient ratio and this one:
const int s=float(0.75*1.570796*float(r*r));
Leads to even better match for you. The smaller it is the more the polygon can overlap outside footprint. Result:
If the solution set must be a union of disks of given radius, I would try a greedy approach. (I suspect that the problem might be intractable - exponential running time - if you want an exact solution.)
For all pixels (your "blocks"), compute the sum of values in the disk around it and take the one with the highest sum. Mark this pixel and adjust the sums of all the pixels that are in its disk by deducing its value, because the marked pixel has been "consumed". Then scan all pixels in contact with it by an edge or a corner, and mark the pixel with the highest sum.
Continue this process until all sums are negative. Then the sum cannot increase anymore.
For an efficient implementation, you will need to keep a list of the border pixels, i.e. the unmarked pixels that are neighbors of a marked pixel. After you have picked the border pixel with the largest sum and marked it, you remove it from the list and recompute the sums for the unmarked pixels inside its disk; you also add the unmarked pixels that touch it.
On the picture, the pixels are marked in blue and the border pixels in green. The highlighted pixels are
the one that gets marked,
the ones for which the sum needs to be recomputed.
The computing time will be proportional to the area of the image times the area of a disk (for the initial computation of the sums), plus the area of the shape times the area of a disk (for the updates of the sums), plus the total of the lengths of the successive perimeters of the shape while it grows (to find the largest sum). [As the latter terms might be costly - on the order of the product of the area of the shape by its perimeter length -, it is advisable to use a heap data structure, which will reduce the sum of the lengths to the sum of their logarithm.]

Closest distance to border of shape

I have a shape (in black below) and a point inside the shape (red below). What's the algorithm to find the closest distance between my red point and the border of the shape (which is the green point on the graph) ?
The shape border is not a series of lines but a randomly drawn shape.
Thanks.
So your shape is defined as bitmap and you can access the pixels.
You could scan ever growing squares around your point for border pixels. First, check the pixel itself. Then check a square of width 2 that covers the point's eight adjacent pixels. Next, width 4 for the next 16 pixels and so on. When you find a border pixel, record its distance and check against the minimum distance found. You can stop searching when half the width of the square is greater than the current minimum distance.
An alternative is to draw Bresenham circles of growing radius around the point. The method is similar to the square method, but you can stop immediately when you have a hit, because all points are supposed to have the same distance to your point. The drawback is that this method is somewhat inaccurate, because the circle is only an approximation. You will also miss some pixels along the disgonals, because Bresenham circles have artefacts.
(Both methods are still quite brute-force and in the worst case of a fully black bitmap will visit every node.)
You need a criterion for a pixel on the border. Your shape is antialiassed, so that pixels on the border are smoothed by making them a shade of grey. If your criterion is a pixel that isn't black, you will chose a point a bit inside the shape. If you cose pure white, you'll land a bit outside. Perhaps it's best to chose a pixel with a grey value greater than 0.5 as border.
If you have to find the closest border point to many points for the same shape, you can preprocess the data and use other methods of [nearest-neighbour serach].
As always, it depends on the data, in this case, what your shapes are like and any useful information about your starting point (will it often be close to a border, will it often be near the center of mass, etc).
If they are similar to what you show, I'd probably test the border points individually against the start. Now the problem is how you find the border without having to edge detect the entire shape.
The problem is it appears you can have sharply concave borders (think of a circle with a tiny spike-like sliver jutting into it). In this case you just need to edge detect the shape and test every point.
I think these will work, but don't hold me to it. Computational geometry seems to be very well understood, so you can probably find a pro at this somewhere:
Method One
If the shape is well behaved or you don't mind being wrong try this:
1- Draw 4 lines (diving the shape into four quandrants). And check the distance to each border. What i mean by draw is keep going north until you hit a white pixel, then go south, west, and east.
2- Take the two lines you have drawn so far that have the closest intersection points, bisect the angle they create and add the new line to your set.
3- keep repeating step two until are you to a tolerance you can be happy with.
Actually you can stop before this and on a small enough interval just trace the border between two close points checking each point between them to refine the final answer.
Method Two (this wil work with the poorly behaved shapes and plays well with anti-aliasing):
1- draw a line in any direction until he hit the border (black to white). This will be your starting distance.
2- draw a circle at this distance noting everytime you go from black to white or white to black. These are your intersection points.
As long as you have more than two points, divide the radius in half and try again.
If you have no points increase your radius by 50% and try again (basically binary search until you get to two points - if you get one, you got lucky and found your answer).
3- your closet point lies in the region between your two points. Run along the border checking each one.
If you want to, to reduce the cost of step 3 you can keep doing step 2 until you get a small enough range to brute force in step 3.
Also to prevent a very unlucky start, draw four initial lines (also east, south, and west) and start with the smallest distance. Those are easy to draw and greatly reduce your chance of picking the exact longest distance and accidentally thinking that single pixel is the answer.
Edit: one last optimization: because of the symmetry, you only need to calculate the circle points (those points that make up the border of the circle) for the first quadrant, then mirror them. Should greatly cut down on computation time.
If you define the distance in terms of 'the minimum number of steps that need to be taken to reach from the start pixel to any pixel on the margin', then this problem can be solved using any shortest path search algorithm like bread first search or even better if you use A* search algorithm.

Finding best neighbour pixel

I am trying to do shape analysis of an object in an image in MATLAB (specifically). To do so, I have found boundary pixels. For each boundary pixel I am calculating it's neighbor using 8-neighborhood theory. Now I am calculating tangent of a point to its only one neighbor (depends how I select clockwise or other way). My algorithm works fine if every pixel has exactly two neighbors. For shapes shown in this picture (order 9 X 15 pixels).
But if there are more than 2 neighbors of a pixel then my algorithm gets confused. For example as shown in (order 9 X 15 pixels).
I want to take tangent of each boundary pixel with its neighbor pixel in clockwise or anti-clockwise direction and if you notice second image, which is valid boundary image, if I am moving in clockwise direction then neighbor of red pixel would be green and neighbor of green in clockwise direction would be "1" and neighbor of "1" is "2" but then I cannot come back to blue and brown pixel and I cannot visit and take tangent of each boundary pixel with its neighbor pixel.
I have learned graph's node visiting algorithms in which you maintain queue or stack but then in this case I don't just want to visit each pixel but also take tangent of every pixel with only right neighbor pixel according to what direction I am moving.
This is an example problem and similar problems can occur in some other way so I am trying to generate some generic algorithm for it. I will appreciate your help. Thank you.
Like btilly already said. The solution is to find the boundaries between the pixels and not the pixels self. I recommend you a part of the potrace Algorithm. It is an Algorith for vectorize binary images. The interesting part is for you the decompisition of the Path. Here is the idea of the Path decompisition:
The Potrace Algorithm you can find here.
An other Algorithm is from Wilhelm Burge and Burger in the Book "digital image processing an algorithmic introduction using enter link description here". In the link you can see some part of the book. The interisting part is the function "TraceContour" at page 538. This Algorithm work like you thought and walks around the "inner" pixels. I found some explenation of the Alorith here, at inner boundary tracing. You can do the Algorithm with a four or eight neighboor connectivity.

Detect a shape as a circle with Matlab

I am writing a program in Matlab to detect a circle.
I've already managed to detect shapes such as the square, rectangle and the triangle, basically by searching for corners, and determining what shape it is based on the distance between them. The images are black and white, with black being the background and white the shape, so for me to find the corners I just have to search each pixel in the image until I find a white pixel.
However I just can't figure out how I can identify the circle.
Here it the an example of how a circle input would look like:
It is difficult to say what the best method is without more information: for example, whether more than one circle may be present, whether it is always centred in the image, and how resilient the algorithm needs to be to distortions. Also whether you need to determine the location and dimensions of the shape or simply a 'yes'/'no' output.
However a really simple approach, assuming only one circle is present, is as follows:
Scan the image from top to bottom until you find the first white pixel at (x1,y1)
Scan the image from bottom to top until you find the last white pixel at (x2,y2)
Derive the diameter of the suspected circle as y2 - y1
Derive the centre of the suspected circle as ((x1+x2)/2, y1+(y2-y1)/2)
Now you are able to score each pixel in the image as to whether it matches this hypothetical circle or not. For example, if a pixel is inside the suspected circle, score 0 if it is white and 1 if it black, and vice-versa if it is outside the suspected circle.
Sum the pixel scores. If the result is zero then the image contains a perfect circle. A higher score indicates an increasing level of distortion.
I think you may read about this two topics:
Theoretical:
Binary images
Hough transform
Matlab:
Circle Detection via Standard Hough Transform
Hough native in matlab
Binary images

How to fill circle with increasing radius?

As part of more complex algorithm I need following:
let say I have a circle with radius R1 drawn on discrete grid (image) (green on image below)
I want to draw circle that have radius R2 that is bigger then R1 with one pixel (red on image below).
At each algorithm step to draw circles with increasing radius in a way that each time I have a filled circle.
How can I find the points to fill at each step so at the end of each step I have fully filed circle?
I have thinking of some circle rasterization algorithm, but this will lead to some gaps in filling. Another way is to use some mathematical morphology operation like dilation but this seems to be computationally expensive to do.
I am generally looking for way to do this on arbitrary shape but initially circle algorithm will be enough.
Your best option is to draw and fill a slightly larger red circle, and then draw and fill the green circle. Then redo on next iteration.
To only draw the 1px border is quite tricky. Your sample image is not even quite consistent. At some places a white pixel occurs diagonally to a green pixel, and in other places that pixel is red.
Edit:
borderPixels = emptySet
For each green pixel, p
For each neighbor n to p
If n is white
Add n to *borderPixels`
Do whatever you like with borderPixels (such as color them red)
My current solution for circle.
Based on well known Midpoint circle algorithm
create set of points for 1 octant for R1 radius (light green pixels)
create set of points for 1 octant for R2 radius (dark orange pixels)
for each row in image compare X coordinate for orange and green pixels and get 0 or 1 (or whatever) number of pixels in-between (light orange).
repeat for each octant (where for some octants columns instead of rows have to be compared)
This algorithm can be applied for other types of parametric shapes (Bezier curve based for example)
For non-parametric shapes (pixel based) image convolution (dilation) with kernel with central symmetry (circle). In other words for each pixel in shape looking for neighbors in circle with small radius and setting them to be part of the set. (expensive computation)
Another option is to draw a circle/shape with a 2pixel wide red border, and then draw a green filled circle/shape with NO border. Which should leave an approximately 1px wide edge.
It depends on how whatever technique you use resolves lines to pixels.
Circle algorithms tend to be optimised for drawing circles.....See the link here

Resources