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.

I was recently looking over this very nice question by March Ho: Counting elements which are inside another element on a different colour channel

There are often times where I find myself wanting to draw a curve or define a polytope to cut out and isolate a part of an image for further analysis. One solution, for example, would be to define a set of polytope vertices, e.g.:

poly = {{658.`, 1224.`}, {672.`, 1054.`}, {507.`, 871.`}, {358.`, 876.`}, {344.`, 1432.`}, {483.`, 1410.`}};

And then calculate a winding number for each pixel in the image, or equivalently apply InPolygonQ, to define a "cutout" region. Here's a naive approach:

CutoutRegion = ImageData[pic];
ImageDimX = ImageDimensions[pic][[1]]
ImageDimY = ImageDimensions[pic][[2]]
Length[CutoutRegion[[1]]]

For[y = 1, y <= ImageDimY, y++,
  For[x = 1, x <= ImageDimX, x++,
    pt = {x, (ImageDimY-y)};
      If[Graphics`Mesh`InPolygonQ[poly, pt] == True,
       CutoutRegion[[y, x]] = 1;
       ,
       CutoutRegion[[y, x]] = 0;
      ];
  ];
 ];

ImageMultiply[Image[CutoutRegion], pic]

This works, however very slowly, and it's a little bit clumsy to define a region of interest with a polygon. Really you'd want to freehand draw something.

My question is:

  • Is there a trivial way to speedup the above approach?
  • Is there a more elegant way to "hand" or "mouse" define a region of interest in an image and isolate it to generate a final product similar to the output of the above approach?
share|improve this question

3 Answers 3

up vote 5 down vote accepted

Is there a trivial way to speedup the above approach?

You can just rasterize a polygon and use the resulting bitmap as a mask:

cutoutRegion = Binarize[Rasterize[
  Graphics[Polygon[poly],
   PlotRangePadding -> 0, 
   PlotRange -> {{0, imageDimX}, {0, imageDimY}}, 
   ImageSize -> imageDimX]]]

(btw: It's bad style to start variable names with uppercase letters)

Is there a more elegant way to "hand" or "mouse" define a region of interest in an image and isolate it to generate a final product similar to the output of the above approach?

The closest thing I'm aware of is using LocatorPane with LocatorAutoCreate -> True to enter the polygon.

share|improve this answer
    
I believe you need PlotRangePadding -> 0 as well; I am adding it to the answer. If this is incorrect just revert the edit. –  Mr.Wizard Aug 6 '13 at 23:23

Here's a small program I wrote for practice. It uses nikie's technique, I also used it here.

The code

locatorPositions[dim_, 0] := {};
locatorPositions[dim_, n_] := Module[{r},
  r = 0.8 Min[dim/2];
  Table[dim/2 + {r Cos[\[Theta]], r Sin[\[Theta]]}, {\[Theta], 0, 
    2 \[Pi], 2 \[Pi]/n}]
  ]
locatorConnectingLines[pos_] := Line /@ Partition[pos, 2, 1, {1, 1}];
locatorMask[dim_, pos_] := 
 ColorNegate[
  Binarize[Rasterize[
    Graphics[Polygon[pos], 
     PlotRange -> {{0, dim[[1]]}, {0, dim[[2]]}}, 
     ImageSize -> dim]]]]
locatorInterface[image_, n_, f_] := 
  DynamicModule[{dim = ImageDimensions[image], 
    pt = locatorPositions[ImageDimensions[image], n], 
    background = image},
   Panel[
    Column[
     {
      LocatorPane[
       Dynamic[pt],
       Dynamic[
        Show[background, 
         Graphics[{Green, Dynamic[locatorConnectingLines[pt]]}]]
        ], Appearance -> Style["*", Large, Green], 
       LocatorAutoCreate -> Length[pt] == 0],
      Button["Apply function", 
       background = 
        Show[background, 
         SetAlphaChannel[f[image], locatorMask[dim, pt]]]
       ]
      }
     ]
    ]
   ];

Example usage

stu = Import["http://upload.wikimedia.org/wikipedia/commons/6/65/2011_State_of_the_Union.jpg"];
locatorInterface[stu, 10, Blur[#, 12] &]

Before pressing the button:

before

After pressing the button:

after

Comments

  • This is not very fast on my computer. It's probably much faster to manipulate the pixels directly.
  • If you set the second argument, the number of locators, to zero, you will be able to create locators by alt-clicking or, on Mac OS, cmd-clicking.
share|improve this answer

Here's another approach, similar to Anon's:

i = ExampleData[{"TestImage", "Girl"}]
Manipulate[
  Row[
  {Show[
    i,
    Graphics[{Red, 
      Opacity[0.6],
      Dynamic[Polygon[u]]},
     PlotRange -> 2, 
     Background -> White]],
   Panel[result]
   }],
 {{u, {{100, 100}, {200, 200}, {200, 100}}},
  Locator,
  LocatorAutoCreate -> True},
 Button["Cookie", result = crop[i, u]], 
 Initialization :> (crop[i_, poly_] := Module[{mask},
     mask = Binarize[
       Rasterize[
        Graphics[
         Polygon[poly],
         PlotRangePadding -> 0,
         PlotRange -> Transpose[{{0, 0},
            ImageDimensions[i]}],
         ImageSize -> ImageDimensions[i]]]];
     ImageAdd[i, mask]])]

girl2

result contains the answer for further experiments...

share|improve this answer
1  
For Mathematica v10, how about adding some different test images! :) –  cormullion Aug 7 '13 at 10:37
    
Have you noticed the new images in V9? –  Matthias Odisio Aug 14 '13 at 22:05
    
@MatthiasOdisio No I hadn't realized that there were 5 or 6 new images - a couple of buildings, some spices, some apples, and a flower! I suppose you have to keep most of the old ones for compatibility. More new ones please! –  cormullion Aug 14 '13 at 22:15
    
The more the better, yes. There are as well a collection of 3D images---and many more with WolframAlpha["image of ..."] –  Matthias Odisio Aug 14 '13 at 22:30

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.