How to delete specific values from matrix in matlab

Viewed 273

I have image matrix 420x700, and I want to delete a specific value in each row, changing the image dimensions. It is like deleting a column from it, but not in a straight line, to become 420x699 image. I should keep the values before the deleted value horizontally and shift all the values after it back by 1 position.

RGB = imread('image.jpg');
I1 = RGB(:,:,1);

How do I do that?

2 Answers

This is a good question, and I cannot think of a way to do this without a for-loop.

Let M be the nr-by-nc matrix from which you want to remove a column, and R the nr-by-1 vector with the column index of the element to be remove on each row.

The following code creates a new matrix A with the "column" removed from M, and vector B with the elements that were removed:

    [nr,nc] = size(M);
    A = zeros(nr,nc-1,'like',M);
    B = zeros(nr,1,'like',M);
    
    for k = 1:nr
        r = R(k);
        t = [ 1:r-1, r+1:nc ];
        
        A(k,:) = M(k,t);
        B(k) = M(k,r);
    end

@beaker and @Cris are correct, but just to add some flavor to this, I've attempted to demonstrate an alternate method - using linear indexing, which can teach an interesting lesson on column major indexing of 2D arrays in MATLAB.

Another point to note is that this kind of process is what's followed in the seam carving algorithm, where we remove a vertical seam in this manner.

Load a test image to run this on - crop it to analyze easier.

I = imread('peppers.png');
I = I(100:100+9, 100:100+19, :);

figure, imshow(I)

Create a mask indicating which pixels are to be removed. This simulates the condition which I think you're pointing to - in this case, we choose random column indices for each row to be removed. You'd likely have this information as an input.

mask = zeros(size(I, [1:2]), 'logical');
for idx = 1:size(mask, 1)
    randidx = randi(size(mask, 2));
    mask(idx, randidx) = 1;
end

figure, imshow(mask)

Use the column major linear indexing trick to do the removal faster! Since we're removing a column at at time, we rotate the image 90 degrees, and translate this problem to removing one row at a time. MATLAB indexes 'vertically', and so we can then use linear indexing to simply remove the masked pixels all at once (rather than one row/column at a time), and then restore the shape using reshape, and finally rotate back to the original orientation.

It = rot90(I);
maskt = rot90(mask);

% Preallocate output
Ioutput = zeros([size(I, 1), size(I, 2) - 1, size(I, 3)], 'like', I);

for nchannel = 1:3
    Icropped = It(:, :, nchannel);
    % MATLAB indexes column wise - so, we can use linear indexing to make
    % this computation simpler!
    Icropped = Icropped(maskt(:) == 0);
    Icropped = reshape(Icropped, [size(maskt, 1) - 1, size(maskt, 2)]);
    % Restore the correct orientation after removing element!
    Icropped = rot90(Icropped, 3);
    Ioutput(:, :, nchannel) = Icropped;
end

figure, imshow(Ioutput)

I've cropped the 'peppers' image to demonstrate this, so that you can convince yourself that this is doing it right. This method should work similarly for larger images as well.

Related