Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I zero out weak elements near stronger ones in a matrix?

I have a pixel matrix containing some points and a lot of zero elements. From those non-zero points, I want to discard those that have a stronger point in range N withing the matrix. The range is an euclidean distance between the pixels.

input  = [0.0 0.0 0.0 0.9 0.0 0.0 
          0.0 0.0 0.2 0.0 0.0 0.5 
          0.0 0.0 0.7 0.0 0.0 0.0 
          0.0 0.4 0.1 0.0 0.0 0.0];

output = [0.0 0.0 0.0 0.9 0.0 0.0   % 0.7 is the largest number in range
          0.0 0.0 0.0 0.0 0.0 0.5   % 0.2 got removed; was next to 0.9 and 0.7
          0.0 0.0 0.7 0.0 0.0 0.0   % 0.7 is the largest number in range
          0.0 0.0 0.0 0.0 0.0 0.0]; % 0.1 and 0.4 both got removed; were next to 0.7

Update: This is what I've came up so far. It iterates over all non-zero pixels and compares the current pixel to the largest of the neighborhood. However, the neighborhood contains to many pixels. Rather than selecting the area through index offsets, I need to select a circular area somehow. Moreover, I'd be grateful if there is a shorter way, maybe replacing the loops with built-in Matlab functions like conv2 or imfilter.

% Discard points near stronger points
points = find(Image > 0);
radius = args.Results.min_dist;
for i = 1:size(points)
    [index_y, index_x] = ind2sub(size(Image), points(i));
    %  Find neighborhood
    from_x = max(index_x-radius, 1);
    from_y = max(index_y-radius, 1);
    to_x = min(index_x+radius, size(Image, 2));
    to_y = min(index_y+radius, size(Image, 1));
    neighbors = Image(from_y:to_y, from_x:to_x);
    % Discard if there is a stronger neighbor
    largest = max(max(neighbors));
    if Image(index_y, index_x) < largest
        Image(index_y, index_x) = 0;
    end
end
like image 765
danijar Avatar asked Feb 09 '15 10:02

danijar


1 Answers

If you had the image processing toolbox installed (or one of the free alternatives mentioned in Try Hard's answer), you could make this happen quite easily:

The function imdilate is basically a sliding max filter. So what we do is, for each pixel we look for the maximum in the neighborhood specified by your radius R. Then we compare the actual value with the found maximum and if it is smaller, we set the value to zero.

function A = zeroOutWeakElements(A, R)
[X,Y] = ndgrid(-ceil(R):ceil(R));
neighborhood = (X.^2 + Y.^2)<=R^2;
A(imdilate(A,neighborhood)>A) = 0;

For large full matrices and small distances this would also be significantly faster than the currently accepted solution. The benefit will wear off with sparse matrices and large radii, but I guess you should test with actual data to be sure what's best.

like image 104
knedlsepp Avatar answered Oct 06 '22 06:10

knedlsepp