基于HSV的背景抠图demo (opencv)绿背扣像

 

效果图:

基于HSV的背景抠图demo (opencv)绿背扣像_第1张图片

 

介绍

这是一个比较简易粗糙的抠图demo ,基于HSV进行抠图.

适合用于背景颜色大片相似的情况下.

但因为是demo,所以比较粗糙。

写的过程中翻看了很多博客,所以很多内容都是从大牛博客中学习的

如有相似代码,那基本上都是学习大牛的 哈哈哈  

写这个demo的目的主要是为了获取合适的HSV的值,当作工具来使用的

 

HSV介绍

基于HSV的背景抠图demo (opencv)绿背扣像_第2张图片

理论:

  • HSV是一种将RGB色彩空间中的点在倒圆锥体中的表示方法。
  • HSV即色相(Hue)、饱和度(Saturation)、明度(Value),又称HSB(B即Brightness)。
  • 色相是色彩的基本属性,就是平常说的颜色的名称,如红色、黄色等。
  • 饱和度(S)是指色彩的纯度,越高色彩越纯,低则逐渐变灰,取0-100%的数值。
  • 明度(V),取0-max(计算机中HSV取值范围和存储的长度有关)。
  • HSV颜色空间可以用一个圆锥空间模型来描述。
  • 圆锥的顶点处,V=0,H和S无定义,代表黑色。圆锥的顶面中心处V=max,S=0,H无定义,代表白色。如上图。

转换:

  •   RGB  ->  HSV   

         设max等于r、g和b中的最大者,min为最小者。对应的HSV空间中的(h,s,v)值为:

         h在0到360°之间,s在0到100%之间,v在0到max之间。

基于HSV的背景抠图demo (opencv)绿背扣像_第3张图片

 

  •  HSV -> RGB

基于HSV的背景抠图demo (opencv)绿背扣像_第4张图片

 

  • opencv 里面给我们提供了一种比较便捷的转换方式:

       RGB -> HSV      cvtColor ( RGB, HSV, COLOR_BGR2HSV );

       HSV -> BGR      cvtColor ( HSV, BGR, COLOR_HSV2BGR );

 

具体内容 

  • 读取配置文件中目的图片和背景图片的地址
  • 读取图片后判断是否成功
    Frame = imread(Add);
    Back = imread(BAdd);
    if (Frame.empty() || Back.empty())
    	{
    		cout << "Frame/Back read Failed !" << endl;
    		system("pause");
    		return -1;
    	}

     

  • 创建滑条 窗口等准备工作
    namedWindow(WIN);
    createTrackbar("Huemin", WIN, &h, hsvMax);
    createTrackbar("Huemax", WIN, &h2, hsvMax);
    createTrackbar("Saturationmin", WIN, &s, hsvMax);
    createTrackbar("Valuemin", WIN, &v, hsvMax);

     

  • 目标图片转成HSV格式
    cvtColor(Frame, Hsv, COLOR_BGR2HSV);

     

  • 处理图片
    //颜色范围,将结果存在mask中  
    inRange(Hsv, Scalar(h, s, v), Scalar(h2, 255, 255), Mask);
    
    //对视频的每一帧的图像与背景进行混合处理 ,返回结果给result 
    Mat result = BlendFrame(Frame, Mask);
    
    string print = format(" Huemin = %d\n 
                            Huemax = %d\n 
                            Saturationmin = %d\n 
                            Valuemin =%d\n\n\n", h, h2, s, v);
    
    cout << print.c_str() << endl;
    imshow("mask", Mask);
    imshow(WIN, result);

     

  • 每一帧进行图像混合
    //创建一张结果图  
    cv::Mat result = cv::Mat(frame.size(), frame.type());
    //图像的高 宽 与通道数  
    int height = result.rows;
    int width = result.cols;
    int channels = result.channels();
    //mask的像素值  
    int m = 0;
    //融合的比例  
    double wt = 0;
    //输出的像素 
    int r = 0, g = 0, b = 0; 
    int r1 = 0, g1 = 0, b1 = 0;
    int r2 = 0, g2 = 0, b2 = 0;
    
    

     

  • 通过图像的宽高进行循环混合
    //读取mask的像素值 
    m = *pmask++;

     

  • 判断是否前景背景
    //如果是背景的话  
    if (m == 255)
    {
        //进行三个通道的赋值  
    	*presult++ = *pbg++;
    	*presult++ = *pbg++;
    	*presult++ = *pbg++;
        //将frame的图像的像素的通道也移动单个保持一致 
    	pframe += 3; 
    }
    //如果是前景的话  
    else if (m == 0)
    {
    	//进行三个通道的赋值  
    	*presult++ = *pframe++;
    	*presult++ = *pframe++;
    	*presult++ = *pframe++;
        //将frame的图像的像素的通道也移动单个保持一致  
    	pbg += 3;
    }

     

  • 其余的情况下
    //背景图每个像素的三个通道  
    b1 = *pbg++;
    g1 = *pbg++;
    r1 = *pbg++;
    
    //每一帧每一个像素的三个通道  
    b2 = *pframe++;
    g2 = *pframe++;
    r2 = *pframe++;
    
    // 权重  
    wt = m / 255.0;
    
    // 混合  
    b = b1*wt + b2*(1.0 - wt);
    g = g1*wt + g2*(1.0 - wt);
    r = r1*wt + r2*(1.0 - wt);
    
    *presult++ = b;
    *presult++ = g;
    *presult++ = r;

     

  • 可以再写一个输出,调整到满意的图像后把该图像的HSV导出,就能实现一个获取目标图像HSV的工具的功能啦

 

运行结果图 分别是原图  背景图  Mask  结果图:

基于HSV的背景抠图demo (opencv)绿背扣像_第5张图片

 

 

备注:

  1. 背景大小要与目标图片一致。
  2. 处理图片时写成循环方便调整。
  3. 处理HSV图像的时候,可以做一些边缘模糊,这样融合后不会太突兀,但是因为时个demo 所以这个版本里就没写。

 

 demo地址:https://download.csdn.net/download/weixin_41794771/11632053

以上为学习笔记。

你可能感兴趣的:(Opencv,抠图,opencv,C++)