# Applying a transformation rule on an Image

I haven't been able to figure out why the following doesn't work:

img = Image[ExampleData[{"TestImage", "Tree"}], "Real"]
img /. {r_, g_, b_} :> 1 - {r, g, b} (* Image left unchanged *)


Looking at the full form of img, I see that the pixels are stored as lists of three real numbers each, so I don't get why the pattern won't match.

This works though, giving me the "negative" image that I expected from the previous code also:

Image[ImageData[img] /. {r_, g_, b_} :> 1 - {r, g, b}]


So what's the problem with the first code?

(Kindly note that the image processing problem that the above code happens to perform is of no interest to me here; I just chose it as an example, so don't misdirect your effort showing how it could be done using library functions. Here, I'm only interested in understanding why the rule application didn't work)

-
Maybe compare img // Dimensions to ImageData[img] // Dimensions ? –  b.gatessucks Apr 4 '13 at 10:07
Yes, I hadn't realised that Image was an atomic type –  Aky Apr 4 '13 at 10:42
Does wrapping an image ExampleData returns here -- in another Image change anything? –  BoLe Apr 4 '13 at 13:13
@BoLe I just did it to convert the image type to "Real". –  Aky Apr 4 '13 at 15:59

ReplaceAll doesn't work on atoms.

img = Image[ExampleData[{"TestImage", "Tree"}], "Real"]
AtomQ@img


True

-
Thanks, that sort of makes sense to me. –  Aky Apr 4 '13 at 10:34
But you could try List@@img, and there are still some problems –  belisarius Apr 4 '13 at 11:44
@belarius I didn't understand your point. Trying to replace the Head of an atom doesn't ordinarily do anything, does it? List@@5==5 is True, for example, and so is List@@img==img. I've probably misunderstood the point you're trying to make, so could you please explain? –  Aky Apr 4 '13 at 11:55
@Aky Try (List @@ Image[ExampleData[{"TestImage", "Tree"}]] /. {x_, y_, z_, w_} -> x // InputForm) /. RawArray :> List –  belisarius Apr 4 '13 at 12:44

Since version 9, Image is an atomic object (AtomQ) and thus it's internal data structures cannot be directly manipulated through Part or pattern matching.

Don't let the fact that it has an InputForm and FullForm with apparent structure confuse you. This is for convenience only (to make it human readable) and happens with other atomic objects too, such as Rational/Graph/etc. In reality you just can't take an Image apart.

Use ImageData and other Image* functions to extract data.

-

Image[ ] is a kind of wrapper that contains information about the image: the size, the color map, and of course the ImageData. There are lots of functions that deal directly with the image wrapper, for instance, you can accomplish the task you asked using

ImageApply[(1 - #) &, img]


More generally, you can define your own function f and then do: ImageApply[f, img]

-