Why doesn't this view assignment work?

Hello. I am using the Images package to do some processing. I have an RGB image img, and I’d like to create a view such that I can index channels by name. My idea was to derive view slices from the channelView:

cv = channelview(img)
myview = Dict("red" => (@view cv[1, :, :]), "green" => (@view cv[2, :, :]), "blue" => (@view cv[3, :, :]))
#Rotate the red channel 180 degrees:
myview["red"] = imrotate(myview["red"], pi, axes(img), 0) #converting error 

Can someone explain why this doesn’t work, yet the cv[1,:,:] equivalent does?

The Dict value type is inferred as array view. So, you cannot assign arrays into it, only 2D views of 3D arrays. You can modify the elements in-place, however, if the dimensions won’t change:

myview["red"] .= imrotate(myview["red"], pi, axes(img), 0)
1 Like

And the type of cv[1,:,:] is not inferred as array view? How would I change the Dict value type so that the assignment in my example works (assuming dimensions don’t change)?

Slices like cv[1,:,:] make copies that are independent from the parent array. Views produce objects that are indexed just like arrays, but share data with the parent array.

See this manual section:
https://docs.julialang.org/en/v1/manual/performance-tips/#Consider-using-views-for-slices-1

2 Likes

And regarding the question of how to change the Dict type, that depends.
If you want the changes to the dict values to reflect on the original cv, you should have the dict as it is and modify its elements in-place. If you just want to split the image into three channels, then use cv[i,:,:] - as you have noticed, it will work, but you may need additional work to join the channels back into one image.

I read that part of the documentation. But in my case I’m talking about the lefthand side slice, i.e. non-copy assignment. The purpose of my view dictionary was to replace the lefthanded cv [1,:,:] = some_floatarray indexing with a more meaningful view indexing: cv["red"] = some_floatarray.

In my opinion,

change the array (or view) stored in the Dictionary for another one. If you want to change its values, not changing it for another one (because in that case the original array is not updated) you must use .= as it was previouosly suggested (".=" copy all the elements).

If it does not solve your question, I do not actually understand what you want to do.

2 Likes

It sounds like you might be coming from C++, where doing y = x may actually mutate y by copying the contents of x into it. Julia doesn’t work that way–doing y = x just attaches the label y to the value of x, disregarding whatever value may have been previously attached to y. If you want to mutate the array which is currently labeled myview["red"], then you want .= which does actually modify the array elements rather than just changing a label.

2 Likes

@rdeits I think it clicked. I thought cv[1,:,:] was a label the same as myview["red"].

So when I did:
cv[1,:,:] = some_array #assigns lhs label to a new object
I should have done:
cv[1,:,:] .= some_array #overwrites object belonging to lhs label

1 Like