I am new to Julia, and I am trying to understand basic data visualization. I am creating a 2D array of noise with:
xRange, yRange = 1:1:300, 1:1:300
maxVal = 0.3
noiseArr = rand(length(xRange),length(yRange))*maxVal
The resulting array is shown below (left). I would like to identify specific pixels -- defined by a rectangle with length, width, and rotation -- and set those values to a known number. Ultimately, I would like something like the image shown below (right).
I've no package preferences, but I've been looking at Images, OpenCV, etc. I'm hoping there's a straight-forward way to do this.
Create an array filled with the value x . For example, fill(1.0, (10,10)) returns a 10x10 array of floats, with each element initialized to 1.0 . If x is an object reference, all elements will refer to the same object. fill(Foo(), dims) will return an array filled with the result of evaluating Foo() once.
Julia provides a very simple notation to create matrices. A matrix can be created using the following notation: A = [1 2 3; 4 5 6]. Spaces separate entries in a row and semicolons separate rows. We can also get the size of a matrix using size(A).
Hello Julia: Learn the New Julia Programming Language In Julia, arrays are actually mutable type collections which are used for lists, vectors, tables, and matrices. That is why the values of arrays in Julia can be modified with the use of certain pre-defined keywords. With the help of push!
Here is a quick example of drawing it using primitives with Luxor.jl
using Luxor
function b()
Drawing(300, 300, "hello-world.png")
background("black")
sethue("white")
#Luxor.scale(1,1)
Luxor.translate(150, 30)
Luxor.rotate(10 * pi / 180)
w = 40
h = 200
rect(O, w, h, :fill)
finish()
preview()
end
Now, instead of drawing it directly with Luxor you can extract the transformation matrix and use it somewhere else.
using Plots
using GR
using LinearAlgebra
gr(size = (300, 300), legend = false)
function a(transform=Matrix{Int}(I, 3, 3))
side = 300
width = side
height = side
xs = [string("x", i) for i = 1:width]
ys = [string("y", i) for i = 1:height]
z = float((1:height) * reshape(1:width, 1, :))
# Plots.heatmap(xs, ys, z, aspect_ratio = 1)
white = maximum(z)
# Draw a rectangle with a rotation matrix applied
for x in 0:40
for y in 0:200
t = transform*[x;y;1]
z[round(Int, t[2]), round(Int, t[1])] = white
end
end
Plots.heatmap(xs, ys, z, aspect_ratio = 1)
end
using Luxor
function b()
Drawing(300, 300, "hello-world.png")
background("black")
sethue("white")
#Luxor.scale(1,1)
Luxor.translate(100, 60)
Luxor.rotate(-10 * pi / 180)
w = 40
h = 200
rect(O, w, h, :fill)
finish()
preview()
tranformation_matrix = Luxor.cairotojuliamatrix(Luxor.getmatrix())
a(tranformation_matrix)
end
Note this leaves stray pixels, because my for loop isn't efficient at rasterizing the fill. Accessing pixel data out of Luxor may be better, or using some other function that applies affine transformations to a matrix.
Caution about plots in julia:
Time to first plot is slow. And to do any real iterations on it, you should leverage Revise.jl
and save your test functions in a file and include it with includet("test.jl")
. Then your julia session is persistent and you only have to wait for your using
statements once.
I would like to identify specific pixels -- defined by a rectangle with length, width, and rotation
Knowing length, width and rotation is not enough to uniquely position a rectangle on a plane. You also need translation.
Here is a simple code that gives you an example what you can do (it is not super efficient, but is fast enough for demo purposes):
function rectangle!(x1, x2, x3, noiseArr, val)
A = [x2-x1 x3-x1]
b = x1
iA = inv(A)
for i in axes(noiseArr, 1), j in axes(noiseArr, 2)
it, jt = iA * ([i, j]-b)
0 <= it <= 1 && 0 <= jt <= 1 && (noiseArr[i, j] = val)
end
end
x1 = [40, 140]
x2 = [230, 100]
x3 = [50, 170]
rectangle!(x1, x2, x3, noiseArr, 0.0)
In it - instead of passing a rotation, scaling and translation I thought it is easier to assume you pass three vertices of the rectangle x1
, x2
, and x3
(assuming that its sides are formed by x1-x2
and x1-x3
pairs) and it calculates the affine transformation you need. val
is the value the pixels inside of the rectangle should get.
Note that essentially what we do is computing a reverse affine transformation of a rectangle back to a unit square and check which points lie within a unit square (which is easy).
(as commenters noted above - this is not an optimal way to do it as you do a lot of computations that are not needed, but I hope that it has the benefit of being easier to understand; also the benefit of Julia is that writing of such a loop is not a problem and it still runs fast enough)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With