Convert Packed Image Format into Planar Format without Dependency

I am loading images using FileIO.jl.

I want to convert the output into a Planar Format of the appropriate element type.
I want to achieve this without any farther dependencies, so channelview() as in Most idomatic way to convert an Images.jl Image to a 3-d array? is not available.

The problem I have is figuring and supporting all the different formats of used the by the Julia Images.

I don’t mind solving it in a brute force using a loop but I need to solve the following 2 sub problems:

  1. How to extract the number of channels given the image array.
  2. How to map the elements into the regular element types (UIntx and Floatx usually).

I am struggling with finding a robust and global solution to this.

For instance:

using FileIO;

img001Url = "https://i.stack.imgur.com/WsSFV.png";
mT = load(download(img001Url));

The type of mT is Matrix{RGBA{N0f8}} so it has 4 channels (RGBA -> 4) and uses UInt8 (N0f8 -> UInt8).
But sometimes there are Gray and N0f16 etc… So I wonder if there is something elegant to do here.

I got something like:

using ColorTypes;
using FileIO;

function ConvertJuliaImgArray001(mI :: Matrix{<: TransparentColor{C, T, N}}) where {C, T, N}
    
    numRows, numCols = size(mI);
    numChannels = N;
    dataType = T.types[1];

    if numChannels > 1
        mO = Array{dataType, 3}(undef, numRows, numCols, numChannels);
        for ii ∈ 1:numRows, jj ∈ 1:numCols
            for kk ∈ 1:numChannels
                mO[ii, jj, kk] = getfield(getfield(mI[ii, jj], kk), 1); #<! Accordign to ColorTypes data always in order RGBA
            end
        end
    else
        mO = Matrix{dataType}(undef, numRows, numCols);
        for ii ∈ 1:numRows, jj ∈ 1:numCols
            mO[ii, jj] = getfield(mI[ii, jj], 1);
        end
    end

    return mO;

end

Similarly I created for mI :: Matrix{<: Color{T, N}} and mI :: Matrix{<: Color{T, 1}}.
It requires ColorTypes.jl yet since it is a dependency of FileIO.jl I am OK with this.

What I’m not sure is about getfield(). Is there anything more robust or that is the correct way to access the data?

I would be tempted to start with reinterpret(dataType, mI) and go from there.

Edit: Or actually reinterpret(reshape, dataType, mI), which I just found out that it was added in Julia 1.6.

@GunnarFarneback , I think walking that path requires the function channelview().
Can you think a way to avoid it with the path you suggested?

In what way do you need channelview to make use of reinterpret? Is there some specific piece of information you’re missing?

As far as I know reshape() can not change the order in memory, only the strides.
Since images, by default in the Julia Images eco system, are in packed format (R1G1B1R2G2B3...) you can’t convert it into planar form (R1R2R3...G1G2G3...B1B2B3...).

If you have a code sample, I’d like to try.

I fail to see the difficulty so I guess I’m missing something. Do you want something significantly different from this?

x = rand(RGB{N0f16}, 4, 5)
y = permutedims(reinterpret(reshape, UInt16, x), (2, 3, 1))
1 Like

I tried it again and it worked.
I am not sure why I was under the impression channelview() is required.

Thank You.