find contiguous region with highest values
Afficher commentaires plus anciens
I'm trying to get the indexes of the region covering 10% of an m x n graph that has the highest values.
For example:
0 0 0 0 0 3
2 2 2 0 0 0
0 0 0 0 0 1
0 0 0 0 1 2
0 0 0 0 0 0
Should give me rows 2,2,2 and columns 1,2,3 (the output format doesn't matter for my purposes).
The region needs to be contiguous, and not just the region with the single highest value. Could someone point me in the right direction?
4 commentaires
Walter Roberson
le 22 Oct 2016
The maximum pixel of the 1 2 1 "L" is the same as the maximum pixel of the 2 2 2 line. Shouldn't that be a tie? Or is it the total over the region that is important?
Walter Roberson
le 23 Oct 2016
This does not answer to the question of what happens for a tie, and does not answer to the question of how you determine which cluster has the "highest values" across clusters of different sizes and where simple maximum is not the key. Is the key the mean over the cluster? Is the key the sum over the cluster?
Réponses (3)
There may be a nice (but slightly complicated) way of getting the linear indices here. The idea is something like this: Get connected components ( blobs shall we say?) --> Get pixel index list --> For each set of pixels, compute their pixel sum --> Find the index of the maximum pixelsum --> Get linear indices for the blob with the maximum pixelsum.
The code would be something like this:
x = [0 0 0 0 0 3 % your example here
2 2 2 0 0 0
0 0 0 0 0 1
0 0 0 0 1 2
0 0 0 0 0 0];
CC = bwconncomp(x); % Blobs and their data
SumPixels = cell2mat(cellfun(@(y) sum(x(y)),CC.PixelIdxList,'UniformOutput',0)); % Get Pixelsum
[~,idx] = max(SumPixels);
LinIdx = CC.PixelIdxList{idx};
And Voila! I get:
LinIdx =
2
7
12
You could find the row and column indices from the above, but this is where I leave you.
PS: For pedagogical reasons, I suggest you look up the bwconncomp and cellfun functions. To learn more about linear indices, please look at the "More About" section here .
2 commentaires
amen45
le 22 Oct 2016
It would depend on how you separate your regions of interest. How do you define that certain pixels or a certain contiguous region belongs to your object of interest and not the background?
Also, you could always adapt/modify your non-integer-valued array long enough to get your program running. You could even change all your background values to zeros with a logical statement. My point is, the entire logic of the code depends on where the 'edges' of your regions lie, and a handful of pixels more or less makes a big difference to the region that you would obtain.
Image Analyst
le 22 Oct 2016
Try ismember() and you can do it in 2 lines. See this well commented demo:
% Define sample data consisting of integers
% (Slightly different than your example)
m = [0 0 0 0 0 3
2 2 2 0 0 0
0 0 0 0 0 1
0 3 3 0 1 2
0 0 0 0 0 0]
% 3 is the "highest value" and is what is sought.
% 3 occurs in two regions (places).
% Find those two regions of highest value
% and put locations into a logical array.
locations = ismember(m, max(m(:)))
% Get a new matrix withteh actual values.
highestValueRegions = m .* locations
Image Analyst
le 22 Oct 2016
If you have floating point values, I think what you're trying to say is that you want a matrix with only elements that are in the highest 10% of all values in the array. You can do this like:
% Define sample data consisting of floating point numbers
m = 100 * rand(6, 5)
% Sort the array
sortedm = sort(m(:), 'descend')
% Find the 10% index
index10 = ceil(0.1 * numel(m))
% Determine the value that 10% of the values lie above
value10 = sortedm(index10)
% Get binary "map" of where these highest 10% of values live:
binaryImage = m >= value10
% Extract a matrix with only the highest 10% of floating point values:
output = m .* binaryImage
When I ran it, this is what I got. Tell me if this is what you were thinking of:
m =
9.1113 64.762 23.623 77.029 25.644
57.621 67.902 11.94 35.022 61.346
68.336 63.579 60.73 66.201 58.225
54.659 94.517 45.014 41.616 54.074
42.573 20.893 45.873 84.193 86.994
64.444 70.928 66.194 83.292 26.478
sortedm =
94.517
86.994
84.193
83.292
77.029
70.928
68.336
67.902
66.201
66.194
64.762
64.444
63.579
61.346
60.73
58.225
57.621
54.659
54.074
45.873
45.014
42.573
41.616
35.022
26.478
25.644
23.623
20.893
11.94
9.1113
index10 =
3
value10 =
84.193
binaryImage =
6×5 logical array
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 1 0 0 0
0 0 0 1 1
0 0 0 0 0
output =
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 94.517 0 0 0
0 0 0 84.193 86.994
0 0 0 0 0
13 commentaires
I think the OP wants a code that would produce the indices for a contiguous region in an array that occupies at least 10% of the array (by size) and whose sum of array values is a maximum among such regions as those would satisfy the size condition.
Image Analyst
le 22 Oct 2016
Modifié(e) : Image Analyst
le 22 Oct 2016
Yes, it's ambiguous. What you say would require that regions are defined first, so that their area can be measured with regionprops. This would require that the regions be labeled. Originally he provided an integer image which you could then assume might be labels, or at least could be thresholded and labeled to produce a labeled image. However he then said that the "image" could be anything, not just integers, so it could be any arbitrary floating point array. There are no regions in such an array. You'd first have to define what constitutes a region, for example by thresholding at some level. My Image Segmentation Tutorial goes over the steps in well commented detail, but, in short, it would go like this:
binaryImage = floatingPointImage > someThreshold;
labeledImage = bwlabel(binaryImage);
props = regionprops(labeledImage, 'Area');
allAreas = [props.Area];
area10Percent = 0.1 * numel(binaryImage ); % The 10% area.
bigAreaIndexes = find(allAreas > area10Percent); % Which blobs are bigger than 10% of image.
bigAreaImage = ismember(labeledImage, bigAreaIndexes); % Extract only the big blobs.
Now bigAreaImage is a binary image showing every blob that has an area at least as big as 10% of the whole image.
I agree about the definition of a 'region' as it relates to this question. Your code snippet above renders the original array as a binary one and might as well be treated as an image, which is sort of the point I was trying to get across earlier in my answer.
PS : Your tutorial seemingly links to the Enigma Machine on Wikipedia! Perhaps that was an oversight?
Image Analyst
le 22 Oct 2016
Sorry. Yes (copy apparently didn't work after an earlier copy for an earlier post). Fixed. Thanks for the catch.
Image Analyst
le 22 Oct 2016
Let's hope amen45 comes back and clears up what "region with highest values" means exactly. Like does it mean "region with the biggest area" or "region with the greatest numerical values" or whatever. And also hopefully he'll give a floating point (non-integer) example and tell us where the "regions" in it are, and what data he wants out.
amen45
le 22 Oct 2016
Image Analyst
le 22 Oct 2016
Modifié(e) : Image Analyst
le 22 Oct 2016
The greatest value is 0.998700000000000. It occurs at row 4, column 3. It has only three 4-connected neighbors, and five 8-connected neighbors. Or four and six if you also include the value itself. But if you're not at an edge, you will have 8 8-connected pixels (9 total) and 4 four-connected pixels (5 total with the center one). So I'm still not clear what region you want. Perhaps if you described why you wanted it, or what you would do as the next step if you had this information.
By the way, round is a built in function and you should not use it as a variable name. And you can get the local mean image with a call to conv() or imfilter() instead of that double for loop.
Are you perhaps trying to track a particular region and its changes through a set of images? A quick and dirty way might be to simply define a square mask (>k) such that your elements of interest are given a higher 'weight'. This is only so you could define a clear threshold or shape for the connected region you are interested in through a little numerical manipulation.
Consider this:
x = [0.115754943948525 0.254835774407905 0.418797235529874
0.133596512865232 0.267704112017176 0.427967388090852
0.148849791641271 0.274078404255313 0.425934632215066
0.166527249110295 0.977300000000000 0.998700000000000
0.196980352387009 0.923140000000000 0.987890000000000
0.224172402663761 0.323278947773164 0.431610265045853
0.283912660670702 0.380237101362344 0.466341084111908];
h = [1 1 1 % A 3x3 mask that weights the center value greater than its surroundings
1 100 1
1 1 1];
y = conv2(x,h,'same'); % Filter your original array
z = y.*x; % This is only to exaggerate the differences between the array values
From z, you would just pick out the k highest valued elements. This is just a quick illustrative example that I have not tried on any other data (it may mostly work or not).
To add to the above, I would suggest a square mask (or scrolling array, if you'd like) with odd number of elements so you would have something of a 'center' value. This is a common tactic used in filtering operations. Also, the mask size and shape would influence the data, so choose as small a square size as possible so you would not end up manipulating your data over the necessary amount. In my example, I have chosen a 3x3 mask because it is the smallest odd square that I could use that is greater than k.
Image Analyst
le 22 Oct 2016
To get the mean of the interactions (pixels) in a horizontal 1-by-2 sliding window, do this:
[rows, columns] = size(im)
for col = 1 : columns
windowWidth = col;
kernel = ones(1, windowWidth) / windowWidth;
meanImage = conv2(im, kernel, 'same');
% Now do something with meanImage.....
end
where m is your interaction matrix.
To do the same but in a vertical 2-by-1 sliding window, do this:
[rows, columns] = size(im)
for row = 1 : rows
windowHeight = row;
kernel = ones(windowHeight, 1) / windowHeight;
meanImage = conv2(im, kernel, 'same');
% Now do something with meanImage.....
end
If you want, you could use a double for loop over both rows and columns to create all possible kernel shapes:
[rows, columns] = size(im)
for col = 1 : columns
for row = 1 : rows
kernel = ones(row, col)/(row * col);
meanImage = conv2(im, kernel, 'same');
% Now do something with meanImage.....
end
end
Not sure what you want to do with the mean image once you have it though.
Catégories
En savoir plus sur Linear Algebra dans Centre d'aide et File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!