Finding point height on a cup using OpenCV - opencv

Suppose that I want to find the 3D position of a cup with its rotation, with image input like this (this cup can be rotated to point in any direction):
Given that I have a bunch of 2D points specifying the top circle and bottom circle like the following image. (Let's assume that these points are given by a person drawing the lines around the cup, so it won't be very accurate. Ellipse fitting or SolvePnP might be needed to recover a good approximation. And the bottom circle is not a complete circle, it's just part of a circle. Sometimes the top part will be occluded as well so we cannot rely that there will be a complete circle)
I also know the physical radius of the top and bottom circle, and the distance between them by using a ruler to measure them beforehand.
I want to find the complete 2 circle like following image (I think I need to find the position of the cup and its up direction before I could project the complete circles):
Let's say that my ultimate goal is to be able to find the closest 2D top point and closest 2D bottom point, given a 2D point on the side of the cup, like the following image:
A point can also be inside of the cup, like so:
Let's define distance(a, b) as a function that find euclidean distance from point a and point b in pixel units.
From that I would be able to calculate the distance(side point, bottom point) / distance(top point, bottom point) which will be a scale number from 0 to 1, if I multiply this number to the physical height of the cup measured by the ruler, then I will know how high the point is from the bottom of the cup in metric unit.
What is the method I can use to find the corresponding top and bottom point given point on the side, so that I can finally find out the height of the point from the bottom of the cup?
I'm thinking of using PnP to solve this but my points do not have correct IDs associated with them. And I don't want to know the exact rotation of the cup, I only want to know the up direction of the cup.
I also think that fitting the ellipse might help somewhat, but maybe it's not the best because the circle is not complete.
If you have any suggestions, please tell me how to obtain the point height from the bottom of the cup.

Given the accuracy issues, I don't think it is worth performing a 3D reconstruction of the cone.
I would perform a "standard" ellipse fit on the top outline, which is the most accurate, then a constrained one on the bottom, knowing the position of the vertical axis. After reduction of the coordinates, the bottom ellipse can be written as
x²/a² + (y - h)²/b² = 1
which can be solved by least-squares.
Note that it could be advantageous to ask the user to point at the endpoints of the straight edges at the bottom, plus the lowest point, instead of the whole curve.
Solving for the closest top and bottom points is a pure 2D problem (draw the line through the given point and the intersection of the sides, and find the intersection points with the ellipse.

Related

Extend a square in world space to a cube when only screen space coordinates are available

I have a photo of a Go-board, which is basically a grid with n*n squares, each of size a.
Depending on how the image was taken, the grid can have either one vanishing point like this (n = 15, board size b = 15*a):
or two vanishing points like this (n = 9, board size b = 9*a):
So what is available to me are the four screen space coordinates of the four corners of the flat board: p1, p2, p3, p4.
What I would like to do is to calculate the corresponding four screen space coordinates q1, q2, q3, q4 of the corners of the board, if the board was moved 'upward' (perpendicular to the plane of the board) in world space by a, or in other words the coordinates on top of the board, if the board had a thickness of a.
Is the information about the four points even sufficient to calculate this?
If this is not enough information, maybe it would help to make the assumption that the distance of the camera to the center of the board is typically of the order of 1.5 or 2 times the board size b?
From my understanding, the four lines p1-q1, p2-q2, p3-q3, p4-q4 would all go through the same (yet unknown) vanishing point, located somewhere below the board.
Maybe a sufficient approximation (because typically for a Go board n=18 and therefore square size a is small in comparison to the board size) for the direction of each of the lines p1-q1, p2-q2, ... in screen space would be to simply choose a line perpendicular to the horizon (given by the two vanishing points vp1-vp2 or by p1-p2 in the case of only one vanishing point)?
Having made this approximation, still the length of the four lines p1-q1, p2-q2, p3-q3, p4-q4 would need to be calculated ...
Any hints are highly appreciated!
PS: I am using Objective-C & OpenCV
Not yet a full answer but this might help to move forward. As MvG pointed out 4 points alone are not enough. Luckily we know the board is a square so even with perspective distortion the diagonals in 2D should/will intersect at board center (unless serious fish-eye or other distortions are present in the image). Here a test image (created by OpenGL I used as a test input):
The grayish surface is 2D QUAD using 2D perspective distorted corner points (your input). The aqua/bluish grid is 3D OpenGL grid I created the 2D corner points with (to see if they match). The green lines are 2D diagonals and Orange points are the 2D corner points and the diagonals intersection. As you can see 2D diagonal intersection correspond exactly with 3D board mid cell center.
Now we can use the ratio between half diagonal lengths to assume/fit the perspective. If we handle cell coordinates in range <0,9> we want to achieve further division of halve diagonals like this:
I am still not sure how exactly (linear ratio l0/(l0+l1) is not working) so I need to inspect perspective mapping equations to find relative ratio dependence and compute inverse (when I have time mood for this).
If that will be a success than we can compute any points along the diagonals (we want the cell edges). If that is done from that we can easily compute visual size of any cell size a and use the vanishing point without any 3D transform matrices at all.
In case this is not doable there is still the option to use DIP/CV techniques to detect the cell crossings like this:
OpenCV Birdseye view without loss of data
using just the bullet #2 but for that you need to take into account type of images you will have and adjust the detector or add preprocessing for it ...
Now back to your offsetting you can simply offset your cells up by the visual size of the cell like this:
And handle the left side points (either interpolate the size or use the sane as neighboring cell) That should work unless too weird angles of the board are used.

how to find orientation of a picture with delphi

I need to find orientation of corn pictures (as examples below) they have different angles to right or left. I need to turn them upside (90 degree angle with their normal) (when they look like a water drop)
Is there any way I can do it easily?
As starting point - find image moments (and Hu moments for complex forms like pear). From the link:
Information about image orientation can be derived by first using the
second order central moments to construct a covariance matrix.
I suspect that usage of some image processing library like OpenCV could give more reliable results in common case
From the OP I got the impression you a rookie in this so I stick to something simple:
compute bounding box of image
simple enough go through all pixels and remember min,max of x,y coordinates of non background pixels
compute critical dimensions
Just cast few lines through the bounding box computing the red points positions. So select the start points I choose 25%,50%,75% of height. First start from left and stop on first non background pixel. Then start from right and stop on first non background pixel.
axis aligned position
start rotating the image with some step remember/stop on position where the red dots are symmetric so they are almost the same distance from left and from right. Also the bounding box has maximal height and minimal width in axis aligned position so you can also exploit that instead ...
determine the position
You got 4 options if I call the distance l0,l1,l2,r0,r1,r2
l means from left, r means from right
0 is upper (bluish) line, 1 middle, 2 bottom
then you wanted position is if (l0==r0)>=(l1==r1)>=(l2==r2) and bounding box is bigger in y axis then in x axis so rotate by 90 degrees until match is found or determine the orientation directly from distances and rotate just once ...
[Notes]
You will need accessing pixels of image so I strongly recommend to use Graphics::TBitmap from VCL. Look here gfx in C specially the section GDI Bitmap and also at this finding horizon on high altitude photo might help a bit.
I use C++ and VCL so you have to translate to Pascal but the VCL stuff is the same...

Is edge points of object represent an ellipse?

Given an edge points of object. Let us say Obj = (xi,yi); i=1,2,3,....
How can we know if these edge points represent an ellipse or not?
As long as you have more than 2 points you could try linear fitting by using least squares:
See here:https://math.stackexchange.com/a/153150/104118
See section 7 Fitting an Ellipse to 2D Points in the actual link: http://www.geometrictools.com/Documentation/LeastSquaresFitting.pdf
Off the top of my head, I would calculate the axis with minimal variance (call it a) and the axis with maximal variance (call it b).
I would check that those axes are reasonably close to being perpendicular - if not then it's probably not an ellipse. If they are close to being perpendicular, I would rotate the point cloud so that a and are aligned with the x- and y-axes.
Next step would be to translate the point cloud so its center is at (0,0) and then check that each translated point lie close to the perimeter of an ellipse with axes a and b by putting each of the points into the equation of the ellipse and checking that the value is close to 0.
This is all based on me reading "edge points" as just looking at the points used by edges. If the edges themselves are to be involved, you would have to check that the edges go "around the clock" as well.
Well I know this was loose... hope it made sense somehow :-).

Keeping Squares Along A Circle's Circumference

I'm drawing squares along a circular path for an iOS application. However, at certain points along the circle, the squares start to go out of the circle's circumference. How do I make sure that the squares stay inside?
Here's an illustration I made. The green squares represent the positions I need the squares to actually be in. The red squares are where they actually appear given the following values for each square's upper-left corner:
x = origin.x + radius * cos(DEGREES_TO_RADIANS(angle));
y = origin.y + radius * sin(DEGREES_TO_RADIANS(angle));
Origin refers to the center of the circle. I have a loop that repeats this for every angle from 1 till 360 degrees.
EDIT: I've changed my design to position the centers of the squares along the circular path rather than their upper left corners.
why not just draw the centers of the squares along a smaller circle inside of the bigger one?
You could do the math to figure out exactly what the radius would have to be to ensure an exact fit, but you could probably trial and error your way there quickly too.
Doing it this way ensures that your objects would end up laid out in an actual circle too, which is not the case if you were merely making sure that one and only one corner of each square touched the larger bounding circle (that would create a slightly octagonal shape instead of a circle)
ryan cumley's answer made me realize how dumb I was all along. I just needed to change each square's anchor point to its center & that solved it. Now every calculated value for x & y would position every square's center exactly on the circular path.
Option 1) You could always find the diameter of the circle and then using Pythagorean Theorem, you could create a square that would fit perfectly within the circle. You could then loop through the square that was just made in the circle to create smaller squares, but I doubt this is what you are aiming for.
Option2) Find out what half of the length of one of the diagonals of the squares should be, and create a ring within the first ring. Then lay down squares at key points (like ever 30 degrees or 15 degrees, etc) along the inner path. Ex: http://i.imgur.com/1XYhoQ0.png
As you can see, the smaller (inner) circle is in the center of each green square, and that ensures that the corners of each square just touches the larger (outer) circle. Obviously my cheaply made picture in paint is not perfect, but mathematically it will work.

Calculate the area of a trapezoid from picture while adjusting for angle

Here's a general math problem I was hoping someone could help me with. My app has the user take a picture of a roof and then mark the perimeter of the roof. I would like to calculate the area of the trapezoid drawn by the user. However, since roofs are angled, I need adjust for that fact.
Can anyone point me in the right direction? My math skills are quite rusty (and were never particularly strong).
--
a picture might help. A user might outline the roof as shown below with the red line. But if the roof could be magically rotated to be perpendicular with the ground, it would look likely fill the space closer to the blue line. So, what I'm wondering is, is there any math that I can do that might accomplish this? (I realize there are other options such as calculating the length of two sides using separate pictures and multiplying them.)
Getting the area of the actual roof from a mere picture is impossible. You couldn't know whether the picture was taken at five or fifty meters, so a roof that looks tiny in the picture could be enormous. You would need a depth map to get the actual size of the roof, and even that would be tricky.
This is possible, but only if you can add a host of constraints to the situation where the picture is being taken:
If you know the opening angle of the lens used to take the picture, and you know the exact distance to the roof at the time the picture was taken (distance between camera and gutter), and the picture was taken exactly as in your sample with the roof perpendicular to the camera axis, and the camera pointed directly at the horizontal center of the gutter, and you know for certain the roof is rectangular, then it is surprisingly simple. If you don't mind being off by something between 10 and 25%. (depending on the accuracy of various measurements).
If you can't know the opening angle of the lens (because the picture is not taken by a camera you control, or because the picture is taken by a camera with a zoom lens) but there is an object of known size, a known distance from the camera in the image then it is still surprisingly simple, because you can determine the opening angle from the known object. The object needs to be significantly large in the image (50% of the horizontal width in the image or so) but it can be closer to the photographer, so it won't have to be as large as the roof.
If you can't control the exact position from which the picture was taken (i.e. it won't be taken directly opposite the center of the gutter) your accuracy will be way off.
If you know the horizontal opening angle alpha of the camera, the distance Dgut between camera and gutter, the width of the gutter in pixels Wgut and the width of the image in pixels Wim, then you can determine the approximate length of the gutter Lgut from:
Dpixgut= Wim/(tan(alpha/2)) # distance to the gutter in pixel space
tan(anggut) = Wgut/Dpixgut # tan of half "opening angle" of the gutter
Lgut= 2*tan(anggut)*Dgut
Because you know Ltop (the lenght of the top of the roof) equals Lgut (this is one of the constraints) you can use the width of the top in pixels Wtop to calculate the distance to the top of the roof Dtop:
Dpixtop=Wim/(tan(alpha/2)) #dist to top in pixel space
tan(angtop)=Wtop/Dpixtop
Dtop=Ltop/(2*tan(angtop)) #dist to roof in real space (note that Ltop=Lgut)
Dtop-Dgut gives you a rough estimate of the length Lroof of the roof, so Dgut*Lroof is a rough approximation of the area. To be more exact you have to include some calculations similar to the ones above to determine the height of the gutter and the top of the roof above the camera axis, and then adjust Lroof for that.
Note that this approximation is just that. An approximation. Try some examples from roofs for which you know the area to get a feel for the accuracy (which could be surprisingly bad I fear).

Resources