May seem strange at first, but can you make mathematica change the value of 0 to 10 and 11 to 1 for all occurrences. Let me explain:

I'm looping through a matrix and for each element, I want something to happen depending on the values in each element above, below, to the left and to the right. When you're at the first element however there is nothing to the left, or above, so instead I would like to use the values on either side of the matrix as if you'd curled the matrix back round onto itself, as shown below.

X denotes what element you're looking at and then T,B,L & R, correspond to the cells at the Top, bottom, to the left & right respectively. Here's the code I wrote without thinking too much and it throws up an error because it asks for elements that do no exist. (e.g. "i-1" when i=1)

{n, m} = RandomChoice[{image[[i + 1, j]], image[[i, j + 1]], 
image[[i - 1, j]], image[[i,j - 1]]} -> {{i + 1, j}, {i, j + 1}, {i - 1, j}, {i,j - 1}}];
newimage[[n, m]] = image[[i, j]];
, {j, columns}];
  , {i, rows}];

So, without whacking loads of If statements in there, is there an elegant way to accomplish this?

Hope I explained this half decently.

  • $\begingroup$ Mod seems like a quick fix, but would be neat with some Periodic attribute to a SparseArray $\endgroup$ – ssch Mar 31 '13 at 0:33
  • $\begingroup$ @ssch oh yeah Mod would be a quick and easy way around. thanks :) $\endgroup$ – Tom Mar 31 '13 at 1:12
  • $\begingroup$ @ssch hmm although not sure that helps me when i=1 as then i-1=0 and Mod doesn't help there $\endgroup$ – Tom Mar 31 '13 at 1:15
  • 2
    $\begingroup$ Check out the offset argument: Mod[0,10,1]==10 $\endgroup$ – ssch Mar 31 '13 at 1:18
  • $\begingroup$ @ssch perfect!! $\endgroup$ – Tom Mar 31 '13 at 1:23

ImageFilter is also a good solution here, and you can create any filtering action you want. In outline, this would look something like:

myFun[x_] := Module[{},(* Your code here*)];
ImageFilter[myFun, img, n]

where myFun takes as input a (2n+1) by (2n+1) array of pixel/matrix values and calculates a single output. The ImageFilter command applies myFun to every (2n+1) by (2n+1) block in the image, and handles the edge conditions easily using the Padding option.

  • $\begingroup$ Here's a Wolfram demo that uses this technique: demonstrations.wolfram.com/AdaptiveThresholdingOfImages The thing I remember when writing this demo is that it is very important to make sure that your function takes the proper inputs and gives back the proper outputs. Otherwise, all is lost... $\endgroup$ – bill s Mar 31 '13 at 13:10

As a direct answer you could use replacement, e.g.:

{-1, 0, 1, 10, 11, 12} /. {0 -> 10, 11 -> 1}
{-1, 10, 1, 10, 1, 12}

But more significantly this problem can likely be handled better by built-in functions that already make allowance for wrapping around, or by padding the array to start with. I am looking at this now.

  • $\begingroup$ I did think about padding, but then thought it could be fun (see the comment on other answer about turning an image into a many body gravitational problem) to wrap the matrix around on itself so there are no boundaries. $\endgroup$ – Tom Mar 31 '13 at 0:55
  • $\begingroup$ @Thomas I believe there is another question specifically about wrapping indicies and I believe that the answer there was to use Mod as ssch recommended in a comment. Is your code example actually representative of what you want to do? I'd be happy to explore other ways to approach this. $\endgroup$ – Mr.Wizard Mar 31 '13 at 4:49
  • $\begingroup$ Yes, that is mu code so far, apart from a bit at the top to load an image and turn it into image data and a part at the bottom to display the new image. I'm happy with the Mod trick, seems to get the job done :) $\endgroup$ – Tom Mar 31 '13 at 13:03

Going by your choice of example (which is incomplete) and the variables used, I'm guessing you want to perform some operations on an image in which the output for each pixel depends on its immediate neighbours one city block apart.

For this, you can use a CrossMatrix as a convolution kernel and ImageConvolve will handle the edges for you.

(* {{0, 1, 0}, {1, 1, 1}, {0, 1, 0}} *)

For example, here is what you get if you convolve Lena with a cross matrix:

With[{lena = ExampleData[{"TestImage", "Lena"}]}, 
    ImageConvolve[lena, CrossMatrix[1]]]

This might be all that you need to proceed, but unless you provide more information, it's hard to say what exactly it is that you need.

  • $\begingroup$ What if the data isn't an image? $\endgroup$ – Mr.Wizard Mar 31 '13 at 0:39
  • $\begingroup$ Apologies for the limited information, always a fine balance between under and over explaining. I've started toying with the idea of reading in black and white images into an array and then letting those images evolve under some kind of many-body problem, where the grayscale values of each pixel interact with each other and producing a video from it. For example pretend the grayscale value corresponds to mass and see how all the pixels of the original image form clusters etc. I dunno, experimenting with abstract mathematica art. But this looping problem is something that cropped up $\endgroup$ – Tom Mar 31 '13 at 0:52

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.