10
$\begingroup$

When I ask ComponentMeasurements to return "IntensityData" for some set of rectangular morphological components:

m = MorphologicalComponents[image, Method -> "BoundingBox"];
intensityDataArray = ComponentMeasurements[{m, image}, "IntensityData"][[All, 2]];

The pixel value data is returned as an unpartitioned one-dimensional array. This makes it difficult for me to understand where a particular pixel is in the image. Now, if I know the exact dimensions of each morphological component, I suppose I could fix the problem using Partition. I could also fix the problem with Partition if I could ask for something like a bounding square instead of a bounding rectangular box, though I don't think this is possible (is it?).

Besides manually measuring the dimensions of each rectangular morphological component, is there a workaround to fix this problem?

Letting m consist of strictly rectangular morphological components, it would, for example, be very nice to be able to write something like:

ComponentMeasurements[m, "Dimensions"][[All, 2]]

And have this return something like:

{{5,8}, {87, 40}, {7, 7}, ...}

Meaning that we have morphological components of dimensions $(x, y) = (5 \times 8)$, $(87 \times 40)$, $(7 \times 7)$, and so forth. Here, we're provided ordered values for the extent of the component along the $x$- and $y$-axes, respectively, allowing us to trivially use Partition to restore the cropped section of an image underlying a morphological component (i.e. the image one would have if a morphological component is used as a "cropping mask").


Clarification: Masking approaches are really neat, but not quite what I'm looking for here unless they're part of a larger approach. I need a method of grabbing the pixel data strictly underlying a morphological component (for a set of morphological components) and retaining $(x, y)$ data for each pixel. My downstream procedure then does further image processesing on this rectangular matrix. If I do a matrix multiplication masking procedure, I still need to trim away the dark space to get down to a bounding box (the size of the morphological component mask).

Also, it seems a little wasteful to have to perform multiplication operation on all pixels in the image to accomplish my goal?

$\endgroup$
6
  • $\begingroup$ I think "IntensityData" is meant to be used for histogram processing, where the position of the intensities doesn't matter. Couldn't you just measure the "BoundingBox" instead and pass the result to ImageTrim to cut out the right area of the image? You can measure "Mask" to get a sparse array where the pixels of the component are set to 1. (I'm not sure what you're trying to achieve, I that's what I use when I need both the intensity and the location of the pixels in a component.) $\endgroup$ Commented Nov 2, 2013 at 11:02
  • $\begingroup$ @nikie How do I ask for the dimensions of a rectangular morphological component? If I can do this, I can just use Partition, right? I mean, I can figure this out up to rotation and reflection symmetries using metrics like Elongation, but how do I nail down the orientation as well? $\endgroup$ Commented Nov 2, 2013 at 11:10
  • $\begingroup$ @nikie I'll also note that I have maybe a few thousand of these morphological components, so I'm kind of hoping for some automated solution. $\endgroup$ Commented Nov 2, 2013 at 11:16
  • $\begingroup$ Use Partition on the returned IntensityData? I don't think so, because some lines might be longer than others. At least unless the components are all perfectly rectangular. $\endgroup$ Commented Nov 2, 2013 at 11:34
  • $\begingroup$ @nikie I'm specifying that the morphological components are bounding boxes, and must be rectangular. I'll try to clarify this better in the question. $\endgroup$ Commented Nov 2, 2013 at 11:35

2 Answers 2

13
$\begingroup$

I'm answering the question you posted in a comment:

but how do I then crop to a bounding box around that component

List I said, the easiest way is probably to measure the "BoundingBox"es and pass them to ImageTrim:

image=ExampleData[{"TestImage","APC"}]

enter image description here

m=MorphologicalComponents[Binarize@ColorNegate[ColorConvert[image,"Grayscale"]]];
Colorize[m]

enter image description here

components=ComponentMeasurements[{m,image},{"Area","BoundingBox"},#1>100&];
ImageTrim[image,#]&/@components[[All,2,2]]

enter image description here

$\endgroup$
4
  • $\begingroup$ I don't have the rep. to upvote you, but I follow you now. I didn't know how ImageTrim worked! $\endgroup$ Commented Nov 2, 2013 at 11:47
  • $\begingroup$ @RVoight Please note that you still have to mask this! Otherwise you work on all the image values and not only on the ones from your component. $\endgroup$ Commented Nov 2, 2013 at 11:51
  • $\begingroup$ @halirutan: He doesn't if his components are all rectangular (because of Method -> "BoundingBox"). Otherwise, you're right of course. I just wanted to show how BoundingBox and ImageTrim can work together and didn't want to complicate things with masking. $\endgroup$ Commented Nov 2, 2013 at 11:54
  • $\begingroup$ @nikie Ahh, haven't notice this before. $\endgroup$ Commented Nov 2, 2013 at 12:06
5
$\begingroup$

Why don't you use the "Mask" for a component to separate it in the original image?

image = ExampleData[{"TestImage", "JellyBeans"}];
m = MorphologicalComponents[
   Binarize@ColorNegate[ColorConvert[image, "Grayscale"]]];

mask = ComponentMeasurements[m, "Mask"];
ImageMultiply[image, Image[3 /. mask]]

In this way you can extract from the original image

Mathematica graphics

the 3rd component

Mathematica graphics

Answer to your comment

ImageTrim as suggested by nikie is better than using ImageTake because you can give it the bounding box directly.

mask = ComponentMeasurements[m, {"Mask", "BoundingBox"}];
ImageTrim[ImageMultiply[image, Image[First[# /. mask]]], 
   Last[# /. mask]] & /@ Range[Length[mask]]

Mathematica graphics

$\endgroup$
2
  • $\begingroup$ It's great to know we can do this, but how do I then crop to a bounding box around that component (my components are already rectangular)? $\endgroup$ Commented Nov 2, 2013 at 11:36
  • $\begingroup$ @RVoight You just use "BoundingBox" as additional measure and provide this to ImageTake. Be careful, because the ordering of the min/max box values is different and you have to incorporate the image dimensions in y direction. $\endgroup$ Commented Nov 2, 2013 at 11:45

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.