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
    $\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 '13 at 20:14
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

| improve this answer | |
$\endgroup$
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} *)
| improve this answer | |
$\endgroup$
  • $\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 '15 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 '15 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 )

| improve this answer | |
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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