why the curve have been into a straight line in image [duplicate] - opencv

There a is an ellipse on the picture,just as following.
I have got the points of the contour by using opencv. But you can see the pictrue,because the resolution is low, there is a straight line on the contour.How can i fit it into curve like the blue line?

One Of the method to solve your problem is to vectorize your shape (moving from simple intensity space to vectors space).
I am not aware of the state-of-art in this field. However, from school information, I can suggest this solution.
Bezier curves, you can try to model your shape using simple bezier curve.This is not a hard operation you can google for dozen of them. Then, you can resizing it as much as you want after that you may render it to simple image.
Be aware that you may also Splines instead of Bezier.
Another method would be more simple but less efficient. Since you mentioned OpenCV, you can apply the cv::fitEllipse on the points. Be aware that this will return a RotatedRect which contains the ellipse. You can infer your ellipse simply like this:
Center = Center of RotatedRect.
Longest Radius = The Line which pass from the center and intersect with the two small sides of the RotatedRect.
Smallest Radius = The Line which pass from the center and intersect with the two long sides of the RotatedRect.
After you got your Ellipse Parameters, You can resize it as you want then just repaint it in the size you want using cv::ellipse.
I know that this is a pseudo answer. However, I think every thing is easy to apply. If you faced any problem implementing it, just give me a comment.

Related

Calculate Area Size of UIBezierPath Custom Shapes

I have UIBezierPathes like this:
And I want to calculate the area size of this kind of custom shapes. I don't have any idea to manage this calculation for this complex shapes in Objective c. I found here something for Android but didn't found something similar for iOS: Click
I dont need a working solution, just need an idea or some pseudo code to solve this problem if there is an way.
Thanks!
If you regions are surrounded by Bezier curves (including straight lines), then you can exploit Green's theorem for parametric curves (formula 10 here) to find area of region. Just calculate value of integral for every curve of contour:
A = Integral[t=0..1] (y(t)*x'(t)*dt)
for cubic Bezier curve, defined by control points P[]:
A = Integral[0..1](y(t)*x'(t)*dt)=
Integral[0..1](
(P[0].Y*(1-t)^3+3*P[1].Y*t*(1-t)^2+3*P[2].Y*t^2*(1-t)+P[3].Y*t^3)*
(P[0].X*(1-t)^3+3*P[1].X*t*(1-t)^2+3*P[2].X*t^2*(1-t)+P[3].X*t^3)' * dt)
We have to expand the brackets, differentiate the second line expression, multiply expressions, and integrate the result. Resulting formulas are rather large, but easy to implement. Maple work to derive formulas:

How to compute the overlapping ratio of two rotated rectangles?

Given two rectangles, and we know the position of four corners, widths, heights, angles.
How to compute the overlapping ratio of these two rectangles?
Can you please help me out?
A convenient way is by the Sutherland-Hodgman polygon clipping algorithm. It works by clipping one of the polygons with the four supporting lines (half-planes) of the other. In the end you get the intersection polygon (at worst an octagon) and find its area by the polygon area formula.
You'll make clipping easier by counter-rotating the polygons around the origin so that one of them becomes axis parallel. This won't change the area.
Note that this approach generalizes easily to two general convex polygons, taking O(N.M) operations. G.T. Toussaint, using the Rotating Caliper principle, reduced the workload to O(N+M), and B. Chazelle & D. P. Dobkin showed that a nonempty intersection can be detected in O(Log(N+M)) operations. This shows that there is probably a little room for improvement for the S-H clipping approach, even though N=M=4 is a tiny problem.
Use rotatedRectangleIntersection function to get contour and use contourArea function to get area and find the ratios
https://docs.opencv.org/3.0-beta/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html#rotatedrectangleintersection
Lets say you have rectangle A and B the you can use the operation:
intersection_area = (A & B).area();
from this area you can calculate de respective ratio towards one of the rectangles. there will be harder more dynamic ways to do this as well.

iOS: CGPath Line Drawing with dynamic width

I want to draw a line with dynamic width as shown in attached picture. What should be the best approach for this. ?
Updated:
My task is to draw line on finger move. And the line width is changes as speed of swipe is change. both (Line width and finger swipe speed) are directly proportional .
As the image you posted doesn't has any consistent height-width proportion to calculate and change, i doubt this cannot be achieved.
In other solution you can draw a line of fixed pixel say 2 pixel and based on drawn length inflate the width if line till center and then again start deflate from center point to end point.
You need to see the difference between x coordinates otherwise if a sine wave is drawn with high nodes the line width will overlap each other.
Edited : This link might be of your interest then.You can modify it according to your need, its in cocos2d.
There is no direct support for variable thickness curves in iOS (or Mac OS for that matter.) The cocos2d project looks like a good approach.
There is also no support for soft-edged curves who's edges are feathered to transparent. I've thought about implementing a similar approach to the one outlined in the Cocos link using OpenGL. This would be a good application for a vertex shader, since it would take advantage of the parallel vertex processing and vector math available in shaders.
Take a look at this article Smooth Freehand Drawing. It might be helpfull.
You can manipulate with control points of
[path addCurveToPoint:pts[3] controlPoint1:pts[1] controlPoint2:pts[2]];
and fill the area between two bezierPaths. I am not sure if it will work, but you can try if you dont find anything else.

Draw curve with varying line width

I know how to draw curve with Core Graphic or using UIBezierPath.
But, I want to draw a curve that is wide to begin with and thin at the end:
I searched many question about curve, bezier path or something similar on Google. But i can't find any ideal for implementing it.
Can you help me ?
The two methods that immediately come to mind are...
Calculating the path
This is probably the most complex. It would involve calculating the path for the entire shape and adding this as a path and filling it.
Using a line method
You create a series of points that will lie along the centre line of your curve. Maybe 5 points between each point.
Then at each point you can use that as a centre point of a line perpendicular to the tangent of the curve at the point.
The perpendicular line will have a length which you can calculate depending on how far through the curve you are.
Then use this line to create a square path to the line from the previous point.
Then fill that square.
Move to the next point. Add the line and create a box back to the previous line and so on.
At the end are a circle with centre point of the last point. This will create the end.
It's complex but doable if you split down the functions.

Given a set of points to define a shape, how can I contract this shape like Photoshop's Selection>Contract

I have a set of points to define a shape. These points are in order and essentially are my "selection".
I want to be able to contract this selection by an arbitrary amount to get a smaller version of my original shape.
In a basic example with a triangle, the points are simply moved along their normal which is defined by the points to the left and the right of the points in question.
Eventually all 3 points will meet and form one point but until that point they will make a smaller and smaller triangle.
For more complex shapes, when moving the individual points inward, they may pass through the outer edge of the shape resulting in weird artifacts. Obviously I'll need to cull these points and remove them from the array.
Any help in exactly how I can do that would be greatly appreciated.
Thanks!
This is just an idea but couldn't you find the center of mass of the object, create a vector from the center to each point, and move each point along this vector?
To find the center of mass would of course involve averaging each x and y coordinate. Getting a vector is as simple a subtracting the point in question with the center point. Normalizing and scaling are common vector operations that can be found with the Google.
EDIT
Another way to interpret what you're asking is you want to erode your collection of points. As in morphology erosion. This is typically applied to binary images but you can slightly modify the concept to work with a collection of points. Essentially, you need to write a function that, given a point, will return true (black) or false (white) depending on if that point is inside or outside the shape defined by your points. You'd have to look up how to do that for shapes that aren't always concave (it's harder but not impossible).
Now, obviously, every single one of your actual points will return false because they're all on the border (by definition). However, you now have a matrix of points around your point of interest that define where is "inside" and where is "outside". Average all of the "inside" points and move your actual point along the vector between itself and towards this average. You could play with different erosion kernels to see what works best.
You could even work with a kernel with floating point weights instead of either/or values which will affect your average calculation proportional to their weights. With this, you could approximate a circular kernel with a low number of points. Try the simpler method first.
Find the selection center (as suggested by colithium)
Map the selection points to the coordinate system with the selection center at (0,0). For example, if the selection center is at (150,150), and a given selection point is at (125,75), the mapped position of the point becomes (-25,-75).
Scale the mapped points (multiply X and Y by something in the range of 0.0..1.0)
Remap the points back to the original coordinate system
Only simple maths required, no need to muck about normalizing vectors.

Resources