Perspective warp an image in Julia - julia

I have an image and a 3x3 perspective projection matrix M. How do I apply the transform on the image?
I tried to use the warp(img, tform) function but don't know how to construct the transform object from the matrix.
Tried tform = PerspectiveMap() ∘ inv(LinearMap(M)), no idea if this is a correct to create the transform, but it fails with:
ERROR: Inverse transformation for CoordinateTransformations.PerspectiveMap has not been defined.

There are two components to the answer:
You have to define a transformation that takes a 2-vector to a 2-vector
If the transformation isn't invertible, then you have to specify the range of indices of the final image manually.
For the first, the following suffices:
julia> using StaticArrays, CoordinateTransformations
julia> M = #SMatrix [1 0 0; 0 1 0; -1/1000 0 1] # a 3x3 perspective transformation matrix
3×3 StaticArrays.SArray{Tuple{3,3},Float64,2,9}:
1.0 0.0 0.0
0.0 1.0 0.0
-0.001 0.0 1.0
julia> tform = PerspectiveMap() ∘ inv(LinearMap(M))
(CoordinateTransformations.PerspectiveMap() ∘ LinearMap([1.0 0.0 0.0; -0.0 1.0 0.0; 0.001 -0.0 1.0]))
julia> tform(#SVector([1,1,1])) # this takes a 3-vector as input and returns a 2-vector
2-element SVector{2,Float64}:
0.999001
0.999001
julia> push1(x) = push(x, 1)
push1 (generic function with 1 method)
julia> tform2 = PerspectiveMap() ∘ inv(LinearMap(M)) ∘ push1 # here's one that takes a 2-vector as input (appends 1 to the 2-vector)
(::#55) (generic function with 1 method)
julia> tform2(#SVector([1,1]))
2-element SVector{2,Float64}:
0.999001
0.999001
Now let's try this on an image. We'll create an output image that has the same indices as the input image, although you can choose any indices you want:
julia> using Images, TestImages
julia> img = testimage("lighthouse");
julia> imgw = warp(img, tform2, indices(img)); # 3rd argument sets the indices
julia> using ImageView
julia> imshow(imgw)
img looks like this:
and imgw looks like this:

Related

Using quadgk() after a real() function in Julia

when I want to extract a real part of g(x) and integrate a new function g1(x), the result b contains a Vector {Float 64} rather than just a number. How to get its integrated result?
Here is the code
g(x) = (exp.(-x).^2).*exp.(1im*x)
R_initial=real(g(x));
g1(x)= R_initial
b = quadgk(g1,0.6,0.7)
c = b[1]
Just do the following:
julia> g(x) = real((exp(-x)^2)*exp(1im*x))
g (generic function with 1 method)
julia> quadgk(g,0.6,0.7)
(0.021750435727577098, 3.469446951953614e-18)
In your code:
R_initial=real(g(x))
takes some global value of x that you probably have and R_initial is bound to some value. So you get something like:
julia> R_initial = [1.0, 2.0]
2-element Vector{Float64}:
1.0
2.0
julia> g1(x) = R_initial
g1 (generic function with 1 method)
julia> quadgk(g1,0.6,0.7)
([0.09999999999999998, 0.19999999999999996], 0.0)
which produces a vector in the first element as the input is multi-dimensional. Note that g1 is just a constant function.

Evaluate vectors or tuples in a function (julia)

I want to evaluate a set of vectors (or tuples) in a function $f$ but Julia says me that is imposible.
For example: If I have an array of tuples p=[(1,1), (1,-1), (-1,1), (-1,-1)] and a function f(x,y)=x+y. I would like to calculate f(p[1]) = f(1,1)= 2. But Julia says me that the types are incompatible.
Can you help me please?
You have to splat a tuple like this:
julia> p=[(1,1), (1,-1), (-1,1), (-1,-1)]
4-element Array{Tuple{Int64,Int64},1}:
(1, 1)
(1, -1)
(-1, 1)
(-1, -1)
julia> f(x,y)=x+y
f (generic function with 1 method)
julia> f(p[1]...)
2
you could also define a higher order function splat that would conveniently wrap any function and perform splatting. It is useful as then you can e.g. broadcast such function:
julia> splat(f) = x -> f(x...)
splat (generic function with 1 method)
julia> splat(f)(p[1])
2
julia> splat(f).(p)
4-element Array{Int64,1}:
2
0
0
-2
Alternatively you can define your function f like this:
julia> f((x,y),)=x+y
f (generic function with 1 method)
julia> f(p[1])
2
and now you do not have to do splatting.
Just use the ... operator to unpack the tuple as parameters:
julia> f(p[1]...)
2
In addition to other answers, if your task allows you, you can just define
julia> f(x) = f(x...)
and use it as
julia> f.(p)
4-element Vector{Int64}:
2
0
0
-2

I want to find the number which act to 0 of Julia - I mean the nearest number of 0

Why does this happen in Julia?
My input is
A = []
for i = 17:21
t = 1/(10^(i))
push!(A, t)
end
return(A)
And the output was:
5-element Array{Any,1}:
1.0e-17
1.0e-18
-1.1838881245526248e-19
1.2876178137472069e-19
2.5800991659088344e-19
I observed that
A[3]>0
false
I want to find the number which act to 0 of Julia, but I found this and don’t understand.
The reason for this problem is when you have i = 19, note that then:
julia> 10^19
-8446744073709551616
and it is unrelated to floating point numbers, but is caused by Int64 overflow.
Here is the code that will work as you expect. Either use 10.0 instead of 10 as 10.0 is a Float64 value:
julia> A=[]
Any[]
julia> for i=17:21
t=1/(10.0^(i))
push!(A,t)
end
julia> A
5-element Array{Any,1}:
1.0e-17
1.0e-18
1.0e-19
1.0e-20
1.0e-21
or using high precision BigInt type that is created using big(10)
julia> A=[]
Any[]
julia> for i=17:21
t=1/(big(10)^(i))
push!(A,t)
end
julia> A
5-element Array{Any,1}:
9.999999999999999999999999999999999999999999999999999999999999999999999999999967e-18
9.999999999999999999999999999999999999999999999999999999999999999999999999999997e-19
9.999999999999999999999999999999999999999999999999999999999999999999999999999997e-20
1.000000000000000000000000000000000000000000000000000000000000000000000000000004e-20
9.999999999999999999999999999999999999999999999999999999999999999999999999999927e-22
You can find more discussion of this here https://docs.julialang.org/en/v1/manual/integers-and-floating-point-numbers/#Overflow-behavior.
For example notice that (which you might find surprising not knowing about the overflow):
julia> x = typemin(Int64)
-9223372036854775808
julia> x^2
0
julia> y = typemax(Int64)
9223372036854775807
julia> y^2
1
Finally to find smallest positive Float64 number use:
julia> nextfloat(0.0)
5.0e-324
or
julia> eps(0.0)
5.0e-324

Julia - console behaving differently than include("myfile.jl")

I would like to execute the following code, which works perfectly well when I type every line into my Julia console on Windows 10, but throws an error because of the mismatching type LinearAlgebra.Adjoint{Float64,Array{Float64,2}} (my subsequent code expects Array{Float64,2}).
This is the code:
x = [0.2, 0.1, 0.2]
y = [-0.5 0.0 0.5]
fx = x * y
fy = fx'
return fx::Array{Float64,2}, fy::Array{Float64,2}
There is a TypeError, because fy seems to be of type LinearAlgebra.Adjoint{Float64,Array{Float64,2}} instead of Array{Float64,2}.
How can I do a transpose and get a "normal" Array{Float64,2} object ?
And why does this work when I type every line into my Julia console, but does not when I run the file via include("myfile.jl") ?
Use collect to have a copy of actual data rather than a transformed view of the original (note that this rule applies to many other similar situations):
julia> x = [0.2, 0.1, 0.2];
julia> y = [-0.5 0.0 0.5];
julia> fx = x * y
3×3 Array{Float64,2}:
-0.1 0.0 0.1
-0.05 0.0 0.05
-0.1 0.0 0.1
julia> fy = fx'
3×3 LinearAlgebra.Adjoint{Float64,Array{Float64,2}}:
-0.1 -0.05 -0.1
0.0 0.0 0.0
0.1 0.05 0.1
julia> fy = collect(fx')
3×3 Array{Float64,2}:
-0.1 -0.05 -0.1
0.0 0.0 0.0
0.1 0.05 0.1
To get a normal Matrix{Float64} use:
fy = permutedims(fx)
or
fy = Matrix(fx')
Those two are not 100% equivalent in general as fx' is a recursive adjoint operation (conjugate transpose), while permutedims is a non-recursive transpose, but in your case they will give the same result.
What does recursive adjoint mean exactly?
recursive: the conjugate transpose is applied recursively to all entries of the array (in your case you have array of numbers and transpose of a number is the same number so this does not change anything);
adjoint: if you would have complex numbers then the operation would return their complex conjugates (in your case you have real numbers so this does not change anything);
Here is an example when both things matter:
julia> x = [[im, -im], [1-im 1+im]]
2-element Array{Array{Complex{Int64},N} where N,1}:
[0+1im, 0-1im]
[1-1im 1+1im]
julia> permutedims(x)
1×2 Array{Array{Complex{Int64},N} where N,2}:
[0+1im, 0-1im] [1-1im 1+1im]
julia> Matrix(x')
1×2 Array{AbstractArray{Complex{Int64},N} where N,2}:
[0-1im 0+1im] [1+1im; 1-1im]
However, unless you really need to you do not have to do it if you really need to get a conjugate transpose of your data. It is enough to change type assertion to
return fx::Array{Float64,2}, fy::AbstractArray{Float64,2}
or
return fx::Matrix{Float64}, fy::AbstractMatrix{Float64}
Conjugate transpose was designed to avoid unnecessary allocation of data and most of the time this will be more efficient for you (especially with large matrices).
Finally the line:
return fx::Array{Float64,2}, fy::Array{Float64,2}
throws an error also in the Julia command line (not only when run from a script).

How to append a vector to Julia matrix as a row?

I have an empty matrix initially:
m = Matrix(0, 3)
and a row that I want to add:
v = [2,3]
I try to do this:
[m v]
But I get an error
ERROR: ArgumentError: number of rows of each array must match
What's the proper way to do this?
That is because your matrix sizes don't match. Specifically v does not contain enough columns to match m. And its transposed
So this doesnt work
m = Matrix(0, 3)
v = [2,3]
m = cat(1, m, v) # or a = [m; v]
>> ERROR: DimensionMismatch("mismatch in dimension 2 (expected 3 got 1)")
whereas this does
m = Matrix(0, 3)
v = [2 3 4]
m = cat(1, m, v) # or m = [m; v]
>> 1x3 Array{Any,2}:
>> 2 3 4
and if you run it again it creates another row
m = cat(1, m, v) # or m = [m; v]
>> 2x3 Array{Any,2}:
>> 2 3 4
>> 2 3 4
Use the vcat (concatenate vertically) function:
help?> vcat
search: vcat hvcat VecOrMat DenseVecOrMat StridedVecOrMat AbstractVecOrMat levicivita is_valid_char #vectorize_2arg
vcat(A...)
Concatenate along dimension 1
Notice you have to transpose the vector v, ie. v', else you get a DimensionMismatch error:
julia> v = zeros(3)
3-element Array{Float64,1}:
0.0
0.0
0.0
julia> m = ones(3, 3)
3x3 Array{Float64,2}:
1.0 1.0 1.0
1.0 1.0 1.0
1.0 1.0 1.0
julia> vcat(m, v') # '
4x3 Array{Float64,2}:
1.0 1.0 1.0
1.0 1.0 1.0
1.0 1.0 1.0
0.0 0.0 0.0
julia> v' # '
1x3 Array{Float64,2}:
0.0 0.0 0.0
julia> vcat(m, v)
ERROR: DimensionMismatch("mismatch in dimension 2 (expected 3 got 1)")
in cat_t at abstractarray.jl:850
in vcat at abstractarray.jl:887
Note: the comments; # ' are there just to make syntax highlighting work well.
Isn't that Matrix creates a two-dimensional array in Julia? If you try with m =[0, 3], which creates a one-dimensional Vector for you, you can append it by [m; v].
I think using [m v] is create a two-dimensional array as well, from the Julia Document

Resources