I am very new to Windows Phone 7. I am writing a sample game in which I want to move the Image randomly.
While discussing with one of my friend, he told me to use Bezier path. I search in the net to understand Bezier path concept. It looks like it will suit for my solution. But I did not found any sample code which will do this.
Please help me to find sample.
A Bezier path is a valid solution to your problem, but might I suggest using a Catmull-Rom spline instead. It is far eaiser to implement, not least of all because XNA already includes a function for generating such a spline. It is also easier to use (each control point is also a point on the spline).
The function in question is Vector2.CatmullRom (there are also versions for Vector3 and for floats in MathHelper). You specify four points. The middle two of which are valid for your spline. If you need more than two points, simply cycle the inputs as you move (second becomes first, third becomes second, and so on). The amount argument species the position that you want, along the path.
The Catmull-Rom spline is described here on Wikipedia.
And here is an interactive demo showing how the spline works.
For simple draw of bezier curve you can use this (for cubic Bezier curve):
private Vector2 Bezier(int t, Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3)
{
var x = OrdinateX((float)t / 100, p0, p1, p2, p3);
var y = OrdinateY((float)t / 100, p0, p1, p2, p3);
return new Vector2(x, y);
}
private float OrdinateX(float t, Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3)
{
return (float)((Math.Pow((double)(1 - t), 3) * p0.Y) + (3 * Math.Pow((double)(1 - t), 2) * t * p1.X) + (3 * (1 - t) * (t * t) * p2.X) + ((t * t * t) * p3.X));
}
private float OrdinateY(float t, Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3)
{
return (float)((Math.Pow((double)(1 - t), 3) * p0.Y) + (3 * Math.Pow((double)(1 - t), 2) * t * p1.Y) + (3 * (1 - t) * (t * t) * p2.Y) + ((t * t * t) * p3.Y));
}
So, and in Update you have to put this:
for (int t = 0; t <= 100; t++)
object.position = Bezier(t, new Vector(0, 0), new Vector(100, 100), new Vector(300,300), new Vector(0, 300));
But I think, that easier way to get curve is to use Catmull-Rom spline, how Andrew Russell wrote.
Related
I am working on robotic arm, and trying to find the distance between one camera and one object, knowing the dimensions of the object using open CV.
I not sure how to do it.
I tried using visual servoing method but not succeeded.
Any help will be nice
Here is a simple solution for starting:
1.) First, you have to calibrate your camera to receive the C matrix. For example:
http://docs.opencv.org/doc/tutorials/calib3d/camera_calibration/camera_calibration.html
2.) Then you have to identify on the image two points of the object which distance is known. Let's be these points P1(X1, Y1, Z1) and P2(X2, Y2, Z2) in the 3D space and p1(x1, y1) and p2(x2, y2) in 2D image plane. Certainly P1 and P2 are not known, only their pairs on the image (p1 and p2) and their distance D.
3.) Next, if you know the camera calibration matrix C, you have two equations:
p1 = C * P1 and p2 = C * P2
Then: C^-1 * p1 = P1' and C^-1 * p2 = P2' where P1' = (X1 / Z1, Y1 / Z1, 1) and P2' = (X2 / Z2, Y2 / Z2, 1). This means that C^-1 * p1 returns the 3D coordinates of the point belong the Z1 = 1 distance.
But the exact distance is not 1 but it is Z1 and Z2. Now, let's suppose that Z1 == Z2 == Z and we are looking for the distance Z.
This follows that Z * C^-1 * p1 = P1 and Z * C^-1 * p2 = P2.
Next (Z * C^-1 * p1) - (Z * C^-1 * p2) = P1 - P2, and
Z * ((C^-1 * p1) - C^-1 * p2)) = P1 - P2, and
Z^2 * ((C^-1 * p1) - C^-1 * p2))^2 = (P1 - P2)^2 = D^2
Now, C, p1, p2 and D are known, only Z is the unknown variable in the last equation.
Certainly, this is only a basic solution and uses the assumpion that the distances of the object's points are very similar, but it can work.
I have used Canny method to get edges of a image.Then I applied the approxPolyDP method to approximate edges,and got a set of polylines (not polygons) and line segments.Each polyline is formed from line segments.My purpose is to get coordinates of each line segment's end points in Cartesian coordinate system (2D plane) and the corresponding parameters (rho,theta) in polar coordinate.Any idea?Thanks!
BTW:I know that we can use the HoughLines method to find lines (not line segments) and get the parameters (rho,theta) in polar coordinate,or we can use the HoughLinesP method to find line segments and coordinates of end points.But the two method can not get the coordinates of end points of line segment and the corresponding parameters (rho,theta) at the same time.
Here's some sample C++ code for interpreting a line from OpenCV HoughLines. If you want the slope, just find two points and compute rise over run.
The important formula, which unfortunately is not as obvious as it should be in the documentation, is: rho = x*cos(theta) + y*sin(theta)
float yForHoughLine(float x, const Vec2f houghLine) {
float rho = houghLine[0];
float theta = houghLine[1];
if (theta == 0)
return NAN;
return (rho - (x * cos(theta))) / sin(theta);
}
float xForHoughLine(float y, const Vec2f houghLine) {
float rho = houghLine[0];
float theta = houghLine[1];
float cosTheta = cos(theta);
if (cosTheta == 0)
return NAN;
return (rho - (y * sin(theta))) / cosTheta;
}
Here's the equivalent Python:
def y_for_line(x, r, theta):
if theta == 0:
return np.nan
return (r - (x * np.cos(theta))) / np.sin(theta)
def x_for_line(y, r, theta):
cos_theta = np.cos(theta)
if cos_theta == 0:
return np.nan
return (r - (y * np.sin(theta))) / cos_theta
I can draw a curve using bezier path, but instead of specifying two control points, I want to specify two points that the path go through it, shown as following
the startPoint is (10,90), end point is (70,70), and the curve pass (20, 50), which is the peak point. and (60,100). Please let me know how to draw it.
From "Bézier curve" article in Wikipedia:
Any series of any 4 distinct points can be converted to a cubic Bézier curve that goes through all 4 points in order. Given the starting and ending point of some cubic Bézier curve, and any two other distinct points in sequence along that curve, the control points for the original Bézier curve can be recovered.[3]
and at the end follows link to http://people.sc.fsu.edu/~jburkardt/html/bezier_interpolation.html
You can use UIBezierPath's addCurveToPoint:controlPoint1:controlPoint2: method.
CGPoint startPt, endPt, cPt1, cPt2;
// init points here
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:startPt];
[path addCurveToPoint:endPt controlPoint1:cPt1 controlPoint2:cPt2];
Assuming we have four points D0(x0,y0), D1(x1,y1), D2(x2,y2), D2(x3,y3). We have to find Bezier cubic spline P0-P1-P2-P3 passing through D0, D1, D2 and D3.
Obviously,
P0 = D0
P3 = D2
Then there are infinite number of Bezier splines passing through point D1 and point D2 defined by equations
P2 = (D1 - (1-t1)^3 * P0 - t1^3 * P3) / (3*(1-t1)*t1^2) -
(1-t1) * P1/t1;
P2 = (D2 - (1-t2)^3 * P0 - t2^3 * P3) / (3*(1-t2)*t2^2) -
(1-t2) * P1/t2;
where t1 is Bezier curve parameter corresponding to point D1 and t2 is corresponding parameter of D2.
Solving this system of equations will give us P1
P1 = t2*(D1 - (1-t1)^3 * P0 - t1^3 * P3) / (3*(1-t1)*t1*(t2-t1)) -
t1*(D2 - (1-t2)^3 * P0 - t2^3 * P3) / (3*(1-t2)*t2*(t2-t1));
We still need to define t1 and t2. Their values can be pretty much anything as long as they are not equal and not equal to 1. One obvious choice is 0.25 and 0.75.
Here is a resulting curve for a set of random input values
Then P1 and P2 can be used as controlPoint1 and controlPoint2 in
UIBezierPath's addCurveToPoint:controlPoint1:controlPoint2 method.
Well the question says it all,
I know the function Line(), which draws line segment between two points.
I need to draw line NOT a line segment, also using the two points of the line segment.
[EN: Edit from what was previously posted as an answer for the question]
I used your solution and it performed good results in horizontal lines, but I still got problems in vertical lines.
For example, follows below an example using the points [306,411] and [304,8] (purple) and the draw line (red), on a image with 600x600 pixels. Do you have some tip?
I see this is pretty much old question. I had exactly the same problem and I used this simple code:
double Slope(int x0, int y0, int x1, int y1){
return (double)(y1-y0)/(x1-x0);
}
void fullLine(cv::Mat *img, cv::Point a, cv::Point b, cv::Scalar color){
double slope = Slope(a.x, a.y, b.x, b.y);
Point p(0,0), q(img->cols,img->rows);
p.y = -(a.x - p.x) * slope + a.y;
q.y = -(b.x - q.x) * slope + b.y;
line(*img,p,q,color,1,8,0);
}
First I calculate a slope of the line segment and then I "extend" the line segment into image's borders. I calculate new points of the line which lies in x = 0 and x = image.width. The point itself can be outside the Image, which is a kind of nasty trick, but the solution is very simple.
You will need to write a function to do that for yourself. I suggest you put your line in ax+by+c=0 form and then intersect it with the 4 edges of your image. Remember if you have a line in the form [a b c] finding its intersection with another line is simply the cross product of the two. The edges of your image would be
top_horizontal = [0 1 0];
left_vertical = [1 0 0];
bottom_horizontal = [0 1 -image.rows];
right_vertical = [1 0 -image.cols];
Also, if you know something about the distance between your points you could also just pick points very far along the line in each direction, I don't think the points handed to Line() need to be on the image.
I had the same problem and found out that there it is a known bug on 2.4.X OpenCV, fixed already for newer versions.
For the 2.4.X versions, the solution is to clip the line before plot it using cv::clipLine()
Here there is a function I did to myself that works fine on the 2.4.13 OpenCV
void Detector::drawFullImageLine(cv::Mat& img, const std::pair<cv::Point, cv::Point>& points, cv::Scalar color)
{
//points of line segment
cv::Point p1 = points.first;
cv::Point p2 = points.second;
//points of line segment which extend the segment P1-P2 to
//the image borders.
cv::Point p,q;
//test if line is vertical, otherwise computes line equation
//y = ax + b
if (p2.x == p1.x)
{
p = cv::Point(p1.x, 0);
q = cv::Point(p1.x, img.rows);
}
else
{
double a = (double)(p2.y - p1.y) / (double) (p2.x - p1.x);
double b = p1.y - a*p1.x;
p = cv::Point(0, b);
q = cv::Point(img.rows, a*img.rows + b);
//clipline to the image borders. It prevents a known bug on OpenCV
//versions 2.4.X when drawing
cv::clipLine(cv::Size(img.rows, img.cols), p, q);
}
cv::line(img, p, q, color, 2);
}
This answer is forked from pajus_cz answer but a little improved.
We have two points and we need to get the line equation y = mx + b to be able to draw the straight line.
There are two variables we need to get
1- Slope(m)
2- b which can be retrieved through the line equation using any given point from the two we have already after calculating the slope b = y - mx .
void drawStraightLine(cv::Mat *img, cv::Point2f p1, cv::Point2f p2, cv::Scalar color)
{
Point2f p, q;
// Check if the line is a vertical line because vertical lines don't have slope
if (p1.x != p2.x)
{
p.x = 0;
q.x = img->cols;
// Slope equation (y1 - y2) / (x1 - x2)
float m = (p1.y - p2.y) / (p1.x - p2.x);
// Line equation: y = mx + b
float b = p1.y - (m * p1.x);
p.y = m * p.x + b;
q.y = m * q.x + b;
}
else
{
p.x = q.x = p2.x;
p.y = 0;
q.y = img->rows;
}
cv::line(*img, p, q, color, 1);
}
I was looking for a helper function to calculate the intersection of two lines in OpenCV. I have searched the API Documentation, but couldn't find a useful resource.
Are there basic geometric helper functions for intersection/distance calculations on lines/line segments in OpenCV?
There are no function in OpenCV API to calculate lines intersection, but distance is:
cv::Point2f start, end;
double length = cv::norm(end - start);
If you need a piece of code to calculate line intersections then here it is:
// Finds the intersection of two lines, or returns false.
// The lines are defined by (o1, p1) and (o2, p2).
bool intersection(Point2f o1, Point2f p1, Point2f o2, Point2f p2,
Point2f &r)
{
Point2f x = o2 - o1;
Point2f d1 = p1 - o1;
Point2f d2 = p2 - o2;
float cross = d1.x*d2.y - d1.y*d2.x;
if (abs(cross) < /*EPS*/1e-8)
return false;
double t1 = (x.x * d2.y - x.y * d2.x)/cross;
r = o1 + d1 * t1;
return true;
}
There's one cool trick in 2D geometry which I find to be very useful to calculate lines intersection. In order to use this trick we represent each 2D point and each 2D line in homogeneous 3D coordinates.
At first let's talk about 2D points:
Each 2D point (x, y) corresponds to a 3D line that passes through points (0, 0, 0) and (x, y, 1).
So (x, y, 1) and (α•x, α•y, α) and (β•x, β•y, β) correspond to the same point (x, y) in 2D space.
Here's formula to convert 2D point into homogeneous coordinates: (x, y) -> (x, y, 1)
Here's formula to convert homogeneous coordinates into 2D point: (x, y, ω) -> (x / ω, y / ω). If ω is zero that means "point at infinity". It doesn't correspond to any point in 2D space.
In OpenCV you may use convertPointsToHomogeneous() and convertPointsFromHomogeneous()
Now let's talk about 2D lines:
Each 2D line can be represented with three coordinates (a, b, c) which corresponds to 2D line equation: a•x + b•y + c = 0
So (a, b, c) and (ω•a, ω•b, ω•c) correspond to the same 2D line.
Also, (a, b, c) corresponds to (nx, ny, d) where (nx, ny) is unit length normal vector and d is distance from the line to (0, 0)
Also, (nx, ny, d) is (cos φ, sin φ, ρ) where (φ, ρ) are polar coordinates of the line.
There're two interesting formulas that link together points and lines:
Cross product of two distinct points in homogeneous coordinates gives homogeneous line coordinates: (α•x₁, α•y₁, α) ✕ (β•x₂, β•y₂, β) = (a, b, c)
Cross product of two distinct lines in homogeneous coordinates gives homogeneous coordinate of their intersection point: (a₁, b₁, c₁) ✕ (a₂, b₂, c₂) = (x, y, ω). If ω is zero that means lines are parallel (have no single intersection point in Euclidean geometry).
In OpenCV you may use either Mat::cross() or numpy.cross() to get cross product
If you're still here, you've got all you need to find lines given two points and intersection point given two lines.
An algorithm for finding line intersection is described very well in the post How do you detect where two line segments intersect?
The following is my openCV c++ implementation. It uses the same notation as in above post
bool getIntersectionPoint(Point a1, Point a2, Point b1, Point b2, Point & intPnt){
Point p = a1;
Point q = b1;
Point r(a2-a1);
Point s(b2-b1);
if(cross(r,s) == 0) {return false;}
double t = cross(q-p,s)/cross(r,s);
intPnt = p + t*r;
return true;
}
double cross(Point v1,Point v2){
return v1.x*v2.y - v1.y*v2.x;
}
Here is my implementation for EmguCV (C#).
static PointF GetIntersection(LineSegment2D line1, LineSegment2D line2)
{
double a1 = (line1.P1.Y - line1.P2.Y) / (double)(line1.P1.X - line1.P2.X);
double b1 = line1.P1.Y - a1 * line1.P1.X;
double a2 = (line2.P1.Y - line2.P2.Y) / (double)(line2.P1.X - line2.P2.X);
double b2 = line2.P1.Y - a2 * line2.P1.X;
if (Math.Abs(a1 - a2) < double.Epsilon)
throw new InvalidOperationException();
double x = (b2 - b1) / (a1 - a2);
double y = a1 * x + b1;
return new PointF((float)x, (float)y);
}
Using homogeneous coordinates makes your life easier:
cv::Mat intersectionPoint(const cv::Mat& line1, const cv::Mat& line2)
{
// Assume we receive lines as l=(a,b,c)^T
assert(line1.rows == 3 && line1.cols = 1
&& line2.rows == 3 && line2.cols == 1);
// Point is p=(x,y,w)^T
cv::Mat point = line1.cross(line2);
// Normalize so it is p'=(x',y',1)^T
if( point.at<double>(2,0) != 0)
point = point * (1.0/point.at<double>(2,0));
}
Note that if the third coordinate is 0 the lines are parallel and there is not solution in R² but in P^2, and then the point means a direction in 2D.
my implementation in Python (using numpy array)
with line1 = [[x1, y1],[x2, y2]] & line2 = [[x1, y1],[x2, y2]]
def getIntersection(line1, line2):
s1 = numpy.array(line1[0])
e1 = numpy.array(line1[1])
s2 = numpy.array(line2[0])
e2 = numpy.array(line2[1])
a1 = (s1[1] - e1[1]) / (s1[0] - e1[0])
b1 = s1[1] - (a1 * s1[0])
a2 = (s2[1] - e2[1]) / (s2[0] - e2[0])
b2 = s2[1] - (a2 * s2[0])
if abs(a1 - a2) < sys.float_info.epsilon:
return False
x = (b2 - b1) / (a1 - a2)
y = a1 * x + b1
return (x, y)