Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.
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?

share|improve this question

migrated from stackoverflow.com Apr 6 '13 at 14:34

This question came from our site for professional and enthusiast programmers.

    
Thanks, will ask it there. –  March Ho Apr 3 '13 at 18:29
1  
the direct fix is to use AppendTo, though of course you dont really want to use for loops at all. –  george2079 Apr 3 '13 at 20:14

3 Answers 3

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

share|improve this answer

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} *)
share|improve this answer
    
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 –  March Ho Apr 20 at 18:33
    
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. –  rhennigan Apr 20 at 23:06

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 )

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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