Fisheye camera calibration, when the Angle of incidence is greater than 75 degrees, the calculated pixel coordinates are out of the picture - camera-calibration

The fisheye calibration results as follow:
DIM=(570, 570)
K=np.array([[266.36324787557334, 0.0, 286.1343601122261], [0.0, 265.62825365308095, 278.7737221129092], [0.0, 0.0, 1.0]])
D=np.array([[-0.0759953338456378], [0.021844363556585086], [-0.0788346808974877], [0.03431624249604429]])
The projection method is given in opencv org:
https://docs.opencv.org/3.4/db/d58/group__calib3d__fisheye.html
def get_pixel_location(ele,azi,isDeg=True):
print("ele azi:",ele,azi)
if(isDeg):
ele,azi=ele*deg2rad,azi*deg2rad
# print()
xc,yc,zc=np.cos(ele)*np.sin(azi),np.cos(ele)*np.cos(azi),np.sin(ele)
print("xc yc zc:",ele,azi)
a=xc/zc
b=yc/zc
r=np.sqrt(a*a+b*b)
import math
theta=math.atan(r)
theta_d=theta*(1+D[0]*theta**2+D[1]*theta**4+D[2]*theta**6+D[3]*theta**8)
x_=theta_d[0]/r*a
y_=theta_d[0]/r*b
res=np.matmul(K,np.array([x_,y_,1]).T)
return res[0],res[1]
I calculate its corresponding pixel coordinates based on the incidence Angle and azimuth Angle, and when the incidence Angle is greater than 75 degrees, the calculation results are out of my image range
azi=90
eles=range(5,30,5)
for ele in eles:
pix_x1,pix_y1=get_pixel_location(ele,azi)
print("像素坐标:",pix_x1,pix_y1)
output:
ele azi: 5 90
xc yc zc: 0.08726646259971647 1.5707963267948966
像素坐标: 643.0703082567584 278.7737221129092
ele azi: 10 90
xc yc zc: 0.17453292519943295 1.5707963267948966
像素坐标: 600.9383069020462 278.7737221129092
ele azi: 15 90
xc yc zc: 0.2617993877991494 1.5707963267948966
像素坐标: 576.6204832801376 278.7737221129092
ele azi: 20 90
xc yc zc: 0.3490658503988659 1.5707963267948966
像素坐标: 560.5995805890057 278.7737221129092
ele azi: 25 90
xc yc zc: 0.4363323129985824 1.5707963267948966
像素坐标: 547.3589855919477 278.7737221129092

Related

Find a point at a specific angle from a center point in Go

I want to be able to use a center point (x,y) and an angle to find a second point (x2,y2) at a given distance from center.
For example:
Center is 0,0
Angle is 50 degrees
Distance is 10
The code below is wrong and trying to interpret this answer https://math.stackexchange.com/questions/143932/calculate-point-given-x-y-angle-and-distance however I have no idea how to incorporate the θ using Go.
Sorry I have not done this kind of math for many years and the question may sound stupid.
x := math.Cos(50)
y := math.Sin(50)
x2 := x *10
y2 := x *10
How do I find x2, y2 using Golang? Any help would be appreciated.
The Go math functions use radians. You may need to convert from degrees to radians first. See the example below:
package main
import (
"fmt"
"math"
)
func main() {
x0 := float64(0)
y0 := float64(0)
// Assume the positive X axis represents 0 degrees (anti-clockwise direction).
fmt.Printf("(x0,y0)\tDegrees\tRadians\t(x1,y1)\n")
for _, degrees := range []float64{0, 30, 45, 90, 135, 180, 225, 270, 315} {
radians := degrees * math.Pi / 180
distance := float64(1)
x1 := x0 + distance*math.Cos(radians)
y1 := y0 + distance*math.Sin(radians)
fmt.Printf("(%g, %g)\t%g\t%.3f\t(%.3f, %.3f)\n", x0, y0, degrees, radians, x1, y1)
}
}
Output:
(x0,y0) Degrees Radians (x1,y1)
(0, 0) 0 0.000 (1.000, 0.000)
(0, 0) 30 0.524 (0.866, 0.500)
(0, 0) 45 0.785 (0.707, 0.707)
(0, 0) 90 1.571 (0.000, 1.000)
(0, 0) 135 2.356 (-0.707, 0.707)
(0, 0) 180 3.142 (-1.000, 0.000)
(0, 0) 225 3.927 (-0.707, -0.707)
(0, 0) 270 4.712 (-0.000, -1.000)
(0, 0) 315 5.498 (0.707, -0.707)

How do you rectify a 3D planar polygon?

I have a 3D planar (all vertices lie in some plane) polygon with vertices: [(x1, y1, z1) ... (x1, y1, z1)].
I would like to transform this polygon so that I'm viewing it orthographically (as if I'm looking at it straight on).
How can this be done in Python?
I assume you have no information except for vertex coordinates.
Take three non-collinear (perhaps consequent) vertices C, A, B. Calculate normalized vector (divide by vector length)
b = (B - A) / |B - A|
then normal vector (using vector/cross multiplication)
N = b.cross.(A-C) and normalize it
un = N / |N|
and another unit vector in polygon plane
v = b.cross.n
Now we want find such matrix of affine transformations, that transforms vertex A into point (0,0,0), edge AB will be collinear with OX axis, normal will be collinear with OZ axis, vector q will be collinear with OY axis. This all means that rotated polygon will lie in OXY plane.
Mathematically: points A, u=A+b, v=A+q, n=A+un should be transformed in quadruplet (0,0,0), (1,0,0), (0,1,0), (0,0,1). In matrix form
[Ax ux vx nx] [0 1 0 0]
M * [Ay uy vy ny] = [0 0 1 0]
[Az uz vz nz] [0 0 0 1]
[1 1 1 1 ] [1 1 1 1]
or
M * S = D
Using matrix inverse
M * S * Sinv = D * Sinv
and finally
M = D * Sinv
So calculate matrix M and multiply it with every vertex coordinates. New coordinates should have zero Z-component (or very small due to numerical errors).
You can perform all described operations with numpy library with a little code
Example with specific data
Quick-made implementation in plain Python for reference
import math
def calcMatrix(ax, bx, cx, ay, by, cy, az, bz, cz):
ux, uy, uz = bx - ax, by - ay, bz - az
mag = math.sqrt(ux*ux+uy*uy +uz*uz)
ux, uy, uz = ux / mag, uy / mag, uz / mag
Cx, Cy, Cz = ax - cx, ay - cy, az - cz
nx, ny, nz = uy * Cz - uz * Cy, uz * Cx - ux * Cz, ux * Cy - uy * Cx
mag = math.sqrt(nx*nx+ny*ny+nz*nz)
nx, ny, nz = nx / mag, ny / mag, nz / mag
vx, vy, vz = uy * nz - uz * ny, uz * nx - ux * nz, ux * ny - uy * nx
denom = 1.0 / (ux*ux+uy*uy + uz*uz)
M = [[0.0]*4 for _ in range(4)]
M[3][3] = 1.0
M[0][0] = denom*(ux)
M[0][1] = denom*(uy)
M[0][2] = denom*(uz)
M[0][3] = denom*(-ax*ux-ay*uy+az*uz)
M[1][0] = denom*(vx)
M[1][1] = denom*(vy)
M[1][2] = denom*(vz)
M[1][3] = -denom*(ax*vx-ay*vy+az*vz)
M[2][0] = denom*(nx)
M[2][1] = denom*(ny)
M[2][2] = denom*(nz)
M[2][3] = denom*(-ax*nx-ay*ny+az*nz)
return M
def mult(M, vec):
res = [0]*4
for k in range(4):
for i in range(4):
res[k] += M[k][i] * vec[i]
return res
#test corners and middle point
M = calcMatrix(1, 0, 0, 0, 1, 0, 0, 0, 1)
#print(M)
p = [1, 0, 0, 1]
print(mult(M, p))
p = [0, 1, 0, 1]
print(mult(M, p))
p = [0, 0, 1, 1]
print(mult(M, p))
p = [1/3, 1/3, 1/3, 1]
print(mult(M, p))
test results:
[0.0, 0.0, 0.0, 1.0]
[1.4142135623730951, 0.0, 0.0, 1.0]
[0.7071067811865476, 1.2247448713915892, 0.0, 1.0]
[0.7071067811865476, 0.4082482904638631, 1.1102230246251565e-16, 1.0]
Find a normal n to the polygon, by means of a cross-product between two non-parallel sides. Take the cross-product of n with a vertical vector, to get an horizontal vector u. Then take the cross product of n and u to get v, and normalize the vectors. u and v are parallel to the plane of the polygon and orthogonal to each other.
Finally, for every vertex p compute the 2D coordinates (p.u, p.v) which show you the polygon in its plane.
numpy supplies the cross and dot vector functions. Also linalg.norm (or sqrt(dot(v, v))).
Here's a robust approach using NumPy (project(); the rest is test code).
import numpy
import scipy.spatial
def project(x):
# Center the plane on the origin
x = x - numpy.mean(x, axis=0)
# Compute the Singular Value Decomposition
u, s, v = numpy.linalg.svd(x)
# Return the top two principal components
return u[:, :2] # numpy.diag(s[:2])
def test():
n = 10
x = (numpy.random.rand(n, 2) # numpy.random.rand(2, 3)) + numpy.random.rand(3)
y = project(x)
print(x.shape, y.shape)
print(
numpy.max(
numpy.abs(
scipy.spatial.distance_matrix(x, x)
- scipy.spatial.distance_matrix(y, y)
)
)
)
if __name__ == "__main__":
test()
Sample output:
(10, 3) (10, 2)
5.551115123125783e-16

Calculating a location on a circle given an angle of rotation

Okay algebra and trig are not my strong suit by any means so here is what I need to do.
I have a circle which is measured in degrees from +180 to -180 (360 total)
Given the center point of the circle stays the same, Cx , Cy.
The angle varies from -180 to +180
I need to locate a point that regardless the given angle is + 3 units away that is at the 90 degree position and the 270 degree position (from the given degrees)
So like...
Angle = 0
Point 1 -> x = 0, y -3
Point 2 -> x = 0, y + 3
And if the angle was say 90 (provided its measured Clockwise)
Point 1 -> x = -3, y = 0
Point 2 -> x = 3, y = 0
What I need is a forumla that will accept Angle, then tell me what my x/y should be 3 units away from the origin.
I have tried: EDIT Updated to double precision using Java.
`double x = Cx + 3 * Math.cos((d + 90) * Math.PI / 180);'
'double y = Cy + 3 * Math.sin((d + 90) * Math.PI / 180);`
this gives me mixed results, I mean sometimes it's where I think it should be and other times its quite wrong.
Assuming Cx = 0.500, Cy = 0.500
Sample Data: Result:
Deg = 0 x = 2 / y = 5
Deg = 90 x = -1 / y = 2
Deg = 125 x = -0.457 / y = 0.297
Deg = 159 x = 0.924 / y = -0.800
I realize I am only calculating one point at this point but do you have any suggestions on how to get the first point working? at say 90 degrees from whatever degree I start with?
x = Cx + r * Math.cos( (d+90) * Math.PI / 180 );
y = Cy + r * Math.sin( (d+90) * Math.PI / 180 );
Seems that this is the correct formula for what I was trying to accomplish. This will take any value for Cx/Cy's origin add the Radius r, then calculate the degrees + 90 and convert to radians.. Once all that magic takes place, you're left with an x/y coord that is 90 degrees of where you started.

Rotating a matrix in a non standard 2d plane

I have some problems figuring out how to rotate a matrix in a 2d plane since my coordinate system is not a standard mathematical one, my plane has an inverted y-axis, meaning higher y value is lower on the screen. I also want to rotate the matrix clockwise instead of the standard anticlockwise.
So if I try to illustrate how I want it to work:
O = origin
X = points to rotate
Then 0 degrees looks like this:
XXX
O
I want 90 degrees to look like this:
X
OX
X
180 degrees should look like this:
O
XXX
270 degrees should look like this:
X
XO
X
Any ideas on how to calculate the new x and y for a point after rotating in this plane?
The clockwise rather than anti-clockwise just means flipping the sign on the angle.
To get the full result, we just transform into 'standard coords', do the rotation, and transform back:
The coordinate transform and its inverse is:
(x') = ( 1 0 ) (x)
(y') ( 0 -1 ) (y)
A rotation anti-clockwise is:
(x') = ( cos(angle) -sin(angle) ) (x)
(y') ( sin(angle) cos(angle) ) (y)
So a rotation clockwise is:
(x') = ( cos(angle) sin(angle) ) (x)
(y') ( -sin(angle) cos(angle) ) (y)
Altogether this gives:
(x') = ( 1 0 )( cos(angle) sin(angle) ) ( 1 0 )(x)
(y') ( 0 -1 )( -sin(angle) cos(angle) ) ( 0 -1 )(y)
Multiply the matrices to get:
(x') = ( cos(angle) sin(angle) ) (x)
(y') ( -sin(angle) cos(angle) ) (y)
Now, as you may by now have realized, this is actually the same matrix as rotating 'standard coords' in the anti-clockwise direction.
Or in code:
// Angle in radians
double x2 = cos(angle) * x1 - sin(angle) * y1;
double y2 = sin(angle) * x1 + cos(angle) * y1;
For example, if angle is 180 degrees, cos(angle) is -1, and sin is 0, giving:
double x2 = -x1;
double y2 = -y1;

Animating With Gloss in Haskell

Here's my code for a little pattern that looks something like this. (Not the most efficient code I know). Now, I want to make stars rotate using animate. but I'm not sure how to use display and animate together in one program. Any help would be appreciated. Thanks.
import Graphics.Gloss
main = display (InWindow "Gloss" (700,700) (0,0))
black (picture 100)
picture :: Float -> Picture
picture 0 = text "Value cannot be 0"
picture number = scale 6.5 6.5 (color rose $ drawpicture number)
orangered, orangered2, orangered3 :: Color
orangered = makeColor 1.0 0.251 0.0 0.7
orangered2 = makeColor 1.0 0.251 0.0 0.5
orangered3 = makeColor 1.0 0.251 0.0 0.3
intervalsmall = [0,11.25,22.5,33.75,45,56.25,67.5,78.75]
intervalbig = [0,22.5,45,67.5,90,112.5,135,157.5,180,202.5,225,247.5,270,292.5,315,337.5]
xlist = [2,4..50]
ylist = [0,2..48]
squares = pictures[rotate x (line [(-50,0),(0,50),(50,0),(0,-50),(-50,0)]) | x <- intervalsmall]
stars = pictures[rotate x ((pictures [line [(-8.5,0),(0,50),(8.5,0)],line[(0,50),(0,0)]])) | x <- intervalbig]
grid = pictures[line [(0,y),(x,50)] | x <- xlist, y <- ylist, x-y==2]
insidegrid = pictures[
translate 0 (-50) grid,
rotate 90 (translate 0 (-50) grid),
rotate 180 (translate 0 (-50) grid),
rotate 270 (translate 0 (-50) grid)]
drawpicture :: Float -> Picture
drawpicture number = pictures [
color red (pictures [circle 50,circle 8.5]),
line [(-50,-50),(-50,50),(50,50),(50,-50),(-50,-50)],
squares,
scale 0.7 0.7 squares,
scale 0.49 0.49 squares,
scale 0.347 0.347 squares,
scale 0.242 0.242 squares,
color orange stars,
color orange (scale 0.178 0.178 stars),
rotate 11.25 (scale 0.178 0.178 stars),
translate (-50) 0 grid,
rotate 90 (Translate (-50) 0 grid),
rotate 180 (Translate (-50) 0 grid),
rotate 270 (Translate (-50) 0 grid),
color orangered insidegrid,
color orangered2 (rotate 45 insidegrid),
color orangered3 (rotate 22.5 insidegrid),
color orangered3 (rotate 67.5 insidegrid)
]
It's easier if you have separate draw functions for each visual element, but the basic answer is: to animate it just use the animate function and rotate the image components you desire to "move":
import Graphics.Gloss
main = animate (InWindow "Gloss" (700,700) (0,0))
black picture
picture :: Float -> Picture
picture 0 = text "Value cannot be 0"
picture number = scale 6.5 6.5 (color rose $ drawpicture number)
orangered, orangered2, orangered3 :: Color
orangered = makeColor 1.0 0.251 0.0 0.7
orangered2 = makeColor 1.0 0.251 0.0 0.5
orangered3 = makeColor 1.0 0.251 0.0 0.3
intervalsmall = [0,11.25,22.5,33.75,45,56.25,67.5,78.75]
intervalbig = [0,22.5,45,67.5,90,112.5,135,157.5,180,202.5,225,247.5,270,292.5,315,337.5]
xlist = [2,4..50]
ylist = [0,2..48]
squares = pictures[rotate x (line [(-50,0),(0,50),(50,0),(0,-50),(-50,0)]) | x <- intervalsmall]
stars = pictures[rotate x ((pictures [line [(-8.5,0),(0,50),(8.5,0)],line[(0,50),(0,0)]])) | x <- intervalbig]
grid = pictures[line [(0,y),(x,50)] | x <- xlist, y <- ylist, x-y==2]
insidegrid = pictures[
translate 0 (-50) grid,
rotate 90 (translate 0 (-50) grid),
rotate 180 (translate 0 (-50) grid),
rotate 270 (translate 0 (-50) grid)]
rotVal :: Float -> Float
rotVal x = x - (x / (2*pi))
drawpicture :: Float -> Picture
drawpicture number = pictures [
rot $ color red (pictures [circle 50,circle 8.5]),
line [(-50,-50),(-50,50),(50,50),(50,-50),(-50,-50)],
rot $ squares,
rot $ scale 0.7 0.7 squares,
rot $ scale 0.49 0.49 squares,
rot $ scale 0.347 0.347 squares,
rot $ scale 0.242 0.242 squares,
rot $ color orange stars,
rot (color orange (scale 0.178 0.178 stars)),
rot (rotate 11.25 (scale 0.178 0.178 stars)),
translate (-50) 0 grid,
rotate 90 (Translate (-50) 0 grid),
rotate 180 (Translate (-50) 0 grid),
rotate 270 (Translate (-50) 0 grid),
rot $ color orangered insidegrid,
rot $ color orangered2 (rotate 45 insidegrid),
rot $ color orangered3 (rotate 22.5 insidegrid),
rot $ color orangered3 (rotate 67.5 insidegrid)
]
where rot = rotate (rotVal number)
It is too much to write out all for you but you just have to add another argument to your picture function that is a Float and represents time. So display would be replaced by animate. So.
main = animate (InWindow "Gloss" (700,700) (0,0))
black (picture 100)
picture :: Float -> Float -> Picture
picture number time = -- whatever you have to do
You'll have to change your helping drawing functions to take this time param. Let's say you want to rotate the whole think once ever 5 seconds you can just multiply this time coming in and get an angle angle = time*(pi*2/5) then you can use this angle for trig functions to calculate new x and y positions from the center.

Resources