# RGB image operations: addition works, multiplication doesn't?

**URL:** <https://discourse.julialang.org/t/rgb-image-operations-addition-works-multiplication-doesnt/39383>\
**Category:** New to Julia\
**Tags:** images\
**Created:** [May 13, 2020, 9:02am UTC](https://discourse.julialang.org/t/rgb-image-operations-addition-works-multiplication-doesnt/39383 "2020-05-13T09:02:54Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Klaas\_Pauly](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/klaas_pauly/32/14819_2.png) [@Klaas\_Pauly](https://discourse.julialang.org/u/Klaas_Pauly)\
**Post date:** [May 13, 2020, 9:02am UTC](https://discourse.julialang.org/t/rgb-image-operations-addition-works-multiplication-doesnt/39383/1 "2020-05-13T09:02:54Z")

</div>

Hi all  
I’m new to Julia, working on a script to perform flat field correction on images (as an introductory project, coming from python).

```julia
using TestImages, Images, Statistics
img = testimage("mandrill")

```

Now, looking at the following operations:

- `test = img.*0.5` → works
- `test = img.+img` and `test = img.-img` → works
- `test = img.*img` and `test = img./img` → doesn’t work:

```julia
ERROR: MethodError: no method matching *(::RGB{Normed{UInt8,8}}, ::RGB{Normed{UInt8,8}})
Closest candidates are:
  *(::Any, ::Any, ::Any, ::Any...) at operators.jl:529
  *(::Normed, ::AbstractRGB{T}) where T<:Normed at C:\Users\paulyk\.juliapro\JuliaPro_v1.4.1-1\packages\ColorVectorSpace\B9KU5\src\ColorVectorSpace.jl:130
  *(::Real, ::AbstractRGB{T}) where T<:Normed at C:\Users\paulyk\.juliapro\JuliaPro_v1.4.1-1\packages\ColorVectorSpace\B9KU5\src\ColorVectorSpace.jl:126
  ...
Stacktrace:
 [1] _broadcast_getindex_evalf at .\broadcast.jl:631 [inlined]
 [2] _broadcast_getindex at .\broadcast.jl:604 [inlined]
 [3] getindex at .\broadcast.jl:564 [inlined]
 [4] copy at .\broadcast.jl:854 [inlined]
 [5] materialize(::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{2},Nothing,typeof(*),Tuple{Array{RGB{Normed{UInt8,8}},2},Array{RGB{Normed{UInt8,8}},2}}}) at .\broadcast.jl:820
 [6] top-level scope at none:0

```

Consequently, statistics like `test = median(img, dims=(1,2))` also don’t work with a similar error. Any ideas why? I am able to get it working by “converting” to channelview:

```julia
img_chanview = channelview(img)
test = img_chanview.*img_chanview
median = median(channelview(img),dims=(2,3))

```

That works, however this whole process seems to be much slower compared to reading images in as numpy arrays in python and doing similar operations. My RGB files are 36 MP and I need to recombine frames like this. I am working on a laptop Windows 10, intel i7-6600U CPU, the whole process of reading images, converting/operating and writing back to image file took roughly 4.5 sec/image in python but using channelview around 15 sec/image in Julia, so I’m trying to understand how to do it as efficiently as possible.

Best regards  
Klaas

---

<div class="post-metadata">

**Author:** ![francesco.alemanno](https://avatars.discourse-cdn.com/v4/letter/f/e8c25b/32.png) [@francesco.alemanno](https://discourse.julialang.org/u/francesco.alemanno)\
**Post date:** [May 13, 2020, 10:09am UTC](https://discourse.julialang.org/t/rgb-image-operations-addition-works-multiplication-doesnt/39383/2 "2020-05-13T10:09:50Z")

</div>

same experience

> [@Klaas\_Pauly](#):
>
> this whole process seems to be much slower compared to reading images in as numpy arrays in python and doing similar operations.

---

<div class="post-metadata">

**Author:** ![lwabeke](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lwabeke/32/4005_2.png) [@lwabeke](https://discourse.julialang.org/u/lwabeke)\
**Post date:** [May 13, 2020, 1:08pm UTC](https://discourse.julialang.org/t/rgb-image-operations-addition-works-multiplication-doesnt/39383/3 "2020-05-13T13:08:49Z")

</div>

I suspect your problem comes from not having a definition of multiply defined between RGB objects. What is that supposed to mean?  
What is RGB1_RGB2 supposed to do?  
Element wise (R1_R2, G1_G2, B1_B2) ?  
Or is it a dot product (R1_R2+ G1_G2 + B1\*B2)  
Or something like a vector cross product?

Or think of complex multiplication for the 2 element case: (A+Bim) \* (C+Dim) = (AC - BD) + (BC + AD)im ?

Similar for the median problem, it needs a way to be able to sort RGB values. Based on what? Intensity, Hue, Saturation, R, … etc.

Breaking it apart of channels resolves what your doing. I don’t have enough experience with the Image libraries, but you should be able to do this without the channel breakup by custom defining the operators you need.

---

<div class="post-metadata">

**Author:** ![Iulian.Cioarca](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/iulian.cioarca/32/30166_2.png) [@Iulian.Cioarca](https://discourse.julialang.org/u/Iulian.Cioarca)\
**Post date:** [May 13, 2020, 1:15pm UTC](https://discourse.julialang.org/t/rgb-image-operations-addition-works-multiplication-doesnt/39383/4 "2020-05-13T13:15:49Z")

</div>

About the performance, you could try timing each operation and see where the bottleneck is. First I would try to decouple the load/save operations from the actual Julia processing.  
How do you load the images? I observed that FileIO is a bit slower than directly loading with ImageMagick.

---

<div class="post-metadata">

**Author:** ![waldyrious](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/waldyrious/32/80_2.png) [@waldyrious](https://discourse.julialang.org/u/waldyrious)\
**Post date:** [May 14, 2020, 9:56am UTC](https://discourse.julialang.org/t/rgb-image-operations-addition-works-multiplication-doesnt/39383/5 "2020-05-14T09:56:34Z")

</div>

This seems relevant: [Important decisions with respect to color math (please comment) · Issue #126 · JuliaGraphics/ColorVectorSpace.jl · GitHub](https://github.com/JuliaGraphics/ColorVectorSpace.jl/issues/126)

/cc @tim.holy, @kimikage

---

<div class="post-metadata">

**Author:** ![kimikage](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kimikage/32/14534_2.png) [@kimikage](https://discourse.julialang.org/u/kimikage)\
**Post date:** [May 14, 2020, 11:18am UTC](https://discourse.julialang.org/t/rgb-image-operations-addition-works-multiplication-doesnt/39383/6 "2020-05-14T11:18:54Z")

</div>

This is off-topic, but the median is generally not suitable for fast processing. If you need the true median values and the pixel type is `RGB{N0f8}`, I think the histogram-based algorithm is fast.

FYI, currently, the multiplication of `N0f8` is slow, so I think `ColorBlendModes.BlendMultiply` is worth considering “for now”. 😄

---

<div class="post-metadata">

**Author:** ![Klaas\_Pauly](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/klaas_pauly/32/14819_2.png) [@Klaas\_Pauly](https://discourse.julialang.org/u/Klaas_Pauly)\
**Post date:** [May 14, 2020, 11:45am UTC](https://discourse.julialang.org/t/rgb-image-operations-addition-works-multiplication-doesnt/39383/7 "2020-05-14T11:45:29Z")

</div>

Thanks all for the input!

The main bottlenecks were actually in converting to channelviews and especially saving back to image.  
In the meantime, I took a different approach using ArchGDAL to load images into 3D arrays, that bypasses the bottleneck of channelview very efficiently. I get the point about median being a bottleneck now, I will revisit that later (the whole process of calculating the median (per band) of a 3D array and applying the correction now takes about a second per frame).

`@time img_cor=AG.read(AG.read(joinpath(root,file))).*flatmed./flat`  
 → 1.08 sec per image for my 36 MP files (where flat is the 3D array of the flat field image and flatmed the 3D array with a median value per band, determined beforehand). This is called for each image in a folder. Actually I use this in a function to optimize the execution.

The only problem I still face in that approach is converting the resulting 3D array img\_cor back into ArchGDAL dataset (after converting the resulting Float64 back into UInt8) to then write it to a resulting jpeg file, but I should probably address that in another discussion thread.

---

<div class="post-metadata">

**Author:** ![kimikage](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kimikage/32/14534_2.png) [@kimikage](https://discourse.julialang.org/u/kimikage)\
**Post date:** [May 14, 2020, 12:38pm UTC](https://discourse.julialang.org/t/rgb-image-operations-addition-works-multiplication-doesnt/39383/8 "2020-05-14T12:38:12Z")

</div>

You seem to be using fixed size images (arrays). If so, I think moving pixel values to a pre-allocated array is faster than using views.  
I’m not against using the ArchGDAL package, but converting images to/from arrays is very simple.
