【全解】基于OpenCv的SVM实现车牌检测与识别

您所在的位置:网站首页 mv车牌是什么 【全解】基于OpenCv的SVM实现车牌检测与识别

【全解】基于OpenCv的SVM实现车牌检测与识别

2024-07-07 16:05| 来源: 网络整理| 查看: 265

都说深度学习的出现极力地打压着传统机器学习算法的地位,作为一个二刷机器学习经典算法的小伙伴告诉你:还真多半是这样,咳,毕竟还是差距较大,深度学习处理真实世界多维度的问题更权威!不过,有的事情还是机器学习能做的,经典永不过时,下面我们来做一个实践。

前两篇博客比较仓促,今天我把全部整理了一遍,流程图过程也全部展现,让大家更好的明白流程 ,篇幅字数上万,建议细品!

我们来看看车牌检测基本的识别流程:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vwa39CwX-1589343456697)(D:\CSDN\pic\车牌检测(一)\1.png)]

我使用的是OpenCv自带的SVM模型,由于SVM的突出表现,得到了更多官方的青睐,就诞生出了很多方便使用的封装,正如Opencv的SVM封装。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SvNSyXrX-1589343456699)(D:\CSDN\pic\车牌检测(一)\1588637654566.png)]

核心代码介绍:

调用Opencv的SVM

​ OpenCV(开源计算机视觉库:http://opencv.org)是一个bsd授权的开源库,包含数百种计算机视觉算法。该文件描述了所谓的opencv2。x API,本质上是一个c++ API,而不是基于C的OpenCV 1。x API(自OpenCV 2.4发布以来,C API被弃用,并且没有使用“C”编译器进行测试)

​ Python与C/ c++这样的语言相比,Python要慢一些,但是Python可以很容易地使用C/ c++进行扩展,这允许我们用C/ c++编写计算密集型代码,并创建可以用作Python模块的Python包装器。这给了我们两个好处:首先,代码和原始的C/c++代码一样快(因为Python在后台工作的代码实际上是c++代码);其次,用Python编写代码比用C/c++更容易。

​ OpenCV支持多种编程语言,如c++、Python、Java等,可以在不同的平台上使用,包括Windows、Linux、OS X、Android和iOS。基于CUDA和OpenCL的高速GPU操作接口也在积极开发中。

​ OpenCV-Python是OpenCV的Python API,是原始OpenCV c++实现的Python包装器。结合了OpenCV c++ API和Python语言的最佳特性。

支持向量机(Support Vector Machine, SVM)的基本模型是在特征空间上找到最佳的分离超平面使得训练集上正负样本间隔最大。SVM是用来解决二分类问题的有监督学习算法(实际上还有多分类),在引入了核方法之后SVM也可以用来解决非线性问题。 一般SVM有下面三种:

​ 硬间隔支持向量机(线性可分支持向量机):当训练数据线性可分时,可通过硬间隔最大化学得一个线性可分支持向量机。 ​ 软间隔支持向量机:当训练数据近似线性可分时,可通过软间隔最大化学得一个线性支持向量机。 ​ 非线性支持向量机:当训练数据线性不可分时,可通过核方法以及软间隔最大化学得一个非线性支持向量机。

​ 它在解决小样本、非线性及高维模式识别中表现出许多特有的优势,并能够推广应用到函数拟合等其他机器学习问题中。

​ 支持向量机方法是建立在统计学习理论的VC维理论和结构风险最小原理基础上的,根据有限的样本信息在模式的复杂性(即对特定训练样本的学习精度,Accurary)和学习能力(即无错误地识别任意样本的能力)之间寻求最佳折衷,以期获得最好的推广能力。

SVM实质上是一个类分类器,是一个能够将不同类样本在样本空间分隔的超平面。

换句话说,给定一些标记(label)号的训练样本,SVM算法输出一个最优化的分隔超平面。

class SVM(StatModel): def __init__(self, C = 1, gamma = 0.5): self.model = cv2.ml.SVM_create() self.model.setGamma(gamma) self.model.setC(C) self.model.setKernel(cv2.ml.SVM_RBF) self.model.setType(cv2.ml.SVM_C_SVC) 这边的cv2.ml.SVM_create()生成一个SVM模型

setGamma(gamma),设置Gamma参数,demo中是0.5

setC(C), 设置惩罚项, 为:1

setKernel(cv2.ml.SVM_RBF):设置核函数:RBF

setType(cv2.ml.SVM_C_SVC):设置SVM的模型类型:SVC是分类模型,SVR是回归模型

接下来继续走: 训练svm

1:定义

class SVM(StatModel): def __init__(self, C = 1, gamma = 0.5): self.model = cv2.ml.SVM_create() self.model.setGamma(gamma) self.model.setC(C) self.model.setKernel(cv2.ml.SVM_RBF) self.model.setType(cv2.ml.SVM_C_SVC) #训练svm def train(self, samples, responses): self.model.train(samples, cv2.ml.ROW_SAMPLE, responses)

2:

调用方法,并且喂数据:

def train_svm(self): #识别英文字母和数字 self.model = SVM(C=1, gamma=0.5) #识别中文 self.modelchinese = SVM(C=1, gamma=0.5) if os.path.exists("svm.dat"): self.model.load("svm.dat")

这边已经训练好模型就执行IF语句中的load操作(常用的调取持久化模型的方法),否则要是没有模型就开始训练(喂数据):

else: chars_train = [] chars_label = [] for root, dirs, files in os.walk("train\\chars2"): if len(os.path.basename(root)) > 1: continue root_int = ord(os.path.basename(root)) for filename in files: filepath = os.path.join(root,filename) digit_img = cv2.imread(filepath) digit_img = cv2.cvtColor(digit_img, cv2.COLOR_BGR2GRAY) chars_train.append(digit_img) #chars_label.append(1) chars_label.append(root_int) chars_train = list(map(deskew, chars_train)) chars_train = preprocess_hog(chars_train) #chars_train = chars_train.reshape(-1, 20, 20).astype(np.float32) chars_label = np.array(chars_label) print(chars_train.shape) self.model.train(chars_train, chars_label)

调用的相对路径是:"train\chars2是数据集:

这是从1-9,A到Z的数据集~

有点像MNIST手写数字体有木有! 在这里插入图片描述

比如A: [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vKkJC7qm-1589343456703)(D:\CSDN\pic\车牌检测(一)\1588602809104.png)]

这些是字母的训练数据,同样的还有我们车牌的省份简写:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NuG5sXtf-1589343456709)(D:\CSDN\pic\车牌检测(一)\1588638135115.png)]

来看一个:广西的简称:桂

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2IgT8j2H-1589343456712)(D:\CSDN\pic\车牌检测(一)\1588638324603.png)]

在此分成了SVC分别训练省份简称和右边的英文字符和数字 def train_svm(self): #识别英文字母和数字 self.model = SVM(C=1, gamma=0.5) #识别中文 self.modelchinese = SVM(C=1, gamma=0.5) if os.path.exists("svm.dat"): self.model.load("svm.dat") else: chars_train = [] chars_label = [] for root, dirs, files in os.walk("train\\chars2"): if len(os.path.basename(root)) > 1: continue root_int = ord(os.path.basename(root)) for filename in files: filepath = os.path.join(root,filename) digit_img = cv2.imread(filepath) digit_img = cv2.cvtColor(digit_img, cv2.COLOR_BGR2GRAY) chars_train.append(digit_img) #chars_label.append(1) chars_label.append(root_int) chars_train = list(map(deskew, chars_train)) chars_train = preprocess_hog(chars_train) #chars_train = chars_train.reshape(-1, 20, 20).astype(np.float32) chars_label = np.array(chars_label) print(chars_train.shape) self.model.train(chars_train, chars_label) if os.path.exists("svmchinese.dat"): self.modelchinese.load("svmchinese.dat") else: chars_train = [] chars_label = [] for root, dirs, files in os.walk("train\\charsChinese"): if not os.path.basename(root).startswith("zh_"): continue pinyin = os.path.basename(root) index = provinces.index(pinyin) + PROVINCE_START + 1 #1是拼音对应的汉字 for filename in files: filepath = os.path.join(root,filename) digit_img = cv2.imread(filepath) digit_img = cv2.cvtColor(digit_img, cv2.COLOR_BGR2GRAY) chars_train.append(digit_img) #chars_label.append(1) chars_label.append(index) chars_train = list(map(deskew, chars_train)) chars_train = preprocess_hog(chars_train) #chars_train = chars_train.reshape(-1, 20, 20).astype(np.float32) chars_label = np.array(chars_label) print(chars_train.shape) self.modelchinese.train(chars_train, chars_label) 同上的,先判断我们本地是否训练好了,免得多此一举,同样的

解读一下:

os.walk方法,主要用来遍历一个目录内各个子目录和子文件。

os.walk(top, topdown=True, onerror=None, followlinks=False)

可以得到一个三元tupple(dirpath, dirnames, filenames), 我们这里换名了: root, dirs, files

第一个为起始路径,第二个为起始路径下的文件夹,第三个是起始路径下的文件。

dirpath 是一个string,代表目录的路径,

dirnames 是一个list,包含了dirpath下所有子目录的名字。

filenames 是一个list,包含了非目录文件的名字。

这些名字不包含路径信息,如果需要得到全路径,需要使用os.path.join(dirpath, name).

os.path.basename(),返回path最后的文件名。若path以/或\结尾,那么就会返回空值。

标好了训练集和标签,就可以“喂”给分类器了:

self.modelchinese.train(chars_train, chars_label) 特征提取:获取车牌的可能位置(以下为根据车牌颜色再定位,缩小边缘非车牌边界) def accurate_place(self, card_img_hsv, limit1, limit2, color): row_num, col_num = card_img_hsv.shape[:2] xl = col_num xr = 0 yh = 0 yl = row_num #col_num_limit = self.cfg["col_num_limit"] row_num_limit = self.cfg["row_num_limit"] col_num_limit = col_num * 0.8 if color != "green" else col_num * 0.5#绿色有渐变 for i in range(row_num): count = 0 for j in range(col_num): H = card_img_hsv.item(i, j, 0) S = card_img_hsv.item(i, j, 1) V = card_img_hsv.item(i, j, 2) if limit1


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3