OpenCV 笔记_1

news2024/12/26 11:17:57

笔记_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);

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue 生命周期

人的-生命周期 一组件从 创建 到 销毁 的整个过程就是生命周期 Vue_生命周期 1. 钩子函数 Vue 框架内置函数&#xff0c;随着组件的生命周期阶段&#xff0c;自动执行 作用: 特定的时间点&#xff0c;执行特定的操作 场景: 组件创建完毕后&#xff0c;可以在created 生命周期…

实际项目中使用gorm-gen来生成实体类

一、为什么要使用gorm-gen来生成实体类和查询 1、根据gorm官网地址&#xff0c;正常的写法是先写数据模型,然后由数据模型自动同步生成到数据库中,但是这样的工作量会比较大,对于写后端的人来说都熟悉sql语句,正常来说都是先自己手动创建表,利用工具将表字段同步到项目实体类中…

java商业销售分析系统Myeclipse开发mysql数据库web结构jsp编程计算机网页项目

一、源码特点 java 商业销售分析系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0&…

电脑重装系统后需要更新哪些驱动

在电脑重装系统后&#xff0c;由于系统的重置&#xff0c;您需要重新安装和更新一些关键的驱动程序&#xff0c;以确保硬件设备正常工作和性能最佳化。以下是在电脑重装系统后需要更新的一些常见驱动程序。 工具/原料&#xff1a; 系统版本&#xff1a;win10系统 品牌型号&…

TOGAF10®标准中文版-(介绍和核心概念)摘要

第1章&#xff1a;简介 TOGAF标准是企业架构的框架。任何希望开发企业架构以在该组织内使用的组织都可以免费使用它&#xff08;见第1.3.1节&#xff09;。 TOGAF标准由The Open Group成员在架构论坛内开发和维护&#xff08;请参阅www.opengroup.org/Architecture&#xff0…

java8 (jdk 1.8) 新特性——Lambda 以及函数式接口

1. 什么是lambda? 目前已知的是&#xff0c;有个箭头 -> 说一大段官方话&#xff0c;也没有任何意义 我们直接看代码&#xff1a; 之前我们创建线程是这样的 Runnable runnable new Runnable() {Overridepublic void run() {System.out.println("run。。。。。。…

阿里云服务器的网络性能如何?有多快?是否适合高流量应用?

阿里云服务器的网络性能如何&#xff1f;有多快&#xff1f;是否适合高流量应用&#xff1f;   [本文由阿里云代理商[聚搜云www.4526.cn]撰写]    阿里云服务器网络性能简介   阿里云服务器&#xff08;ECS&#xff09;在网络性能方面表现卓越&#xff0c;可满足用户对高…

通过环路分析仪得到系统的闭环传递函数方法(Matlab System Identification)

目录 前言 环路分析仪数据整理 Matlab导入环路分析仪的数据 System Identification使用 闭环传递函数导出 总结 前言 之前开发的时候通过Matlab的环路设计工具实现了控制系统的补偿器参数整定&#xff0c;然后在系统硬件上面进行了验证&#xff0c;设计带宽和环路分析仪的…

基于Java实验中心管理系统设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a; ✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战 ✌ &#x1f345; 文末获取源码联系 &#x1f345; &#x1f447;&#x1f3fb; 精…

排序算法:插入排序(直接插入排序、希尔排序)

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下有关排序算法的相关知识点&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入门到精通…

CQ 社区版 v2.1.0 发布 | 新增数据发布变更、内置脱敏规则等功能

Hello&#xff0c;社区的小伙伴们&#xff0c;又到了每月版本发布时间。&#x1f389;&#x1f389;&#x1f389; 本次社区版更新带来了新功能 「发布变更」&#xff0c;以及内置脱敏规则、授权粒度细化、连接池管理、变更链接密钥等&#xff0c;信息量不少&#xff0c;一起来…

在生信中利用Chat GPT/GPT4

论文链接Ten Quick Tips for Harnessing the Power of ChatGPT/GPT-4 in Computational Biology | Papers With Code 之前在paper with code上比较火的一篇文章&#xff0c;最近要给生科的学长学姐们个分享所以把这个翻了翻&#xff0c;原文自认为废话比较多&#xff0c;于是选…

基于Java物流管理系统设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a; ✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战 ✌ &#x1f345; 文末获取源码联系 &#x1f345; &#x1f447;&#x1f3fb; 精…

【图书推荐 | 14】后端系列

【赠书活动第十四期 】 图书推荐 本期书籍&#xff1a;后端系列 图书列表 本期图书列表&#xff1a; Spring Cloud 微服务快速上手项目驱动零起点学JavaNode.js 从基础到项目实战Diango Web 开发实例精解Flask Web 全栈开发实战精通Hadoopsmysql 数据库基础与实战应用Neo4j 图谱…

ChatGLM-6B云服务器部署教程

目录 一、准备服务器1.购买服务器2.开机进入终端3.进入终端 二、部署ChatGLM1.执行命令2.本地代理访问地址2.1 结果如下2.2 api接口一样操作 三、Fastapi流式接口1.api_fast.py1.2 将api_fast.py上传到服务器 2.准备插件3.访问地址 博客园地址&#xff1a;https://www.cnblogs.…

【裸机开发】中断系统 —— IRQ 中断服务函数(汇编部分)

IRQ 和前面的Reset 函数不大一样&#xff0c;当一个IRQ中断产生时&#xff0c;我们也不知道这个IRQ中断来自哪个外设&#xff0c;因此&#xff0c;需要先获取到中断ID&#xff0c;随后才会跳转到真正的中断服务函数执行处理逻辑。 整个 IRQ 中断处理可以看做是包含了两个部分&…

CSS查缺补漏之选择器

最近在复盘CSS基础知识&#xff0c;发现很多CSS选择器里面还是大有学问&#xff0c;需要详细总结一番&#xff0c;以备差缺补漏~ 作为CSS基础的一大类别&#xff0c;选择器又分为多种类别&#xff0c;本篇内容默认读者已了解并掌握基础选择器【通配符选择器】、【元素选择器】…

springboot+vue项目之MOBA类游戏攻略分享平台(java项目源码+文档)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的MOBA类游戏攻略分享平台。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 &#x1f495;&#x1f495;作者&#xf…

自动化测试框架Playwright安装以及使用

最近&#xff0c;微软开源了一个非常强大的自动化项目叫 playwright-python 它支持主流的浏览器&#xff0c;包含&#xff1a;Chrome、Firefox、Safari、Microsoft Edge 等&#xff0c;同时支持以无头模式、有头模式运行&#xff0c;并提供了同步、异步的 API&#xff0c;可以…

C++学习——第二节课-输入输出

大家好&#xff0c;我是涵子。今天我们来学习C中的输入输出。 一、电脑中的输入输出 日常生活中常见的电脑、手机、电视机外部接口&#xff0c;也就是I/O&#xff08;输入/输出&#xff09;接口部分&#xff0c;其样式、种类较多&#xff0c;不同的接口配置也体现了设备的档次…