umbe1987
umbe1987

Reputation: 3610

Select n elements in matrix left-wise based on certain value

I have a logical matrix A, and I would like to select all the elements to the left of each of my 1s values given a fixed distant. Let's say my distance is 4, I would like to (for instance) replace with a fixed value (saying 2) all the 4 cells at the left of each 1 in A.

A= [0 0 0 0 0 1 0
   0 1 0 0 0 0 0
   0 0 0 0 0 0 0
   0 0 0 0 1 0 1]

B= [0 2 2 2 2 1 0
   2 1 0 0 0 0 0
   0 0 0 0 0 0 0
   2 2 2 2 2 2 1]

In B is what I would like to have, considering also overwrting (last row in B), and cases where there is only 1 value at the left of my 1 and not 4 as the fixed searching distance (second row).

Upvotes: 4

Views: 129

Answers (4)

Divakar
Divakar

Reputation: 221754

Approach #1 One-liner using imdilate available with Image Processing Toolbox -

A(imdilate(A,[ones(1,4) zeros(1,4+1)])==1)=2

Explanation

Step #1: Create a morphological structuring element to be used with imdilate -

morph_strel = [ones(1,4) zeros(1,4+1)]

This basically represents a window extending n places to the left with ones and n places to the right including the origin with zeros.

Step #2: Use imdilate that will modify A such that we would have 1 at all four places to the left of each 1 in A -

imdilate_result = imdilate(A,morph_strel)

Step #3: Select all four indices for each 1 of A and set them to 2 -

A(imdilate_result==1)=2

Thus, one can write a general form for this approach as -

A(imdilate(A,[ones(1,window_length) zeros(1,window_length+1)])==1)=new_value

where window_length would be 4 and new_value would be 2 for the given data.


Approach #2 Using bsxfun-

%// Paramters
window_length = 4;
new_value = 2;

B = A' %//'
[r,c] = find(B)
extents = bsxfun(@plus,r,-window_length:-1)
valid_ind1 = extents>0
jump_factor = (c-1)*size(B,1)
extents_valid = extents.*valid_ind1
B(nonzeros(bsxfun(@plus,extents_valid,jump_factor).*valid_ind1))=new_value
B = B' %// B is the desired output

Upvotes: 2

Luis Mendo
Luis Mendo

Reputation: 112769

d = 4; %// distance
v = 2; %// value

A = fliplr(A).'; %'// flip matrix, and transpose to work along rows.
ind = logical( cumsum(A) ...
    - [ zeros(size(A,1)-d+2,size(A,2)); cumsum(A(1:end-d-1,:)) ] - A );
A(ind) = v;
A = fliplr(A.');

Result:

A =
     0     2     2     2     2     1     0
     2     1     0     0     0     0     0
     0     0     0     0     0     0     0
     2     2     2     2     2     2     1

Upvotes: 2

Robert Seifert
Robert Seifert

Reputation: 25242

How about this lovely one-liner?

n = 3;
const = 5;
A = [0 0 0 0 0 1 0;
     0 1 0 0 0 0 0;
     0 0 0 0 0 0 0;
     0 0 0 0 1 0 1]

A(bsxfun(@ne,fliplr(filter(ones(1,1+n),1,fliplr(A),[],2)),A)) = const

results in:

A =

     0     0     5     5     5     1     0
     5     1     0     0     0     0     0
     0     0     0     0     0     0     0
     0     5     5     5     5     5     1

here some explanations:

Am = fliplr(A);                      %// mirrored input required
Bm = filter(ones(1,1+n),1,Am,[],2);  %// moving average filter for 2nd dimension
B = fliplr(Bm);                      %// back mirrored
mask = bsxfun(@ne,B,A)               %// mask for constants
A(mask) = const

Upvotes: 8

Dennis Jaheruddin
Dennis Jaheruddin

Reputation: 21561

Here is a simple solution you could have come up with:

w=4;                            % Window size
v=2;                            % Desired value

B = A;
for r=1:size(A,1)               % Go over all rows
  for c=2:size(A,2)             % Go over all columns
    if A(r,c)==1                % If we encounter a 1
       B(r,max(1,c-w):c-1)=v;   % Set the four spots before this point to your value (if possible)
    end
  end
end

Upvotes: 3

Related Questions