The array comprehension is just a for
loop. For each pixel x
in the image, we will run some function.
julia> const corgi_url = "https://user-images.githubusercontent.com/6933510/107239146-dcc3fd00-6a28-11eb-8c7b-41aaf6618935.png"
"https://user-images.githubusercontent.com/6933510/107239146-dcc3fd00-6a28-11eb-8c7b-41aaf6618935.png"
julia> image = load(corgi_url);
julia> [println(x) for x in corgi];
RGB{N0f8}(0.157,0.141,0.106)
RGB{N0f8}(0.157,0.141,0.106)
RGB{N0f8}(0.157,0.141,0.106)
RGB{N0f8}(0.157,0.141,0.106)
RGB{N0f8}(0.145,0.129,0.094)
RGB{N0f8}(0.145,0.129,0.094)
RGB{N0f8}(0.145,0.129,0.094)
...
The above array comprehension is similar to the following loop.
values = []
for x in corgi
val = println(x)
push!(values, val)
end
return values
The function you (or ChatGPT) proposed has some issues.
function noisify(x::Number, s)
s = rand()*rand((1,-1))
noise = x+s
return noise
end
The above function ignores the argument s
. It also does not generate a random value between -s
and s
.
In Julia, you can generate a random integer between s
and -s
as follows:
julia> let s = 5
rand(-s:s)
end
-3
julia> let s = 5
rand(-s:s)
end
-4
julia> let s = 5
rand(-s:s)
end
-1
julia> let s = 5
rand(-s:s)
end
-4
julia> let s = 5
rand(-s:s)
end
5
I’m not sure what image
is your in space, but it appears to be a simple matrix of numbers rather than a matrix of RGB values. A matrix of numbers can be interpreted as a gray scale image going from 0 (black) to 1 (white).
The slider above suggests that s
is a a floating point value (Float64) between 0 and 1. Thus it seems we do not want an integer between -s and s but a floating point value in that range.
rand()
by itself will return a pseudo-random floating point value between 0
and 1
. Let’s manipulate this to be a value between -1
and 1
. First, let’s multiply this rand()
by 2
. Now we have a psuedo-random number between 0
and 2
.
julia> [rand()*2 for x in 1:5]
5-element Vector{Float64}:
0.29105644396254204
0.4805402794429039
0.7185490585199521
1.0051175366207994
1.8548283774237921
Second, let’s subtract one so that the range of the psuedo-random number is between -1
and 1
.
julia> [rand()*2-1 for x in 1:5]
5-element Vector{Float64}:
-0.7154356748800863
0.5931495061220962
-0.5112898446445013
0.5877524288483504
-0.39967985881552304
Third, let’s scale this so that the random values are between -s
and s
. To do so, we just multiply the above result by s
:
julia> let s = 0.5
[s*(rand()*2-1) for x in 1:5]
end
5-element Vector{Float64}:
0.010240801151369938
0.3113220164047772
0.42303223201915907
-0.22238035973003045
-0.322278836649768
The homework assignment suggests clamp
.
function noisify(x::Number, s)
noise = s*(rand()*2-1)
return clamp(x + noise, 0, 1)
end
We can apply that function direct to values to generate “nosified” values.
julia> [noisify(x,0.1) for x in 0:0.1:1]
11-element Vector{Float64}:
0.04185649966271443
0.059601413880822074
0.17569873187297833
0.23385349040162423
0.37913057544096834
0.5253420496055848
0.5290349279141047
0.6933767312224085
0.8389770893749297
0.9442019869910827
0.9293120465194884
To noisify
the image, however, you need to write a version of noisify for RGB values. I’m not going to describe exactly how to do this part since it’s the homework assignment, but I’m to describe how to work with RGB values.
Below I extract the first pixel of the image and find it’s red, green, and blue values.
julia> px = image[1] # get the first pixel
RGB{N0f8}(0.157,0.141,0.106)
julia> px.r
0.157N0f8
julia> px.g
0.141N0f8
julia> px.b
0.106N0f8
Notice that I can apply the noisify
function above.
julia> noisify(px.r, 0.1)
0.10024330653215385
julia> noisify(px.g, 0.1)
0.2120751894938211
julia> noisify(px.b, 0.1)
0.0671814168720399
I can then create a new RGB value in the following way.
julia> noisified_px = RGB{N0f8}(
noisify(px.r, 0.1),
noisify(px.g, 0.1),
noisify(px.b, 0.1)
)
RGB{N0f8}(0.188,0.149,0.122)
You’ll notice that you cannot apply noisify
direct to the pixel:
julia> noisify(px, 0.1)
ERROR: MethodError: no method matching noisify(::RGB{N0f8}, ::Float64)
Closest candidates are:
noisify(::Number, ::Any)
@ Main REPL[139]:1
To do so, you need to define noisify
as follows:
function noisify(px::RGB, s)
# create a noisified RGB value
# return the value
end
When complete, then you can do the following:
julia> noisify(px, 0.1)
RGB{N0f8}(0.255,0.09,0.078)
julia> noisify(px, 0.1)
RGB{N0f8}(0.063,0.11,0.161)
Finally, then you can use the array comprehension.
julia> [noisify(x,0.1) for x in image]
864×700 Array{RGB{N0f8},2} with eltype RGB{N0f8}:
RGB{N0f8}(0.239,0.055,0.137) … RGB{N0f8}(0.78,0.655,0.706)
RGB{N0f8}(0.078,0.075,0.188) RGB{N0f8}(0.604,0.729,0.765)
...