【问题标题】:Separating Background and Foreground分离背景和前景
【发布时间】:2013-01-03 14:54:04
【问题描述】:

我是 Matlab 和图像处理的新手。我正在努力在这样的图像中分离背景和前景

我有数百张这样的图片,找到here。通过反复试验,我发现了一个阈值(在 RGB 空间中):背景所在的红色层始终小于 150,绿色和蓝色层大于 150。

所以如果我的 RGB 图像是 I 而我的 rgb 图层是

redMatrix = I(:,:,1);
greenMatrix = I(:,:,2);
blueMatrix = I(:,:,3);

通过查找红色、绿色和蓝色值大于或小于 150 的坐标,我可以得到背景的坐标,例如

[r1 c1] = find(redMatrix < 150);
[r2 c2] = find(greenMatrix > 150);
[r3 c3] = find(blueMatrix > 150);

现在我在r1,c1,r2,c2,r3 and c3 中获得了数千像素的坐标。

我的问题:

  1. 如何找到常用值,例如红色小于 150 且绿色和蓝色大于 150 的像素坐标? 我必须迭代r1c1 的每个坐标,并检查它们是否出现在r2 c2r3 c3 中以检查它是否是一个共同点。但这将非常昂贵。 这可以在没有循环的情况下实现

  2. 如果我以某种方式想出了[commonR commonC]commonRcommonC 之类的共同点5000 X 1,那么要访问图像I 的这个背景像素,我必须先访问@987654339 @ 然后commonC 然后访问图片I 喜欢

    I(commonR(i,1),commonC(i,1))

那也太贵了。所以我的问题是这可以在没有循环的情况下完成。

任何帮助将不胜感激。

我得到了@Science_Fiction 答案的解决方案

只是详细说明他/她的答案

我用过

mask = I(:,:,1) < 150 & I(:,:,2) > 150 & I(:,:,3) > 150;

【问题讨论】:

    标签: image matlab image-processing


    【解决方案1】:

    不需要循环。你可以这样做:

    I = imread('image.jpg');
    redMatrix = I(:,:,1);
    greenMatrix = I(:,:,2);
    blueMatrix = I(:,:,3);
    J(:,:,1) = redMatrix < 150;
    J(:,:,2) = greenMatrix > 150;
    J(:,:,3) = blueMatrix > 150;
    J = 255 * uint8(J);
    imshow(J);
    

    灰度图像也足以分隔背景。

    K = ((redMatrix < 150) + (greenMatrix > 150) + (blueMatrix > 150))/3;
    imshow(K);
    

    编辑

    我又看了看,也使用了您链接到的其他图像。 考虑到背景颜色的差异,我认为从图像直方图导出阈值而不是硬编码会得到更好的结果。

    有时,此算法有点过于严格,例如与背景一起擦除部分衣服。但我认为超过 90% 的图像被很好地分离,这比你希望通过固定阈值实现的更强大。

    close all;
    
    path = 'C:\path\to\CUHK_training_cropped_photos\photos';
    files = dir(path);
    bins = 16;
    
    for f = 3:numel(files)
        fprintf('%i/%i\n', f, numel(files));
        file = files(f);
        if isempty(strfind(file.name, 'jpg'))
            continue
        end
    
        I = imread([path filesep file.name]);
    
        % Take the histogram of the blue channel
        B = I(:,:,3);
        h = imhist(B, bins);
        h2 = h(bins/2:end);
    
        % Find the most common bin in the *upper half*
        % of the histogram 
        m = bins/2 + find(h2 == max(h2));
    
        % Set the threshold value somewhat below  
        % the value corresponding to that bin
        thr = m/bins - .25;
        BW = im2bw(B, thr);
        % Pad with ones to ensure background connectivity
        BW = padarray(BW, [1 1], 1);
        % Find connected regions in BW image
        CC = bwconncomp(BW);    
        L = labelmatrix(CC);
        % Crop back again
        L = L(2:end-1,2:end-1);
    
        % Set the largest region in the orignal image to white
        for c = 1:3
            channel = I(:,:,c);
            channel(L==1) = 255;
            I(:,:,c) = channel;
        end 
    
        % Show the results with a pause every 16 images    
        subplot(4,4,mod(f-3,16)+1);
        imshow(I);
        title(sprintf('Img %i, thr %.3f', f, thr));
    
        if mod(f-3,16)+1 == 16
            pause
            clf
        end    
    
    end
    
    pause
    close all;
    

    结果:

    【讨论】:

    • 兄弟谢谢你的回答,但是这种做法是在改变人的坐标值,我不能不改变他们吗?
    【解决方案2】:

    你的方法看起来很基本但很体面。因为对于这个特定的图像,背景主要由蓝色组成,所以你很粗糙,然后:

    mask = img(:,:,3) > 150;
    

    这会将那些在 > 150 时为 true 的像素设置为 0,将 false 设置为 1。不过,您将获得一张黑白图像。

    imshow(mask);
    

    添加颜色

    mask3d(:,:,1) = mask; 
    mask3d(:,:,2) = mask; 
    mask3d(:,:,3) = mask;
    
    img(mask3d) = 255;
    imshow(img);
    

    应该给你一张脸的彩色图像,有一个纯白色的背景。所有这些都需要反复试验。

    【讨论】:

    • 这种方法很有帮助,但是当我添加颜色时,它仍然会替换脸部的某些部分。
    • 是的,因为这是一种粗略的方法。脸部的某些部分将具有较高的蓝色水平,因此将设置为 0。您可以更多地使用数字,并包括对 R 和 G 的检查。如前所述,将需要大量试验和错误。
    • 找到阈值(本例中为 150)的更通用方法是使用 Otsu 算法。这个函数是matlab内置的。
    猜你喜欢
    • 2015-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-13
    相关资源
    最近更新 更多