1

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

护照图像蓝色背景

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

所以如果我的 RGB 图像是I和我的r,gb图层是

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 的像素坐标?我必须迭代 and 的每个坐标r1c1检查它们是否出现在r2 c2r3 c3检查它是否是一个共同点。但这将非常昂贵。 这可以在没有循环的情况下实现吗?

  2. 如果不知何故我想出了像[commonR commonC]andcommonRcommonC两者都是有序的共同点5000 X 1,那么要访问 Image 的这个背景像素I,我必须先访问commonR然后commonC再访问I图像

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

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

任何帮助,将不胜感激。

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

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

我用了

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

2 回答 2

4

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

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;

结果:

在此处输入图像描述

于 2013-01-20T10:50:16.057 回答
3

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

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);

应该给你一张脸的彩色图像,背景是纯白色的。所有这些都需要一些试验和错误。

于 2013-01-20T10:52:45.007 回答