Opencv基础知识1(待补全...)

目录

1.Opencv简说

2.MAt类

3.拷贝构造

4.灰度化 

5.高斯模糊

6.边缘检测、膨胀、腐蚀

7.改变通道数据

8.金子塔 放大缩小

9.阈值处理

10.滤波

11.算子(Scharr、Sobel、Laplacian)

12.重映射


1.Opencv简说

从真实世界中获取数字图像有很多方法,比如数码相机、扫描仪、CT或者磁共振成像。无论哪种方法,我们(人类)看到的是图像,而让数字设备来“看“的时候,则是在记录图像中的每一个点的数值,这些数值在Opencv里就是用矩阵的方式来表示的,在Opencv中用图像类Mat来表示的。

说道图像不得不提颜色是怎么表示的:

有很多的颜色系统,各有自身优势:

  • RGB是最常见的,这是因为人眼采用相似的工作机制,它也被显示设备所采用。
  • HSV和HLS把颜色分解成色调、饱和度和亮度/明度。这是描述颜色更自然的方式,比如可以通过抛弃最后一个元素,使算法对输入图像的光照条件不敏感。
  • YCrCb在JPEG图像格式中广泛使用。
  • CIE L*a*b*是一种在感知上均匀的颜色空间,它适合用来度量两个颜色之间的 距离 。

每个组成元素都有其自己的定义域,取决于其数据类型。如何存储一个元素决定了我们在其定义域上能够控制的精度。最小的数据类型是 char ,占一个字节或者8位,可以是有符号型(0到255之间)或无符号型(-127到+127之间)。尽管使用三个 char 型元素已经可以表示1600万种可能的颜色(使用RGB颜色空间),但若使用float(4字节,32位)或double(8字节,64位)则能给出更加精细的颜色分辨能力。但同时也要切记增加元素的尺寸也会增加了图像所占的内存空间。

2.MAt类

在Opencv里,Mat是我们经常用到储存图像数据的类,这类有很多构造函数。

例如:

Mat M(2,2, CV_8UC3, Scalar(0,0,255)); 

 CV_8UC3 表示使用8位的 unsigned char 型,每个像素由三个元素组成三通道。预先定义的通道数可以多达四个。 Scalar 是个short型vector。指定这个能够使用指定的定制化值来初始化矩阵。当然,如果你需要更多通道数,你可以使用大写的宏并把通道数放在小括号中,如下所示

int sz[3] = {2,2,2}; 
Mat L(3,sz, CV_8UC(1), Scalar::all(0));

`3`:这是矩阵的行数。矩阵`L`有3行。
`sz`:这是指向包含矩阵列数数组的指针。在这种情况下,`sz`包含3个值:2, 2, 2。这意味着矩阵`L`有3个列块,每个列块有2列。因此,`L`是一个3x2x2的3D矩阵。
 `CV_8UC(1)`:这是矩阵的数据类型和通道数。`CV_8UC1`表示每个元素是8位无符号单通道数据。在这里,`C`代表`CV_8U`(8位无符号整数)的通道数,而`(1)`表示单通道。因此,`L`的每个元素都是一个8位无符号整数,并且它是单通道的。
 `Scalar::all(0)`:这是矩阵的初始值。`Scalar::all(0)`表示使用`Scalar`对象来初始化矩阵,其中所有元素都设置为0。因此,矩阵`L`的每个元素都被初始化为0。

cv::Mat A = Mat_<double>(3,3);//创建一个3*3的矩阵用于存放double类型数据

更多初始化可以查看源码了解

 Mat有哪些常见的属性?
dims:表示矩阵M的维度,如2*3的矩阵为2维,3*4*5的矩阵为3维
data:uchar型的指针,指向内存中存放矩阵数据的一块内存
rows, cols:矩阵的行数、列数
type:表示了矩阵中元素的类型(depth)与矩阵的通道个数(channels);命名规则为CV_ + (位数)+(数据类型)+(通道数)
其中:U(unsigned integer)-- 无符号整数
S(signed integer)-- 有符号整数
F(float)-- 浮点数
例如CV_8UC3,可拆分为:CV_:type的前缀,
8U:8位无符号整数(depth),C3:3通道(channels)
depth:即图像每一个像素的位数(bits);这个值和type是相关的。例如CV_8UC3中depth则是CV_8U。

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

channels:通道数量,若图像为RGB、HSV等三通道图像,则channels = 3;若图像为灰度图,则为单通道,则channels = 1,目前C1、C2、C3、C4分别表示单通道(灰度图像)、双通道(特定图像算法通道不常用)、3通道(BGR)和4通道(BGRA其中A代表图像透明度)
elemSize:矩阵中每一个元素的数据大小
elemSize = channels * depth / 8 
例如:type是CV_8UC3,elemSize = 3 * 8 / 8 = 3bytes
elemSize1:单通道的矩阵元素占用的数据大小
elemSize1 = depth / 8
例如:type是CV_8UC3,elemSize1 = 8 / 8 = 1bytes

3.拷贝构造

基本上讲 Mat 是一个类,由两个数据部分组成:矩阵头(包含矩阵尺寸,存储方法,存储地址等信息)和一个指向存储所有像素值的矩阵(根据所选存储方法的不同矩阵可以是不同的维数)的指针。矩阵头的尺寸是常数值,但矩阵本身的尺寸会依图像的不同而不同,通常比矩阵头的尺寸大数个数量级。因此,当在程序中传递图像并创建拷贝时,大的开销是由矩阵造成的,而不是信息头。因此除非万不得已,我们不应该拷贝  的图像,因为这会降低程序速度

OpenCV使用引用计数机制。其思路是让每个 Mat 对象有自己的信息头,但共享同一个矩阵。这通过让矩阵指针指向同一地址而实现。而拷贝构造函数则 只拷贝信息头和矩阵指针 ,而不拷贝矩阵

Mat A, C;                                 // 只创建信息头部分
A = imread(argv[1], CV_LOAD_IMAGE_COLOR); // 这里为矩阵开辟内存
Mat B(A);                                 // 使用拷贝构造函数
C = A;                                    // 赋值运算符

以上代码中的所有Mat对象最终都指向同一个也是唯一一个数据矩阵。虽然它们的信息头不同,但通过任何一个对象所做的改变也会影响其它对象 ,如果矩阵属于多个 Mat 对象,通过引用计数机制来实现负责清理。某些时候你仍会想拷贝矩阵本身(不只是信息头和矩阵指针),这时可以使用函数 clone() 或者 copyTo()

4.灰度化 

图像本来有色彩为什么灰度化?

因为灰度化只有单一色彩,数据较少,处理起来速度比较快,其次也比较容易处理图片细节以及纹理

{
	Mat iamge, rhgMat, hsvMat;
	string strPath = "..//Qt_OpenCV_01//res//a.png";
    // 读取图片  保存图片就用imwrite
	iamge = imread(strPath);
    
    //将图片处理成灰度图片,cvtColor第三个参数有多重颜色,这里不细细展开自己看
	cvtColor(iamge, rhgMat, COLOR_BGR2GRAY);
	cvtColor(iamge, hsvMat, COLOR_BGR2HSV);
	if (rhgMat.empty() || hsvMat.empty())
	{
		return;
	}

	imshow("HSV", hsvMat);
	imshow("GRAY", rhgMat);
	SaveImage("C:/Users/admin/Desktop/GRAY.png", rhgMat);
	SaveImage("C:/Users/admin/Desktop/HSV.png", hsvMat);
}

5.高斯模糊

高斯模糊是另一种平滑技术,使用低通滤波器,其权重源自高斯函数,是最常用的计算机视觉应用之一。高斯滤波器的属性使其变得高效,如线性可分性,可近似不可分离滤波器,应用多个连续的高斯核相当于应用单个更大的高斯模糊,主要用于减少图像的噪声和降低细节层次

{
	string strPath = "..//Qt_OpenCV_01//res//a.png";
	Mat mat = imread(strPath);
	if (mat.empty())
	{
		return;
	}

	Mat gaussMat;
    //参数3,指内核大小一般为基数,参数4/5,表示X/Y方向上的高斯核标准差(模糊程度)
	GaussianBlur(mat, gaussMat, Size(3, 3), 3, 0);
	imshow("Gaussian", gaussMat);
}

6.边缘检测、膨胀、腐蚀

{
	string strPath = "..//Qt_OpenCV_01//res//a.png";
	Mat mat = imread(strPath);
	if (mat.empty())
	{
		return;
	}

	Mat gaussMat, cannyMay, imgDil, imgErode;
	//降噪 当值误边缘
	GaussianBlur(mat, gaussMat, Size(3, 3), 3, 0);
	//边缘检测  参数3/4  处理图像阈值
	Canny(gaussMat, cannyMay, 27, 75);

	//获取 大小位3X3的结构性元素,并当做下面操作的核
	Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
	//膨胀操作
	dilate(cannyMay, imgDil, kernel);
	//侵蚀操作
	erode(imgDil, imgErode, kernel);

	imshow("Gaussian", cannyMay);
	imshow("GaussianDilation", imgDil);
	imshow("GaussianErode", imgErode);
}

7.改变通道数据

前面我们提到Mat类,其实他就是个矩阵数据,那我们试着能不能改变图的亮度呢?

{
	Mat inputMat = imread("..//Qt_OpenCV_01//res//a.jpg");
    // 确保新Mat与输入图像类型相同
	Mat newMat = Mat::zeros(inputMat.size(), inputMat.type()); 


	double dAlpha = 2; // 你可以考虑将这个值限制在0到255之间,以避免溢出对比度
	int nBeta = 50;//明亮度

    //修改点 (row, col) 的 B/G/R 通道数据
	for (int y = 0; y < inputMat.rows; y++)
	{
		for (int x = 0; x < inputMat.cols; x++)
		{
			for (int c = 0; c < inputMat.channels(); c++) // 使用channels()函数自动处理通道数
			{
                // 将double转换为uchar
				uchar alpha = static_cast<uchar>(dAlpha); 
                // 同样处理nBeta,尽管在你的代码中nBeta没有被使用
				uchar beta = static_cast<uchar>(nBeta);   
				newMat.at<Vec3b>(y, x)[c] = saturate_cast<uchar>(alpha * inputMat.at<Vec3b>(y, x)[c] + beta); // 确保结果在uchar范围内
			}
		}
	}

	namedWindow("Original Image", WINDOW_AUTOSIZE);
	namedWindow("New Image", WINDOW_AUTOSIZE);
	imshow("Original Image", inputMat);
	imshow("New Image", newMat);
	waitKey();
}

8.金子塔 放大缩小

{
	Mat src, dst, tmp;
	const char* window_name = "Sample Demp";
	src = imread("..//Qt_OpenCV_01//res//a.jpg");
	tmp = src;
	dst = tmp;

	namedWindow(window_name, WINDOW_AUTOSIZE);
	imshow(window_name, dst);

	if (!down)
	{
		pyrUp(tmp, dst, Size(tmp.cols * 2, tmp.rows * 2));
	}
	else
	{
		pyrDown(tmp, dst, Size(tmp.cols / 2, tmp.rows / 2));
	}
	imshow(window_name, dst);
}

9.阈值处理

namespace Threshold
{
	int threshold_type = 3;
	int threshold_value = 0;
	int const max_value = 255;
	int const max_type = 4;
	int const max_BINARY_value = 255;
	Mat src, src_gray, dst;
	const char* window_name = "threshold demo";
	const char* trackbar_type = "Type: \n 0: Binary \n 1: Binary Inverted \n 2: Truncate \n 3: To Zero \n 4: To Zero Inverted";
	const char* trackbar_value = "Value";
	void Threshold_demo(int, void*);
}
void Qt_OpenCV_01::Thresholdong()
{
	Threshold::src = imread("..//Qt_OpenCV_01//res//q.jpg");
	// change color
	cvtColor(Threshold::src, Threshold::src_gray, COLOR_RGB2GRAY);
	namedWindow(Threshold::window_name, WINDOW_AUTOSIZE);
    //创建滑块 参数1滑块名称 参数2窗口名称 参数3滑块的默认值 参数4最大值 参数5回调函数
	createTrackbar(Threshold::trackbar_type, Threshold::window_name, &Threshold::threshold_type, Threshold::max_type, Threshold::Threshold_demo);
	createTrackbar(Threshold::trackbar_value, Threshold::window_name, &Threshold::threshold_value, Threshold::max_value, Threshold::Threshold_demo);
	Threshold::Threshold_demo(0, 0);
	waitKey(0);
}

void Threshold::Threshold_demo(int, void*)
{
	/*
	0 二进制
	1 反向二进制
	2 截断
	3 阈值为零
	4 反向阈值为零
	*/
	threshold(Threshold::src_gray, Threshold::dst, Threshold::threshold_value, Threshold::max_BINARY_value, Threshold::threshold_type);
	imshow(Threshold::window_name, Threshold::dst);
}

10.滤波

filter2D是OpenCV库中的一个函数,用于对二维矩阵(通常是图像)进行卷积运算。其函数原型如下:

void cv::filter2D(InputArray src, OutputArray dst, int ddepth, InputArray kernel,Point anchor=Point(-1,-1), double delta=0, int borderType=BORDER_DEFAULT);

其中参数的意义如下:

  • src:输入矩阵或图像。
  • dst:输出图像,与src大小相同、通道数相同。
  • ddepth:目标图像的所需深度。
  • kernel:卷积核(或者更确切地说是相关核),单通道浮点矩阵。如果要将不同的内核应用于不同的通道,请使用split将图像分割为单独颜色平面并单独处理它们。
  • anchor:内核的锚点,指示内核中过滤点的相对位置。锚点应该位于内核内;默认值(-1,-1)表示锚点位于内核中心。
  • delta:在将过滤像素存储到dst之前添加到过滤像素的可选值。
  • borderType:像素外推方法,定义了如何处理图像边界外的像素。

卷积核的作用是将周围像素的灰度值与自己的灰度值进行加权平均,从而得到新的像素值。不同的卷积核会得到不同的平滑效果。卷积核的形状、大小、权重都需要用户自己定义。

卷积运算是图像处理中的基础且重要的步骤,通常用于图像过滤,例如边缘检测、模糊等。filter2D函数允许用户自定义卷积核,从而实现各种图像滤波效果,如均值滤波、高斯滤波等

{
	Mat src, dst, kernel, blur_tmp;
	Point anchor;
	double delta;
	int ddepth;
	int kernel_size;
	const char* window_name = "filder2D demo";
	int c;

	src = imread("..//Qt_OpenCV_01//res//a.jpg");
	namedWindow(window_name, WINDOW_AUTOSIZE);

	//核
	anchor = Point(-1, -1);
	// 卷积过程加到每个像素值
	delta = 0;
	// 深度
	ddepth = -1;

	//每 500毫秒用不同的核滤波图像
	int ind = 0;
	for (;;)
	{
		c = waitKey(500);
		if ((char)c == 27)
		{
			break;
		}

		//以归一化块滤波更新核大小
		kernel_size = 3 + 2 * (ind % 5);
		kernel = Mat::ones(kernel_size, kernel_size, CV_32F) / (float)(kernel_size * kernel_size);
		//平均滤波
		blur(src, blur_tmp, Size(5, 5));
		imshow("blur", blur_tmp);
		//滤波
		//
		filter2D(src, dst, ddepth, kernel, anchor, delta, BORDER_DEFAULT);
		imshow(window_name, dst);
		ind++;
	}
}

11.算子(Scharr、Sobel、Laplacian)

Sobel主要用于获得数字图像的一阶梯度,常见的应用和物理意义是边缘检测。该算子根据图像中每个像素的上下左右四领域的灰度值加权差,在边缘处达到极值从而检测边缘。Sobel算子对于图像中较弱的边缘提取效果可能较差。为了能够有效提取出较弱的边缘,需要将像素间的差距增大,于是引入了Scharr算子

函数的主要参数包括 

  • dst 代表目标图像。
  • src 代表原始图像。
  • ddepth 代表输出图像的深度。
  • dx 代表 x 方向上的求导阶数。
  • dy 代表 y 方向上的求导阶数。
  • ksize 代表 Sobel 核的大小。该值为-1 时,则会使用 Scharr 算子进行运算。
  • scale 代表计算导数值时所采用的缩放因子,默认情况下该值是 1,是没有缩放的。
  • delta 代表加在目标图像 dst 上的值,该值是可选的,默认为 0。
  • borderType 代表边界样式。

Scharr通常指的是Scharr算子,它是一种用于图像边缘检测的算法。Scharr算子是Sobel算子的改进版,与Sobel算子在原理上相似,都是使用右边一列减去左边一列来检测边缘,但Scharr算子的系数与Sobel算子不同,因此其运算准确度更高,效果也更好

函数的主要参数包括同上 

Laplacian(拉普拉斯算子)是n维欧几里德空间中的一个二阶微分算子,主要用于检测图像的二阶导数,即边缘。它通过对图像进行二阶微分来检测图像的边缘,对于不同方向的边缘都能够进行检测,对边缘的粗细和强度变化也比较敏感

函数的主要参数包括

  • src:输入图像,可以是任意通道数的图像,但通常是单通道灰度图像。
  • dst:输出图像,与输入图像src具有相同的尺寸和通道数
  • ddepth:输出图像的深度,若src为CV_8U,则可取-1/CV_16S/CV_32F/CV_64F;若src为CV_16U/CV_16S,可取-1/CV_32F/CV_64F;若src为CV_32F,可取-1/CV_32F/CV_64F;若src为CV_64F,可取-1/CV_64F。,当赋值为-1时,输出图像的数据类型自动选择。
  • ksize:用于计算二阶导数的核尺寸大小,必须为正奇数。
  • scale:对导数计算结果进行缩放的缩放因子,默认系数为1,表示不进行缩放。也称对比度
  • delta:偏值,在计算结果中加上偏值。也称亮度
  • borderType:像素外推法选择标志,默认参数为BORDER_DEFAULT,表示不包含边界值倒序填充。
{
	Mat src, src_gray, grad;

	const char* window_name = "Sobel Demo - Simple";

	int scale = 1;
	int delta = 0;
	int ddepth = CV_16S;
	int kernel_size = 3;
	// 
	src = imread("..//Qt_OpenCV_01//res//a.jpg");

	//对原图使用高斯模糊 降噪
	GaussianBlur(src, src, Size(3, 3), 0, 0, BORDER_DEFAULT);

	//变成灰度
	cvtColor(src, src_gray, COLOR_RGB2GRAY);
	//
	namedWindow(window_name, WINDOW_AUTOSIZE);
	Mat grad_x, grad_y;
	Mat abs_grad_x, abs_grad_y;

	//倾斜度x
	// Scharr(src_gray, grad_x, ddepth, 1, 0, scale, delta, BORDER_DEFAULT);
	Sobel(src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT);
	// Laplacian(src_gray, grad_x, ddepth, kernel_size, scale, delta, BORDER_DEFAULT);

	//变换绝对值8位图像
	convertScaleAbs(grad_x, abs_grad_x);
	//倾斜度Y
	// Scharr(src_gray, grad_y, ddepth, 0, 1, scale, delta, BORDER_DEFAULT);
	Sobel(src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT);
	// Laplacian(src_gray, grad_y, ddepth, kernel_size, scale, delta, BORDER_DEFAULT);

	Canny(src_gray, grad, 50, 200, 3);
	convertScaleAbs(grad_y, abs_grad_y);
	//总倾斜度
	addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad);
	imshow(window_name, grad);
	waitKey(0);
}

12.重映射

remap

  • 参数一:InputArray类型的src,一般为cv::Mat;
  • 参数二:OutputArray类型的dst,目标图像。它的大小与map1相同,类型与src相同。
  • 参数三:InputArray类型的map1,它有两种可能的表示对象:表示点(x,y)的第一个映射或者表示CV_16SC2 , CV_32FC1 或CV_32FC2类型的x值。
  • 参数四:InputArray类型的map2,它也有两种可能的表示对象,而且他是根据map1来确定表示哪种对象。若map1表示点(x,y)时,这个参数不代表任何值,否则,表示CV_16UC1 , rCV_32FC1类型的y值(第二个值)。
  • 参数五:int类型的interpolation,使用的插值方法;
  • 参数六:int类型的borderMode,边界处理方式;
  • 参数七:Scalar类型的borderValue,重映射后,离群点的背景,需要broderMode设置为BORDER_CONSTRANT时才有效。(离群点:当图片大小为400x300,那么对应的map1和map2范围为0399、0299,小于0或者大于299的则为离散点,使用该颜色填充);

 

namespace remapping {
	Mat src, dst;
	Mat map_x, map_y;
	const char* remap_window = "remap demo";
	int ind = 0;
}
void update_map(void);
void Qt_OpenCV_01::Remapping()
{
	remapping::src = imread("..//Qt_OpenCV_01//res//r.png");

	remapping::dst.create(remapping::src.size(), remapping::src.type());
	remapping::map_x.create(remapping::src.size(), CV_32FC1);
	remapping::map_y.create(remapping::src.size(), CV_32FC1);

	namedWindow(remapping::remap_window, WINDOW_AUTOSIZE);
	for (;;)
	{
		int c = waitKey(1000);

		if ((char)c == 27)
		{
			break;
		}

		update_map();
		remap(remapping::src, remapping::dst, remapping::map_x, remapping::map_y, CV_INTER_LANCZOS4, BORDER_CONSTANT, Scalar(0, 0, 0));
		imshow(remapping::remap_window, remapping::dst);
	}
}

void update_map(void)
{
	remapping::ind = remapping::ind % 4;
	for (int j = 0; j < remapping::src.rows; j++)
	{
		for (int i = 0; i < remapping::src.cols; i++)
		{
			switch (remapping::ind)
			{
			case 0:
				if (i > remapping::src.cols * 0.25 && i < remapping::src.cols * 0.75 && j > remapping::src.rows * 0.25 && j < remapping::src.rows * 0.75)
				{
					remapping::map_x.at<float>(j, i) = 2 * (i - remapping::src.cols * 0.25f) + 0.5f;
					remapping::map_y.at<float>(j, i) = 2 * (j - remapping::src.rows * 0.25f) + 0.5f;
				}
				else
				{
					remapping::map_x.at<float>(j, i) = 0;
					remapping::map_y.at<float>(j, i) = 0;
				}
				break;
			case 1:
				remapping::map_x.at<float>(j, i) = (float)i;
				remapping::map_y.at<float>(j, i) = (float)(remapping::src.rows - j);
				break;
			case 2:
				remapping::map_x.at<float>(j, i) = (float)(remapping::src.cols - i);
				remapping::map_y.at<float>(j, i) = (float)(j);
				break;
			case 3:
				remapping::map_x.at<float>(j, i) = (float)(remapping::src.cols - i);
				remapping::map_y.at<float>(j, i) = (float)(remapping::src.rows - j);
				break;
			}
		}
	}
	remapping::ind++;
}

 级联分类器

通常被用于处理复杂的分类任务,其中每个分类器负责识别特定类型的样本或特征。每个分类器在处理样本时,可以根据需要执行不同的特征提取和处理操作。这种级联的结构能够逐步降低分类问题的复杂性,并提高分类的准确性。级联分类器是一种将多个分类器级联起来的机器学习模型。它可以处理复杂的分类任务,并通过逐步降低问题复杂性的方式提高分类的准确性

人脸识别

{
	VideoCapture cap(0);
	if (!cap.isOpened())
	{
		return;
	}

	CascadeClassifier face_detetor;
	face_detetor.load("F:\\opencv4.8.0\\opencv\\build\\etc\\haarcascades\\haarcascade_frontalface_default.xml");

	namedWindow("face", WINDOW_AUTOSIZE);

	while (1)
	{
		Mat face_mat;
		cap >> face_mat;
		Mat gra_mat;
		cvtColor(face_mat, gra_mat, COLOR_BGR2GRAY);
		vector<Rect> faces;
		face_detetor.detectMultiScale(gra_mat, faces, 1.1, 2, 0 | CASCADE_SCALE_IMAGE, Size(30, 30));

		for (size_t i = 0; i < faces.size(); ++i)
		{
			rectangle(face_mat, faces[i], Scalar(0, 0, 255), 2, 8, 0);
		}
		imshow("face", face_mat);
		waitKey(5);
	}
}

自己做级联分类器

参考

基于OpenCV训练分类器-CSDN博客

Opencv训练自己分类器_opencv正样本与负样本尺寸-CSDN博客

opencv(11):训练自己的opencv级联分类器_生成pos.txt-CSDN博客

  • 11
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

路奇怪

有钱出钱,没钱多出编程主意啊

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值