I’m loading an RGB image from disk with JuicyPixels-repa. Unfortunately the Array representation of the image is Array F DIM3 Word8 where the inner dimension is the RGB pixels. That’s a bit incompatibe with existing repa imageprocessing algorithms where an RGB image is Array U DIM2 (Word8, Word8, Word8).
I want to calculate the RGB histograms of the image, I’m searching a function with the Signature:
type Hist = Array U DIM1 Int
histogram:: Array F DIM3 Word8 -> (Hist, Hist, Hist)
how can I fold my 3d array to get a 1d array for each colorchannel?
Edit:
The main problem is not that I’m not able to convert from DIM3 to DIM2 for each channel (easy done with slicing). The problem is that I have to iterate the source image DIM2 or DIM3 and have to accumulate to an DIM1 array of a different Shape (Z:.256) and extent.
So I can’t use repa’s foldS as it reduces the dimension by one, but with the same extent.
I also experimented with traverse but it iterates over the extent of the destination image, providing a function to get pixels from the source image, that would lead to very inefficient code, counting the same pixels for each colorvalue.
A good way would be a simple folding over a Vector with the histogram type as accumulator, but unfortunately I have no U (unboxed) or V (vector) based array, from which I can efficiently get a Vector. I have an Array F (foreign pointer).
Ok, I found a few minutes. Below, I cover four solutions and have made the worst solutions (the middle two, involving O(n) data conversion) really easy for you.
Lets Acknowledge the Dumb Solution
It’s reasonable to start with the obvious. You could use
Data.List.foldlto traverse the rows and columns, building up your histograms from initial zero arrays (untested/partial code follows):I’m not sure how efficient this will be, but suspect that it will do too much bounds checking. Switching to unsafeIndex should do reasonably, assuming the delayed arrays,
hist*, do well due to however you’d pick to implementincElem.You Can Build the Array You Want
Using
traverseyou can actually convert JP-Repa style arrays intoDIM2arrays with tuples for elements:Could you point me to the body of code you talked about that uses this format? It would be simple to patch JP-Repa to include a function of this type.
You can build the Unboxed Vector You Mentioned
You mentioned an easy solution is to fold over unboxed vectors, but lamented that JP-repa doesn’t provide an unboxed array. Luckily, conversion is simple:
We Could Patch Repa
This is really only a problem because Repa doesn’t have what I consider a normal
traversefunction. Repa’s traverse is more of an array construction that happens to provide an indexing function into another array. We want traverse in the form:but of coarse this is actually just a malformed fold. So lets rename it and reorder the arguments:
which contrasts nicely with the (preexisting)
foldAllSoperation:Notice how our new fold has two critical characteristics. The result type is not required to match the element type, so we could start with a tuple of Histograms. Second, our version of fold passes the index, which allows you to select which histogram in the tuple to update (if any).
You can lazily use the latest JuicyPixels-Repa
To acquire your preferred Repa array format, or to acquire an unboxed vector, you can just use the newly uploaded JuicyPixels-Repa-0.6.
Now you can fold over the vector or use the tuple array directly, as you originally desired.
I also took an ugly stab at fleshing out the first, horribly naive, solution:
I’m too wary of the performance of this code (3 traversals per index… I must be tired) to throw it into JP-Repa, but if you find it works well then let me know.