【问题标题】:How to delete specific values from matrix in matlab如何从matlab中的矩阵中删除特定值
【发布时间】:2021-08-23 05:33:52
【问题描述】:

我有 420x700 的图像矩阵,我想删除每一行中的特定值,从而更改图像尺寸。这就像从中删除一列,但不是直线,成为 420x699 图像。我应该将删除值之前的值保持水平,并将其之后的所有值移回 1 个位置。

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

我该怎么做?

【问题讨论】:

  • 对于图像中的每一行r,将该行存储在一个临时数组中,删除所需的元素,然后将修改后的数组复制到输出图像的r行。
  • 我认为您完全按照您的描述进行操作:对于每一行,将您选择的索引后面的值移回 1 个位置。然后你就可以删除最后一列了。

标签: matlab image-processing matrix


【解决方案1】:

这是一个很好的问题,我想不出没有 for 循环的方法。

M 成为您要从中删除列的nr-by-nc 矩阵,并让R 成为nr-by-1 向量,其中包含每行上要删除的元素的列索引。

以下代码创建一个新矩阵A,其中“列”从M 中删除,向量B 中删除的元素:

    [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

【讨论】:

    【解决方案2】:

    @beaker 和@Cris 是正确的,但只是为了增加一些风味,我尝试演示另一种方法 - 使用线性索引,它可以教授关于 MATLAB 中二维数组的列主要索引的有趣课程。

    需要注意的另一点是,这种过程是接缝雕刻算法所遵循的,我们以这种方式去除垂直接缝。

    加载一个测试图像来运行它 - 裁剪它以便于分析。

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

    创建一个掩码,指示要删除哪些像素。这模拟了我认为您指向的条件 - 在这种情况下,我们为要删除的每一行选择随机列索引。您可能会将这些信息作为输入。

    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)
    

    使用列主要线性索引技巧来更快地进行删除!由于我们一次删除一列,我们将图像旋转 90 度,并将此问题转换为一次删除一行。 MATLAB 是“垂直”索引的,因此我们可以使用线性索引来简单地一次性移除所有被遮罩的像素(而不是一次一行/一列),然后使用 reshape 恢复形状,最后旋转回原来的形状方向。

    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)
    

    我已经裁剪了“辣椒”图像来演示这一点,这样您就可以说服自己这样做是正确的。这种方法对于较大的图像也应该同样适用。

    【讨论】:

    • 我认为这是不对的。您应该转置而不是使用rot90,这样做两次(之前和之后)的成本远远超过了跨行迭代大型矩阵的成本,因此这种方法实际上比使用 for 循环慢。
    • @JonathanH - 我已经手动测试了旋转的想法 - 因为删除一列中的像素独立于其他列,所以旋转应该与此处的转置相同。我们只需要“方向”是“垂直的”。我没有进行严格的性能测试,所以你可能是正确的 w.r.t.传统方法更快。因此,我在此处的答案中编辑/删除了性能声明。感谢您分享您的想法!
    • 感谢您提出了一种在这种情况下避免 for 循环的有趣方法!它非常巧妙,尽管它可能不是最有效的方法。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-21
    • 2012-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-16
    • 1970-01-01
    相关资源
    最近更新 更多