15、用YCbCr颜色模型根据肤色提取相关内容

本文主要使用 YCbCr 颜色模型根据肤色提取相关内容。

在前面讲到 YCbCr 颜色模型时说过,Cr 分量图中像素点的值在 140-160 范围内的像素点和人的肤色非常接近,因此可以使用该分量图进行和肤色相关内容的提取。下面介绍了几个关于该用法的例子。

1. 根据肤色提取图中的手


在这里插入图片描述
思路:将图片先转换为 YCbCr 图片,然后提取出来 Cr 分量图,筛选出来其中值在140-160 的像素点。将这些像素点置为 255,其他像素点置为 0。再转换为二值图,用二值图点乘原图,提取出该部分的彩色图。

步骤

  1. 先将图片转换为YCbCr图片,然后提取出来 Cr 分量图

    在这里插入图片描述
    代码:

    clc,clear,close all;
    f=imread('hand.jpg');
    imshow(f);
    fy=rgb2ycbcr(f);
    cr=fy(:,:,3);
    figure,imshow(cr);
    
  2. 将分量图中值在140-160 部分的像素点的值置为 255,其他部分的值置为 0

    在这里插入图片描述
    新增代码:

    cr(cr<140|cr>160)=0;   %将分量图中值在140-160范围之外的像素点置为0
    cr(cr~=0)=255;         %将剩余的值在140-160的点置为255
    figure,imshow(cr);
    
  3. 将图片转换为二值图

    在这里插入图片描述
    新增代码:

    bw=imbinarize(cr);
    figure,imshow(bw);
    
  4. 观察上图可以发现在手的范围内还有很多黑色部分,因此要先去除小坑洞

    在这里插入图片描述新增代码:

    bw=imfill(bw,'holes');
    figure,imshow(bw);
    
  5. 下面的问题便是将上面白色区域在原图中对应的区域提取出来。这里应用一种点乘的方法。

    首先对于上一步得到的 bw 图片来说,手所在区域的值都是 1 ,而其他部分的值都是 0 。我们可以用这张图的每个像素点和原图对应位置的像素点的值相乘,这样对于手的区域的像素点,留下的是原有的值,对于其他部分得到的是 0

    matlab中有运算符 .*,可以实现对于相同维度相同大小的图片,将对应位置的每个点的值相乘。由于上面得到的 bw 图是二维的,因此我们再次用 cat 函数将上图重叠三层,得到三维的新图,将新图和原图相点乘。

    但是在matlab中的运算都会转换为 double 类型的数据,因此在做点乘时候还需要将原图转换为double类型的。对于得到的结果还需要将其转换为8位图(用函数 uint8

    (关于运算时的类型转换和图片显示可以查看这篇文章)

    在这里插入图片描述
    本例代码:

    clc,clear,close all;
    f=imread('hand.jpg');
    imshow(f);
    fy=rgb2ycbcr(f);
    cr=fy(:,:,3);
    figure,imshow(cr);
    cr(cr<140|cr>160)=0;
    cr(cr~=0)=255;
    figure,imshow(cr);
    
    bw=imbinarize(cr);
    figure,imshow(bw);
    bw=imfill(bw,'holes');
    figure,imshow(bw);
    
    bws=cat(3,bw,bw,bw);
    result=double(f).*bws;
    figure,imshow(uint8(result));
    

2. 截取图片中的人脸头像


在这里插入图片描述
思路:通过观察可以发现,该图的操作方式和上一个例子差不多,只需要将后几步改为切割即可。

步骤

  1. 转换,分离,填补小坑洞。这几部分代码和上面的一样。

    在这里插入图片描述
    代码:

    clc,clear,close all;
    f=imread('qqm.jpg');
    imshow(f);
    fy=rgb2ycbcr(f);
    cr=fy(:,:,3);
    figure,imshow(cr);
    cr(cr<140|cr>160)=0;
    cr(cr~=0)=255;
    figure,imshow(cr);
    bw=imbinarize(cr);
    figure,imshow(bw);
    bw=imfill(bw,'holes');
    figure,imshow(bw);
    
  2. 观察上图可以发现有其它的连通区域干扰,我们用函数 bwareaopen 去除这些连通区域。

    在这里插入图片描述
    新增代码:

    bwao=bwareaopen(bw,500);
    figure,imshow(bwao);
    
  3. find 函数找到图中非0点的坐标点,然后再进行切割。

    在这里插入图片描述
    本例代码:

    clc,clear,close all;
    f=imread('qqm.jpg');
    imshow(f);
    fy=rgb2ycbcr(f);
    cr=fy(:,:,3);
    figure,imshow(cr);
    cr(cr<140|cr>160)=0;
    cr(cr~=0)=255;
    figure,imshow(cr);
    bw=imbinarize(cr);
    figure,imshow(bw);
    bw=imfill(bw,'holes');
    figure,imshow(bw);
    
    bwao=bwareaopen(bw,500);
    figure,imshow(bwao);
    
    [r,c]=find(bwao);
    resual=f(min(r):max(r),min(c):max(c),:);
    figure,imshow(resual);
    

3. 将图片中的头和两只手截取出来


在这里插入图片描述
思路:本例对肤色的提取和上面类似,改变点在于如何将图中的三部分都截取出来,本例用了一种方法见下所示,大家可以先尝试自己动手,用自己的方法来解决。

步骤

  1. 首先将图片的cr分量图分离,然后将肤色部分找出来,转换为二值图。

    在这里插入图片描述
    代码:

    clc,clear,close all;
    f=imread('man.jpg');
    imshow(f);
    fy=rgb2ycbcr(f);
    cr=fy(:,:,3);
    figure,imshow(cr);
    cr(cr<140|cr>160)=0;
    cr(cr~=0)=255;
    figure,imshow(cr);
    bw=imbinarize(cr);
    figure,imshow(bw);
    
  2. 观察二值图,我们发现在脸的下方有多余的部分和脸直接相连,我们需要去除,以防止对后续的操作造成影响。

    我是直接用腐蚀,便将脸部下面相连的圆圈直接去除了(如果和脸部下方相连的是一大片区域,该怎么去除呢?大家可以思考一下,在本例末尾我会说一下我的思路。)。

    在这里插入图片描述
    新增代码:

    bw=imerode(bw,strel('disk',1));
    figure,imshow(bw);
    
  3. 我们可以发现在中间手指头的食指上有黑色区域,我们可以用膨胀去除,同时可以恢复上一步腐蚀掉的一点区域。

    在这里插入图片描述
    新增代码:

    bw=imdilate(bw,strel('disk',1));
    figure,imshow(bw);
    
  4. 然后我们去除连通区域中的小坑洞。

    在这里插入图片描述
    新增代码:

    bw=imfill(bw,'holes');
    figure,imshow(bw);
    
  5. 再去除图中的小对象。

    在这里插入图片描述
    新增代码:

    bwao=bwareaopen(bw,500);
    figure,imshow(bwao);
    
  6. 可以看到图中就只剩下手和头的区域了,之后我选择了标记连通分量的方法来标记每个连通区域,再用 for 循环来切割每个区域。关于标记连通分量的函数 label 的详细讲解,请看这里
    在这里插入图片描述
    本例代码:

    clc,clear,close all;
    f=imread('man.jpg');
    imshow(f);
    fy=rgb2ycbcr(f);
    cr=fy(:,:,3);
    figure,imshow(cr);
    cr(cr<140|cr>160)=0;
    cr(cr~=0)=255;
    figure,imshow(cr);
    bw=imbinarize(cr);
    figure,imshow(bw);
    
    bw=imerode(bw,strel('disk',1));
    figure,imshow(bw);
    
    bw=imdilate(bw,strel('disk',1));
    figure,imshow(bw);
    
    bw=imfill(bw,'holes');
    figure,imshow(bw);
    
    bwao=bwareaopen(bw,500);
    figure,imshow(bwao);
    
    [L,n]=bwlabel(bwao);
    for i=1:n
        [r,c]=find(L==i);
        resual=f(min(r):max(r),min(c):max(c),:);
        figure,imshow(resual);
    end
    

    对于第二步的问题,我的思路为:先用腐蚀将两个部分断开,然后用去除小对象将下方区域去除,再用膨胀将脸部恢复原大小。

  • 7
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值