opencv C艹:色彩空间转换,像素最值,二值化,LUT

色彩空间

RGB,RGBA,YUV(亮度,红色分量与亮度信号的插值,蓝色与亮度的插值),HSV(色度,饱和度,亮度)。。。。。

void cv::cvtColor	(	InputArray 	src,
						OutputArray 	dst,
						int 	code,
						int 	dstCn = 0 
						)	

// 数据类型转换
void cv::Mat::convertTo	(	OutputArray 	m,
int 	rtype,
double 	alpha = 1,
double 	beta = 0 
)		const

改变色彩空间,前两个参数用于输入图像,目标图像,第三个参数指明转换的色彩空间,第四个参数默认就行。。需要注意的是该函数变换前后的图像取值范围
8位无符号图像的像素为0 - 255。CV_8U
16 无符号图像的像素为 0-65535. CV_16U
32 位浮点图像的像素为 0-1 ,
因此一定要注意目标图像的像素范围.在线性变换的情况下,范围问题不需要考虑,目标图像的像素不会超出范围。如果在非线性变换的情况下,那么应将输入 RGB 图像归一化到适当的范围以内来获得正确的结果,例如将 8位无符号图像转成 位32浮点图像 需要先将图像像素通过除以 255 缩放0-1 范围内 以防止产生错误结果.

opencv C艹:色彩空间转换,像素最值,二值化,LUT_第1张图片
数据类型转换,参数为输出图像,转换图像的目标类型,alpha ,beta缩放因子,偏置因子。
m ( x , y ) = s a t u r a t e c a s t < r t p y e > ( α ( ∗ t h i s ) ( x , y ) + β ) m(x,y) = saturate_cast(\alpha(*this)(x,y) + \beta) m(x,y)=saturatecast<rtpye>(α(this)(x,y)+β)

转换方式就是线性变换,按照指定的类型输出。

#include                        
#include 
#include 
#include 
using namespace std;
using namespace cv;
 
int main(int argc, char *argv[])
{
	system("color E");
	Mat img = imread("D:\\壁纸\\2k.jpg");
	cout<<img.type()<<endl;
	cout << size(img) << img.type() << endl;
	if (img.empty())
	{
		cout << "error";
	}
	Mat gray, HSV, YUV, Lab, img32;
	img.convertTo(img32, CV_32F, 1.0 / 255);  // 类型转换,将CV_8U转换成CV_32F
	cvtColor(img32, HSV, COLOR_BGR2HSV);
	cvtColor(img32, YUV, COLOR_BGR2YUV);
	cvtColor(img32, Lab, COLOR_BGR2Lab);
	cvtColor(img32, gray, COLOR_BGR2GRAY);

	imshow("原图", img32);
	imshow("hsv", HSV);
	imshow("YUV", YUV);
	imshow("Lab", Lab);
	imshow("gray", gray);
	waitKey(100);
	return 0;
}

通道的分离和合并

图片的不同分量存放在不同通道里,通道的分离处理,在合并重新生成图像。

void cv::split	(	const Mat & 	src,
					Mat * 	mvbegin   // 分离的通道,为数组的形式,需要知道通道数
)	
void cv::split	(	InputArray 	m,
					OutputArrayOfArrays 	mv // 分离的单通道,向量vector格式,不用知道通道数
)	
void cv::merge	(	const Mat * 	mv, // 数组,尺寸,类型相同
					size_t 	count,   // 输入图像数组的长度,大于0
					OutputArray 	dst 
)	
void cv::merge	(	InputArrayOfArrays 	mv,  // 与split对应
OutputArray 	dst 
)	


#include                        
#include 
#include 
#include 
using namespace std;
using namespace cv;
 
int main(int argc, char *argv[])
{
	system("color E");
	Mat img = imread("D:\\壁纸\\2k.jpg");
	Mat HSV;
	cvtColor(img, HSV, COLOR_RGB2HSV);
	Mat imgs0, imgs1, imgs2;    // 存放数组类型的结果
	Mat imgv0, imgv1, imgv2;    // 存放vector类型的结果
	Mat result0, result1, result2; // 合并结果

	Mat imgs[3];
	split(img, imgs);

	imgs0 = imgs[0];
	imgs1 = imgs[1];
	imgs2 = imgs[2];

	imshow("B", imgs0);   // 分离的结果
	imshow("G", imgs1);
	imshow("R", imgs2);

	imgs[2] = img;   // 改变通道数
	merge(imgs, 3, result0);   // 合并成 5 通道
	// imshow("result0", result0);  // imshow最多显示 4 个通道。可以在image watch中查看

	Mat zero = cv::Mat::zeros(img.rows, img.cols, CV_8UC1);
	imgs[0] = zero;
	imgs[2] = zero;

	merge(imgs, 3, result1);  // 只剩绿色通道
	imshow("resutl1", result1);

	vector<Mat> imgv;
	split(HSV, imgv);
	imgv0 = imgv.at(0);
	imgv1 = imgv.at(1);
	imgv2 = imgv.at(2);
	imshow("H", imgv0);
	imshow("S", imgv1);
	imshow("V", imgv2);
	imgv.push_back(HSV);    // 通道数改变
	merge(imgv, result2);    // 六通道
	// imshow("result2", result2);
	waitKey(0);
	return 0;
}

像素操作

像素最大,最小值


void cv::minMaxLoc	(	InputArray 	src,     // 单通道,多个最值返回左上第一个
						double * 	minVal,     // 值,不需要的值设置为NULL
						double * 	maxVal = 0,  // 输入参数加上 &
						Point * 	minLoc = 0,  // 坐标指针,左上角为远点,Point(x,y)
						Point * 	maxLoc = 0,  // 水平x轴,数值y轴
						InputArray 	mask = noArray()  // 掩模,指定区域
)	
cv::Point2i 对二维坐标设置的整形类型,Point2d double Point2f float,三维Point3i
Point.x 具体坐标可以通过对变量的 x,y,z 属性访问。

Mat cv::Mat::reshape	(	int 	cn,    // 转换后矩阵的通道数
							int 	rows = 0   // 转换后矩阵的行数,0表示不变
							)		const

#include                        
#include 
#include 
#include 
using namespace std;
using namespace cv;
 
int main(int argc, char *argv[])
{
	system("color E");
	// Mat img = imread("D:\\壁纸\\2k.jpg");
	float a[12] = { 1,2,3,4,5,10,6,7,8,9,10,0 };
	Mat img = Mat(3, 4, CV_32FC1, a);   // 单通道
	Mat imgs = Mat(2, 3, CV_32FC2, a);  // 多通道
	double minVal, maxVal;
	Point minIdx, maxIdx;

	minMaxLoc(img, &minVal, &maxVal, &minIdx, &maxIdx);  // 放入地址
	cout << "max" << maxVal << " " << " point" << maxIdx << endl;
	cout << "min" << minVal << " " << "point" << minIdx << endl;

	Mat imgs_re = imgs.reshape(1, 4);  // 多通道的最值要转换成单通道,(4,3)
	minMaxLoc(imgs_re, &minVal, &maxVal, &minIdx, &maxIdx);
	cout << "max" << maxVal << " " << " point" << maxIdx << endl;
	cout << "min" << minVal << " " << "point" << minIdx << endl;

	return 0;
}
	

平均值,标准差


Scalar cv::mean	(	InputArray 	src,   // 通道为 1-4,返回Scalar类型变量,4位单通道后三位为0
					InputArray 	mask = noArray()  // 掩模
)	

void cv::meanStdDev	(	InputArray 	src, 
						OutputArray 	mean,  // 平均值,标准差
						OutputArray 	stddev,  // Mat型变量,数据个数与传入的通道数一样
						InputArray 	mask = noArray() 
)

int main(int argc, char *argv[])
{
	system("color E");
	// Mat img = imread("D:\\壁纸\\2k.jpg");
	float a[12] = { 1,2,3,4,5,10,6,7,8,9,10,0 };
	Mat img = Mat(3, 4, CV_32FC1, a);   // 单通道
	Mat imgs = Mat(2, 3, CV_32FC2, a);  // 多通道
	
	Scalar Mean;
	Mean = mean(imgs);
	cout << Mean << Mean[0] << Mean[1] << endl;

	Mat MeanMat, StddevMat;
	meanStdDev(img, MeanMat, StddevMat);
	cout << MeanMat << StddevMat << endl;
	meanStdDev(imgs, MeanMat, StddevMat);
	cout << MeanMat << StddevMat << endl;

	return 0;
}

图像比较操作

求两幅图每个像素的大值,小值,保留较大值

#include                        
#include 
#include 
#include 
using namespace std;
using namespace cv;
 
int main(int argc, char *argv[])
{
	system("color E");
	Mat img0 = imread("lena.png");
	Mat img1 = imread("noobcv.jpg");
	Mat comMin, comMax;

	max(img0, img1, comMax); // 保留两幅图像对应位置较大的值
	min(img0, img1, comMin);
	imshow("max", comMax);
	imshow("min", comMin);

	Mat src1 = Mat::zeros(Size(512, 512), CV_8UC3); 
	Rect rect(100, 100, 300, 300);  // x,y,w,h
	src1(rect) = Scalar(255, 255, 255);  // 此范围内赋值,构建一个掩模
	Mat comsrc1, comsrc2;
	min(img0, src1, comsrc1);  // 显示较小值,就提取了掩模 255(白色)的部分。
	imshow("src1", comsrc1);  

	Mat img0G, img1G, comMinG, comMaxG;
	cvtColor(img0, img0G, COLOR_BGR2GRAY);
	cvtColor(img1, img1G, COLOR_BGR2GRAY);
	max(img0G, img1G, comMaxG);
	min(img0G, img1G, comMinG);
	imshow("MinG", comMinG);
	imshow("MaxG", comMaxG);

	return 0;
}

逻辑操作

就是逐位的 与 或 非 异或。对应的函数就是 bitwise_and/or/xor/not ,参数一样,两个输入图像,一个输出图像,一个掩模。

int main()
{
	Mat img = imread("lena.png");
	if (img.empty())
	{
		cout << "请确认图像文件名称是否正确" << endl;
		return -1;
	}
	//创建两个黑白图像
	Mat img0 = Mat::zeros(200, 200, CV_8UC1);
	Mat img1 = Mat::zeros(200, 200, CV_8UC1);
	Rect rect0(50, 50, 100, 100);
	img0(rect0) = Scalar(255);
	Rect rect1(100, 100, 100, 100);
	img1(rect1) = Scalar(255);
	imshow("img0", img0);
	imshow("img1", img1);

	//进行逻辑运算
	Mat myAnd, myOr, myXor, myNot, imgNot;
	bitwise_not(img0, myNot);
	bitwise_and(img0, img1, myAnd);
	bitwise_or(img0, img1, myOr);
	bitwise_xor(img0, img1, myXor);
	bitwise_not(img, imgNot);
	imshow("myAnd", myAnd);
	imshow("myOr", myOr);
	imshow("myXor", myXor);
	imshow("myNot", myNot);
	imshow("img", img);
	imshow("imgNot", imgNot);
	waitKey(0);
	return 0;
}

二值化

非黑即白

double cv::threshold	(	InputArray 	src,  // CV_8U,CV_32F 两种类型,通道数与选择的方法有关
							OutputArray 	dst,  // 结果图
							double 	thresh,  // 阈值
							double 	maxval,  // 二值化过程中的最大值,BINARY方法有关
							int 	type   // 二值化的标志
)
标志 简记 作用
THRESH_BINARY 0 灰度值大于阈值的为最大值,其余为0
THREESH_BINARY_INY 1 灰度值大于阈值的为0,其余为最大值
THRESH_TRUNC 2 灰度值大于阈值的为阈值,其他值不变
THRESH_TOZERO 3 灰度值大于阈值的不变,其他为0
THRESH_TOZERO_INV 4 灰度值大于阈值的为0,其他不变
THRESH_OTSU 8 大津法自动求全局阈值
THRESH_TRIANGLE 16 三角形法自动求全局阈值

后两个标志是获取阈值的方法,可以与前面的标志一起使用比如“ THRESH_OTSU|THRESH_BINARY" ,前面5种需要认为的设置阈值,自动获取的会更加合适。但是调用时还是要输入thresh参数,就是系统不会认。
opencv C艹:色彩空间转换,像素最值,二值化,LUT_第2张图片
threshold() 函数全局就用一个阈值,实际上,由于光照,阴影的影响,全局只有一个i阈值是不合理的。adativeThershold() 提供了两个局部自适应阈值的二值化方法。

void cv::adaptiveThreshold	(	InputArray 	src, // 只能是CV_8U
		OutputArray 	dst,
			double 	maxValue,  // 二值化的最大值
			int 	adaptiveMethod, // 自适应阈值的方法两种。高斯法或均值法
			int 	thresholdType, // 二值化的标志,只能是BINART OR BINARY_INV 两种
			int 	blockSize, // 自适应确定阈值的邻域,3,5,7奇数
			double 	C // 平均值或加权平均值种减去的常数,可正可负
)	



int main()
{
	Mat img = imread("lena.png");

	Mat gray;
	cvtColor(img, gray, COLOR_BGR2GRAY);
	Mat img_B, img_B_V, gray_B, gray_B_V, gray_T, gray_T_V, gray_TRUNC;

	//彩色图像二值化
	threshold(img, img_B, 125, 255, THRESH_BINARY);
	threshold(img, img_B_V, 125, 255, THRESH_BINARY_INV);
	imshow("img_B", img_B);
	imshow("img_B_V", img_B_V);

	//灰度图BINARY二值化
	threshold(gray, gray_B, 125, 255, THRESH_BINARY);
	threshold(gray, gray_B_V, 125, 255, THRESH_BINARY_INV);
	imshow("gray_B", gray_B);
	imshow("gray_B_V", gray_B_V);

	//灰度图像TOZERO变换
	threshold(gray, gray_T, 125, 255, THRESH_TOZERO);
	threshold(gray, gray_T_V, 125, 255, THRESH_TOZERO_INV);
	imshow("gray_T", gray_T);
	imshow("gray_T_V", gray_T_V);

	//灰度图像TRUNC变换
	threshold(gray, gray_TRUNC, 125, 255, THRESH_TRUNC);
	imshow("gray_TRUNC", gray_TRUNC);

	//灰度图像大津法和三角形法二值化
	Mat img_Thr = imread("threshold.png", IMREAD_GRAYSCALE);
	Mat img_Thr_O, img_Thr_T;
	threshold(img_Thr, img_Thr_O, 100, 255, THRESH_BINARY | THRESH_OTSU);
	threshold(img_Thr, img_Thr_T, 125, 255, THRESH_BINARY | THRESH_TRIANGLE);
	imshow("img_Thr", img_Thr);
	imshow("img_Thr_O", img_Thr_O);
	imshow("img_Thr_T", img_Thr_T);

	//灰度图像自适应二值化
	Mat adaptive_mean, adaptive_gauss;
	adaptiveThreshold(img_Thr, adaptive_mean, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 55, 0);
	adaptiveThreshold(img_Thr, adaptive_gauss, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 55, 0);

	imshow("adaptive_mean", adaptive_mean);
	imshow("adaptive_gauss", adaptive_gauss);
	waitKey(0);
	return 0;
}

LUT(显示查找表)

前面介绍的阈值比较方法都只有一个阈值,需要与多个阈值比较,就用LUT,一个像素灰度值的映射表,,它以像索灰度值作为索引,以灰度值映射后的数值作为表中的内容。

void cv::LUT	(	InputArray 	src,  // 输入图像矩阵,只能是cv_8u,可以多通道
					InputArray 	lut,  // 1*256的像素灰度值的查找表,单通道或多通道
					OutputArray 	dst  // 输出类型与LUT 的类型一致,将灰度值映射到了新的空间种
)	

#include                        
#include 
#include 
#include 
using namespace std;
using namespace cv;
 
int main()
{
	//LUT查找表第一层
	uchar lutFirst[256];
	for (int i = 0; i < 256; i++)
	{
		if (i <= 100)
			lutFirst[i] = 0;
		if (i > 100 && i <= 200)  // 就是原图像的i像素,映射为我们指定的。
			lutFirst[i] = 100;
		if (i > 200)
			lutFirst[i] = 255;
	}
	Mat lutOne(1, 256, CV_8UC1, lutFirst);

	//LUT查找表第二层
	uchar lutSecond[256];
	for (int i = 0; i < 256; i++)
	{
		if (i <= 100)
			lutSecond[i] = 0;
		if (i > 100 && i <= 150)
			lutSecond[i] = 100;
		if (i > 150 && i <= 200)
			lutSecond[i] = 150;
		if (i > 200)
			lutSecond[i] = 255;
	}
	Mat lutTwo(1, 256, CV_8UC1, lutSecond);

	//LUT查找表第三层
	uchar lutThird[256];
	for (int i = 0; i < 256; i++)
	{
		if (i <= 100)
			lutThird[i] = 100;
		if (i > 100 && i <= 200)
			lutThird[i] = 200;
		if (i > 200)
			lutThird[i] = 255;
	}
	Mat lutThree(1, 256, CV_8UC1, lutThird);

	//拥有三通道的LUT查找表矩阵
	vector<Mat> mergeMats;
	mergeMats.push_back(lutOne);
	mergeMats.push_back(lutTwo);
	mergeMats.push_back(lutThree);
	Mat LutTree;
	merge(mergeMats, LutTree);  // 通道合并

	//计算图像的查找表
	Mat img = imread("lena.png");
	if (img.empty())
	{
		cout << "请确认图像文件名称是否正确" << endl;
		return -1;
	}

	Mat gray, out0, out1, out2;
	cvtColor(img, gray, COLOR_BGR2GRAY);
	LUT(gray, lutOne, out0);
	LUT(img, lutOne, out1);
	LUT(img, LutTree, out2);
	imshow("out0", out0);
	imshow("out1", out1);
	imshow("out2", out2);
	waitKey(0);
	return 0;
}

可以看到,每个通道的像素都映射到了我们的规定值。
opencv C艹:色彩空间转换,像素最值,二值化,LUT_第3张图片

总结

函数 说明
cvtColor 色彩空间转换
converTo 数据类型转换
saturate_cast() 缩放到标准
split 通道的分割
merge 通道的合并
minMaxLoc 像素最大最小值与位置
mean 平均值
meanStdDev 平均值加标准差
max/min 比较两幅图像的较大较小值
bitwise_and/or/xor/not 两幅图像素之间的逻辑操作
threshold 二值化
adaptiveThreshold 局部自适应二值化
LUT 灰度值映射,多阈值
// 构建一个掩模
Mat src1 = Mat::zeros(Size(512, 512), CV_8UC3); 
Rect rect(100, 100, 300, 300);  // x,y,w,h
src1(rect) = Scalar(255, 255, 255);  // 此范围内赋值,构建一个掩模

你可能感兴趣的:(opencv从入门到放弃,opencv,c++)