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

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);

}
在这里插入图片描述

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

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

相关文章

Day03:Web架构OSS存储负载均衡CDN加速反向代理WAF防护

目录 WAF CDN OSS 反向代理 负载均衡 思维导图 章节知识点&#xff1a; 应用架构&#xff1a;Web/APP/云应用/三方服务/负载均衡等 安全产品&#xff1a;CDN/WAF/IDS/IPS/蜜罐/防火墙/杀毒等 渗透命令&#xff1a;文件上传下载/端口服务/Shell反弹等 抓包技术&#xff1a…

腾讯云4核8G服务器收费贵不贵?

腾讯云4核8G服务器多少钱&#xff1f;轻量应用服务器4核8G12M带宽一年446元、646元15个月&#xff0c;云服务器CVM标准型S5实例4核8G配置价格15个月1437.3元&#xff0c;5年6490.44元&#xff0c;标准型SA2服务器1444.8元一年&#xff0c;在txy.wiki可以查询详细配置和精准报价…

ky10-server docker 离线安装包、离线安装

离线安装脚本 # ---------------离线安装docker------------------- rpm -Uvh --force --nodeps *.rpm# 修改docker拉取源为国内 rm -rf /etc/docker mkdir -p /etc/docker touch /etc/docker/daemon.json cat >/etc/docker/daemon.json<<EOF{"registry-mirro…

蓝桥杯刷题2

1. 修建灌木 import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scan new Scanner(System.in);int n scan.nextInt();for (int i 1;i < n1;i){int distance Math.max(i-1,n-i);System.out.println(distance*2);}scan.close…

Android13 Audio框架

一、Android 13音频代码结构 1、framework: android/frameworks/base 1.AudioManager.java &#xff1a;音频管理器&#xff0c;音量调节、音量UI、设置和获取参数等控制流的对外API 2.AudioService.java &#xff1a;音频系统服务&#xff08;java层&#xff09;&#xff0c…

Eslint在Vscode中使用技巧的相关技巧

ps :该文章会详细结论构建一个脚手架遇到的问题&#xff0c;会持续更新&#xff0c;请定时查看 Eslint相关​ 在vscode中使用eslint插件 在vscode中用户配置没有开启eslint.enable 在vscode中工作区配置开启eslint.enable settings.json中没有做eslint相关配置 在编写的vue…

了解docker与k8s

随着 k8s 作为容器编排解决方案变得越来越流行&#xff0c;有些人开始拿 Docker 和 k8s 进行对比&#xff0c;不禁问道&#xff1a;Docker 不香吗&#xff1f; k8s 是 kubernetes 的缩写&#xff0c;8 代表中间的八个字符。 其实 Docker 和 k8s 并非直接的竞争对手两者相互依存…

java Springboot vue 健身房系统,简单练手项目

该项目主要分为管理员和会员模块 管理员具有&#xff1a;会员管理&#xff0c;器材管理,员工管理&#xff0c;健身课程管理 会员模块&#xff0c;可以在线报名健身课程&#xff0c;查看自己课程 采用VUE前端开发和springboot后端开发&#xff0c;极简代码编写&#xff0c;没…

java使用itex生成PDF

Text是著名的开放源码的站点sourceforge一个项目&#xff0c;是用于生成PDF文档的一个java类库。通过iText不仅可以生成PDF或rtf的文档&#xff0c;而且可以将XML、Html文件转化为PDF文件。 项目要使用iText&#xff0c;必须引入jar包。才能使用&#xff0c;maven依赖如下&…

浅析ARMv8体系结构:原子操作

文章目录 概述LL/SC机制独占内存访问指令多字节独占内存访问指令 独占监视器经典自旋锁实现 LSE机制原子内存操作指令CAS指令交换指令 相关参考 概述 在编程中&#xff0c;当多个处理器或线程访问共享数据&#xff0c;并且至少有一个正在写入时&#xff0c;操作必须是原子的&a…

idea 更新maven java版本变化

今天遇到个问题就是&#xff0c;点击maven的reload&#xff0c;会导致setting 里的java compiler 版本变化 这里的话&#xff0c;应该是settings.xml文件里面的这个限定死了&#xff0c;修改一下或者去掉就可以了 <profile><id>JDK-1.8</id><activatio…

MFC 打印图片 dc.EndDoc(); 并没有释放怎么办? 原因:打印到pdf才会出现,打印到真实打印机就正常

最后找到原因&#xff1a;打印到pdf才会出现&#xff0c;打印到真实打印机就正常 MFC释放资源 BOOL bPrintingOK dc.StartDoc(&di); 在MFC (Microsoft Foundation Classes) 应用程序中&#xff0c;当你使用 CDC::StartDoc 方法开始一个打印任务时&#xff0c;如果该任务…

HP笔记本电脑如何恢复出厂设置?这里提供几种方法

要恢复出厂设置Windows 11或10的HP笔记本电脑,你可以使用操作系统的标准方法。如果你运行的是早期版本,你可以使用HP提供的单独程序清除计算机并重新安装操作系统。 恢复出厂设置运行Windows 11的HP笔记本电脑​ 所有Windows 11计算机都有一个名为“重置此电脑”的功能,可…

rust下载文件

背景 最近晚上给娃听故事 这页面不能连续播放,想着下载下来用默认播放器播放好了, 刚好最近在学rust,就用rust实现mp4下载. 动手 整理下载链接 由于链接可能涉及不必要的纠纷就先不明文列出来了 编码 解析json use serde::{Deserialize,Serialize}; use serde_json;#[der…

AI学习(5):PyTorch-核心模块(Autograd):自动求导

1.介绍 在深度学习中&#xff0c;自动求导是一项核心技术&#xff0c;它使得我们能够方便地计算梯度并优化模型参数。PyTorch 提供了一个强大的自动求导模块(Autograd)&#xff0c;它可以自动计算张量的导数得出梯度信息&#xff0c;同时也支持高阶导数计算。 1.1 概念词 在学…

pop链构造 [NISACTF 2022]babyserialize

打开题目 题目源代码如下 <?php include "waf.php"; class NISA{public $fun"show_me_flag";public $txw4ever;public function __wakeup(){if($this->fun"show_me_flag"){hint();}}function __call($from,$val){$this->fun$val[0];…

Oracle 基础表管理(Heap-Organized Table Management)

表是数据库中负责数据存储的对象&#xff0c;在RDBMS中&#xff0c;数据以行、列的形式存储在表中。Oracle中表有很多种类型&#xff0c;最基础且应用最常用的类型就是堆表&#xff08;Heap-Organized Table&#xff09;&#xff0c;本文列举了Oracle堆表的常用管理操作。 一、…

LeetCode--134

134. 加油站 在一条环路上有 n 个加油站&#xff0c;其中第 i 个加油站有汽油 gas[i] 升。 你有一辆油箱容量无限的的汽车&#xff0c;从第 i 个加油站开往第 i1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发&#xff0c;开始时油箱为空。 给定两个整数数组 …

WPF 【十月的寒流】学习笔记(1):DataGrid过滤

文章目录 相关链接代码仓库前言环境DataGrid 数据筛选项目配置使用原理主要代码&#xff08;详细代码可以看我的GitHub仓库&#xff09;Models.PersonDataGirdViewDataGridViewModel 实现效果 DataGrid直接绑定CollectionViewxamlViewModel 总结 相关链接 十月的寒流 在 WPF 中…

【开源】使用opencv进行交互式抠图,让你开发效率翻倍

这是一个简单的交互式图像分割应用程序&#xff0c;由python opencv和pyqt编写。 这个应用程序在opencv中应用Grabcut算法对图像进行抠图。Grabcut是Graphcut算法的改进版本。查看这些论文(paper1, paper2)了解详细信息~~ gui部分主要来自这个伟大的工作labelImg。这是一个非常…