Steve on Image Processing and MATLAB

Concepts, algorithms & MATLAB

This is machine translation

Translated by Microsoft
Mouseover text to see original. Click the button below to return to the Original version of the page.

Gray scale pixel values in labeled regions 58

Posted by Steve Eddins,

The functions bwlabel and regionprops are very useful for measuring the properties of shapes in a binary image. There are documentation examples and product demos showing how to do this, and I've shown these functions in action several times in this blog.

But sometimes I get questions about how to process pixel values in the "original" gray scale image. In other words, suppose your process is something like this:

  • Segment gray scale image to get a binary image of objects
  • Label the binary image objects using bwlabel
  • Do something with the original gray scale pixel values corresponding to each labeled object

This post is about how to do that last step. Let's start by creating some simple sample images to work with.

I = imread('coins.png');
imshow(I)
bw = im2bw(I, graythresh(I));
bw = imfill(bw, 'holes');
imshow(bw)
title('Thresholded, with holes filled')
L = bwlabel(bw);
imshow(label2rgb(L, @jet, [.7 .7 .7]))
title('Label matrix')

The key for using L to process the pixels in I is to use regionprops to get the 'PixelIdxList' for each labeled region.

s = regionprops(L, 'PixelIdxList')
s = 

10x1 struct array with fields:
    PixelIdxList

s is a struct array. s(k).PixelIdxList is a vector of the linear indices of the k-th region. You can use these values to index directly into I. For example, here is the mean pixel value of the 3rd coin:

idx = s(3).PixelIdxList;
mean(I(idx))
ans =

  172.8769

You can also replace object pixel values in I by indexing on the left side of an assignment statement, like this:

% Turn the 4th coin white and the 5th coin black:
J = I;
J(s(4).PixelIdxList) = 255;
J(s(5).PixelIdxList) = 0;
imshow(J)

Here's a loop that replaces the pixel values for each coin by the mean pixel value for that coin:

F = I;
for k = 1:numel(s)
    idx = s(k).PixelIdxList;
    F(idx) = mean(I(idx));
end
imshow(F)

I'll finish with a question that Mat asked in a blog comment: "How can I find the location of the maximum pixel value in each labeled region?" Here's how to find the locations and then plot them on top of the original image. (In addition to 'PixelIdxList', I'll also ask regionprops for 'PixelList', which gives the x and y coordinates of each pixel in the region.)

s = regionprops(L, 'PixelIdxList', 'PixelList');
imshow(I)
hold on
for k = 1:numel(s)
    idx = s(k).PixelIdxList;
    pixels_in_region_k = I(idx);
    [max_value, max_idx] = max(pixels_in_region_k);
    max_location = s(k).PixelList(max_idx, :);
    plot(max_location(1), max_location(2), '*')
end
hold off


Get the MATLAB code

Published with MATLAB® 7.4

Note

Comments are closed.

58 CommentsOldest to Newest

Martin Berger replied on : 1 of 58
Hi Steve! I am looking for an efficient solution to relabel an already existing label image. My problem is, that I start with a valid label image (e.g. returned from bwlabel) and then I do some modifications where some already labeled regions split, some labeled regions are removed. Thus, I am destroying the label image structure, e.g. after removing the region with ID = i I do not have any label i in my label image anymore. How do I regain a valid label structure from the modified image in the most efficient way (without loops)? Thx, Martin
Steve replied on : 2 of 58
Martin—That's a great question, worthy of another post. I recall having to "relabel" a label matrix before, but I don't remember exactly why. Before I work up something in detail, though, can you say more specifically what output you are looking for? From your description, I imagine you have bw and a corresponding L, and you have a modified bw in which some original regions are split and some removed. Are you looking for a mapping from the label values for the modified bw back to the original label values?
Martin Berger replied on : 3 of 58
Steven, in my special case I do not have the corresponding bw image anymore. I have a label image (representing a segmentation result of a color image) and I do some post-processing as e.g. removing the smaller regions, which destroys the label structure (as e.g. a split). And now I just want to repair the label structure to be valid again (meaning no missing ids and not having two unconnected regions with the same id - somehow a labeling of a label image) thx Martin
Steve replied on : 4 of 58
Martin—It sounds like calling bwlabel on the modified label matrix would satisfy your requirements.
L2 = bwlabel(modified_L ~= 0);
Daphne replied on : 5 of 58
Hi Steve, Is there a way to find, for example, the intensity weighted centroid of each of the labeled regions, and not just the location of the brightest spot ? What about only finding the centroids of regions where the brigtest spot is over a certain threshold? Thanks, dpahne
Martin Berger replied on : 6 of 58
Steve, L2 = bwlabel(modified_L ~= 0) will not work because in the step: modified_L ~= 0 -> neigbouring regions with different labels > 0 will be merged. Martin
Bob replied on : 7 of 58
Hi Steve, This is great! been looking for similar items for ages... I wonder if you would be able to solve a similar problem to Martins for me... I have a set of 3d slices each with individual labels/slice. However I need to be able to match different labels between slices.... For instance currently blob 1 in slie 1 maybe labelled as blob 2 in slice 2 etc... How can I recompute all these around, so that I am not missing labelled items and the blobs are accounted for vertically. I can post you some images if that helps. Thanks so much, I've been stumped by an easy way to do this for ages! Bob
Steve replied on : 8 of 58
Daphne—Yes, there's a good way to find the intensity-weighted centroid. I'll write a blog post about it in a few days. Can you say a little more about how you want to use this calculation? What is your scenario? Your second question is also worth a follow-up post. Thanks!
Steve replied on : 9 of 58
Martin—I'm not being dense on purpose :-) but I'm still having difficulty interpreting your problem description. Would you please send me a small example of an L, a modified L, and what your desired output would be?
Steve replied on : 10 of 58
Bob—I believe I can help with that, and it might be worth a follow-up post. Would you please send me a couple of representative slices? And let me know if I have permission to use them in a blog post.
Daphne replied on : 11 of 58
Hi Steve, Thanks! My uses are for tracking fluorescent particles, in real time inside living cells. Basically, round-ish (pretty pixelated) bright spots on a dark background. Localizing the intensity-weighted centroid allows us to get sub-pixel resolution and effectively use the microscope under the resolution limit of light. Having the option to pick only blobs > a threshold allows us to remove any unfocused particles. We filter out noises before-hand. I'm currently using my own code, which I wrote when I had no access to any of the toolboxes, and am curious to see how much this can be improved. Since we use this to analyze entire movies, frame-by-frame, any unnecessary slowdown is painful. Thanks again, Daphne
Steve replied on : 12 of 58
Daphne—Thanks for the additional information, Daphne. When we hear feature requests, we try to make sure we understand the complete use case. That helps us prioritize our work and make sure that it really satisfies the real user need.
Patrick replied on : 13 of 58
Hi Steve, I'm working on rendering images of 3D models in Matlab. My immediate question is: can I use getframe (or any other built-in function) to grab an image without the figure ever being visible? Basically what I have been doing is rendering my model using fill3 and surf commands, to an invisible figure. I'm doing this inside nested 'for' loops to generate lots of candidate images, then computing some stats on the images, and once the whole program is working I won't ever want to see the 1000's of candidates, just the eventual winner. But the call to getframe always makes a figure pop up as each candidate image is captured. Is there a way to circumvent this? Thanks! Patrick
Walid replied on : 15 of 58
Hi Steve, I wont to fin the meighbor region in my labled image. do you have an idea about how to do it? Thanks. Walid
Sven replied on : 17 of 58
Hi Steve, To perhaps add to some questions from earlier comments about re-labeling blobs: Imaging a case where you label your binary image then find that you want to remove blobs 5, 8 and 11. L = bwlabel(I); L(ismember(L,[5 8 11])) = 0; For your next function downstream, you want to have your labels run continually from 1 to (number of blobs), without skipping 5, 8 and 11. Of course, you could just rerun bwlabel with { L = bwlabel(L>0); }. *However*, this duplicates the effort of separating blobs which has already been done by the first call to bwlabel. When dealing with big matrices (I am using bwlabeln on some 3D voxel spaces), this is inefficient. Do you have any smart little tricks to 'relabel' without recomputing connectivity? My guess is a loop over the unique elements of L... Cheers, Sven.
Sven replied on : 19 of 58
Cheers Steve. My initial solution is below. I found it works just fine for 2d cases. It was surprisingly slow however for a 3d case. In my particular application I don't have any blobs connected along the 3rd dimension, so I found that nesting the code below in a loop over the 3rd dimension to work quickest. current_blob_id = 0; for found_blob_id = unique(L(L>0))' current_blob_id = current_blob_id+1; L(L==found_blob_id) = current_blob_id; end
Steve replied on : 20 of 58
Sven—Use regionprops to get the PixelIdxList for each labeled object, and then use linear indexing to reassign labels as you desire. I expect that will be a lot faster than what you're doing now.
Sven replied on : 21 of 58
Thanks Steve, much faster and simpler! It's almost as if you have the inside scoop on these functions ;)
Siam replied on : 22 of 58
Hi Steve, How do you label the regions of imbedded structures?. For example three squares of decreasing size imbedded inside each other in sequential order. Another example would be three concentric circles. Since the image is connected and there is no background level separating the circles, I'm doubting that binary labeling would would work. Thanks in advance,
mathan replied on : 23 of 58
hi. I would like to know how to relabel an image. The normal bwlabel function label an image (1 to L) from left coloumn to right coloumn. I need to label it from top to bottom, left to right of an image so that those segmented images can extrated according to an order.
Steve replied on : 24 of 58
Siam—Look up "flat-zones labeling" algorithms. Although there's nothing in the Image Processing Toolbox for this yet, some of the algorithm development techniques I've described in this blog could be used to implement something like that.
Steve replied on : 25 of 58
Mathan—You can post-process the labels to sort them in whatever order you wish. For example, use regionprops to get the 'BoundingBox' of each labeled object, and then use sortrows to sort first on y and then on x.
Regina replied on : 26 of 58
I have a microarray image with defined spot boundary for each spot. Is there any way to get the pixel intensities for each spot within a spot boundary? I mean, do you know how to get pixel intensities that are not only bw? Thank you very much!!
James replied on : 28 of 58
hi Steve~ I have some problems with the code. I enter the code you provided but appeals an error on Error in ==> bwlabel at 48 iptcheckinput(BW, {'logical' 'numeric'}, {'real', '2d', 'nonsparse'}, ... Error in ==> SteveEddins at 38 L = bwlabel(I); I have no idea how to solve it. Could you help me with it? Actually, your code can deal with many objects in one picture. But i only need to measure one object centroid in one picture. So is there any way to get to it?
Mikle Norton replied on : 29 of 58
I have a similar question to the one left by Daphne, again having to do with determining the subpixel location of the center of a gaussian point spread function of the imaging system. Essentially finding the center of a subwavelength diameter sphere. However, what would be of use to us would be having this ability "live" during the point designation process in image alignment in the image processing toolbox. This would make something called 2 color FIONA (fluorescence imaging at one nanometer accuracy) easier. Must admit, this site is not on my frequent views listing, so an email hint to hit the link would be great, Thanks, Mike
Mike Norton replied on : 30 of 58
I'm hoping to get something like 1 percent pixel resolution ie center of gaussian determined to .01 pixel level
Mike Norton replied on : 31 of 58
The blog system erases old posts ? My question is similar to Daphne's and different We are implementing 2 color FIONA ( fluorescence imaging at one nanometer accuracy) and it would be helpful to designate control and object points with subpixel resolution using a gaussian point spread function ( or gaussian fit) in order to set up the cp2tform for image registration. I'm hoping to get something like 1 percent pixel resolution ie center of gaussian determined to .01 pixel level
Steve replied on : 32 of 58
Mike, The system does not erase old comments. All comments are held for moderation, meaning that I have to see and approve them before they appear. You might try computing the region centroid, weighted by the point-spread function values. See this post. In R2008a, the regionprops function can compute this measurement. I don't know about getting 1% accuracy, though. That may be expecting too much. To get e-mail notification of new content on this blog, click on the "Posts (e-mail)" link under my picture on the right side of the page.
Steve replied on : 33 of 58
James—The code I provided does not contain the line:
L = bwlabel(I);
You need to check your work. Or try clicking on the "Get the MATLAB code" link at the bottom of the post. To select just one object in a binary image, try using bwselect.
Xavier replied on : 34 of 58
Steve, I am interested in getting the statistics of each grayscale blob, such as its mean, minimum value, maximum value, and a distribution of the pixel values. Is it possible to do that with regionprops? An example would be very helpful. Thanks much.
Steve replied on : 35 of 58
Xavier—Doesn't this post help you? It includes code showing how to compute the mean value. You can use this code with minor modifications to compute the other things you mentioned. If you have the R2008a release, regionprops supports the min, max, and mean value measurements.
shawkat m. replied on : 36 of 58
hi stev i want to know how can i find the cross_sectional area for each labled coin
Steve replied on : 37 of 58
Shawkat—I'm not sure exactly what you mean by "cross-sectional area" of a coin, but regionprops might do what you want.
shawkat m. replied on : 38 of 58
hi steve i mean by The cross-sectional area of each coin and the average area the total number of pixels in each coin
Rusty Parrett replied on : 40 of 58
The manual that I have has a regionprops property for 'weightedcentroid'. However it is not mentioned in the help files. Is this new since Matlab 7.4.0? can I get it?
Steve replied on : 41 of 58
Rusty—This feature was added in R2008a. You can get it by upgrading your MATLAB version. But I've also written about how to calculate this yourself. See this August 2007 post.
allen j replied on : 42 of 58
Steve- My question lies along the same as shawkat. You will have to excuse me as I stumbled upon this while doing some research for my thesis project. I am working on finding drag coefficients for a number of different odd objects. The dilemna is that finding the frontal area of these objects can be very difficult. One of my professors said that maybe doing a pixel count would then be able to tell be the area. I am following all of what you are doing with the coins, I just want to know if it is at all possible to help me find say the area of one of those coins, or if not at least the amount of pixels that make up one of the coins and then I could try to calculate area from there. I am more familiar with Mathcad as it is emphasized in our program, however we have matlab at school and so Im willing to learn if this would work. Let me know what you think. Thank you for your time and any help.
Steve replied on : 43 of 58
Allen—Yes, what you describe is possible. bwlabel and regionprops are the key functions.
Santosh Bansode replied on : 44 of 58
Hi there, I have made a grey chart from black to white reducing the greyness. I have done it through normal Excel using fill color option, I printed it then and then took a picture of it. Now i want to read average value of pixels in different areas of grey level, probably in the centre of each grey area as there might be a bit of noise where a grey level meets another grey level. Please let me know how to do it. Kind Regards.
Steve replied on : 45 of 58
Santosh—Use something like this code to compute the mean of a subimage:
subimage = original_image(r1:r2, c1:c2);
average_value = mean2(subimage);
Marco replied on : 46 of 58
This technique is very interesting....but what if the image is not oroginally segmented as this one (I mean I have a single entity instead of multiple entities) and you want to divide it in a certain number of parts, and then ask the average value??
Steve replied on : 47 of 58
Marco—Your question is pretty vague. What's stopping you from dividing it in a certain number of parts? Presumably you know how you want to divide it, so divide away.
Varun replied on : 48 of 58
Hey, Steve..great post..I have just started using matlab and I stumbled over a problem..i.e If i have an array (NxN..say 100X100) and i store random pixel values into it (in the range of 0-255) and do 'imshow()' should it show the different grey colors..I ran the code but it just showed white for values >0 and black for values=0...Why is it so? and how to I reflect the various greyscale color values of the array onto the image window..
Steve replied on : 49 of 58
Varun—The convention followed by the Image Processing Toolbox is that gray-scale images represented as floating-point arrays have the range [0, 1], not [0, 255]. I recommend that you take a look at the intro sections in the Image Processing Toolbox users guide that describes the interactions between image type and data type conventions. Note also that the default display range can be overridden when you call imshow using this syntax:
imshow(A, [0 255])
Take a look at the documentation for imshow for more details.
opcs replied on : 50 of 58
sir,i have an image and want to perform some operations on selective pixels of the image, means to transform an image into different image. how to apply that function on that pixels, leaving remaining pixels unaffected in the resulted image ? I'm in new in matlab and have no more time to complete the assignment so please help me out thanx...
Manju replied on : 54 of 58
well if we have a few ovals within each other like in a cell how do we measure the distance from the center point to the boundary of each region?How do we calculate individual regions? Thanks
Steve replied on : 55 of 58
Manju@mdash;I suppose it depends on how you define "distance from center point to boundary." Center point can be identified by regionprops. The boundary locations of a region can be identified using bwperim, find, and the 'Image' property returned by regionprops. Then you can use a function such as hypot to compute the distances between the center and each boundary location.
mogh replied on : 56 of 58
hello sir can you help me,what i shoud do if the background of the original image (i.e. 'coins.png')was complex instead of uniform one? thanks
sara replied on : 57 of 58
hi steve,the example shows on how to get the maximun pixel.can you help me on how to get the value for all pixels?i really need your help, tq vr much