NAO_GolfVision_ML使用说明

概述

  本博客是我的Github上的NAO_GolfVision_ML项目的使用说明。该项目是NAO高尔夫比赛中的视觉系统设计,主要是利用opencv和机器学习算法对视觉系统中的目标进行分类检测。详细的代码解释见另一篇博客:NAO比赛视觉系统设计

平台

  Windows 10
  python2.7 32(NAO支持的版本)

文件夹结构

文件夹说明
  该文件夹主要分为三个部分,第一部分是数据集,包含图片和标签的数据集,其中图片为NAO摄像头实际拍摄的图像,像素大小为640*480,标签为labelImg软件标注生成的xml文件,其中正负样本分开存放。
  第二部分是代码,其中TargetDetection.pyTargetFeature.pyopnecv对目标的检测和机器学习对目标的特征提取文件,Classifier,pyClassifierTrain,py是机器学习的分类器和训练文件。其中ClassifierTrain,py是主函数文件。
  第三部分是其他文件,主要包含3张测试图片,即足球、红球和黄杆,3张数据文件,即总数据,正样本数据和负样本数据,另外包含一个renamefile.py,主要是为了统一图片和标签的名字。

TargetDetection.py

  该文件包含3个类,其中TargetDetection是基类,HoughDetection是霍夫圆检测类,ContoursDetection是轮廓检测类。读者也可以使用其他检测算法新建自己的检测类。

TargetDetection

  该类包含图像预处理函数preProcess(),滤波函数filter()和滑动条函数sliderObjectHSV()

使用方法

1
2
3
4
5
6
if __name__ == '__main__':
Img = cv2.imread("stick.jpg") # 注意替换照片

# 测试HSV滑动条函数
tarDet = TargetDetection(Img)
tarDet.sliderObjectHSV("stick")

  首先打开一张测试图片,实际比赛中可以将此替换为NAO拍摄的图片,然后实例化类,并调用滑动条函数。注意图片名字和类别名字要一致。 HSV测试
  不断调整滑动条的参数,以得到理想效果。

HoughDetection

  该类包含霍夫圆检测函数houghDetection(),信息转换函数circle2Rect(),显示结果函数showHoughResult()和霍夫圆检测滑动条函数houghSlider()

使用方法

1
2
3
4
5
6
if __name__ == '__main__':
Img = cv2.imread("redBall.jpg") # 注意替换照片

# 测试霍夫圆检测滑动条(球类目标专用)
houghDet = HoughDetection(Img)
houghDet.houghSlider("redBall")

霍夫圆检测
  不断调整滑动条的参数,以得到理想效果。

ContoursDetection

  该类包含轮廓检测函数contoursDetection(),信息转换函数contour2Rect(),显示结果函数showContourResult()和轮廓检测滑动条函数contoursSlider()

使用方法

1
2
3
4
5
6
if __name__ == '__main__':
Img = cv2.imread("stick.jpg") # 注意替换照片

# 测试轮廓检测滑动条(黄杆专用)
ContoursDet = ContoursDetection(Img)
ContoursDet.contoursSlider("stick")

轮廓检测
  不断调整滑动条的参数,以得到理想效果。

TargetFeature.py

  该文件包含2个类,其中HogFeature是提取HOG特征,ColorFeature是提取颜色特征。读者也可以使用其他特征提取算法。最后统一成向量的形式即可。

使用方法

  这部分主要是结合之后的分类器训练使用。

Classifier.py

  该文件包含2个类,其中Logistic是逻辑回归分类器,KNN是K近邻分类器。读者也可以使用自己的分类器。

使用方法

  这部分主要是结合之后的分类器训练使用。

ClassifierTrain.py

  该文件包含以下函数:

  1. parseXml():解析标注文件函数,
  2. reshapeBallRect():重造球类目标矩形框函数,
  3. reshapeStickRect():重造黄杆类目标矩形框函数,
  4. circle2Rect():转换信息函数,
  5. calColorFeature():计算颜色特征函数,
  6. calHOGFeature():计算HOG特征函数,
  7. calPosVector():计算正样本向量函数
  8. calNegVector():计算负样本向量函数
  9. resultTest():分类结果测试函数

使用方法

  首先将数据集正确的放入到文件夹中,越多越好,至少上百张,其次更改calPosVector()函数里面的路径位置及信息。
  其中画图部分的函数,即:

1
2
3
4
5
    # cv2.rectangle(srcImg, (newInitX, newInitY), (newEndX, newEndY), (0, 0, 255), 2)  # 画矩形 

# cv2.imshow("test " + str(i), srcImg)
# cv2.waitKey(300)
# cv2.destroyAllWindows()

  在实际训练时需要注释掉,否则会把标注框也认为是正样本。该部分主要是为了测试标注框是否准确,读者可以先保留该部分运行一遍,再注释后运行一遍,实际的特征向量以加了注释后的为准。

1
2
if __name__ == '__main__':
calPosVector("data_pos.txt") # 计算正样本的特征向量

正样本测试
  运行过程中,会显示出特征向量的总数,如果是320则是正确的,当然了如果读者自己加入了其他的特征提取,可以自己算一遍。
  最后所有的特征向量会存放在data_pos.txt的文件夹下。

  负样本的使用方法同上。其最终的特征向量会存放在data_neg.txt文件夹下,最后将这2个txt文件的数据合并到data.txt文件中。

  最后再调用测试分类结果函数resultTest()即可,在里面输入相应的分类器,当然也可以是自己的。
测试结果
  最终结果如图所示,红色为正确的,黄色为错误的。实际测试发现,只要目标不在边界上,其正确率几乎可以达到100%,对于边界上的情况,个别几个情况分类错误,但这对比赛也并没有太大的影响。整体效果还是非常不错的,可以达到比赛的实时检测要求。

注:我这里只对足球类目标进行了检测,没用对红球和黄杆测试,读者有兴趣的话可以自己采集数据并测试一下,欢迎大家留言讨论。

附:sklearn机器学习库实现分类器

  这里提供一个强大的机器学习库sklearn来实现之前的分类器,首先需要通过pip安装(pip install -U scikit-learn),由于NAO本身并不支持这个第三方库,所以我们如果要使用的话,需要将下载好的sklearn库上传至NAO中。
  和之前一样,还是新建一个py文件,里面可以新建若干各类,每个类实现一个分类器。

实现原理

  sklearn实现机器学习算法特别简单,大致可以分为三步,1.读取数据,2.构建分类器并训练参数,3.使用分类器预测。
  下面以Logistic回归为例,详细讲解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import sklearn
from sklearn.linear_model import LogisticRegressionCV, LinearRegression
from sklearn.model_selection import train_test_split
import numpy as np

from sklearn.externals import joblib


class LogisticSk(object):
def __init__(self, filename):
self.filename = filename

def file2matrix(self):
fr = open(self.filename)
arrayOfLines = fr.readlines()
numberOfLines = len(arrayOfLines)
returnMat = np.zeros((numberOfLines, 320))

classLabelVector = []
index = 0
for line in arrayOfLines:
line = line.strip()
listFromLine = line.split(' ')
returnMat[index, :] = listFromLine[0:320]

if listFromLine[-1] == '0':
classLabelVector.append(0)
elif listFromLine[-1] == '1':
classLabelVector.append(1)

index += 1
return returnMat, classLabelVector

def trainClassify(self):
X, Y = self.file2matrix()
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.1, random_state=0)

lr = LogisticRegressionCV(multi_class="ovr", fit_intercept=True, Cs=np.logspace(-2, 2, 20), cv=2, penalty="l2", solver="lbfgs", tol=0.01)
lr.fit(X_train, Y_train)

return lr

def saveClassify(self, model, path):
joblib.dump(model, path)

def readClassify(self, path):
return joblib.load(path)

def predictClassify(self, lr, X_test):
Y_predict = lr.predict(X_test)

return Y_predict

  这里为了和之前的变量名不一样,在分类器后面加了SK,表示是用sklearn库实现的。

读取数据

  这部分可以参考之前的file2matrix()函数。

构建分类器并训练

  在构建分类器之前,我们可以先用train_test_split()函数将数据集分为训练集和测试集,以便后续的分析(当然也可以直接用原来的数据)。
  接下来就是使用sklearn库中自带的分类器训练,这里注意首先要将分类器所在的类导入进来,比如这里是LogisticRegressionCV()分类器函数,它是在sklearn.linear_model类中的。然后可以设置分类器的参数,当然也可以使用默认值。最后使用fit()函数训练以得到相应的参数。

保存和读取模型

  训练一次数据集通常需要花费一定的时间,这对实时性的要求显然是不利的,所以通常的做法是先将训练好的模型保存下来,然后再读取。
  sklearn中保存和读取的模块是joblib(也有其他的),其dump()load()函数分别是读取和保存。
注:保存的模型一般后缀名为.m

使用模型预测

  使用predict()函数预测即可,输入参数为待预测的数据。

结果分析

  实际测试下来发现,sklearn库的分类器函数和自己写的分类器的效果几乎差不多,总体效果还是比较好的。

谢谢老板!
-------------本文结束感谢您的阅读给个五星好评吧~~-------------