Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add matrix dimension with map()

Tags:

julia

I have a 2D array of colours in Julia

using Images

white = RGB{Float32}(1, 1, 1)
green = RGB{Float32}(0.1, 1, 0.1)
blue = RGB{Float32}(0, 0.1, 1)

A = [white white;
     green blue;
     blue blue]

I want to turn each RGB colour into a Array{Float32, 3} in the higher dimension. This is what I tried:

B = map(A) do a
  [a.r, a.g, a.b]
end

size(B) == (3, 2, 3)   # (rows, cols, channels)
# => false

Instead, B is a 2D-matrix of 1D-arrays.

Does Julia have a map-like method for expanding the dimensions of a matrix?

like image 651
liamdiprose Avatar asked Dec 31 '22 11:12

liamdiprose


2 Answers

You should use ImageCore's channelview instead:

julia> Av = channelview(A)
3×3×2 reinterpret(reshape, Float32, ::Array{RGB{Float32},2}) with eltype Float32:
[:, :, 1] =
 1.0  0.1  0.0
 1.0  1.0  0.1
 1.0  0.1  1.0

[:, :, 2] =
 1.0  0.0  0.0
 1.0  0.1  0.1
 1.0  1.0  1.0

The color channel is the first dimension (the fastest dimension). You can check that by setting some values and seeing the impact on the original, since Av is a view of A:

julia> Av[1,2,1] = -5
-5

julia> Av[1,2,2] = -10
-10

julia> A
3×2 Array{RGB{Float32},2} with eltype RGB{Float32}:
 RGB{Float32}(1.0,1.0,1.0)   RGB{Float32}(1.0,1.0,1.0)
 RGB{Float32}(-5.0,1.0,0.1)  RGB{Float32}(-10.0,0.1,1.0)
 RGB{Float32}(0.0,0.1,1.0)   RGB{Float32}(0.0,0.1,1.0)

In both cases we tweaked the red channel, because of using 1 as the first index.

like image 193
tholy Avatar answered Jan 02 '23 00:01

tholy


map doesn't work because it is elementwise, so it can only allocate an output with the same size as the input. It's not difficult to allocate your output array in this case:

function RGBtoT_loop(x::Array{RGB{T}, N}) where {T,N}
  # allocate output array without any (valid) instances
  result = Array{T, N+1}(undef, size(x)..., 3)
  # write RGB values into output array
  for i in CartesianIndices(x)
    result[i, 1] = x[i].r
    result[i, 2] = x[i].g
    result[i, 3] = x[i].b
  end
  result
end

EDIT: I figured out how to do the same thing by broadcasting the getfield method where getfield(RGBvalue, 1) is equivalent to RGBvalue.r. Interestingly, ndims(A) and thus the Tuple of ones is calculated at compile-time from A's type parameters, so this method ends up type-stable and only allocates 1 thing at run-time: the result array.

RGBtoT(x) = getfield.(x, reshape(1:3, ntuple(i->1, ndims(x))..., 3) )
like image 32
BatWannaBe Avatar answered Jan 02 '23 01:01

BatWannaBe