1
$\begingroup$
getAvgs[A_, M_] := Module[{i, j, rArr, gArr, bArr},
   rArr = {};
   gArr = {};
   bArr = {};
   For[i = 1, i <= Length[A], i += 1,
    For[j = 1, j <= Length[A[[1]]], j += 1,
      If[M[[i, j]] == 255,
        Append[rArr, A[[i, j, 1]]];
        Append[gArr, A[[i, j, 2]]];
        Append[bArr, A[[i, j, 3]]];
        ];
      ];
    ];
   Return[{rArr, gArr, bArr}];
   ];

This code returned an array containing three blank arrays {{},{},{}}, meaning none of the Append functions worked. A_ and M_ are two images, A is 24-bit 3-channel colour, while M is black and white. They have the same dimensions, the idea is to use M as a mask to find the average colour of all pixels that are shown by the mask. However, none of the Append functions worked.

Append[{}, ImageData[,Byte][[30, 30, 3]]] correctly returned the value, so the syntax should be fine. When I made the for loop increment a counter, the counter correctly returned the number of masked pixels, so the for loop is working correctly too.

From what I know, Module basically declares the variables locally, preventing variable collisions. Is this correct as well?

$\endgroup$
1
  • 1
    $\begingroup$ the direct fix is to use AppendTo, though of course you dont really want to use for loops at all. $\endgroup$
    – george2079
    Apr 3, 2013 at 20:14

3 Answers 3

5
$\begingroup$

You are trying to find the mean for each channel of an image after masking. So, your code could be much simpler:

image = ExampleData[{"TestImage", "Mandrill"}];
mask = DiskMatrix[#1/10, #2] & @@ ImageDimensions@image;
channels =  Pick[Flatten@#, Flatten@mask, 1] & /@ (ImageData /@ ColorSeparate[image]);
Mean /@ channels
(*
{0.846919, 0.435261, 0.408555}
*)

You may compare this result with the mean over the whole image

Mean /@ Flatten /@ ImageData /@ ColorSeparate[image]
(*
{0.53879, 0.505329, 0.443596}
*)

You can easily see that the result {R,G,B} behaves qualitatively as expected:

Mathematica graphics

$\endgroup$
0
1
$\begingroup$

Append doesn't change the original list, it just returns a new one with one element added.

list = {1, 2, 3};
Append[list, 4]

(* {1, 2, 3, 4} *)

list

(* {1, 2, 3} *)

If you want to change the original list, use AppendTo.

AppendTo[list, 4]

(* {1, 2, 3, 4} *)

list

(* {1, 2, 3, 4} *)
$\endgroup$
2
  • $\begingroup$ Thanks for the old answer, in the 2 intervening years I have realised that this is a really common beginner mistake, hopefully I won't make this kind of mistake again :P $\endgroup$
    – March Ho
    Apr 20, 2015 at 18:33
  • $\begingroup$ Oops, I didn't even notice the date. For some reason this post showed up at the top of my 'active' list, so I just figured it was recent. $\endgroup$
    – rhennigan
    Apr 20, 2015 at 23:06
0
$\begingroup$

In case you really want a loop.. this is prefered over using AppendTo..

 getAvgs[A_, M_] := Module[{i, j, rArr, gArr, bArr},
    Transpose[Reap[ 
       For[i = 1, i <= Length[A], i += 1,
          For[j = 1, j <= Length[A[[1]]], j += 1,
             If[M[[i, j]] == 255,
               Sow[A[[i, j]]]
                   ;];];]][[2, 1]]]];

and another way more mathematica-esque..

getAvgs[A_, M_] := 
     Transpose[ Last /@ Select [
        Transpose[{Flatten[ M , 1] , Flatten[A, 1]}] , #[[1]] ==  255 & ]]

(not to disagree about using image tools, but it may be more instructive to learn the basics without that )

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.