How to convert Matrix of Ints into image

I have a matrix of Ints. I’m using it for semantic classification so each pixel is a groundtruth label value, e.g.

(10,20)=3 where at coordinate 10,20 there is a pixel value 3 which is the class.

This ground truth label will be used in UNet. I’m wondering how to convert this matrix into a ‘Target Image’ for UNet. I’ve looked at Get an image from a matrix of signed integers `

imadjustintensity(Float64.(gt), extrema(gt))

` but its very indistinguishable for different classes, they are all a shade of similar gray. Could/Should I enhance it? Is there a better way than converting to float?

With Plots.jl, see if the following heatmap example with 10 classes can help:

using Plots
n = 10
M = rand(1:n,20,20)
dc = distinguishable_colors(n)
heatmap(M, color=palette(dc, n), lims=(0.5,20.5), ratio=1, clims=(0.5,n+0.5))

3 Likes

You can try the AstroImages.jl function imview. It takes any matrix and an optional Color scheme and converts directly to an image without going through Plots. It should have nice normalization by default or you can tweak contrast etc.

You can also do this with only the standard Images package:

using Images
matrix = rand(1:10, 20, 20)
scheme = rand(RGB, 10) # specify your colouring here

img = scheme[matrix]

download

In a Jupyter or Pluto notebook you will see the image as the return value. You can save to a file with

save("output.png", img)

Thanks, I tried but I got an error ‘Segmentation fault’

Plots.jl version used and size of matrix?

Matrx is size

(5041, 6001)

type Matrix{Int64} (alias for Array{Int64, 2})
and Plots.jl v1.31.5

I tried it, but got the following error? The maximum label is n=28

julia> img=scheme[gt_mat]
ERROR: BoundsError: attempt to access 28-element Array{RGB{Float64},1} with eltype RGB{Float64} at index [[0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0]]
Stacktrace:
 [1] throw_boundserror(A::Vector{RGB{Float64}}, I::Tuple{Matrix{Int64}})
   @ Base ./abstractarray.jl:651
 [2] checkbounds
   @ ./abstractarray.jl:616 [inlined]
 [3] _getindex
   @ ./multidimensional.jl:831 [inlined]
 [4] getindex(A::Vector{RGB{Float64}}, I::Matrix{Int64})
   @ Base ./abstractarray.jl:1170
 [5] top-level scope
   @ REPL[24]:1
 [6] top-level scope
   @ ~/.julia/packages/CUDA/DfvRa/src/initialization.jl:52

gt_mat should be an array of integers equal to or greater than 1 (and less than scheme’s length). Otherwise you’ll be indexing arrays with 0…

If you write a function label_color(label) which takes your labels — whether they start at zero or whatever else — you can convert your integer matrix to a colour matrix with:

img = [label_color(label) for label in gt_mat]

This array comprehension preserves the shape of the matrix, so produces a matrix of colours.


For example, you might use a dictionary:

julia> using Plots: distinguishable_colors

julia> scheme = Dict(0:28 .=> distinguishable_colors(29));

julia> img = [scheme[label] for label in gt_mat];
1 Like

Yes, I missed that. Thank you big time

1 Like

label_color
So this color label is fixed everytime a new image is colored ? e.g. from 0-28 each label has a fixed color or is it randomly generated?

Using same Plots.jl version, Julia 1.7.3 on Win11, no problem to display such matrix with ~30 million cells:

using Plots; gr(dpi=300)
n = 10
M = rand(1:n, 5041, 6001)
dc = distinguishable_colors(n)
heatmap(M, color=palette(dc,n), framestyle=:none, ratio=1, clims=(0.5,n+0.5))

But with so many pixels it might be difficult to read: