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);
}
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 doing a project about ray tracing, right now I can do some basic rendering.
The image below have:
mirror reflection,
refraction,
texture mapping
and shadow.
I am trying to do the glossy reflection, so far this is what I am getting.
Could anyone tell me if there is any problem in this glossy reflection image?
In comparison, the image below is from the mirror reflection
This is my code about glossy reflection, basically, once a primary ray intersect with an object.
From this intersection, it will randomly shot another 80 rays, and take the average of this 80 rays color. The problem I am having with this code is the magnitude of x and y, I have to divide them by some value, in this case 16, such that the glossy reflect ray wouldn't be too random. Is there anything wrong with this logic?
Colour c(0, 0, 0);
for (int i = 0; i < 80; i++) {
Ray3D testRay;
double a = rand() / (double) RAND_MAX;
double b = rand() / (double) RAND_MAX;
double theta = acos(pow((1 - a), ray.intersection.mat->reflectivity));
double phi = 2 * M_PI * b;
double x = sin(phi) * cos(theta)/16;
double y = sin(phi) * sin(theta)/16;
double z = cos(phi);
Vector3D u = reflect.dir.cross(ray.intersection.normal);
Vector3D v = reflect.dir.cross(u);
testRay.dir = x * u + y * v + reflect.dir;
testRay.dir.normalize();
testRay.origin = reflect.origin;
testRay.nbounces = reflect.nbounces;
c = c + (ray.intersection.mat->reflectivity)*shadeRay(testRay);
}
col = col + c / 80;
Apart from the hard coded constants which are never great when coding, there is a more subtle issue, although your images overall look good.
Monte-Carlo integration consists in summing the integrand divided by the probability density function (pdf) that generated these samples. There are thus two problems in your code:
you haven't divided by the pdf although you seem to have used a pdf for Phong models (if I recognized it well ; at least it is not a uniform pdf)
you have further scaled your x and y components by 1./16. for apparently no reason which further changes your pdf.
The idea is that if you are able to sample your rays exactly according to Phong's model times the cosine law then you don't even have to multiply your integrand by the BRDF. In practice, there are no exact formula that allow to sample exactly a BRDF (apart from Lambertian ones), so you need to compute:
pixel value = sum BRDF*cosine*incoming_light / pdf
which mostly cancels out if BRDF*cosine = pdf.
Of course, your images overall look good, so if you're not interested in physical plausibility, that may as well be good.
A good source about the various pdfs used in computer graphics and Monte-Carlo integration (with the appropriate formulas) is the Global Illumination Compendium by Philip Dutré.
I have read similar topics in order to find solution, but with no success.
What I'm trying to do is make the tool same as can be found in CorelDraw, named "Pen Tool". I did it by connecting Bezier cubic curves, but still missing one feature, which is dragging curve (not control point) in order to edit its shape.
I can successfully determine the "t" parameter on the curve where dragging should begin, but don't know how to recalculate control points of that curve.
Here I want to higlight some things related to CorelDraw''s PenTool behaviour that may be used as constaints. I've noticed that when dragging curve strictly vertically, or horizontally, control points of that Bezier curve behave accordingly, i.e. they move on their verticals, or horizontals, respectively.
So, how can I recalculate positions of control points while curve dragging?
Ive just look into Inkspace sources and found such code, may be it help you:
// Magic Bezier Drag Equations follow!
// "weight" describes how the influence of the drag should be distributed
// among the handles; 0 = front handle only, 1 = back handle only.
double weight, t = _t;
if (t <= 1.0 / 6.0) weight = 0;
else if (t <= 0.5) weight = (pow((6 * t - 1) / 2.0, 3)) / 2;
else if (t <= 5.0 / 6.0) weight = (1 - pow((6 * (1-t) - 1) / 2.0, 3)) / 2 + 0.5;
else weight = 1;
Geom::Point delta = new_pos - position();
Geom::Point offset0 = ((1-weight)/(3*t*(1-t)*(1-t))) * delta;
Geom::Point offset1 = (weight/(3*t*t*(1-t))) * delta;
first->front()->move(first->front()->position() + offset0);
second->back()->move(second->back()->position() + offset1);
In you case "first->front()" and "second->back()" would mean two control points
The bezier curve is nothing more then two polynomials: X(t), Y(t).
The cubic one:
x = ax*t^3 + bx*t^2 + cx*t + dx
0 <= t <= 1
y = ay*t^3 + by*t^2 + cy*t + dy
So if you have a curve - you have the poly coefficients. If you move your point and you know it's t parameter - then you can simply recalculate the poly's coefficients - it will be a system of 6 linear equations for coefficients (for each of the point). The system is subdivided per two systems (x and y) and can be solved exactly or using some numerical methods - they are not hard too.
So your task now is to calculate control points of your curve when you know the explicit equation of your curve.
It can be also brought to the linear system. I don't know how to do it for generalized Bezier curve, but it is not hard for cubic or quadric curves.
The cubic curve via control points:
B(t) = (1-t)^3*P0 + 3(1-t)^2*t*P1 + 3(1-t)*t^2*P2 + t^3*P3
Everything you have to do is to produce the standard polynomial form (just open the brackets) and to equate the coefficients. That will provide the final system for control points!
When you clicks on curve, you already know position of current control point. So you can calculate offset X and offset Y from that point to mouse position. In case of mouse move, you would be able to recalculate new control point with help of X/Y offsets.
Sorry for my english
I am trying to do inverse kinematics for a serial chain of arbitrarily many links.
In the following paper, I have found an example for how to calculate the Jacobian matrix.
Entry (i, j) = v[j] * (s[i] - p[j])
where:
v[j] is the unit vector of the axis of
rotation for joint j
s[i] is the position (int world
coords?) of joint i
p[j] is the position (in world
coords?) of joint j
The paper says that this works if j is a rotational joint with a single degree of freedom. But my rotational joints have no constraints on their rotation. What formula do I then want? (Or am I possibly misunderstanding the term "degree of freedom"?)
This question is old, but I'll answer anyway, as it is something I have thought about but never really gotten around to implement.
Rotational joints with no constraints are called ball joints or spherical joints; they have 3 degrees of freedom. You can use the formula in the tutorial for spherical joints also, if you parameterize each spherical joint in terms of 3 rotational (revolute) joints of one degree of freedom each.
For example: Let N be the number of spherical joints. Suppose each joint has a local transformation T_local[i] and a world transformation
T_world[i] = T_local[0] * ... * T_local[i]
Let R_world[i][k], k = 0, 1, 2, be the k-th column of the rotation matrix of T_world[i]. Define the 3 * N joint axes as
v[3 * j + 0] = R_world[i][0]
v[3 * j + 1] = R_world[i][1]
v[3 * j + 2] = R_world[i][2]
Compute the Jacobian J for some end-effector s[i], using the formula of the tutorial. All coordinates are in the world frame.
Using for example the pseudo-inverse method gives a displacement dq that moves the end-effector in a given direction dx.
The length of dq is 3 * N. Define
R_dq[j] =
R_x[dq[3 * j + 0]] *
R_y[dq[3 * j + 1]] *
R_z[dq[3 * j + 2]]
for j = 0, 1, ..., N-1, where R_x, R_y, R_z are the transformation matrices for rotation about the x-, y-, and z-axes.
Update the local transformations:
T_local[j] := T_local[j] * R_dq[j]
and repeat from the top to move the end-effector in other directions dx.
Let me suggest a simpler approach to Jacobians in the context of arbitrary many DOFs: Basically, the Jacobian tells you, how far each joint moves, if you move the end effector frame in some arbitrarily chosen direction. Let f(θ) be the forward kinematics, where θ=[θ1,...,θn] are the joints. Then you can obtain the Jacobian by differentiating the forward kinematics with respect to the joint variables:
Jij = dfi/dθj
is your manipulator's Jacobian. Inverting it would give you the inverse kinematics with respect to velocities. It can still be useful though, if you want to know how far each joint has to move if you want to move your end effector by some small amount Δx in any direction (because on position level, this would effectively be a linearization):
Δθ=J-1Δx
Hope that this helps.
Given two image buffers (assume it's an array of ints of size width * height, with each element a color value), how can I map an area defined by a quadrilateral from one image buffer into the other (always square) image buffer? I'm led to understand this is called "projective transformation".
I'm also looking for a general (not language- or library-specific) way of doing this, such that it could be reasonably applied in any language without relying on "magic function X that does all the work for me".
An example: I've written a short program in Java using the Processing library (processing.org) that captures video from a camera. During an initial "calibrating" step, the captured video is output directly into a window. The user then clicks on four points to define an area of the video that will be transformed, then mapped into the square window during subsequent operation of the program. If the user were to click on the four points defining the corners of a door visible at an angle in the camera's output, then this transformation would cause the subsequent video to map the transformed image of the door to the entire area of the window, albeit somewhat distorted.
Using linear algebra is much easier than all that geometry! Plus you won't need to use sine, cosine, etc, so you can store each number as a rational fraction and get the exact numerical result if you need it.
What you want is a mapping from your old (x,y) co-ordinates to your new (x',y') co-ordinates. You can do it with matrices. You need to find the 2-by-4 projection matrix P such that P times the old coordinates equals the new co-ordinates. We'll assume that you're mapping lines to lines (not, for instance, straight lines to parabolas). Because you have a projection (parallel lines don't stay parallel) and translation (sliding), you need a factor of (xy) and (1), too. Drawn as matrices:
[x ]
[a b c d]*[y ] = [x']
[e f g h] [x*y] [y']
[1 ]
You need to know a through h so solve these equations:
a*x_0 + b*y_0 + c*x_0*y_0 + d = i_0
a*x_1 + b*y_1 + c*x_1*y_1 + d = i_1
a*x_2 + b*y_2 + c*x_2*y_2 + d = i_2
a*x_3 + b*y_3 + c*x_3*y_3 + d = i_3
e*x_0 + f*y_0 + g*x_0*y_0 + h = j_0
e*x_1 + f*y_1 + g*x_1*y_1 + h = j_1
e*x_2 + f*y_2 + g*x_2*y_2 + h = j_2
e*x_3 + f*y_3 + g*x_3*y_3 + h = j_3
Again, you can use linear algebra:
[x_0 y_0 x_0*y_0 1] [a e] [i_0 j_0]
[x_1 y_1 x_1*y_1 1] * [b f] = [i_1 j_1]
[x_2 y_2 x_2*y_2 1] [c g] [i_2 j_2]
[x_3 y_3 x_3*y_3 1] [d h] [i_3 j_3]
Plug in your corners for x_n,y_n,i_n,j_n. (Corners work best because they are far apart to decrease the error if you're picking the points from, say, user-clicks.) Take the inverse of the 4x4 matrix and multiply it by the right side of the equation. The transpose of that matrix is P. You should be able to find functions to compute a matrix inverse and multiply online.
Where you'll probably have bugs:
When computing, remember to check for division by zero. That's a sign that your matrix is not invertible. That might happen if you try to map one (x,y) co-ordinate to two different points.
If you write your own matrix math, remember that matrices are usually specified row,column (vertical,horizontal) and screen graphics are x,y (horizontal,vertical). You're bound to get something wrong the first time.
EDIT
The assumption below of the invariance of angle ratios is incorrect. Projective transformations instead preserve cross-ratios and incidence. A solution then is:
Find the point C' at the intersection of the lines defined by the segments AD and CP.
Find the point B' at the intersection of the lines defined by the segments AD and BP.
Determine the cross-ratio of B'DAC', i.e. r = (BA' * DC') / (DA * B'C').
Construct the projected line F'HEG'. The cross-ratio of these points is equal to r, i.e. r = (F'E * HG') / (HE * F'G').
F'F and G'G will intersect at the projected point Q so equating the cross-ratios and knowing the length of the side of the square you can determine the position of Q with some arithmetic gymnastics.
Hmmmm....I'll take a stab at this one. This solution relies on the assumption that ratios of angles are preserved in the transformation. See the image for guidance (sorry for the poor image quality...it's REALLY late). The algorithm only provides the mapping of a point in the quadrilateral to a point in the square. You would still need to implement dealing with multiple quad points being mapped to the same square point.
Let ABCD be a quadrilateral where A is the top-left vertex, B is the top-right vertex, C is the bottom-right vertex and D is the bottom-left vertex. The pair (xA, yA) represent the x and y coordinates of the vertex A. We are mapping points in this quadrilateral to the square EFGH whose side has length equal to m.
Compute the lengths AD, CD, AC, BD and BC:
AD = sqrt((xA-xD)^2 + (yA-yD)^2)
CD = sqrt((xC-xD)^2 + (yC-yD)^2)
AC = sqrt((xA-xC)^2 + (yA-yC)^2)
BD = sqrt((xB-xD)^2 + (yB-yD)^2)
BC = sqrt((xB-xC)^2 + (yB-yC)^2)
Let thetaD be the angle at the vertex D and thetaC be the angle at the vertex C. Compute these angles using the cosine law:
thetaD = arccos((AD^2 + CD^2 - AC^2) / (2*AD*CD))
thetaC = arccos((BC^2 + CD^2 - BD^2) / (2*BC*CD))
We map each point P in the quadrilateral to a point Q in the square. For each point P in the quadrilateral, do the following:
Find the distance DP:
DP = sqrt((xP-xD)^2 + (yP-yD)^2)
Find the distance CP:
CP = sqrt((xP-xC)^2 + (yP-yC)^2)
Find the angle thetaP1 between CD and DP:
thetaP1 = arccos((DP^2 + CD^2 - CP^2) / (2*DP*CD))
Find the angle thetaP2 between CD and CP:
thetaP2 = arccos((CP^2 + CD^2 - DP^2) / (2*CP*CD))
The ratio of thetaP1 to thetaD should be the ratio of thetaQ1 to 90. Therefore, calculate thetaQ1:
thetaQ1 = thetaP1 * 90 / thetaD
Similarly, calculate thetaQ2:
thetaQ2 = thetaP2 * 90 / thetaC
Find the distance HQ:
HQ = m * sin(thetaQ2) / sin(180-thetaQ1-thetaQ2)
Finally, the x and y position of Q relative to the bottom-left corner of EFGH is:
x = HQ * cos(thetaQ1)
y = HQ * sin(thetaQ1)
You would have to keep track of how many colour values get mapped to each point in the square so that you can calculate an average colour for each of those points.
I think what you're after is a planar homography, have a look at these lecture notes:
http://www.cs.utoronto.ca/~strider/vis-notes/tutHomography04.pdf
If you scroll down to the end you'll see an example of just what you're describing. I expect there's a function in the Intel OpenCV library which will do just this.
There is a C++ project on CodeProject that includes source for projective transformations of bitmaps. The maths are on Wikipedia here. Note that so far as i know, a projective transformation will not map any arbitrary quadrilateral onto another, but will do so for triangles, you may also want to look up skewing transforms.
If this transformation has to look good (as opposed to the way a bitmap looks if you resize it in Paint), you can't just create a formula that maps destination pixels to source pixels. Values in the destination buffer have to be based on a complex averaging of nearby source pixels or else the results will be highly pixelated.
So unless you want to get into some complex coding, use someone else's magic function, as smacl and Ian have suggested.
Here's how would do it in principle:
map the origin of A to the origin of B via a traslation vector t.
take unit vectors of A (1,0) and (0,1) and calculate how they would be mapped onto the unit vectors of B.
this gives you a transformation matrix M so that every vector a in A maps to M a + t
invert the matrix and negate the traslation vector so for every vector b in B you have the inverse mapping b -> M-1 (b - t)
once you have this transformation, for each point in the target area in B, find the corresponding in A and copy.
The advantage of this mapping is that you only calculate the points you need, i.e. you loop on the target points, not the source points. It was a widely used technique in the "demo coding" scene a few years back.