Replies: 1 comment 2 replies
-
It is unclear exactly what you want when you say you want to convert a RGB pixel to Float64. A The red, green, and blue components can be accessed as follows via the underlying package julia> using ColorTypes
julia> @which RGB
ColorTypes
julia> p = rand(RGB)
RGB{Float64}(0.6123750590186987,0.560934020985612,0.6942792994166388)
julia> red(p)
0.6123750590186987
julia> green(p)
0.560934020985612
julia> blue(p)
0.6942792994166388
julia> comp1(p), comp2(p), comp3(p)
(0.6123750590186987, 0.560934020985612, 0.6942792994166388) If you wanted a single value, perhaps the grayscale conversion of the RGB value, you might do the following. julia> gp = Gray(p) # convert(Gray, p)
0.5915162570283196
julia> gray(gp)
0.5915162570283196
julia> comp1(gp)
0.5915162570283196 The underlying implementation of struct RGBFloat64
r::Float64
g::Float64
b::Float64
end You can learn that from introspection. julia> fieldnames(typeof(p))
(:r, :g, :b)
julia> fieldtypes(typeof(p))
(Float64, Float64, Float64) Note that we have RGB types that have different layouts, but use a similar interface. julia> p24 = RGB24(p)
RGB24(0.612N0f8,0.561N0f8,0.694N0f8)
julia> red(p24)
0.612N0f8
julia> green(p24)
0.561N0f8
julia> blue(p24)
0.694N0f8
julia> fieldnames(typeof(p24))
(:color,)
julia> fieldtypes(typeof(p24))
(UInt32,) In either case, perhaps you would like to reduce such a pixel to a julia> p .|> (red,green,blue)
(0.6123750590186987, 0.560934020985612, 0.6942792994166388)
julia> p24 .|> (red,green,blue)
(0.612N0f8, 0.561N0f8, 0.694N0f8)
julia> p24 .|> (red,green,blue) .|> Float64
(0.611764705882353, 0.5607843137254902, 0.6941176470588235) For an image, I can generalize this using the broadcast notation. Note that this eagerly extracts the values and allocates new memory for the result. julia> img = rand(RGB, 2, 2)
2×2 Array{RGB{Float64},2} with eltype RGB{Float64}:
RGB{Float64}(0.491911,0.880987,0.430793) … RGB{Float64}(0.633592,0.168878,0.61858)
RGB{Float64}(0.962367,0.754885,0.873799) RGB{Float64}(0.839588,0.606721,0.685134)
julia> red.(img)
2×2 Matrix{Float64}:
0.491911 0.633592
0.962367 0.839588
julia> blue.(img)
2×2 Matrix{Float64}:
0.430793 0.61858
0.873799 0.685134
julia> green.(img)
2×2 Matrix{Float64}:
0.880987 0.168878
0.754885 0.606721 It may also be worth discussing the underlying Julia array facilities, in particular the julia> reinterpret(NTuple{3,Float64}, img)
2×2 reinterpret(Tuple{Float64, Float64, Float64}, ::Array{RGB{Float64},2}):
(0.491911, 0.880987, 0.430793) (0.633592, 0.168878, 0.61858)
(0.962367, 0.754885, 0.873799) (0.839588, 0.606721, 0.685134)
julia> reinterpret(reshape, Float64, img)
3×2×2 reinterpret(reshape, Float64, ::Array{RGB{Float64},2}) with eltype Float64:
[:, :, 1] =
0.491911 0.962367
0.880987 0.754885
0.430793 0.873799
[:, :, 2] =
0.633592 0.839588
0.168878 0.606721
0.61858 0.685134
julia> reinterpret(Float64, Gray.(img))
2×2 reinterpret(Float64, ::Array{Gray{Float64},2}):
0.713331 0.359093
0.830478 0.685288 The last output is essentially the same as what you get when you use To convert the lazy views to an actual memory allocation, you can use julia> reinterpret(reshape, Float64, img) |> collect
3×2×2 Array{Float64, 3}:
[:, :, 1] =
0.491911 0.962367
0.880987 0.754885
0.430793 0.873799
[:, :, 2] =
0.633592 0.839588
0.168878 0.606721
0.61858 0.685134
julia> reinterpret(reshape, Float64, img) |> copy
3×2×2 Array{Float64, 3}:
[:, :, 1] =
0.491911 0.962367
0.880987 0.754885
0.430793 0.873799
[:, :, 2] =
0.633592 0.839588
0.168878 0.606721
0.61858 0.685134 Regarding your julia> using MappedArrays, BenchmarkTools
julia> imageToFloatArray_lazy(img::Array{<:Colorant}) = mappedarray(p->gray(Gray(p)), img)
imageToFloatArray_lazy (generic function with 1 method)
julia> bigimg = rand(RGB, 1024, 1024);
julia> @btime imageToFloatArray($bigimg);
4.669 ms (2 allocations: 8.00 MiB)
julia> @btime imageToFloatArray_lazy($bigimg);
2.577 ns (0 allocations: 0 bytes) |
Beta Was this translation helpful? Give feedback.
-
TLDR; Is there a straightforward way to convert a single pixel to a numeric value? If not, could one please be implemented (and mentioned in the quickstart)?
Explanation:
This works:
channelview(rand(Gray,1))[1]
But this does not:
channelview(rand(Gray))
This works:
convert.(Float64,rand(Gray))
But this does not:
convert.(Float64,rand(RGB))
As far as I can tell, there is no uniform way to get the numeric value of a single pixel other than wrapping it in an array, applying
channelview
, and then subscripting. This seems weirdly discombobulated.More generally, Images.jl seems to try really hard to conceal the underlying numeric data in an image. I find this extremely irritating. I am a physicist, and a lot of my work consists in taking images of e.g. cold atomic gasses. Invariably, I don't really want to look at these images though, I just want to process them with my own custom numerical methods. (Concrete example: FFTW does not work on images with color values.) I would appreciate if the package made it easier to just "get in and out", importing an image and converting it to numerical values. If such methods exist, I would love for them to be mentioned in the quickstart. I have my own methods like
imageToFloatArray(img::Matrix) = convert.(Float64,Gray.(img))
that I frequently add to the beginning of my notebooks, but it would be better if there were such functions conspicuously built in to the package.Beta Was this translation helpful? Give feedback.
All reactions