Opencv -- 12图像色彩空间转换应用 -- 给证件照换颜色背景

Opencv -- 12图像色彩空间转换应用 -- 给证件照换颜色背景_第1张图片

应用:给证件照换颜色背景

利用HSV中的常见色彩区分度比RGB中的色彩区分度更明显的优势,再结合inRange()函数可以将图片中不同的颜色给提取出来。

openCV中的HSV颜色体系

使用 OpenCV 中的 cvtColor 函数,并设置参数为CV_BGR2HSV,那么所得的H、S、V值范围分别是[0,180),[0,255),[0,255),这时我们可以查下面的表格来确定颜色的大致区间。
Opencv -- 12图像色彩空间转换应用 -- 给证件照换颜色背景_第2张图片

inRange()函数

OpenCV中的inRange()函数可实现二值化功能(这点类似threshold()函数),更关键的是可以同时针对多通道进行操作,使用起来非常方便!主要是将在两个阈值内的像素值设置为白色(255),而不在阈值区间内的像素值设置为黑色(0)。

要特别注意的是:该函数输出的是一幅二值化之后的图像。

程序如下:

#include <iostream>
#include "12_opencv_mat.h"

using namespace std;

void QuickDemo::inrange_demo(Mat &image)
{
	Mat hsv = Mat::zeros(image.size(), image.type());
	//我们这里输入的是一张白底图像
	cvtColor(image,hsv,COLOR_BGR2HSV);

	/*
	 *   inRange
	 *   函数功能:
	 *   inRange()函数可实现二值化功能(这点类似threshold()函数),
	 * 更关键的是可以同时针对多通道进行操作,使用起来非常方便!
	 * 主要是将在两个阈值内的像素值设置为白色(255),而不在阈值区间内的像素值设置为黑色(0)。
	 * 
	 *  void inRange(InputArray src, InputArray lowerb, InputArray upperb, OutputArray dst)
	 * 
	 *  参数1:输入要处理的图像,可以为单通道或多通道。
	 *	参数2:包含下边界(最小值)的数组或标量。
     *  参数3:包含上边界(最大值)的数组或标量。
     *  参数4:输出图像,与输入图像src其大小和通道数量且为 CV_8U 类型。
	 * 
	 *  要特别注意的是:该函数输出的DST是一幅二值化之后的图像。
	 */
	Mat mask;
	
	inRange(hsv, Scalar(0,0,221), Scalar(180,30,255), mask);//注意集合的开闭
	
	imshow("输出图像", mask);
}

运行程序:
Opencv -- 12图像色彩空间转换应用 -- 给证件照换颜色背景_第3张图片
理论上,输入图像中除了白色部分都应该变成黑色。但从输入图像和输出图像对比来看,输入图像中的左半部分的颜色有点偏粉红并没有被识别出来。所以这种处理有些粗糙。

Opencv -- 12图像色彩空间转换应用 -- 给证件照换颜色背景_第4张图片
下面程序要求弄懂对mask的理解。
12_opencv_mat.h

#pragma once

#ifndef _12_OPENCV_MAT_H
#define _12_OPENCV_MAT_H

#include <opencv2/opencv.hpp>

using namespace cv;

class QuickDemo {
public:
	void inrange_demo(Mat& image);
};
#endif

12_opencv_mat.cpp

#include <iostream>
#include "12_opencv_mat.h"

using namespace std;

void QuickDemo::inrange_demo(Mat &image)
{
	Mat hsv = Mat::zeros(image.size(), image.type());

	cvtColor(image,hsv,COLOR_BGR2HSV);

	/*
	 *   inRange
	 *   函数功能:
	 *   inRange()函数可实现二值化功能(这点类似threshold()函数),
	 * 更关键的是可以同时针对多通道进行操作,使用起来非常方便!
	 * 主要是将在两个阈值内的像素值设置为白色(255),而不在阈值区间内的像素值设置为黑色(0)。
	 * 
	 *  void inRange(InputArray src, InputArray lowerb, InputArray upperb, OutputArray dst)
	 * 
	 *  参数1:输入要处理的图像,可以为单通道或多通道。
	 *	参数2:包含下边界(最小值)的数组或标量。
     *  参数3:包含上边界(最大值)的数组或标量。
     *  参数4:输出图像,与输入图像src其大小和通道数量且为 CV_8U 类型。
	 * 
	 *  要特别注意的是:该函数输出是一幅二值化之后的图像。
	 */
	Mat mask;
	//我们这里输入的是一张白底图像
	inRange(hsv, Scalar(0,0,221), Scalar(180,30,255), mask);//注意集合的开闭
	//mask中白色背景的值为255,人物部分的值为0

	//创建一个空白图像
	Mat redback = Mat::zeros(image.size(), image.type());
	redback = Scalar(22,22,222);//红色
	bitwise_not(mask,mask);//此时mask中白色背景的值为0,人物部分的值为255

	/*
	 *  copyTo的函数功能:将输入图像复制到输出图像。
	 *	copyTo是图像(Mat)对象的成员方法,有两种
	 *	void Mat::copyTo(OutputArray m)
	 *  和
	 *  void Mat::copyTo(OutputArray m, InputArray mask)
	 * 
	 *  参数:
	 *   m   – 输出图像。 如果在操作之前它没有适当的大小或类型,则重新分配它。
     *  mask – 掩码操作(标记操作). 它的非零元素表示需要复制哪些矩阵元素。
	 * 
	 *  使用第二个函数时必须要提供mask参数,没有不能写NULL,否则程序报错。
	 */

	/*
	    该函数把输入图像(数组)image中被选中的(mask不为0对应的部分)元素
	    拷贝到输出图像(redback)中,需要注意的是mask是一个和dst or src大小完全一致的数组(图像)。
	*/
	image.copyTo(redback,mask);
	/*
	 * 能够进行下述操作的前提是,mask是一个和dst or src大小完全一致的数组(图像)。
	 if (mask(I) ! = 0)
	     dst(I) = src(I);
	 else
		 dst(I) = dst(I);
	*/

	imshow("输出图像", redback);
}

main.cpp

#include <iostream>
#include "12_opencv_mat.h"

using namespace std;

int main(int argc,char** argv)
{
    //使用Mat(matrix -- 矩阵)这种类型来读取通过指定路径的图像信息并存放到变量picture中。
    //图像从本质上来说都是二维的数组(矩阵)
    Mat picture = imread("鱼头人.jpeg", IMREAD_COLOR);

    if (picture.empty())
    {
        cout << "could not Load image." << endl;
        system("pause");
        return -1;
    }
    
    // namedWindow("输入窗口",WINDOW_FREERATIO);
   
    imshow("输入窗口", picture);

    QuickDemo qd;
    qd.inrange_demo(picture);

    waitKey(0);
    destroyAllWindows();

    system("pause");
    return 0;
}

最后运行结果如下:
Opencv -- 12图像色彩空间转换应用 -- 给证件照换颜色背景_第5张图片
可以看出来处理后的结果非常粗糙,这种方式只适合背景与人物颜色相差非常明显(区分度很大)的图像的处理。

你可能感兴趣的:(笔记,opencv)