Histogram based Image segmentation (based on a histogram of two datasets)

15 views (last 30 days)
I have two (3d-)datasets from which I create a (correlation) histogram using hist3. Then I create a mask for this histogram.
Now I am trying to create a mask for my original datasets in a way that a data element is set to zero if the corresponding point in the histogram is set to zero by the histogram-mask.
It was relatively easy to do this for mathematically well defined masks, but I'm struggling with the arbitrary masks (created with roipoly). I only can think of nested for-loops which will take way to much time since my datasets are rather big....
An example with two small 2D datasets (problem is still the same)
Data1 = [0 0 0 0 0 0;
0 3 3 3 3 0;
0 3 3 3 3 0;
0 4 4 4 4 0;
0 5 5 5 5 0;
0 0 0 0 0 0];
Data2 = [0 0 0 0 0 0;
0 2 3 4 5 0;
0 2 3 4 5 0;
0 2 3 4 5 0;
0 2 3 4 5 0;
0 0 0 0 0 0];
%Now we create a 2D-histogram and apply a mask
Histogram = hist3([Data1(:),Data2(:)],[6 6]);
Mask=[0 0 0 0 0 0;
0 0 0 0 0 0;
0 0 0 0 0 0;
0 0 0 0 0 0;
0 0 0 0 0 0;
0 0 1 1 1 1];
MaskedHistogram = Mask.*Histogram
% PROBLEM:
% This mask deletes certain bins of the 2d histogram. I like to write a
% code that creates a mask that deletes the pixels in the dataset that
% correspond with the deleted bins.
% For this particular example the result should look like this:
ConvMask= [0 0 0 0 0 0;
0 0 0 0 0 0;
0 0 0 0 0 0;
0 0 0 0 0 0;
0 1 1 1 1 0;
0 0 0 0 0 0];
% To check if this is correct, we can apply this converted mask on the
% original dataset and create a histogram which schould be equal to MaskedHistogram
%(exept for the (0,0) because we create zero pairs by applying the latest mask)
MaskedHistogramCheck = hist3([ConvMask(:).*Data1(:),ConvMask(:).*Data2(:)],[6 6])

Accepted Answer

Image Analyst
Image Analyst on 6 Jan 2016
When you say "create a mask for this histogram" I'm assuming that you want to mask your 2-D histogram created with hist3() rather than mask your input images before taking the histogram of them, because I don't think you can do a polygon on a 3D image with roipoly (unless you do it tediously a slice at a time).
So, with your histogram, display it as a 2-D image. Then use imfreehand() to draw an irregularly shaped region and get the binary image mask from that. I attach a couple of imfreehand demos for you. I'm not sure what you want to do after that though since you didn't say. Do you want to know the gray level pairings in the traced region? Or something else?
  3 Comments
Image Analyst
Image Analyst on 7 Jan 2016
First you get a list of gray level pairs by masking the histogram. Like
maskedHistogram = hist2d .* mask;
[gl1, gl2] = find(maskedHistogram);
Now gl1 and gl2 are a paired list of gray levels to delete, assuming the mask is true where you want to zero out the images. For example at row 1, if gl1(1) = 130, and gl2(1) = 150, then you want to set to zero the same pixel location in both images if that pixel is 130 in image #1 and 150 in image #2, but not for any other pair (unless that pair is also in the list).
You could do it manually by scanning each array (with nested for loops) and finding the gray levels in each pixel (one in each image), then if they match the pair you're checking for, set them both to zero.
for col = 1 : columns
for row = 1 : rows
for k = 1 : length(gl1)
if image1(row, col) == gl1(k) && image2(row, col) == gl2(k)
image1(row, col) = 0;
image2(row, col) = 0;
end
end
end
end
Another option is to get a binary image and then and them and mask both images. This might take shorter or longer than the brute force for loop approach but you could check. It would go something like this:
for k = 1 : length(gl1)
binaryImage1 = image1 == gl1(k);
binaryImage2 = image2 == gl2(k);
binaryImage = binaryImage1 & binaryImage2; % Where both are true.
% Now set both images to zero there.
image1(binaryImage) = 0;
image2(binaryImage) = 0;
end
Geert
Geert on 11 Jan 2016
The first option you give is what I tried earlier more or less, and what I referred to in my question as the "nested for-loops". This works pretty fine for very small datasets as in my given example but takes a lot of time when applied on large 3D volumes. I didn't test your second method I guess this would be faster but still take a lot of time.
In the mean time I found a solution, fast enough, that looks so easy that I feel ashamed that I didnt found it earlier:(at the end, the ConvMask can be applied on the original dataset)
ConvMask=zeros(size(Data1));
for i =1:numel(Data1)
ConvMask(i)=Mask(round(Data1(i))+1,round(Data2(i))+1);
end
PS: the "+1" is because I have zero values and indexing of the histogram starts at 1. PPS: The rounding is because my values are no integers.
Nonetheless, thanks for your help Image Analyst!

Sign in to comment.

More Answers (0)

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!