Is it possible to get principal point from a projection matrix? - matrix

Is it possible to get principal point (cx, cy) from a 4x4 projection matrix? This is the same matrix asked in this question: Getting focal length and focal point from a projection matrix
(SCNMatrix4)
s = (m11 = 1.83226573,
m12 = 0,
m13 = 0,
m14 = 0,
m21 = 0,
m22 = 2.44078445,
m23 = 0,
m24 = 0,
m31 = -0.00576340035,
m32 = -0.0016724075,
m33 = -1.00019991,
m34 = -1,
m41 = 0,
m42 = 0,
m43 = -0.20002,
m44 = 0)
The values I'm trying to calculate in this 3x3 camera matrix is x0 and y0.

I recently confronted this problem, and quite astonished I couldn't find a relevant solution on Internet, because it seems to be a simple mathematics problem.
After a few days of struggling with matrices, I found a solution.
Let's define two Cartesian coordinate system, the camera coordinate system with x', y', z' axes, and the world coordinate system with x, y, z axes. The camera(or the eye) is positioned at the origin of the camera coordinate system and the image plane(a plane containing the screen) is z' = -n, where n is the focal length and the focal point is the position of the camera. I am using the convention of OpenGL and n is the nearVal argument of the glFrustum().
You can define a 4x4 transformation matrix M in a homogeneous coordinate system to deal with a projection. The M transforms a coordinate (x, y, z) in the world coordinate system into a coordinate (x', y', z') in the camera coordinate system like the following, where # means a matrix multiplication.
[
[x_prime_h],
[y_prime_h],
[z_prime_h],
[w_prime_h],
] = M # [
[x_h],
[y_h],
[z_h],
[w_h],
]
[x, y, z] = [x_h, y_h, z_h] / w_h
[x_prime, y_prime, z_prime] = [x_prime_h, y_prime_h, z_prime_h] / w_prime_h
Now assume you are given M = P V, where P is a perspective projection matrix and V is a view transformation matrix. The theoretical projection matrix is like the following.
P_theoretical = [
[n, 0, 0, 0],
[0, n, 0, 0],
[0, 0, n, 0],
[0, 0, -1, 0],
]
In OpenGL, an augmented matrix like the following is used to cover the normalization and nonlinear scaling on z coordinates, where l, r, b, t, n, f are the left, right, bottom, top, nearVal, farVal arguments of the glFrustum().(The resulting z' coordinate is not actually the coordinate of a projected point, but a value used for Z-buffering.)
P = [
[2*n/(r-l), 0, (r+l)/(r-l), 0],
[0, 2*n/(t-b), (t+b)/(t-b), 0],
[0, 0, -(f+n)/(f-n), -2*n*f/(f-n)],
[0, 0, -1, 0],
]
The transformation V is like the following, where r_ij is the element at i-th row and j-th column of the 3x3 rotational matrix R and (c_0, c_1, c_2) is the coordinate of the camera.
V = [
[r_00, r_01, r_02, -(r_00*c_0 + r_01*c_1 + r_02*c_2)],
[r_10, r_11, r_12, -(r_10*c_0 + r_11*c_1 + r_12*c_2)],
[r_20, r_21, r_22, -(r_20*c_0 + r_21*c_1 + r_22*c_2)],
[0, 0, 0, 1],
]
The P and V can be represented with block matrices like the following.
C = [
[c_0],
[c_1],
[c_2],
]
A = [
[2*n/(r-l), 0, (r+l)/(r-l)],
[0, 2*n/(t-b), (t+b)/(t-b)],
[0, 0, -(f+n)/(f-n)],
]
B = [
[0],
[0],
[-2*n*f/(f-n)],
]
P = [
[A,B],
[[0, 0, -1], [0]],
]
V = [
[R, -R # C],
[[0, 0, 0], [1]],
]
M = P # V = [
[A # R, -A # R # C + B],
[[0, 0, -1] # R, [0, 0, 1] # R # C],
]
Let m_ij be the element of M at i-th row and j-th column. Taking the first element of the second row of the above block notation of M, you can solve for the elementary z' vector of the camera coordinate system, the opposite direction from the camera point to the intersection point between the image plane and its normal line passing through the focal point.(The intersection point is the principal point.)
e_z_prime = [0, 0, 1] # R = -[m_30, m_31, m_32]
Taking the second column of the above block notation of M, you can solve for C like the following, where inv(X) is an inverse of a matrix X.
C = - inv([
[m_00, m_01, m_02],
[m_10, m_11, m_12],
[m_30, m_31, m_32],
]) # [
[m_03],
[m_13],
[m_33],
]
Let p_ij be the element of P at i-th row and j-th column.
Now you can solve for p_23 = -2nf/(f-n) like the following.
B = [
[m_03],
[m_13],
[m_23],
] + [
[m_00, m_01, m_02],
[m_10, m_11, m_12],
[m_20, m_21, m_22],
] # C
p_23 = B[2] = m_23 + (m_20*c_0 + m_21*c_1 + m_22*c_2)
Now using the fact p_20 = p_21 = 0, you can get p_22 = -(f+n)/(f-n) like the following.
p_22 * e_z_prime = [m_20, m_21, m_22]
p_22 = -(m_20*m_30 + m_21*m_31 + m_22*m_32)
Now you can get n and f from p_22 and p_23 like the following.
n = p_23/(p_22-1)
= -(m_23 + m_20*c_0+m_21*c_1+m_22*c_2) / (m_20*m_30+m_21*m_31+m_22*m_32 + 1)
f = p_23/(p_22+1)
= -(m_23 + m_20*c_0+m_21*c_1+m_22*c_2) / (m_20*m_30+m_21*m_31+m_22*m_32 - 1)
From the camera position C, the focal length n and the elementary z' vector e_z_prime, you can get the principal point, C - n * e_z_prime.
As a side note, you can prove the input matrix of inv() in the formula for getting C is nonsingular. And you can also find elementary x' and y' vectors of the camera coordinate system, and find the l, r, b, t using these vectors.(There will be two valid solutions for the (e_x_prime, e_y_prime, l, r, b, t) tuple, due to the symmetry.) And finally this solution can be expanded when the transformation matrix is mixed with the world transformation which does an anisotropic scaling, that is when M = P V W and W can have unequal eigenvalues.

Related

Biggest non-contiguous submatrix with all ones

I'm tackling the problem of finding a non-contiguous submatrix of a boolean matrix with maximum size such that all of its cells are ones.
As an example, consider the following matrix:
M = [[1, 0, 1, 1],
[0, 0, 1, 0],
[1, 1, 1, 1]]
A non-contiguous submatrix of M is specified as a set of rows R and a set of columns C. The submatrix is formed by all the cells that are in some row in R and in some column in C (the intersections of R and C). Note that a non-contiguous submatrix is a generalization of a submatrix, so any (contiguous) submatrix is also a non-contiguous submatrix.
There is one maximum non-contiguous submatrix of M that has a one in all of its cells. This submatrix is defined as R={1, 3, 4} and C={1, 3}, which yields:
M[1, 2, 4][1, 3] = [[1, 1, 1],
[1, 1, 1]]
I'm having difficulties finding existing literature about this problem. I'm looking for efficient algorithms that don't necessarily need to be optimal (so I can relax the problem to finding maximal size submatrices). Of course, this can be modeled with integer linear programming, but I want to consider other alternatives.
In particular, I want to know if this problem is already known and covered by the literature, and I want to know if my definition of non-contiguous matrix makes sense and whether already exists a different name for them.
Thanks!
Since per your response to Josef Wittmann's comment you want to find the Rectangle Covering Number, my suggestion would be to construct the Lovász–Saks graph and apply a graph coloring algorithm.
The Lovász–Saks graph has a vertex for each 1 entry in the matrix and an edge between each pair of vertices whose 2x2 matrix contains a zero. In your example,
[[1, 0, 1, 1],
[0, 0, 1, 0],
[1, 1, 1, 1]]
we can label the 1s with letters:
[[a, 0, b, c],
[0, 0, d, 0],
[e, f, g, h]]
and then get edges
a--d, a--f, b--f, c--d, c--f, d--e, d--f, d--h.
a b a 0 0 b b c 0 c 0 d 0 d d 0
0 d e f f g d 0 f h e f f g g h
I think an optimal coloring is
{a, b, c, e, g, h} -> 1
{d} -> 2
{f} -> 3.

Problem using For loop inside module to iterate over permutations

I am trying to write some code to extract all the different subgraphs of a given size from a random graph by creating all the possible permutations of vertices and drawing the subgraph with each of those vertices. However when I attempt to use a For loop to do this, it only draws the first subgraph. I am not very familiar with Mathematica so I am not sure where the issue is.
The individual components that creates the random graph and the list of permutations works, it is only when put together in the loop that it fails to work.
Module creates random graph with n points and edge probability p
G[n_, p_] := Module[{A, M}, A = Table[If[i < j, If[RandomReal[] < p, 1, 0], 0], {i, 1, n}, {j, 1, n}];
M = A + Transpose[A];
Return[AdjacencyGraph[M]];]
Function to find all the subgraphs of G(n,p) with d vertices
Subcount[n_, p_, d_] :=
Module[{i, ex, per, sub1}, ex = G[n, p]; per = Permutations[Range[n], {d}];
For[i = 1, i <= Length[per] , i++, Print[i];
sub1 = HighlightGraph[ex, Subgraph[ex, Part[per, i]]];
Return[sub1]];]
Tested with n =5, p = 0.4, d = 3
Subcount[5, 0.4, 3]
https://imgur.com/10jv51R
Gives the output seen through an example test.
Try this
Subcount[n_, p_, d_] := Module[{i, ex, per, sub1},
ex = G[n, p];
per = Permutations[Range[n], {d}];
Table[{i,{HighlightGraph[ex, Subgraph[ex, Part[per, i]]]}},{i,Length[per]}]];
Subcount[5, 0.4, 3]
which should show you all 60 graphs.

Matrix derivative doesn't get evaluated

I'm trying to evaluate the partial derivative of the most general 3D rotation matrix, like this:
phi, psi, theta = sympy.symbols("phi, psi, theta")
RMatrixPhi = sympy.Matrix([[cos(phi), sin(phi), 0],
[-sin(phi), cos(phi), 0],
[0, 0, 1]])
RMatrixPsi = sympy.Matrix([[cos(psi), 0, sin(psi)],
[0, 1, 0 ],
[-sin(psi), 0, cos(psi)]])
RMatrixTheta = sympy.Matrix([[1, 0, 0 ],
[0, cos(theta), sin(theta)],
[0, -sin(theta), cos(theta) ]])
RMatrix = RMatrixPhi * RMatrixPsi * RMatrixTheta
D = diff(RMatrix, phi)
However,D is then a sympy.Derivative object, and I cannot get it evaluated,
it's just printed out as Derivative(Matrix(...))
The only way I could get it working is by writing
sympy.Matrix([sympy.diff(r, phi) for r in RMatrix]).reshape(3,3)
but that looks ugly. What's the right way to compute such derivatives?
The Matrix class has a method called diff which, according to the documentation ...
Docstring:
Calculate the derivative of each element in the matrix.
So use
RMatrix.diff(phi)
to perform element-wise derivation.

Matlab: Material on image color processing [duplicate]

I have a image(png format) in hand. The lines that bound the ellipses (represent the nucleus) are over straight which are impractical. How could i extract the lines from the image and make them bent, and with the precondition that they still enclose the nucleus.
The following is the image:
After bending
EDIT: How can i translate the Dilation And Filter part in answer2 into Matlab language? I can't figure it out.
Ok, here is a way involving several randomization steps needed to get a "natural" non symmetrical appearance.
I am posting the actual code in Mathematica, just in case someone cares translating it to Matlab.
(* A preparatory step: get your image and clean it*)
i = Import#"http://i.stack.imgur.com/YENhB.png";
i1 = Image#Replace[ImageData[i], {0., 0., 0.} -> {1, 1, 1}, {2}];
i2 = ImageSubtract[i1, i];
i3 = Inpaint[i, i2]
(*Now reduce to a skeleton to get a somewhat random starting point.
The actual algorithm for this dilation does not matter, as far as we
get a random area slightly larger than the original elipses *)
id = Dilation[SkeletonTransform[
Dilation[SkeletonTransform#ColorNegate#Binarize#i3, 3]], 1]
(*Now the real random dilation loop*)
(*Init vars*)
p = Array[1 &, 70]; j = 1;
(*Store in w an image with a different color for each cluster, so we
can find edges between them*)
w = (w1 =
WatershedComponents[
GradientFilter[Binarize[id, .1], 1]]) /. {4 -> 0} // Colorize;
(*and loop ...*)
For[i = 1, i < 70, i++,
(*Select edges in w and dilate them with a random 3x3 kernel*)
ed = Dilation[EdgeDetect[w, 1], RandomInteger[{0, 1}, {3, 3}]];
(*The following is the core*)
p[[j++]] = w =
ImageFilter[ (* We apply a filter to the edges*)
(Switch[
Length[#1], (*Count the colors in a 3x3 neighborhood of each pixel*)
0, {{{0, 0, 0}, 0}}, (*If no colors, return bkg*)
1, #1, (*If one color, return it*)
_, {{{0, 0, 0}, 0}}])[[1, 1]] (*If more than one color, return bkg*)&#
Cases[Tally[Flatten[#1, 1]],
Except[{{0.`, 0.`, 0.`}, _}]] & (*But Don't count bkg pixels*),
w, 1,
Masking -> ed, (*apply only to edges*)
Interleaving -> True (*apply to all color chanels at once*)]
]
The result is:
Edit
For the Mathematica oriented reader, a functional code for the last loop could be easier (and shorter):
NestList[
ImageFilter[
If[Length[#1] == 1, #1[[1, 1]], {0, 0, 0}] &#
Cases[Tally[Flatten[#1, 1]], Except[{0.` {1, 1, 1}, _}]] & , #, 1,
Masking -> Dilation[EdgeDetect[#, 1], RandomInteger[{0, 1}, {3, 3}]],
Interleaving -> True ] &,
WatershedComponents#GradientFilter[Binarize[id,.1],1]/.{4-> 0}//Colorize,
5]
What you have as input is the Voronoi diagram. You can recalculate it using another distance function instead of the Euclidean one.
Here is an example in Mathematica using the Manhattan Distance (i3 is your input image without the lines):
ColorCombine[{Image[
WatershedComponents[
DistanceTransform[Binarize#i3,
DistanceFunction -> ManhattanDistance] ]], i3, i3}]
Edit
I am working with another algorithm (preliminary result). What do you think?
Here is what I came up with, it is not a direct translation of #belisarius code, but should be close enough..
%# read image (indexed image)
[I,map] = imread('http://i.stack.imgur.com/YENhB.png');
%# extract the blobs (binary image)
BW = (I==1);
%# skeletonization + dilation
BW = bwmorph(BW, 'skel', Inf);
BW = imdilate(BW, strel('square',2*1+1));
%# connected components
L = bwlabel(BW);
imshow(label2rgb(L))
%# filter 15x15 neighborhood
for i=1:13
L = nlfilter(L, [15 15], #myFilterFunc);
imshow( label2rgb(L) )
end
%# result
L(I==1) = 0; %# put blobs back
L(edge(L,'canny')) = 0; %# edges
imshow( label2rgb(L,#jet,[0 0 0]) )
myFilterFunc.m
function p = myFilterFunc(x)
if range(x(:)) == 0
p = x(1); %# if one color, return it
else
p = mode(x(x~=0)); %# else, return the most frequent color
end
end
The result:
and here is an animation of the process:

Affine transformation algorithm

Does anyone know of any standard algorithms to determine an affine transformation matrix based upon a set of known points in two co-ordinate systems?
Affine transformations are given by 2x3 matrices. We perform an affine transformation M by taking our 2D input (x y), bumping it up to a 3D vector (x y 1), and then multiplying (on the left) by M.
So if we have three points (x1 y1) (x2 y2) (x3 y3) mapping to (u1 v1) (u2 v2) (u3 v3) then we have
[x1 x2 x3] [u1 u2 u3]
M [y1 y2 y3] = [v1 v2 v3].
[ 1 1 1]
You can get M simply by multiplying on the right by the inverse of
[x1 x2 x3]
[y1 y2 y3]
[ 1 1 1].
A 2x3 matrix multiplied on the right by a 3x3 matrix gives us the 2x3 we want. (You don't actually need the full inverse, but if matrix inverse is available it's easy to use.)
Easily adapted to other dimensions. If you have more than 3 points you may want a least squares best fit. You'll have to ask again for that, but it's a little harder.
I'm not sure how standard it is, but there is a nice formula especially for your case presented in "Beginner's guide to mapping simplexes affinely" and "Workbook on mapping simplexes affinely".
Putting it into code should look something like this (sorry for bad codestyle -- I'm mathematician, not programmer)
import numpy as np
# input data
ins = [[1, 1, 2], [2, 3, 0], [3, 2, -2], [-2, 2, 3]] # <- points
out = [[0, 2, 1], [1, 2, 2], [-2, -1, 6], [4, 1, -3]] # <- mapped to
# calculations
l = len(ins)
B = np.vstack([np.transpose(ins), np.ones(l)])
D = 1.0 / np.linalg.det(B)
entry = lambda r,d: np.linalg.det(np.delete(np.vstack([r, B]), (d+1), axis=0))
M = [[(-1)**i * D * entry(R, i) for i in range(l)] for R in np.transpose(out)]
A, t = np.hsplit(np.array(M), [l-1])
t = np.transpose(t)[0]
# output
print("Affine transformation matrix:\n", A)
print("Affine transformation translation vector:\n", t)
# unittests
print("TESTING:")
for p, P in zip(np.array(ins), np.array(out)):
image_p = np.dot(A, p) + t
result = "[OK]" if np.allclose(image_p, P) else "[ERROR]"
print(p, " mapped to: ", image_p, " ; expected: ", P, result)
This code recovers affine transformation from given points ("ins" transformed to "outs") and tests that it works.

Resources