OpenCV 笔记_1

笔记_1


文章目录

  • 笔记_1
    • Mat类数据类型读取
    • Mat类支持的运算
    • 图像读取,显示,保存
      • imread 图像读取
      • namedWindow 创建要显示的窗口
      • imshow 窗口显示
      • imwrite 图像保存
    • 视频加载与摄像头的使用
      • VideoCapture 加载视频或摄像头
      • get 获取属性
      • VideoWriter 保存视频
    • 图像颜色空间转换
      • RGB
      • HSV
      • convertTo 图像数据类型互相转换
      • cvtColor 颜色转换
    • 多通道分离与合并
      • split 多通道分离
      • merge 多通道合并
    • 两张图像像素比较
      • min (比较两个图像,寻找最小值)
      • max(比较两个图像,寻找最大值)
      • minMaxLoc 图像最大值与最小值寻找
    • 图像像素逻辑操作
      • bitwise_not(图像非运算)
      • bitwise_and(图像与运算)
      • bitwise_or(图像或运算)
      • bitwise_xor(图像异或运算)
    • 图像二值化
      • threshold 二值化
      • adaptiveThreshold 自适应阈值二值化
    • LUT 查找表
      • LUT(LOOK -UP-TABLE)查找表(多值化)


OpenCV 默认通道模型是BGR(蓝绿红)

Mat类数据类型读取

S = 有符号整型 
U = 无符号整型 
F = 浮点型

CV_8U - 8位无符号整数(0…255)

CV_8S - 8位有符号整数(-128…127)

CV_16U - 16位无符号整数(0…65535)

CV_16S - 16位有符号整数(-32768…32767)

CV_32S - 32位有符号整数(-2147483648…2147483647)

CV_32F - 32位浮点数(-FLT_MAX…FLT_MAX,INF,NAN)

CV_64F - 64位浮点数(-DBL_MAX…DBL_MAX,INF,NAN)

CV_8UC3而后面的C1、C2、C3是什么意思呢?
这里的1、2、3代表的是通道数,比如RGB就是3通道,颜色表示最大为255,所以可以用CV_8UC3这个数据类型来表示;灰度图就是C1,只有一个通道;而带alph通道的PNG图像就是C4,是4通道图片。
如果矩阵是类型:CV_8U 则使用 : Mat.at<uchar>(y,x)
如果矩阵是类型:CV_8S 则使用 : Mat.at<schar>(y,x)
如果矩阵是类型:CV_16U 则使用 : Mat.at<ushort>(y,x)
如果矩阵是类型:CV_16S 则使用 : Mat.at<short>(y,x)
如果矩阵是类型:CV_32S 则使用 : Mat.at<int>(y,x)
如果矩阵是类型:CV_32F 则使用 : Mat.at<float>(y,x)
如果矩阵是类型:CV_64F 则使用 : Mat.at<double>(y,x)


typedef Vec<uchar, 2> Vec2b;
typedef Vec<uchar, 3> Vec3b;
typedef Vec<uchar, 4> Vec4b;

typedef Vec<short, 2> Vec2s;
typedef Vec<short, 3> Vec3s;
typedef Vec<short, 4> Vec4s;

typedef Vec<ushort, 2> Vec2w;
typedef Vec<ushort, 3> Vec3w;
typedef Vec<ushort, 4> Vec4w;

typedef Vec<int, 2> Vec2i;
typedef Vec<int, 3> Vec3i;
typedef Vec<int, 4> Vec4i;
typedef Vec<int, 6> Vec6i;
typedef Vec<int, 8> Vec8i;

typedef Vec<float, 2> Vec2f;
typedef Vec<float, 3> Vec3f;
typedef Vec<float, 4> Vec4f;
typedef Vec<float, 6> Vec6f;

typedef Vec<double, 2> Vec2d;
typedef Vec<double, 3> Vec3d;
typedef Vec<double, 4> Vec4d;
typedef Vec<double, 6> Vec6d;

请添加图片描述

        //创建16位无符号整形,每个元素三个通道为1,5,6
	Mat f(4, 5, CV_16UC3, Scalar(1, 5, 6, 9));
	std::cout << f << std::endl;
	/*
	[1, 5, 6, 1, 5, 6, 1, 5, 6, 1, 5, 6, 1, 5, 6;
	1, 5, 6, 1, 5, 6, 1, 5, 6, 1, 5, 6, 1, 5, 6;
	1, 5, 6, 1, 5, 6, 1, 5, 6, 1, 5, 6, 1, 5, 6;
	1, 5, 6, 1, 5, 6, 1, 5, 6, 1, 5, 6, 1, 5, 6]
	*/

	//获取列数
	std::cout << f.cols << std::endl;//5
	//获取行数
	std::cout << f.rows << std::endl;//4
	//获取一行的最大字节数  CV_16UC3 = 2*3=6   6*5=30
	std::cout << f.step << std::endl;//30
	//获取每个元素的字节数  CV_16UC3  = 2*3=6
	std::cout << f.elemSize() << std::endl;//6
	//获取矩阵中元素的个数  4*5 = 20
	std::cout << f.total() << std::endl;//20
	//获取通道数  
	std::cout << f.channels() << std::endl;//3
	//Vec3s 获取(0,0)为第一个元素,为3通道
	cv::Vec3s vc3 = f.at<cv::Vec3s>(0, 0);
	//获取元素中第一个通道值
	std::cout << (int)vc3.val[0] << std::endl;
	/*用数据流指针获取通道值 
	f.data:数据存储的起始地址 (uchar*类型);

	step的几个类别区分:
	step:矩阵第一行元素的字节数
	step[0]:矩阵第一行元素的字节数
	step[1]:矩阵中一个元素的字节数
	step1(0):矩阵中一行有几个通道数
	step1(1):一个元素有几个通道数(channel())
	*/
	std::cout << "通道1:" << (int)*(f.data + f.step[0] * 2 + f.step[1] * 2 + 0) << std::endl;
	std::cout << "通道2:" << (int)*(f.data + f.step[0] * 2 + f.step[1] * 2 + 2) << std::endl;
	std::cout << "通道3:" << (int)*(f.data + f.step[0] * 2 + f.step[1] * 2 + 4) << std::endl;
	//创建一行5列单通道数据 枚举
	Mat a = (cv::Mat_<int>(1, 5) << 1, 2, 3, 4, 5);
	std::cout << a << std::endl;//[1, 2, 3, 4, 5]
	
	//向量生成对角线矩阵
	Mat b = Mat::diag(a);
	std::cout << b << std::endl;
	/*
	[1, 0, 0, 0, 0;
	0, 2, 0, 0, 0;
	0, 0, 3, 0, 0;
	0, 0, 0, 4, 0;
	0, 0, 0, 0, 5]
	*/
	//抠图或者裁剪  获取第2,3行和第3,4列相交 的数据 
	//按照矩阵中的元素抠图
	Mat c = Mat(b, Range(2, 4),Range(3,5));
	std::cout << c << std::endl;
	/*
	[0, 0;
	4, 0]
	*/

	//生成5行6列,对角线为1的数据,每个元素为16位
	Mat d = Mat::eye(5,6,CV_16U);
	std::cout << d << std::endl;
	/*
	[1, 0, 0, 0, 0, 0;
	 0, 1, 0, 0, 0, 0;
	 0, 0, 1, 0, 0, 0;
	 0, 0, 0, 1, 0, 0;
	 0, 0, 0, 0, 1, 0]
	*/

	//生成5行6列,全部元素为1,每个元素为16位
	Mat e = Mat::ones(5, 6, CV_16U);
	std::cout << e << std::endl;
	/*
	[1, 1, 1, 1, 1, 1;
	 1, 1, 1, 1, 1, 1;
	 1, 1, 1, 1, 1, 1;
	 1, 1, 1, 1, 1, 1;
	 1, 1, 1, 1, 1, 1]
	*/
	//生成5行6列,全部元素为0,每个元素为16位
	Mat g = Mat::zeros(5, 6, CV_16U);
	std::cout << g << std::endl;
	/*
	[0, 0, 0, 0, 0, 0;
	 0, 0, 0, 0, 0, 0;
	 0, 0, 0, 0, 0, 0;
	 0, 0, 0, 0, 0, 0;
	 0, 0, 0, 0, 0, 0]
	*/

Mat类支持的运算

在这里插入图片描述
在这里插入图片描述

设为A,B为Mat类型,s是Scalar类型,a是一个实数。下面列出关于Mat的常用运算:

矩阵加减: A+B,A-B,A+s,A-s,s+A,s-A,-A.
矩阵乘以实数: A*a,a*A
逐元素乘除: A.mul(B),A/B,a/A
矩阵乘法: A*BmaxVal; Point minPos,m
矩阵倒置: A.t()
矩阵的逆: A.inv()
矩阵比较: A comp B,A comp a,a comp A。这里comp包括 >, >=,==,!=,<=,<。得出的结果是一个单通道8位的矩阵,元素的值为255或0。
矩阵位操作: A logic B, A logic s,s logic A。这里logic包括:&,|,^
向量的差乘和内积: A.cross(B),A.dot(B);

图像读取,显示,保存

imread 图像读取

在这里插入图片描述在这里插入图片描述

namedWindow 创建要显示的窗口

imshow 窗口显示

在这里插入图片描述

imwrite 图像保存

在这里插入图片描述

视频加载与摄像头的使用

VideoCapture 加载视频或摄像头

在这里插入图片描述在这里插入图片描述

get 获取属性

在这里插入图片描述

VideoWriter 保存视频

在这里插入图片描述

视频打开读取

    VideoCapture video;
	video.open("H:/OBS录像地址/2023-03-25_21-08-01.mp4");
	if (!video.isOpened())
	{
		std::cout << "视频打开失败。。。" << std::endl;
		return -1;

	}
	cout << "视频帧率=" << video.get(CAP_PROP_FPS);
	cout << "视频宽度=" << video.get(CAP_PROP_FRAME_WIDTH);

	while (true)
	{
		Mat frame;
		//读取下一帧图像
		video >> frame; // == video.read(frame);
		
		if (frame.empty())
		{
			break;
		}
		namedWindow("video", WINDOW_NORMAL);
		imshow("video", frame);
		uchar c = waitKey(1000 / video.get(CAP_PROP_FPS));
		if (c == 'q')
		{
			break;
		}
	}
	//释放所有打开的窗口
	destroyAllWindows();

摄像头打开读取


VideoCapture video(0);
	if (!video.isOpened())
	{
		std::cout << "摄像头打开失败。。。" << std::endl;
		return -1;

	}
	
	Mat image;
	//获取图像
	video >> image;
	//判断图像是否读取成功
	if (image.empty())
	{
		std::cout << "图像获取失败。。。" << std::endl;
		return -1;
	}
	//判断相机(视频)类型是否为彩色
	bool isColor = (image.type() == CV_8UC3);
	
	VideoWriter writer;
	//设置编码格式
	int codec = VideoWriter::fourcc('M','P','4','2');
	//设置视频帧率fps
	double fps = 15.0;
	//保存文件名
	string filename = "shexiangtou.mp4";
	writer.open(filename, codec, fps, image.size(), isColor);
	if (!writer.isOpened())
	{
		cout << "打开视频文件失败。。。";
		return -1;
	}

	while (true)
	{
		//判断摄像头能够继续读出一帧图像
		if (!video.read(image))
		{
			cout << "摄像头断开连接或者视频读取完成。。。" << endl;
			break;
		}
		writer.write(image);

		namedWindow("video", WINDOW_NORMAL);
		imshow("video", image);
		uchar c = waitKey(1000 / fps);
		if (c == 'q')
		{
			break;
		}
	}
	//关闭视频流
	video.release();
	writer.release();
	//释放所有打开的窗口
	destroyAllWindows();

图像颜色空间转换

RGB

在这里插入图片描述

HSV

在这里插入图片描述在这里插入图片描述

RGB(红绿蓝)和HSV(色相饱和度亮度)是两种常用的颜色模型,用于描述和表示颜色。

RGB模型是将颜色表示为红色、绿色和蓝色三个分量的组合。每个分量的取值范围是0到255,表示颜色的强度。通过调整这三个分量的数值,可以生成不同的颜色。例如,纯红色可以表示为RGB(255, 0, 0),纯绿色为RGB(0, 255, 0),纯蓝色为RGB(0, 0, 255)。通过组合不同的RGB值,可以创建出各种各样的颜色。

HSV模型将颜色表示为色相(Hue)、饱和度(Saturation)和亮度(Value)三个分量。色相表示颜色在色轮上的位置,取值范围通常是0到360度,对应于不同的颜色。饱和度表示颜色的纯度或深浅程度,取值范围是0到1,其中0表示灰色,1表示饱和的纯色。亮度表示颜色的明暗程度,取值范围也是0到1,其中0表示黑色,1表示最亮的颜色。
H——Hue即色相,就是我们平时所说的红、绿,如果你分的更细的话可能还会有洋红、草绿等等;在HSV模型中,用度数来描述色相,其中红色对应0度,绿色对应120度,蓝色对应240度。
S——Saturation即饱和度,色彩的深浅度(0-100%) ,对于一种颜色比如红色,我们可以用浅红——大红——深红——红得发紫等等语言来描述它(请原谅一个纯理科生的匮乏的颜色系统),对应在画水彩的时候即一种颜料加上不同分量的水形成不同的饱和度。
V——Value即色调,纯度,色彩的亮度(0-100%) ,这个在调整屏幕亮度的时候比较常见。

HSV模型相对于RGB模型更加直观和易于使用,因为它可以更好地描述颜色的特征,例如颜色的明暗度和饱和度。在图像处理、计算机图形学和颜色选择等领域,HSV模型常常用于调整和控制颜色。

如果您想手动将HSV颜色值赋给一个OpenCV的Mat对象,可以按照以下步骤进行操作:

#include <opencv2/opencv.hpp>

int main()
{
    // 创建一个3通道的Mat对象来存储BGR颜色
    cv::Mat bgrImage(1, 1, CV_8UC3);

    // 设置HSV颜色值
    int h = 120;  // 色调 (0-179)
    int s = 255;  // 饱和度 (0-255)
    int v = 255;  // 明度 (0-255)

    // 将HSV颜色值赋给Mat对象
    bgrImage.at<cv::Vec3b>(0, 0) = cv::Vec3b(h / 2, s, v);

    // 将颜色值从HSV转换为BGR
    cv::cvtColor(bgrImage, bgrImage, cv::COLOR_HSV2BGR);

    // 显示BGR颜色
    cv::imshow("BGR Color", bgrImage);
    cv::waitKey(0);

    return 0;
}
  • 注意:
    // 设置HSV颜色值
    int h = 120;  // 色调 (0-179)
    int s = 255;  // 饱和度 (0-255)
    int v = 255;  // 明度 (0-255)
对于HSV颜色空间中的色调(H),OpenCV使用范围为0到179,而不是0到360。在将HSV颜色转换为BGR颜色时,需要将H值除以2。
在OpenCV中,当我们使用8位无符号整数(`CV_8U`)来表示像素值时,通常将其缩放到0到255范围内。这是因为8位无符号整数的范围是0到255,所以将0到1的浮点数映射到这个范围内。

convertTo 图像数据类型互相转换

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

cvtColor 颜色转换

在这里插入图片描述
在这里插入图片描述

多通道分离与合并

split 多通道分离

在这里插入图片描述在这里插入图片描述

OpenCV是一个流行的计算机视觉库,提供了丰富的图像处理和分析功能。split函数是OpenCV中的一个函数,用于将多通道图像拆分为各个通道的单通道图像。

以下是split函数的详细解释和用法示例:

函数原型

void split(InputArray src, OutputArrayOfArrays dst);

参数

  • src:输入的多通道图像(例如CV_8UC3类型的图像)。
  • dst:输出的单通道图像数组,用于存储拆分后的各个通道。

说明
split函数将输入的多通道图像分割为各个通道,并将每个通道保存在输出数组中。输出数组的大小和类型与输入图像的通道数相匹配。例如,对于3通道的输入图像,输出数组将包含3个单通道图像。

merge 多通道合并

在这里插入图片描述

在OpenCV中,merge函数用于将多个单通道图像合并为一个多通道图像。以下是merge函数的详细解释和示例代码(C++):

函数原型:

void merge(const std::vector<cv::Mat>& mv, cv::OutputArray dst);

参数说明:

  • mv:包含多个输入单通道图像的向量。图像必须具有相同的尺寸和深度。
  • dst:输出的多通道图像。

    Mat img = imread("D:/OpenCV4.5.1/opencv/sources/doc/js_tutorials/js_assets/lena.jpg");
	//imshow("mat", mat);
	
	Mat img32;
	//图像转换CV_32F储存
	img.convertTo(img32, CV_32F, 1 / 255.0, 0);
	Mat gray0, gray1;
	//颜色转换
	cvtColor(img, gray0, COLOR_BGR2GRAY);
	cvtColor(img, gray1, COLOR_RGB2GRAY);

	Mat imgs[3];
	//分割三通道图像 按照BGR形式分割
	split(img, imgs);

	Mat imgB = imgs[0];
	Mat imgG = imgs[1];
	Mat imgR = imgs[2];

	Mat imgH;
	//合并三通道为imgH
	merge(imgs, 3, imgH);

	//生成Size(宽,高) 为0的单通道矩阵
	Mat zero = Mat::zeros(Size(img.cols, img.rows), CV_8UC1);
	vector<Mat> imgsV;
	imgsV.push_back(imgB);
	imgsV.push_back(imgG);
	imgsV.push_back(imgR);

	Mat imgsVH;
	//合并三通道为imgH
	merge(imgsV, imgsVH);

两张图像像素比较

min (比较两个图像,寻找最小值)

max(比较两个图像,寻找最大值)

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

minMaxLoc 图像最大值与最小值寻找

在这里插入图片描述

    //创建一个通道矩阵都为1
	Mat a(4, 5, CV_8UC1, Scalar(1));
	//创建一个掩码通道矩阵都为2
	Mat b(4, 5, CV_8UC1, Scalar(2));
	//把掩码矩阵第一个位置设置为0
	*b.data = 0;
	double aa, bb;
	Point cc, dd;
	//aa = 1, bb =1, cc(x=1,y=0),dd(x=1,y=0)
	minMaxLoc(a, &aa, &bb, &cc, &dd,b);
	
    在OpenCV中,minmaxloc函数用于在图像中查找最小和最大像素值及其位置。该函数的第六个参数是一个可选的掩码图像,用于指定在哪些像素上执行最小/最大值查找。
    具体来说,掩码图像是一个与源图像具有相同尺寸和数据类型的图像,其中每个像素的值都是0或非零。在执行最小/最大值查找时,仅考虑掩码图像中像素值为非零的位置。
    例如,如果您有一个源图像和一个掩码图像,其中掩码图像在一些区域中具有非零像素值,那么当您调用minmaxloc函数时,它将仅在掩码图像中像素值为非零的位置上执行最    小/最大值查找。
    这可以用于实现各种功能,例如在ROI(感兴趣区域)内查找最小/最大值,或在二进制掩码图像中查找最小/最大值。

图像像素逻辑操作

在这里插入图片描述

bitwise_not(图像非运算)

bitwise_and(图像与运算)

在这里插入图片描述

bitwise_or(图像或运算)

bitwise_xor(图像异或运算)

在这里插入图片描述

图像二值化

threshold 二值化

在这里插入图片描述

threshold函数是OpenCV中用于图像二值化的函数之一。它可以将灰度图像转换为二值图像,使得图像上的某些区域像素值为0(黑色),而另一些区域像素值为255(白色)。下面是threshold函数的详细解释:

double threshold(InputArray src, OutputArray dst, double thresh, double maxval, int type)

参数解释:

  • src:输入图像,可以是单通道的灰度图像或多通道的彩色图像。
  • dst:输出二值化图像,与输入图像具有相同的大小和类型。
  • thresh:阈值,用于将像素分为两类的分割值。根据不同的类型(type)来确定阈值的使用方式。
  • maxval:当像素值超过阈值时,要为其赋予的最大值。通常为255(白色)。
  • type:二值化类型,指定如何根据阈值对像素进行分割。有多种可选类型。

常见的type参数取值包括:

  • THRESH_BINARY:对于输入图像中的每个像素,如果其值大于阈值,则将输出像素设置为maxval,否则设置为0。
  • THRESH_BINARY_INV:与THRESH_BINARY相反,对于输入图像中的每个像素,如果其值大于阈值,则将输出像素设置为0,否则设置为maxval
  • THRESH_TRUNC:对于输入图像中的每个像素,如果其值大于阈值,则将输出像素设置为阈值,否则保持原始像素值不变。
  • THRESH_TOZERO:对于输入图像中的每个像素,如果其值大于阈值,则保持原始像素值不变,否则设置为0。
  • THRESH_TOZERO_INV:与THRESH_TOZERO相反,对于输入图像中的每个像素,如果其值大于阈值,则设置为0,否则保持原始像素值不变。

返回值:threshold函数的返回值为实际使用的阈值。

threshold 函数对于最大值maxval用不到的时候,就算设置了,也不做运算。
在这里插入图片描述在这里插入图片描述在这里插入图片描述

基本的自动阈值算法
在这里插入图片描述在这里插入图片描述

大津法
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

adaptiveThreshold 自适应阈值二值化

在这里插入图片描述

blockSize 这个参数怎么理解,请用字符绘制方便理解的图形?
blockSize 参数代表的是每个像素周围用来计算阈值的邻域大小。邻域的大小应该是一个奇数,例如 3、5、7、9 等。
下面是一个示例图形,用字符绘制了一个 5x5 的邻域:
+---+---+---+---+---+
|   |   |   |   |   |
+---+---+---+---+---+
|   |   |   |   |   |
+---+---+---+---+---+
|   |   | X |   |   |
+---+---+---+---+---+
|   |   |   |   |   |
+---+---+---+---+---+
|   |   |   |   |   |
+---+---+---+---+---+
在这个示例中,X 表示中心像素,周围 5 个像素组成了一个 5x5 的邻域。当 blockSize 参数为 5 时,算法就会以这个邻域为基础来计算中心像素的阈值。
在实际应用中,可以通过调整 blockSize 参数来控制阈值计算的精度和速度。如果 blockSize 参数太小,算法可能会受到噪声的干扰,导致分割不准确;
如果 blockSize 参数太大,算法的计算时间会变长,可能会降低算法的实时性。因此,需要根据具体的应用场景来选择合适的 blockSize 参数。
>>blockSize 为3,那么坐标(0,0)第一个像素怎么计算的
当 blockSize 为 3 时,以坐标为(0,0)的像素为例,该像素的邻域大小为 3x3,其邻域内包括了 9 个像素,如下所示:
+---+---+---+
| X |   |   |
+---+---+---+
|   |   |   |
+---+---+---+
|   |   |   |
+---+---+---+
为了计算该像素的阈值,我们需要将这 9 个像素的灰度值进行求和,并除以 9 得到邻域内像素的平均灰度值 T。
然后,我们根据参数 C 计算该像素的阈值,例如如果 C 为 5,则阈值为 T - C。最后,我们将该像素的灰度值与阈值进行比较,
如果像素的灰度值大于阈值,则将其设置为前景像素,否则将其设置为背景像素。
需要注意的是,对于位于图像边缘的像素,可能无法找到以其为中心的大小为 blockSize 的邻域,此时可以使用填充方式来处理。
例如,可以使用图像边缘像素的值来填充邻域的边缘,以保证每个像素都能计算出其阈值。
	Mat img = imread("D:/OpenCV4.5.1/opencv/sources/doc/js_tutorials/js_assets/lena.jpg");
	if (img.empty())
	{
		cout << "图像打开失败。。。" << endl;
		return -1;
	}
	Mat gray;
	cvtColor(img, gray, COLOR_BGR2GRAY);
	Mat img_B, img_BV, gray_B, gray_BV, gray_T, gray_TV, gray_TRUNC;


    //    threshold 函数对于最大值maxval用不到的时候,就算设置了,也不做运算。
	//彩色图像二值化,规则:THRESH_BINARY
	threshold(img, img_B, 125, 255, THRESH_BINARY);
	threshold(img, img_BV, 125, 255, THRESH_BINARY_INV);

	//灰度图像二值化 ,规则:THRESH_BINARY
	threshold(gray, gray_B, 125, 255, THRESH_BINARY);
	threshold(gray, gray_BV, 125, 255, THRESH_BINARY_INV);

	//灰度图像二值化 ,规则:THRESH_TOZERO
	threshold(gray, gray_T, 125, 255, THRESH_TOZERO);
	threshold(gray, gray_TV, 125, 255, THRESH_TOZERO_INV);

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

	//灰度图形大津法和三角形法二值化
	Mat img_O,img_thr_O, img_T, img_thr_T;
	threshold(gray, img_thr_O, 125, 255, THRESH_BINARY | THRESH_OTSU);
	threshold(gray, img_thr_T, 125, 255, THRESH_BINARY | THRESH_TRIANGLE);
	threshold(gray, img_O, 125, 255, THRESH_OTSU);
	threshold(gray, img_T, 125, 255, THRESH_TRIANGLE);

	//自适应二值化 均值法和高斯法
	Mat adaptive_mean, adaptive_gauss;
	adaptiveThreshold(gray, adaptive_mean, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 55, 0);
	adaptiveThreshold(gray, adaptive_gauss, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 55, 0);
	

LUT 查找表

LUT(LOOK -UP-TABLE)查找表(多值化)

LUT(LOOK -UP-TABLE)查找表
在这里插入图片描述

`LUT`是OpenCV中的一个函数,用于对图像进行查表操作(Look-Up Table)。它可以根据一个查找表(Look-Up Table)对输入图像中的每个像素进行映射,从而得到一个输出图像。

以下是`LUT`函数的详细说明:

```cpp
void cv::LUT(InputArray src, InputArray lut, OutputArray dst)

参数:

  • src:输入图像,可以是单通道或多通道的图像。
  • lut:查找表,可以是一个一维数组(cv::Mat类型),也可以是一个与输入图像通道数和深度相匹配的多维数组。查找表的数据类型可以是整型或浮点型。
  • dst:输出图像,与输入图像具有相同的大小和类型。

功能:
LUT函数使用查找表对输入图像的每个像素进行映射,并将结果存储在输出图像中。对于输入图像中的每个像素值src(x,y),函数会查找查找表中对应索引位置的值,并将其赋值给输出图像的对应位置dst(x,y)

查找表的大小应该与输入图像的深度相匹配。对于8位深度的图像,查找表应该是一个256元素的一维数组;对于16位深度的图像,查找表应该是一个65536元素的一维数组。

LUT函数要求LUT参数必须满足以下条件:
1:必须是1通道或者与输入图像的通道数相同的通道数。
2:必须包含256个连续的元素,即必须是一个大小为1x256的连续矩阵。
3:元素类型必须是CV_8U或CV_8S。

在这里插入图片描述在这里插入图片描述

代码演示:

    uchar lut1[256];
    for (int i = 0; i < 256; i++)
    {
        if (i <= 100)
        {
            lut1[i] = 0;
        }
        if (i > 100 &&i<=200)
        {
            lut1[i] = 100;
        }
        if (i > 200)
        {
            lut1[i] = 255;
        }
    }
    //LUT查找表第一层
    Mat lutOne(1, 256, CV_8UC1, lut1); // 修改为1x256大小

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

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

    vector<Mat> mergeMats;
    mergeMats.push_back(lutOne);
    mergeMats.push_back(lutTwo);
    mergeMats.push_back(lutThree);

    Mat LutTree;
    merge(mergeMats, LutTree);

    Mat img = imread("D:/OpenCV4.5.1/opencv/sources/doc/js_tutorials/js_assets/lena.jpg");
    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);

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/31252.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【五子棋实战】第6章 调用接口进行联调

【五子棋实战】第6章 调用接口进行联调 Ajax调用接口 调用五子棋接口 点击优化 尾声 更多待开发的功能 Ajax调用接口 引入Jquery&#xff0c;使用JQ封装的ajax&#xff0c;demo如下&#xff1a; <script src"jquery-3.5.0.min.js"></script> <…

Python 操作 Excel 全攻略 | 包括读取、写入、表格操作、图像输出和字体设置

文章目录 前言Python 操作 Excel 教程1. Excel 文件的读取与写入2. Excel 表格的操作2.1 插入和删除行和列2.2 遍历表格中的单元格并修改值 3. 图像的输出3.1 输出柱状图 4. 字体的设置4.1 设置单元格的字体大小和颜色4.2 设置单元格的加粗和斜体4.3 设置单元格的边框和填充颜色…

CSS弹性布局常用设置

目录 一、单位元素 二、弹性容器 三、常用属性 三、项目实战效果 一、单位元素 vm 1vm 为视口的1% vh 视口高的1% vmin 参照长边 vmax 参照长边 rem 等比缩放 需要设置最外层盒子html设置vw 根字号html的--- font-- 1vm 去适配 初始化 //初始化*{padding: 0;margin: 0}//…

【Python GUI编程系列 01】安装python pycharm 和 pyside6

Python GUI编程系列 01 安装python pycharm 和 pyside61、安装python2、安装pycharm3、安装 pyside6 安装python pycharm 和 pyside6 本系列使用python3 pycharmpyside6 来进行python gui设计&#xff0c;首先我们来配置编程环境 PS&#xff1a;为了减少复杂程度&#xff0c;本…

MySQL:事务

事务 在介绍事务之前&#xff0c;我们先来了解一个案例&#xff1a; 在一个买票的软件中&#xff0c;当客户端A检查还有一张票时&#xff0c;将票卖点&#xff0c;但是还没有更新数据库&#xff0c;客户端B检查了票数&#xff0c;发现大于0&#xff0c;于是又卖掉了一张票。然…

【五子棋实战】第3章 算法包装成第三方接口

【五子棋实战】第3章 算法包装成第三方接口 使用Flask开放接口 ## 定义接口输入 ## 开放接口、跨域配置、数据解析 数据预处理 ## 数据检查与异常捕获 ## 预处理数据 ## 定义接口输出 开启接口 继续学习下一篇实战&#xff01; 我们在上一章实现了博弈树负值极大alpha…

Web服务器群集:部署LNMP平台

目录 一、理论 1.LNMP平台 2.Nginx服务基础 3.Nginx访问控制 4.Nginx虚拟主机 5.PHP 二、实验 1.LNMP架构DISCUZ论坛应用 三、问题 1.没有规则可以创建“default”需要的目标“build”。 2.nginx重启报错 3.yum安装提示报错 4.配置文件报错 5.PHP页面无法打开 四…

菲涅尔圆孔衍射matlab完整程序分享

根据惠更斯 &#xff0d; 菲涅耳原理&#xff0c;光的衍射是光束内部的次波之间的相干叠加&#xff0c;衍射光波场的光振动符合菲涅耳积分公式。但直接运用菲涅耳积分公式计算衍射光场是很困难的。对于夫琅和费衍射(远场衍射)&#xff0c;在光源和接收屏距离衍射屏均为无穷远的…

【C++】内存管理、new和delete操作类型、operator new和operator delete函数、new和delete的实现原理

文章目录 1.C/C内存管理2.C语言的内存管理方式3.C内存管理方式3.1 new和delete操作内置类型3.2 new和delete操作自定义类型 4.operator new与operator delete函数5.new和delete的实现原理5.1内置类型5.2 自定义类型 1.C/C内存管理 在C/C中&#xff0c;内存管理是程序员负责管理…

TCP 学习笔记

Win R 打开控制台输入CMD 打开小黑窗&#xff0c; 输入ipconfig 查询本机地址 “外网IP是全世界唯一的IP地址,仅分配给一个网络设备。而内网IP是由路由器分配给每一部内部使用的IP地址,而内网的所有用户都是通过同一个外网IP地址进行上网的,而内网的IP地址每个人的都不一样…

SQL 基础语句

SQL 基础语句 DDL Data Definition Language 数据定义语言创建 create删除 drop修改 alter清空 truncate show tables ; --查看所有表&#xff1a; drop database db1; --删除数据库 create database db1 default character set utf8; --创建数据库 use databas…

十大基础算法

一、选择排序 过程简单描述&#xff1a; 首先&#xff0c;找到数组中最小的那个元素&#xff0c;其次&#xff0c;将它和数组的第一个元素交换位置(如果第一个元素就是最小元素那么它就和自己交换)。其次&#xff0c;在剩下的元素中找到最小的元素&#xff0c;将它与数组的第二…

C++【STL】之priority_queue学习

优先级队列 优先级队列priority_queue也是STL库中容器适配器的一种&#xff0c;常用于进行数据优先级的处理&#xff0c;说到这儿是不是发现有些熟悉&#xff0c;没错它和我们之前讲解的堆本质上就是一个东西&#xff0c;底层都是数组存储的完全二叉树&#xff0c;它在STL库中…

设计模式(二十二):行为型之备忘录模式

设计模式系列文章 设计模式(一)&#xff1a;创建型之单例模式 设计模式(二、三)&#xff1a;创建型之工厂方法和抽象工厂模式 设计模式(四)&#xff1a;创建型之原型模式 设计模式(五)&#xff1a;创建型之建造者模式 设计模式(六)&#xff1a;结构型之代理模式 设计模式…

华为OD机试真题 JavaScript 实现【最短木板长度】【2022Q4 100分】,附详细解题思路

一、题目描述 小明有 n 块木板&#xff0c;第 i ( 1 ≤ i ≤ n ) 块木板长度为 ai。 小明买了一块长度为 m 的木料&#xff0c;这块木料可以切割成任意块&#xff0c;拼接到已有的木板上&#xff0c;用来加长木板。 小明想让最短的木板尽量长。 请问小明加长木板后&#xff0c…

Android12之执行adb disable-verity后android无法启动(一百五十六)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

前沿应用丨大规模无人机集群与“虚实结合”半实物仿真系统

一、应用背景 无人机集群在军事、安全、救援、航空监测、物流配送等领域具有广泛的应用前景。它可以提高任务执行的效率、灵活性和安全性&#xff0c;同时降低人力资源的需求和风险&#xff0c;无人机集群研究涉及多个学科领域&#xff0c;如机器人学、控制理论、通信技术和人工…

Verilog | 基4 booth乘法器

上接乘法器介绍 原理 跟基2的算法一样&#xff0c;假设A和B是乘数和被乘数&#xff0c;且有&#xff1a; A ( a 2 n 1 a 2 n ) a 2 n − 1 a 2 n − 2 … a 1 a 0 ( a − 1 ) B b 2 n − 1 b 2 n − 2 … b 1 b 0 \begin{align}A&(a_{2n1}a_{2n})a_{2n−1}a_{2n−2}……

【ARIMA-LSTM】合差分自回归移动平均方法-长短期记忆神经网络研究(Python代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

基于Nginx1.22+PHP8+MySQL8安装Discuz! X3.5

基于Nginx1.22PHP8MySQL8安装Discuz! X3.5 1. 安装PHP82. 安装MySQL83. 配置Nginx1.224. 安装Discuz! X3.5 1. 安装PHP8 更新系统&#xff1a; yum update安装EPEL存储库&#xff1a; yum install epel-release安装Remi存储库&#xff08;提供了最新的 PHP 版本&#xff09;&…