I have a data cube with 2 dimensions of coordinates and a third dimension for wavelength. My goal is to write a mask for coordinates outside a circle of given radius to the central coordinates (x0 and y0 in my code). For this, I'm trying to use a dictionary, but I'm having throuble because it seems that I'll have to make a double loop inside the dictionary to iterate over the two dimensions, and as a beginner with dictionaries, I don't know yet how to do that.
I wrote the following code
x0 = 38
y0 = 45
radius = 9
xcoords = np.arange(1,flux.shape[1]+1,1)
ycoords = np.arange(1,flux.shape[2]+1,1)
mask = {'xmask': [xcoords[np.sqrt((xcoords[:]-x0)**2 + (y-y0)**2) < radius] for y in ycoords], 'ymask': [ycoords[np.sqrt((x-x0)**2 + (ycoords[:]-y0)**2) < radius] for x in xcoords]}
And it returned several arrays, one for each value of y (for xmasks), and one for each value of x (for ymasks), although I want just one array for each one. Could anyone say what I made wrong and how to achieve my goal?
Note: I also made it without using a dictionary, as
xmask = []
for x in xcoords:
for y in ycoords:
if np.sqrt((x-x0)**2 + (y-y0)**2) < radius:
xmask.append(x)
break
ymask = []
for y in xcoords:
for x in ycoords:
if np.sqrt((x-x0)**2 + (y-y0)**2) < radius:
ymask.append(y)
break
but I hope it's possible to make it more efficiently.
Thanks for any help!
Edit: I realized that no loop was needed. If I select y = y0 and x = x0, I get the values of x and y that are inside the circle, respectively. So I stayed with
mask = {'xmask': [xcoords[abs(xcoords[:]-x0) < radius]], 'ymask': [ycoords[abs(ycoords[:]-y0) < radius]]}
The OP explains that assigning
mask = {'xmask': [xcoords[abs(xcoords[:] - x0) < radius]],
'ymask': [ycoords[abs(ycoords[:] - y0) < radius]]}
solves the problem.
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I have many images consisting of circles(varying from 1 to 4) in each image. I am trying to get a clear circle images by filling the missed pixels along the circle path.
I have tried Hough-transform, but its parameters are image specific: for each image I have to change the parameters. With this problem I am unable keep them in a single for loop.
Please provide some method to do it. Thanks
imfindcircles Does not work
The most "natural" way to approach this problem is to use Matlab's imfindcircles. However, that function assume the circles in the image are "full", yet in your examples you only have the (incomplete) boundaries of the circles, thus imfindcircles cannot be directly applied to your data.
Alternative Approach
You can use ransac to fit circles to your data. Fit one circle at a time to as many points as you can, terminate when there are too few points left that fit no circle at all.
To use RanSac you basically need to implement two methods:
Model fitting method, fitFcn, Given a small sample of your points - fit a circle to them.
Distance to model method, distFcn, Given a circle ("model") find the distance of each point to that circle.
Once you have these two methods, RanSac operates roughly like:
- randomly sample very few points
- use fitFcn to fit a circle to these sampled points
- use distFcn to compute the distance of all points to estimated circle
- if enough points are close to the circle, accept this circle and remove all point that "belongs" to that circle
- terminate if no circle was found or not enough "unexplained" points
This can be easily implemented in Matlab.
First consider fitFcn: we need a function that compute (cx, cy, r) - the three parameters of a 2D circle (center and radii). Given a point (x, y) it fits a circle iff
(x - cx)^2 + (y - cy)^2 = r^2
We can write this equation as a linear relation between known points (x, y) and unknown circle (cx, cy, r) in the following manner
[-2*x, -2*y, 1] [ cx ;
cy ; = [-x^2-y^2]
cx^2 + cy^2 - r^2 ]
Using a least squares estimation (in a similar manner as in this answer), we can recover the circle parameters given enough points (at least 3) on the circle
This is how the code actually looks like
function crc = fit_circle(xy) % xy is n-by-2 matrix of point coordinates
% fit in least squares sens
x = xy(:, 1);
y = xy(:, 2);
X = [-2*x, -2*y, ones(size(x))];
Y = -x.^2 - y.^2;
crc = (X\Y).'; % least squares solution
r2 = -crc(3) +crc(1).^2 + crc(2).^2;
if r2 <= 0
crc(3) = 0;
else
crc(3) = sqrt(r2);
end
% output crc is a 3 vector (cx, cy, r)
Now that we can fit a circle to points, we need to compute the distance using distFcn that is quite simple
function dst = distFcn(crc, xy)
% how good a fit circle for points
x = xy(:, 1) - crc(1);
y = xy(:, 2) - crc(2);
dst = abs(sqrt(x.^2 + y.^2) - crc(3));
Putting it all together with matlab's ransac:
function circles = find_circles(bw)
% parameters
sample_size = 4;
max_distance = 10;
min_num_points_in_circle = 50;
[y, x] = find(bw > max(bw(:))/2); % all edges in the image
circles = {};
counter = 0;
while numel(x) > 10 * sample_size && counter < 10
try
[circle, inlierIdx] = ransac([x, y], #fit_circle, #distFcn, ...
sample_size, max_distance);
catch
break
end
% refit using only inliers
circle = fit_circle([x(inlierIdx) y(inlierIdx)]);
dst = distFcn(circle, [x y]);
founfit = dst < max_distance;
if sum(founfit) > min_num_points_in_circle
% this model fits enough points
circles{end+1} = circle;
x(founfit) = [];
y(founfit) = [];
else
counter = counter + 1;
end
end
circles = vertcat(circles{:});
And the output of this function on your data is (using viscircles to plot the circles):
I am looking for an efficient way to delete points of a meshgrid that comes inside the bounding box of blocks (block 1 and 2 in the code). My Code is:
x_max, x_min, y_max, y_min = 156.0, 141.0, 96.0, 80.0
offset = 5
stepSize = 0.2
x = np.arange(x_min-offset, x_max+offset, stepSize)
y = np.arange(y_min-offset, y_max+offset, stepSize)
xv, yv = np.meshgrid(x, y)
#bounding box (and pints inside) that I want to remove for mesh
block1 = [(139.78, 86.4), (142.6, 86.4), (142.6, 88.0), (139.78, 88.0)]
block2 = [(154.8, 87.2), (157.6, 87.2), (157.6, 88.8), (154.8, 88.8)]
As per one of the answer, I could generate the required result if I have only one block to be removed from the mesh. If I have multiple blocks then it won't work. What could be the optimized way to remove multiple blocks from mesh grid. The final figure should look like this:
Mesh
Edit: Improved questions and edited code.
Simply redefine your x and y around your block:
block_xmin = np.min(block[:,0])
block_xmax = np.max(block[:,0])
block_ymin = np.min(block[:,1])
block_ymax = np.max(block[:,1])
X = np.hstack((np.arange(x_min-offset, block_xmin, stepSize), np.arange(block_xmax, x_max+offset, stepSize)))
Y = np.hstack((np.arange(y_min-offset, block_ymin, stepSize), np.arange(block_ymax, y_max+offset, stepSize)))
XV, YV = np.meshgrid(X, Y)
I think I figured it out based on the explanation of #hpaulj (I cannot up-vote his suggestions as well probably due to low points). I can append blocks in allBlocks array and then run a loop over allBlocks an simultaneous disabling the points in mesh. Here is my solution:
x_new = np.copy(xv)
y_new = np.copy(yv)
ori_x = xv[0][0]
ori_y = yv[0][0]
for block in allBlocks:
block_xmin = np.min((block[0][0], block[1][0]))
block_xmax = np.max((block[0][0], block[1][0]))
block_ymin = np.min((block[0][1], block[1][1]))
block_ymax = np.max((block[0][1], block[3][1]))
rx_min, rx_max = int((block_xmin-ori_x)/stepSize), int((block_xmax-ori_x)/stepSize)
ry_min, ry_max = int((block_ymin-ori_y)/stepSize), int((block_ymax-ori_y)/stepSize)
for i in range(rx_min,rx_max+1):
for j in range(ry_min,ry_max+1):
x_new[j][i] = np.nan
for i in range(ry_min,ry_max+1):
for j in range(rx_min,rx_max+1):
y_new[i][j] = np.nan
In my attempts to practice Julia, I've made a program which draws a bifurcation diagram. My code is as follows:
function bifur(x0,y0,a=1.3,b=0.4,n=1000,m=10000)
i,x,y=1,x0,y0
while i < n && abs(x) < m
x,y = a - x^2 + y, b * x
i += 1
end
if abs(x) < m
return x
else
return 1000
end
end
la = Float64[];
lx = Float64[];
for a=0:400
for j = 1:1000
x0 = rand()
y0 = rand()
x = bifur(x0,y0,a/100)
if x != 1000
push!(la,a/100)
push!(lx,x)
end
end
end
using Gadfly
myplot = Gadfly.plot( x=la, y=lx , Scale.x_discrete, Scale.y_continuous, Geom.point)
draw(PNG("myplot.png",10inch,8inch),myplot)
The output I get is this image:
In order to make my plot look more like this:
I need to be able to set point sizes to as small as one pixel. Then by increasing the iteration length I should be able to get a better bifurcation diagram. Does anyone know how to set the point sizes in Gadfly diagrams in Julia?
[Just to encapsulate the comments as an answer...]
Gadfly's Theme defaults can be changed. In particular, point_size is probably what you are looking for.
For changing the automatic plot scale/range settings, have a look at Gadfly's Scale params.
I want to write something like a virtual telescope that looks into the night sky.
Till now I've a star catalog and I want to project them into a plane to get a mock picture.
I speculate the projection to be a gnomonic projection, which can be found here and here.
In the second link, an alg on calculating the pixel position of stars.
Forward:
Define
scale: number of pixels per degree in the map
alpha, delta: Equatorial coordinates of a given position
alpha0, delta0: Equatorial coordinates of the map center
A = cos(delta) x cos(alpha - alpha0)
F = scale x (180/pi)/[sin(delta0) x sin(delta) + A x cos(delta0)]
then the pixel coordinates in the image are
LINE = -F x [cos(delta0) x sin(delta) - A x sin(delta0)]
SAMPLE = -F x cos(delta) x sin(alpha - alpha0)
Reverse:
Define
X = SAMPLE/(scale x 180/pi)
Y = LINE/(scale x 180/pi)
D = arctan[(X^2 + Y^2)^0.5]
B = arctan(-X/Y)
XX = sin(delta0) x sin(D) x cos(B) + cos(delta0) x cos(D)
YY = sin(D) x sin(B)
then the right ascension and declination are
alpha = alpha0 + arctan(YY/XX)
delta = arcsin[sin(delta0) x cos(D) - cos(delta0) x sin(D) x cos(B)]
NOTE: The arctangent functions for B and alpha must be four-quadrant arctangents.
However I don't know whether the angles should be in deg or rad, and what's the meaning of SAMPLE and LINE.
And I'm neither sure about using gnomonic projection.
Any help or discussion is welcome.
Yeah, just perform an ordinary camera projecion.
is there some good and better way to find centroid of contour in opencv, without using built in functions?
While Sonaten's answer is perfectly correct, there is a simple way to do it: Use the dedicated opencv function for that: moments()
http://opencv.itseez.com/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=moments#moments
It does not only returns the centroid, but some more statistics about your shape. And you can send it a contour or a raster shape (binary image), whatever best fits your need.
EDIT
example (modified) from "Learning OpenCV", by gary bradsky
CvMoments moments;
double M00, M01, M10;
cvMoments(contour,&moments);
M00 = cvGetSpatialMoment(&moments,0,0);
M10 = cvGetSpatialMoment(&moments,1,0);
M01 = cvGetSpatialMoment(&moments,0,1);
centers[i].x = (int)(M10/M00);
centers[i].y = (int)(M01/M00);
What you get in your current piece of code is of course the centroid of your bounding box.
"If you have a bunch of points(2d vectors), you should be able to get the centroid by averaging those points: create a point to add all the other points' positions into and then divide the components of that point with accumulated positions by the total number of points." - George Profenza mentions
This is indeed the right approach for the exact centroid of any given object in two-dimentionalspace.
On wikipedia we have some general forms for finding the centroid of an object.
http://en.wikipedia.org/wiki/Centroid
Personally, I would ask myself what I needed from this program. Do I want a thorough but performance heavy operation, or do I want to make some approximations? I might even be able to find an OpenCV function that deals with this correct and efficiently.
Don't have a working example, so I'm writing this in pseudocode on a simple 5 pixel example on a thorough method.
x_centroid = (pixel1_x + pixel2_x + pixel3_x + pixel4_x +pixel5_x)/5
y_centroid = (pixel1_y + pixel2_y + pixel3_y + pixel4_y +pixel5_y)/5
centroidPoint(x_centroid, y_centroid)
Looped for x pixels
Loop j times *sample (for (int i=0, i < j, i++))*
{
x_centroid = pixel[j]_x + x_centroid
y_centroid = pixel[j]_x + x_centroid
}
x_centroid = x_centroid/j
y_centroid = y_centroid/j
centroidPoint(x_centroid, y_centroid)
Essentially, you have the vector contours of the type
vector<vector<point>>
in OpenCV 2.3. I believe you have something similar in earlier versions, and you should be able to go through each blob on your picture with the first index of this "double vector", and go through each pixel in the inner vector.
Here is a link to documentation on the contour function
http://opencv.itseez.com/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=contours#cv.DrawContours
note: you've tagged your question as c++ visual. I'd suggest that you use the c++ syntax in OpenCV 2.3 instead of c. The first and good reason to use 2.3 is that it is more class based, which in this case means that the class Mat (instead of IplImage) does leak memory. One does not have to write destroy commands all the live long day :)
I hope this shed some light on your problem. Enjoy.
I've used Joseph O'Rourke excellent polygon centroid algorithm to great success.
See http://maven.smith.edu/~orourke/Code/centroid.c
Essentially:
For each point in the contour, find the triangle area from the current index polygon xy to the next 2 polygon xy points e.g.: Math.Abs(((X1 - X0) * (Y2 - Y0) - (X2 - X0) * (Y1 - Y0)) / 2)
Add this triangle area to a list TriAreas
Sum the triangle area, and store in SumT
Find the centroid CTx and CTy from this current triangle: CTx = (X0 + X1 + X2) / 3 and CTy = (Y0 + Y1 + Y2) / 3;
Store these 2 centroid values in 2 other lists CTxs CTys.
Finally after performing this with all points in the contour, find the contours centroid x and y using the 2 triangle x and y lists in 5 which is a weighted sum of signed triangle areas, weighted by the centroid of each triangle:
for (Int32 Index = 0; Index < CTxs.Count; Index++)
{
CentroidPointRet.X += CTxs[Index] * (TriAreas[Index] / SumT);
}
// now find centroid Y value
for (Int32 Index = 0; Index < CTys.Count; Index++)
{
CentroidPointRet.Y += CTys[Index] * (TriAreas[Index] / SumT);
}