Opencv学习七分离混合通道与HSV+MASK提取图像

**

前言

**
打算做点有意思的东西了。
在这里插入图片描述

**

分离通道

**

split用于将一个多通道数组分离成几个单通道数组。

void split(const Mat& src, Mat* mvbegin);
void split(InputArray m, OutputArrayOfArrays mv);
  • 第一个参数const Mat&类型或InputArray类型的需要进行分离的多通道数组
  • 第二个参数,Mat*类型或OutputArrayOfArrays类型的输出数组或输出的vector容器
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;


int main() {

	Mat src = imread("E:/File/fusionImage2.bmp");
	vector<Mat> channels;
	split(src, channels);
	Mat img_B= channels.at(0);
	imshow("img_B", img_B);



	Mat logoImg = Mat::zeros(Size(500, 500), CV_8UC1);
	Mat img_ROI = img_B(Rect(100, 50, logoImg.cols, logoImg.rows));

	double alpha = 1.4;
	addWeighted(img_ROI, alpha, logoImg, 1 - alpha, 0.,img_ROI);
	imshow("分离得到的blue通道的ROI与logoImg混合", img_B);

	
	waitKey(0);
}

由于img_B只是单通道,所以显示出来是灰色。
在这里插入图片描述
在这里插入图片描述
**

合并通道

**

void merge(const Mat* mv, size_t count, OutputArray dst);
void merge(InputArrayOfArrays mv, OutputArray dst);
  • 第一个参数mv,填入需要被合并的输入矩阵或vector容器,这个mv参数中所有的矩阵必须有着一样的尺寸和深度
  • 第二个参数,count。当mv为空白的C数组时,代表输入矩阵的个数,这个参数必须大于1
  • 第三个参数,dst,输出矩阵,和mv[0]拥有一样的尺寸和深度,并且通道数量是矩阵阵列中的通道的总数

输出矩阵中的每个元素都将是输出数组的串接。其中第i个输入数组的元素被视为mv[i]。C一般用其中的Mat::at()方法对某个通道进行存储。

  • Mat::at()返回的是引用,修改一个,另一个也随之改变。

	Mat src = imread("E:/File/face.jpg");
	if (src.empty()) {
		cout << "读取图像有误,请重新输入正确路径!" << endl;
		return;
	}
	imshow("src img", src);



	//分离
	vector<Mat> channels_BGR;
	split(src, channels_BGR);
	Mat img_B = channels_BGR[0];
	Mat img_G = channels_BGR[1];
	Mat img_R = channels_BGR[2];
	imshow("blue img", img_B);			//这个是单通道,所以是灰色
	imshow("green img", img_G);
	imshow("red img", img_R);


	//将BGR色彩空间转换成HSV色彩空间
	Mat img_HSV;
	cvtColor(src, img_HSV, COLOR_BGR2HSV);
	imshow("HSV img", img_HSV);


	//分离
	vector<Mat>  channels_HSV;
	split(img_HSV, channels_HSV);
	Mat img_H = channels_HSV[0];
	Mat img_S = channels_HSV[1];
	Mat img_V = channels_HSV[2];
	imshow("hue img", img_H);
	imshow("saturation img", img_S);
	imshow("value img", img_V);



	//合成
	Mat dst;
	merge(channels_HSV, dst);
	imshow("HSV合成图像", dst);


单独显示一个通道就是0~255的灰色,但是如果是把3个通道的值都让其等于提取的那个通道的话,单独通道的颜色就显示出来了--------同理,单独去除哪个通道也是一样的道理:

	Mat src = imread("E:/wumo.jpg");
	
	imshow("原始图", src);
	vector<Mat> channels;
	split(src, channels);
	vector<Mat> bgr(3);
	//需要隐藏的通道,尺寸与src相同,单通道黑色图像
	Mat hideChannel(src.size(), CV_8UC1, Scalar(0));

	//显示彩色的B-蓝色分量
	Mat img_B(src.size(), CV_8UC3);
	bgr[0] = channels[0];
	bgr[1] = hideChannel;
	bgr[2] = hideChannel;
	merge(bgr, img_B);
	imshow("img_B-蓝色通道", img_B);					//这个是3通道,都是蓝色

	//红蓝混合
	Mat img_RB(src.size(), CV_8UC3);
	bgr[0] = channels[0];
	bgr[1] = hideChannel;
	bgr[2] = channels[2];
	merge(bgr, img_RB);
	imshow("红蓝混合,无绿", img_RB);

在这里插入图片描述

**

HSV提取图像

**

BGR颜色空间中,各个颜色区分性不强。但是对于HSV颜色空间来说,每种颜色都很明确。

  • 根据下表,可以看出,HSV把几个基本的颜色都划定了上下范围。因此,根据HSV范围,可以很容易把某种颜色分离出来。

在这里插入图片描述

#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;

void extract_object() {
	VideoCapture capture("E:/File/tree.avi");
	if (!capture.isOpened()) {
		cout << "cannot open ...";
		system("pause");
	}

	while (true) {
		Mat frame;
		bool ret = capture.read(frame);
		cout << ret << endl;
		if (ret == false)
			break;

		//转换颜色空间
		Mat hsv;
		cvtColor(frame,hsv, COLOR_BGR2HSV);


		imshow("hsv", hsv);

		if (waitKey(30) >= 0)
			break;

	}

}

int main() {

	
	extract_object();
	cout << "END" << endl;
	system("pause");
	destroyAllWindows();
}

在这里插入图片描述
装了Opencv的,都会有一份素材,应该在\opencv\sources\samples\data目录下。上面用的tree.avi,素材里也会有。

MASK是什么?
mask掩码,学过PS的应该知道,其实就是蒙版。但是有时候,Opencv里的mask没有蒙版那么强。只要把物体轮廓显示出来的图像,都叫mask。把前面循环里的改一下:

		//显示源图像
		imshow("源", frame);

		//转换颜色空间
		Mat hsv;
		cvtColor(frame,hsv, COLOR_BGR2HSV);

		//拿到绿色的掩码
		Mat mask;
		inRange(hsv, Scalar(35,43,46), Scalar(77,255,255), mask);

		//显示掩码
		imshow("mask", mask);

在这里插入图片描述
这里用了个inRange()把特定区域的图像印到mask上。

void inRange(InputArray src, 
			InputArray lowerb,
            InputArray upperb, 
            OutputArray dst);

但是如果我不要这种,我想把那块绿色的区域显示出来,啊彩色的。那才是蒙版MASK对吧

//图像与操作
		Mat dst;
		bitwise_and(frame, frame, dst, mask);

在这里插入图片描述
借用了bitwise_and()里有一个传入mask的参数,这里我们没有使用这个函数与的功能,只使用了遮盖的功能。

最后有一点,其他函数中的遮盖操作:
.copyTo()

这个函数第二个参数就是mask。


	Mat src = imread("E:/File/fusionImage2.bmp");
	Mat signal = imread("E:/File/002.jpg");
	if (!src.data||!signal.data) {
		cout << "读取图像有误,请重新输入正确路径!" << endl;
		return;
	}
	imshow("violet evergarden", src);
	imshow("logo", signal);

	Mat img_Roi = src(Rect(450, 20, signal.cols, signal.rows));
	//加载掩模
	Mat mask = imread("E:/File/mask.jpg",0);//0显示为灰度图
	imshow("mask", mask);

	//将掩模复制到ROI
	signal.copyTo(img_Roi,mask);				//mask大小要和img_Roi一样,mask为1 的区域,不要,mask为0的区域,保留
	//将signal复制到ROI
	//signal.copyTo(img_Roi);


	imshow("利用ROI实现图像叠加", src);

在这里插入图片描述

参考:《Opencv3编程入门》

猜你喜欢

转载自blog.csdn.net/weixin_41374099/article/details/86579118