《opencv实用探索·二十二》支持向量机SVM用法

news2025/1/23 3:26:27

1、概述
在了解支持向量机SVM用法之前先了解一些概念:
(1)线性可分和线性不可分
如果在一个二维空间有一堆样本,如下图所示,如果能找到一条线把这两类样本分开至线的两侧,那么这个样本集就是线性可分,否则就是线性不可分。
在这里插入图片描述
如果在一个三维空间有一堆样本,如果能找到一个平面把三维空间中的两类样本分开至平面的两侧,那么这个样本就是线性可分,否则为线性不可分。
如果在一个超过三维空间的更高维度上能找一个平面(这里我们称这个平面为超平面)把两类样本分开至超平面两侧,那么这个样本就是线性可分,否则为线性不可分。

一般情况下,把能够可以被一条直线(更一般的情况,即一个超平面)分割的数据称为线性可分的数据,所以超平面是线性分类器。

(2)支持向量机(Support Vector Machine,SVM)
在OpenCV中,支持向量机(Support Vector Machine,SVM)是一种用于图像分类和对象识别的机器学习算法。SVM 是一种监督学习算法,它可以用于二分类或多分类问题。在图像处理领域,SVM 经常用于训练分类器,从而对图像中的对象进行识别。

SVM 的基本思想是找到一个最优的超平面,将不同类别的样本分开,并且使得两个类别之间的间隔最大化。这个最优的超平面由支持向量(Support Vectors)定义,它们是离超平面最近的样本点。该怎么理解这句话?

我们还是以一个二维平面的样本集为例,如下图所示:
L1,L2,L3都可以把两类样本分离,L1离P1样本向量最近,L3离P2样本向量最近,我们称这两个样本向量为支持向量,这两条线(更宽泛一点称为超平面)称为支撑超平面,他们分别支撑两类数据。L1和L3之间的距离d称为间隔,我们需要找到一个最好的超平面L2使得间隔最大。
在这里插入图片描述

2、支持向量机SVM用法步骤
在OpenCV中,SVM的使用通常涉及以下步骤:
(1)数据准备: 收集并准备训练数据,确保每个样本都有相应的标签。
(2)创建SVM对象: 使用OpenCV的 cv::ml::SVM 类创建一个SVM对象。
(3)设置训练参数: 设置SVM的训练参数,例如核函数、惩罚系数等。
(4)训练SVM模型: 使用训练数据对SVM进行训练。
(5)预测: 使用训练好的SVM模型对新的数据进行分类预测。

1.数据准备
训练数据(Training Data): 这是用于训练SVM模型的输入数据集。对于分类问题,每个训练样本都是一个输入向量,表示数据的特征。下面代码中,trainingDataMat 是一个矩阵,每一行代表一个样本,每一列代表一个特征。在这个例子中,每个样本有两个特征,分别是 x 和 y 的坐标。

// 设置训练数据
float trainingData[4][2] = { {501, 10}, {255, 10}, {501, 255}, {10, 501} };
Mat trainingDataMat(4, 2, CV_32FC1, trainingData);

如果把这4个点在图像上标出来,大致位置如下图所示(注意:501表示像素的列,10表示像素的行,其他坐标也是如此),同时根据下面设置的样本标签来看,图中右上角的点为正样本,其余为负样本,图中红线位置大概就是超平面,把两类样本分至两侧。
在这里插入图片描述
标签(Labels): 这是训练数据对应的输出标签或类别。标签表示每个训练样本所属的类别。在下面代码中,labelsMat 是一个矩阵,每一行对应于训练数据中的一个样本,表示该样本所属的类别。通常,标签是整数值,例如 1 表示正类别,-1 表示负类别。

// 设置标签
int labels[4] = { 1, -1, -1, -1 };
Mat labelsMat(4, 1, CV_32SC1, labels);

对于上面的四个训练样本,每个样本有两个特征。对应的标签是 {1, -1, -1, -1}。这表示第一个样本属于正类别(1),而其余三个样本属于负类别(-1)。这些训练数据和标签将用于训练支持向量机模型,使其能够对新的输入数据进行分类。

2.创建SVM对象

//如果使用OpenCV 4.x 版本请用如下代码
Ptr<SVM> svm = SVM::create();

//如果使用OpenCV 3.x版本请用如下代码
SVM::Params params;

3.设置SVM的训练参数

//如果使用OpenCV 4.x 版本请用如下代码
svm->setType(SVM::C_SVC);
svm->setKernel(SVM::LINEAR);
svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6));

//如果使用OpenCV 3.x版本请用如下代码
params.svmType = SVM::C_SVC;
params.kernelType = SVM::LINEAR;
params.termCrit = TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6);

setType 用于设置 SVM 的类型,即分类器的类型。
SVM 的类型:
cv::ml::SVM::C_SVC:用于分类。
cv::ml::SVM::NU_SVC:用于分类,支持类别不平衡。
cv::ml::SVM::ONE_CLASS:用于单类别分类。
cv::ml::SVM::EPS_SVR:用于回归问题。
cv::ml::SVM::NU_SVR:用于回归问题,支持回归损失参数。

setKernel 用于设置核函数,即 SVM 在高维空间中处理数据的方法
核函数:
cv::ml::SVM::LINEAR:线性核函数,它适用于线性可分的数据。
cv::ml::SVM::POLY:多项式核函数。
cv::ml::SVM::RBF:径向基核函数(高斯核函数)。
cv::ml::SVM::SIGMOID:Sigmoid 核函数。

setTermCriteria 用于设置 SVM 的终止标准,即训练停止的条件。
cv::TermCriteria::MAX_ITER 表示基于最大迭代次数的终止标准,这里设置为最大迭代次数为 100。
1e-6 是一个容差,表示允许的训练误差

4.训练SVM模型

//如果使用OpenCV 4.x 版本请用如下代码
svm->train(trainingDataMat, ROW_SAMPLE, labelsMat);

//如果使用OpenCV 3.x版本请用如下代码
Ptr<SVM> svm = StatModel::train<SVM>(trainingDataMat, ROW_SAMPLE, labelsMat, params);

ROW_SAMPLE: 这是一个标志,表示每行数据是一个训练样本。在分类问题中,每行通常代表一个样本,每列是该样本的特征。这个标志告诉函数按行处理数据

svm->train() 函数用于训练 SVM 模型。在训练期间,模型将学会如何将输入数据映射到给定的类别,以便在未知数据上进行分类。

5.预测
使用训练好的SVM模型对数据进行预测
假如有一个图像宽高都是512,现在把图像中每个像素的坐标作为一个新输入的样本,并对这个样本进行预测是正样本还是负样本,如果是正样本就用绿色标出,如果是负样本就用蓝色标出。

Vec3b green(0, 255, 0), blue(255, 0, 0);
	//显示由SVM给出的决定区域 (Show the decision regions given by the SVM)
	for (int i = 0; i < image.rows; ++i)
		for (int j = 0; j < image.cols; ++j)
		{
		    //把图像中每个像素点的坐标作为一个样本进行创建,i是行对应y坐标,j是列对应x坐标
			Mat sampleMat = (Mat_<float>(1, 2) << j, i);
			//使用训练好的 SVM 模型对当前像素的特征进行分类。response 存储了 SVM 模型对该样本的预测结果
			//response 为1表示正样本用绿色标出,为-1表示负样本用蓝色标出
			float response = svm->predict(sampleMat);

			if (response == 1)
				image.at<Vec3b>(i, j) = green;
			else if (response == -1)
				image.at<Vec3b>(i, j) = blue;
		}

这样,通过遍历整个图像,根据 SVM 模型的分类结果,将图像的不同区域标记为不同的颜色,从而可视化 SVM 模型对数据的分类效果
在这里插入图片描述

最后在画出训练数据和支持向量

//显示训练数据 (Show the training data)
	int thickness = -1;
	int lineType = 8;
	circle(image, Point(501, 10), 5, Scalar(0, 0, 0), thickness, lineType);
	circle(image, Point(255, 10), 5, Scalar(255, 255, 255), thickness, lineType);
	circle(image, Point(501, 255), 5, Scalar(255, 255, 255), thickness, lineType);
	circle(image, Point(10, 501), 5, Scalar(255, 255, 255), thickness, lineType);

	//显示支持向量 (Show support vectors)
	thickness = 2;
	lineType = 8;
	Mat sv = svm->getSupportVectors();  //返回的是支持向量的坐标
	std::cout << "Support Vectors:\n" << sv << std::endl;  //[-0.008130081, 0.008163265]

	for (int i = 0; i < sv.rows; ++i)  //rows为1,表示每个样本类别中只有一个支持向量
	{
		const float* v = sv.ptr<float>(i);
		int x = (int)v[0];
		int y = (int)v[1];
		circle(image, Point((int)v[0], (int)v[1]), 6, Scalar(128, 128, 128), thickness, lineType);
	}

在这里插入图片描述
我的理解是支持向量应该是上面样本中的某个样本的坐标,这里为啥是[-0.008130081, 0.008163265]?
支持向量坐标是相对于输入特征空间的,不是图像坐标,“特征空间” 是指用于训练 SVM 模型的样本数据的特征表示的空间,这些坐标在特征空间中描述了支持向量的位置。由于 SVM 的实现可能对数据进行了缩放或标准化,因此这些坐标可能是相对于某种处理后的特征空间而言的。

最后附上完整的代码:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/ml/ml.hpp>
#include <opencv2/imgproc.hpp>
#include "opencv2/imgcodecs.hpp"
using namespace cv;
using namespace cv::ml;

int main()
{

	// 视觉表达数据的设置(Data for visual representation)
	int width = 512, height = 512;
	Mat image = Mat::zeros(height, width, CV_8UC3);

	//建立训练数据( Set up training data)
	int labels[4] = { 1, -1, -1, -1 };
	Mat labelsMat(4, 1, CV_32SC1, labels);

	float trainingData[4][2] = { {501, 10}, {255, 10}, {501, 255}, {10, 501} };
	Mat trainingDataMat(4, 2, CV_32FC1, trainingData);
	std::cout << trainingDataMat << std::endl;

	//设置支持向量机SVM的参数(Set up SVM's parameters)

	Ptr<SVM> svm = SVM::create();
	svm->setType(SVM::C_SVC);
	svm->setKernel(SVM::LINEAR);
	svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6));


	// 训练支持向量机(Train the SVM)
	svm->train(trainingDataMat, ROW_SAMPLE, labelsMat);

	Vec3b green(0, 255, 0), blue(255, 0, 0);
	//显示由SVM给出的决定区域 (Show the decision regions given by the SVM)
	for (int i = 0; i < image.rows; ++i)
		for (int j = 0; j < image.cols; ++j)
		{
			Mat sampleMat = (Mat_<float>(1, 2) << j, i);
			float response = svm->predict(sampleMat);

			if (response == 1)
				image.at<Vec3b>(i, j) = green;
			else if (response == -1)
				image.at<Vec3b>(i, j) = blue;
		}

	//显示训练数据 (Show the training data)
	int thickness = -1;
	int lineType = 8;
	circle(image, Point(501, 10), 5, Scalar(0, 0, 0), thickness, lineType);
	circle(image, Point(255, 10), 5, Scalar(255, 255, 255), thickness, lineType);
	circle(image, Point(501, 255), 5, Scalar(255, 255, 255), thickness, lineType);
	circle(image, Point(10, 501), 5, Scalar(255, 255, 255), thickness, lineType);

	//显示支持向量 (Show support vectors)
	thickness = 2;
	lineType = 8;
	Mat sv = svm->getSupportVectors();
	std::cout << "Support Vectors:\n" << sv << std::endl;

	for (int i = 0; i < sv.rows; ++i)
	{
		const float* v = sv.ptr<float>(i);
		int x = (int)v[0];
		int y = (int)v[1];
		circle(image, Point((int)v[0], (int)v[1]), 6, Scalar(128, 128, 128), thickness, lineType);
	}

	imwrite("result.png", image);        // 保存图像

	imshow("SVM Simple Example", image); // 显示图像
	waitKey(0);

}
在这里插入图片描述

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

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

相关文章

关于年化收益率的思考

近期&#xff0c;对于投资的年化收益率有一些思考&#xff0c;想着将这些思考整理一下&#xff0c;顺便也就记录在这里。 1. 计算方式 年化收益率常见的计算有三种&#xff1a;算数平均&#xff0c;几何平均&#xff0c;IRR。 1.1 算术平均 算数平均用于度量产品的回报率&a…

【Java EE初阶二十六】简单的表白墙(二)

2. 后端服务器部分 2.1 服务器分析 2.2 代码编写 2.2.2 前端发起一个ajax请求 2.2.3 服务器读取上述请求,并计算出响应 服务器需要使用 jackson 读取到前端这里的数据,并且进行解析&#xff1a; 代码运行图&#xff1a; 2.2.4 回到前端代码&#xff0c;处理服务器返回的响应…

vue项目从后端下载文件显示进度条或者loading

//API接口 export const exportDownload (params?: Object, peCallback?: Function) > {return new Promise((resolve, reject) > {axios({method: get,url: ,headers: {access_token: ${getToken()},},responseType: blob,params,onDownloadProgress: (pe) > {peC…

Flutter(三):Stack、Positioned、屏幕相关尺寸、Navigator路由跳转

页面尺寸 通知栏高度&#xff1a;MediaQuery.of(context).padding.top顶部导航高度&#xff1a;kToolbarHeight底部导航高度&#xff1a;kBottomNavigationBarHeight屏幕宽&#xff1a;MediaQuery.of(context).size.width屏幕高&#xff1a;MediaQuery.of(context).size.height…

SpringMVC 学习(十)之异常处理

目录 1 异常处理介绍 2 通过 SimpleMappingExceptionResolver 实现 3 通过接口 HandlerExceptionResolver 实现 4 通过 ExceptionHandler 注解实现&#xff08;推荐&#xff09; 1 异常处理介绍 在 SpringMVC中&#xff0c;异常处理器&#xff08;Exceptio…

项目解决方案:海外门店视频汇聚方案(全球性的连锁店、国外连锁店视频接入和汇聚方案)

目 录 一、概述 二、建设目标及需求 2.1 建设目标 2.2 需求描述 2.3 需求分析 三、建设方案设计 3.1 系统方案拓扑图 3.2 方案描述 3.3 服务器配置推荐 四、产品功能 4.1 资源管理平台 &#xff08;1&#xff09;用户权限管理 &#xff08;2&#xff09…

AD9226 65M采样 模数转换

目录 AD9220_ReadTEST AD9220_ReadModule AD9226_TEST_tb 自己再写个 260M的时钟&#xff0c;四分频来提供65M的时钟。 用 vivado 写的 AD9226_ReadTEST module AD9226_ReadTEST( input clk, input rstn,output clk_driver, //模块时钟管脚 input [12:0]IO_data, //模块数…

LACP——链路聚合控制协议

LACP——链路聚合控制协议 什么是LACP&#xff1f; LACP&#xff08;Link Aggregation Control Protocol&#xff0c;链路聚合控制协议&#xff09;是一种基于IEEE802.3ad标准的实现链路动态聚合与解聚合的协议&#xff0c;它是链路聚合中常用的一种协议。 链路聚合组中启用了…

Linux运维-Web服务器的配置与管理(Apache+tomcat)(没成功,最后有失败经验)

Web服务器的配置与管理(Apachetomcat) 项目场景 公司业务经过长期发展&#xff0c;有了很大突破&#xff0c;已经实现盈利&#xff0c;现公司要求加强技术架构应用功能和安全性以及开始向企业应用、移动APP等领域延伸&#xff0c;此时原来开发web服务的php语言已经不适应新的…

云服务器ECS价格表出炉_2024年最新价格表——阿里云

2024年最新阿里云服务器租用费用优惠价格表&#xff0c;轻量2核2G3M带宽轻量服务器一年61元&#xff0c;折合5元1个月&#xff0c;新老用户同享99元一年服务器&#xff0c;2核4G5M服务器ECS优惠价199元一年&#xff0c;2核4G4M轻量服务器165元一年&#xff0c;2核4G服务器30元3…

高防IP简介

高防IP可以防御的有包括但不限于以下类型&#xff1a; SYN Flood、UDP Flood、ICMP Flood、IGMP Flood、ACK Flood、Ping Sweep 等攻击。高防IP专注于解决云外业务遭受大流量DDoS攻击的防护服务。支持网站和非网站类业务的DDoS、CC防护&#xff0c;用户通过配置转发规则&#x…

Nginx反向代理ip透传与负载均衡

前言 上篇介绍了nginx服务器单向代理和动静分离等相关内容&#xff0c;可参考Nginx重写功能和反向代理-CSDN博客&#xff0c;这里就ip透传和负载均衡对nginx反向代理做进一步了解。 目录 一、客户端ip透传 1. 概述 2. 一级代理 2.1 图示 2.2 操作过程 3. 二级代理 3.…

type may not be empty [type-empty]

原因是使用了规范commit信息的工具&#xff0c;你的提交信息不符合规范&#xff0c;所以被拒绝了 commit规范工具 commitlinthusky 解决方式一&#xff1a; 修改提交信息&#xff0c; 使其符合规范 git commit -m "feat: 新功能"使用Git Gui的使用以下格式写提交…

wu-framework-parent 项目明细

wu-framework-parent 介绍 springboot 版本3.2.1 wu-framework-parent 是一款由Java语言开发的框架&#xff0c;目标不写代码但是却能完成功能。 框架涵盖无赖ORM( wu-database-lazy-starter)、仿生组件 、easy框架系列【Easy-Excel、easy-listener、easy-upsert】 授权框架(…

华为ipv6 over ipv4 GRE隧道配置

思路&#xff1a; PC1访问PC2时&#xff0c;会先构造源ipv6为2001:1::2&#xff0c;目的IPV6为2001:2::2的ipv6报文&#xff0c;然后查看PC1的路由表&#xff0c;发送到R1&#xff0c;r1接收后&#xff0c;以目的IPV6地址2001:2::2查询IPV6路由表&#xff0c;出接口为tun0/0/0…

C++ 补充之常用遍历算法

C遍历算法和原理 C标准库提供了丰富的遍历算法&#xff0c;涵盖了各种不同的功能。以下是一些常见的C遍历算法以及它们的概念和原理的简要讲解&#xff1a; for_each&#xff1a;对容器中的每个元素应用指定的函数。 概念&#xff1a;对于给定的容器和一个可调用对象&#xff…

jenkins+kubernetes+git+dockerhub构建devops云平台

Devops简介 k8s助力Devops在企业落地实践 传统方式部署项目为什么发布慢&#xff0c;效率低&#xff1f; 上线一个功能&#xff0c;有多少时间被浪费了&#xff1f; 如何解决发布慢&#xff0c;效率低的问题呢&#xff1f; 什么是Devops&#xff1f; 敏捷开发 提高开发效率&…

Linux中数据库sqlite3的基本命令的使用

数据库概念介绍 数据库安装 首先将本地的三个sqlite3安装包移动到共享文件夹然后在移动到自己创建的文件夹中如下&#xff1a; 然后对安装包进行解压如下&#xff1a;sudo dpkg -i *.deb检查是否安装成功sqlite数据库命令 系统命令 &#xff0c; 都以’.开头 .exit .quit .…

springboot+vue+mysql+easyexcel实现文件导出+导出的excel单元格添加下拉列表

Excel导出 EasyExcel官方文档 官方文档本身写的非常详细&#xff0c;我就是根据官方文档内的写Excel里web中的写实现的导出 后端 对象 需要写一个实体类 其中涉及到一些用到的EasyExcel的注解 ColumnWidth(20) 列宽设为20&#xff0c;自定义的&#xff0c;放在实体类上面是…

ImportError: urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the ‘ssl‘报错解决

安装labelme出错了 根据爆栈的提示信息&#xff0c;我在cmd运行以下命令之后一切正常了&#xff0c;解决了问题&#xff01; pip install urllib31.26.6参考网址&#xff1a;ImportError: urllib3 v2.0 only supports OpenSSL 1.1.1, currently the ‘ssl’ module is compile…