OpenCV中的深度学习目标检测

举报
Ustinian_2022 发表于 2022/08/06 21:39:38 2022/08/06
【摘要】 目标检测用来确定图像的某个区域是否含有要识别的对象,计算机视觉中有很多目标检测和是别的技术,这里介绍:梯度直方图(Histogram of Oriented Gradient,HOG),图像金字塔(image pyramid),滑动窗口(sliding window)与特征检测算法不同,这些算法是互补的,在梯度直方图(HOG)里面会用到滑动窗口技术。1.HOG 梯度直方图HOG描述符:HOG...

目标检测用来确定图像的某个区域是否含有要识别的对象,计算机视觉中有很多目标检测和是别的技术,这里介绍:
梯度直方图(Histogram of Oriented Gradient,HOG),图像金字塔(image pyramid),滑动窗口(sliding window)

与特征检测算法不同,这些算法是互补的,在梯度直方图(HOG)里面会用到滑动窗口技术。

1.HOG 梯度直方图

HOG描述符:HOG是一个特殊的特征描述符,HOG与SIFT,SURF,ORB属于同一类型的描述符。

在图像和视频处理中常常会进行目标检测,内部机制都差不多:将图像划分成多个部分,并计算各个部分的梯度,类似的方法,如(人脸检测的LBPH描述符)。

HOG不是基于颜色值二十基于梯度来计算直方图的。HOG所得到的特征描述符能够成为特征匹配和目标检测的重要信息。

HOG提取的卡车图像的特征可以很容易地识别车轮以及车辆的主要结构。

HOG的具体计算

参考文献1
参考文献2
计算图像横坐标和纵坐标方向的梯度,并据此每个像素位置的梯度方向。计算不同的梯度计算方法对于检测器性能有很大影响。作者在对图像进行高斯平滑后,测试了不同的梯度计算方法,包括一维模板[-1,1]、[-1,0,1]、[1,-8,0,8,-1]等,最终选择使用[-1,0,1]计算水平方向梯度,用其转置计算垂直方向梯度。

因此图像中像素点(x,y)的梯度为:

在这里插入图片描述
公式中Gx(x,y)表示像素点(x,y)的水平方向梯度,Gy(x,y)表示像素点(x,y)的垂直方向梯度。

通过Gx(x,y)和Gy(x,y)计算该像素点的梯度大小和方向:

在这里插入图片描述
公式中G(x,y)为梯度大小,θ(x,y)为梯度方向。

HOG特征提取方法就是将一个image(你要检测的目标或者扫描窗口):

1)灰度化(将图像看做一个x,y,z(灰度)的三维图像);

2)采用Gamma校正法对输入图像进行颜色空间的标准化(归一化);目的是调节图像的对比度,降低图像局部的阴影和光照变化所造成的影响,同时可以抑制噪音的干扰;

3)计算图像每个像素的梯度(包括大小和方向);主要是为了捕获轮廓信息,同时进一步弱化光照的干扰。

4)将图像划分成小cells(例如6*6像素/cell);

5)统计每个cell的梯度直方图(不同梯度的个数),即可形成每个cell的descriptor;

6)将每几个cell组成一个block(例如3*3个cell/block),一个block内所有cell的特征descriptor串联起来便得到该block的HOG特征descriptor。

7)将图像image内的所有block的HOG特征descriptor串联起来就可以得到该image(你要检测的目标)的HOG特征descriptor了。这个就是最终的可供分类使用的特征向量了。

HOG特征会受到两个因素的影响:1.位置 2.尺度
两幅图进行比较的时候,如果同一物体,位置不同,尺度不同,可能就会有比较大的影响,为了解决这些问题,就要使用:

  • 图像金字塔
  • 滑动窗口

2.图像金字塔
图像金字塔有助于解决不同尺度下的目标检测。

图像金字塔是一种以多分辨率来解释图像的结构,通过对原始图像进行多尺度像素采样的方式,生成N个不同分辨率的图像。把具有最高级别分辨率的图像放在底部,以金字塔形状排列,往上是一系列像素(尺寸)逐渐降低的图像,一直到金字塔的顶部只包含一个像素点的图像,这就构成了传统意义上的图像金字塔。

总而言之,图像金字塔是自下而上,从大变小生成的,直到到达最小尺寸。清晰度是越来越低的,即是越来越不清晰。
在这里插入图片描述
如何构建图像金字塔
1)获取图像
2)使用任意尺度的参数来调整(缩小)图像的大小
3)平滑图像(使用高斯滤波)
4)如果大小没到最小尺寸,重复1)开始的操作

在这里插入图片描述
这是一个下采样的图像金字塔:它随着采样,图像越来越模糊;
如果是上采样的图像金字塔,它会随着采样,图像越来越清晰;
在这里插入图片描述

前面检测人脸是所用到的检测函数:

faces = face_cascade.detectMultiScale(gray,1.3,5)#检测人脸需要用灰度图像

detectMultiScale()函数的scaleFactor参数就与图像金字塔有关,第一个参数是待处理的图像;第二个是scalefactor即金字塔的层数,通常范围在1,01-1.5之间,参数值越小,层数越多,计算量越大,结果越精确;第三个参数是minneighbors,表示检测到多少次才被认为人脸存在,这里指检测到5次人脸才认为人脸存在。

3.滑动窗口
通过一个滑动窗口扫描较大图像的较小区域来解决定位问题,进而在同一图像的不同尺度下重复扫描。但是滑动窗口会遇到一个问题,区域重叠,比如在对人脸检测的时候可能对同一张人脸的四个不同位置进行匹配,但是我们只需要一个结果,所以我们需要使用非最大抑制来确定一个评价最高的图片区域。

4.非最大抑制
非最大抑制,是指给定一组重叠区域,可以用最大评分来抑制所有未分类的区域。
参考文献3
物体检测中应用NMS算法的主要目的是消除多余(交叉重复)的窗口,找到最佳物体检测位置。
在这里插入图片描述
在这里插入图片描述
如何确定窗口的评分呢,需要一个分类系统来确定某一特征是否存在,而且对这种分类会有一个置信度评分,这里采用支持向量机(SVM)分类。

支持向量机
SVM的最优超平面是目标检测的重要组成部分,用来区分,哪些项目是目标,哪些像素不是目标。

5.检测人

import cv2
import numpy as np

def is_inside(o,i):#如果o框在i框里面,那么就返回True,否则,返回False
    ox,oy,ow,oh = o
    ix,iy,iw,ih = i
    return ox > ix and oy > iy and ox + ow < ix + iw and oy + oh < iy + ih

def draw_person(image,person):#给检测出来的人画框
    x,y,w,h = person
    cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,255),2)
    
img = cv2.imread('E:\opencv3\charpter7\people1.jpg')

#opencv自带的HOGDescriptor可以检测人,作为检测人的默认检测器
hog = cv2.HOGDescriptor()#定义一个模型
hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())#分类是基于人的分类

found,w = hog.detectMultiScale(img)#这里用detectMultiScale来加载图像
#print(found)#found是矩形框的信息,坐标和宽高
#print(w)#w得到的是每一个矩形的置信度

found_filtered = []
for ri,r in enumerate(found):
#    print('ri:',ri,'r:',r)
    for qi,q in enumerate(found):
#        print('qi:',qi,'q:',q)
        if ri != qi and is_inside(r,q):#如果是索引不同的两个框,并且r框在q框里面完全包含了,就直接break
            print('过')#这里我们发现没有这种不同框相互包含的情况,三个框都不是相互包含的关系
            break
        else:
            found_filtered.append(r)
            
for person in found_filtered:
#    print(person)
    draw_person(img,person)
    
cv2.imshow('PEOPLE DETECTION',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

found,w = hog.detectMultiScale(img)
这里与人脸检测算法不一样,不需要再使用目标检测之前将原始图像转化为灰度形式。
该检测返回一个与矩阵有关的数组(点坐标,长宽度),可以用该数组绘制矩形框,如果矩形被完全包含在另一个矩形中,可以确定该矩形应该被舍弃。
最终只会看到一个框。

得到的found是矩形框的信息,w是每个矩形框的置信度:
found:
[[138 82 92 184]
[288 154 70 139]
[323 157 70 140]]
w:
[[0.67573345]
[0.85107389]
[1.1487023 ]]

for ri,r in enumerate(found)里面得到的ri是每个框的索引,r是矩形框的信息
在这里插入图片描述
这里就是比较每两个矩形框的包含关系,这里我们没有发现三个矩形框之间有包含关系,所以break没有发生过。
在这里插入图片描述
5.创建和训练目标检测器
在实际应用中,可能要处理非常具体的检测,如车牌,书的封面,或其他需要检测的对象。那么如何构件分类器呢?

  • SVM
  • 词袋(Bag-Of-Word,BOW)

计算机视觉中的词袋技术(BOW)
我们已经知道很多方法可以提取图像特征(如SURF,SIFT)我们可以给支持向量机提供一组特征,然后使用复杂算法来分类训练数据,预测该输入属于哪一类。

在计算机视觉中,BOW方法的实现步骤如下:
1)取一个样本数据集
2)对数据集中的每幅图像提取描述符(采用SIFT,SURT等方法)
3)将每一个描述符都添加到BOW训练器中
4)使用K-means聚类将描述符聚类到K簇中

以sift特征为例,假设图像集中包含人脸、自行车、吉他等,我们首先对每幅图像提取sift特征,然后使用如kmeans等聚类方法,进行聚类得到码本(dictionary)
在这里插入图片描述
之后在每一幅图像中统计sift特征点在码本上的频数分布,得到的向量就是该图像的BOW向量。
在这里插入图片描述
6.汽车检测
这是一个没有现成分类器,如
hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())
的现成人特征分类器,得训练一个目标检测器。

训练目标检测器需要训练数据,自己构建数据集非常耗时,包括训练图像的大小要一致。我们选择在网上下载免费的数据集:
Http://ai.stanford.edu/~jkrause/cars/car_dataset.html

链接:https://pan.baidu.com/s/187bW8P6DHz4s7XvVEwDTRA
提取码:7l6r
复制这段内容后打开百度网盘手机App,操作更方便哦

import cv2
import numpy as np
from os.path import join

datapath = 'E:/opencv3/charpter7/CarData/CarData/TrainImages'
#当i改变时,依次得到图像的途径,cls可能是pos-也可能是neg-
def path(cls,i):
    print("%s/%s%d.pgm" %(datapath,cls,i+1))
    return ("%s/%s%d.pgm" %(datapath,cls,i+1))
 
pos,neg = "pos-","neg-"

#提取特征点信息
detect = cv2.xfeatures2d.SIFT_create()
extract = cv2.xfeatures2d.SIFT_create()

#FLANN匹配器
flann_params = dict(algorithm = 1,trees = 5)
flann = cv2.FlannBasedMatcher(flann_params,{})

#创建BOW训练器
bow_kmeans_trainer = cv2.BOWKMeansTrainer(40)
#初始化
extract_bow = cv2.BOWImgDescriptorExtractor(extract,flann)

#返回sift特征
def extract_sift(fn):
    im = cv2.imread(fn,0)#以灰度格式读取
#    b = extract.compute(im,detect.detect(im))[1]
#    print(b)
    #得到sift特征,检测关键点,并计算周围区域的特征向量的过程
    #[1]表示得到的关键点周围的特征向量
    #[0]表示的到的关键点<KeyPoint>
    return extract.compute(im,detect.detect(im))[1]

for i in range(8):#每个类从数据集中读取八张图片正样本,负样本
    #将样本的sift特征向量添加到BOW训练器里面去
    #每张图的sift向量都多个,每个关键点都对应一个特征向量
    pos_feature = extract_sift(path(pos,i))
#    print(np.shape(pos_feature))
    bow_kmeans_trainer.add(pos_feature)
    neg_feature = extract_sift(path(neg,i))
#    print(np.shape(neg_feature))
    bow_kmeans_trainer.add(neg_feature)
    
  
vocabulary = bow_kmeans_trainer.cluster()#创建视觉单词词汇
#vocabulary是一个(40,128)的矩阵
extract_bow.setVocabulary(vocabulary)

#返回基于BOW的描述符特征器计算得到的描述符
def bow_features(fn):
    im = cv2.imread(fn,0)#设置为灰度格式读取
    bow_ft = extract_bow.compute(im,detect.detect(im))
#    print(np.shape(bow_ft))
    #每幅图变的sift特征里面关键点数目都不一样,所以得到的sift矩阵的第一个数都不一样
    #但是换成bow特征之后就变成统一的(1,40)大小的bow特征了
    return bow_ft

traindata,trainlabels = [],[]
for i in range(20):
    traindata.extend(bow_features(path(pos,i)))
    trainlabels.append(1)
    traindata.extend(bow_features(path(neg,i)))
    trainlabels.append(-1)
#这个时候,traindata已经是四十张图片的四十个向量组成的traindata了
    
 
#创建SVM实例
svm = cv2.ml.SVM_create()
#训练数据和标签
svm.train(np.array(traindata),cv2.ml.ROW_SAMPLE,np.array(trainlabels))


#显示predict结果
def predict(fn):
    f = bow_features(fn)#提取bow特征
    p = svm.predict(f)
    print(p)
    print(fn,"\t",p[1][0][0])
    return p

#设置两个样本内图像的路径
car = 'E:/opencv3/charpter7/car1.jpg'
notcar = "E:/opencv3/charpter7/people1.jpg"
car_img = cv2.imread(car)
notcar_img = cv2.imread(notcar)

#将图像传给svm,得到检测结果
car_predict = predict(car)
notcar_predict = predict(notcar)

#设置字体格式
font = cv2.FONT_HERSHEY_SIMPLEX

#在图片上显示信息说明
if (car_predict[1][0][0] == 1.0):
    cv2.putText(car_img, "Car Detected",(10,30),font,1,(0, 255, 0), 2, cv2.LINE_AA)
if (notcar_predict[1][0][0] == -1.0):
    cv2.putText(notcar_img,'Car Not Detected', (10,30),font,1,(0,0,255),2,cv2.LINE_AA)

cv2.imshow('BOW + SVM Success',car_img)
cv2.imshow('BOW + SVM Failure',notcar_img)
cv2.waitKey(0)

FLANN参数1代表FLANN_INDEX_KDTREE算法,树的数目是5,参数以字典形式传入

#创建BOW训练器
bow_kmeans_trainer = cv2.BOWKMeansTrainer(40)
#初始化
extract_bow = cv2.BOWImgDescriptorExtractor(extract,flann)

#返回sift特征
def extract_sift(fn):
    im = cv2.imread(fn,0)#以灰度格式读取
    return extract.compute(im,detect.detect(im))[1]

for i in range(8):#每个类从数据集中读取八张图片正样本,负样本
    #将样本的sift特征添加到BOW训练器里面去
    bow_kmeans_trainer.add(extract_sift(path(pos,i)))
    bow_kmeans_trainer.add(extract_sift(path(neg,i)))
    
vocabulary = bow_kmeans_trainer.cluster()#创建视觉单词词汇
extract_bow.setVocabulary(vocabulary)

这段代码就是BOW方法的实现步骤:
可以看出:
(1)为了构建词袋,先在正负样本中分别取了前八幅图
(2)对其中每幅图提取了SIFT特征
(3)描述符添加到BOW训练器中
bow_kmeans_trainer.add(extract_sift(path(pos,i)))
bow_kmeans_trainer.add(extract_sift(path(neg,i)))
在这里插入图片描述
这里我们可以看到16张图里面,每张图对应的关键点个数,sift特征的具体情况,每个特征点都对应一个128维的向量。

(4)聚类到40个簇里面

cluster()函数
BOW模型的实现以及相关的函数解释

#显示predict结果
def predict(fn):
    f = bow_features(fn)#提取bow特征
    p = svm.predict(f)
    print(p)
    print(fn,"\t",p[1][0][0])
    return p

得出的p:
(0.0, array([[1.]], dtype=float32))
(0.0, array([[-1.]], dtype=float32))
所以需要p[1][0][0]看到底是还是不是car
在这里插入图片描述
在这里插入图片描述
总的来说就是,先取8张图做词袋,再取训练图片40张,用sift得到一堆sift特征,每张得到的关键点不一样,所以矩阵不一样(N,128),N不定,然后用这写sift特征得到Bow特征,矩阵一样的(1,128),用这些取训练,预测,得到预测结果

7.滑动窗口
使用BOW方法,我们已经能检测目标是否存在了,但是我们没有办法确定有多少个目标,也无法确定目标的位置,这里就要使用滑动窗口的技术了!

首先对输入图像进行不同窗口大小的滑窗进行从左往右、从上到下的滑动。每次滑动时候对当前窗口执行分类器(分类器是事先训练好的)。如果当前窗口得到较高的分类概率,则认为检测到了物体。对每个不同窗口大小的滑窗都进行检测后,会得到不同窗口检测到的物体标记,这些窗口大小会存在重复较高的部分,最后采用非极大值抑制(Non-Maximum Suppression, NMS)的方法进行筛选。最终,经过NMS筛选后获得检测到的物体。
参考文献4
滑窗法的物体检测流程图:
在这里插入图片描述
这是第一个文件,命名为 ‘slipwindow_car_detection1.py’ ,这里主要目标是取SAMPLE张图片作为词袋,然后提取SAMPLE张图片的bow特征,训练SVM分类器

import cv2
import numpy as np

def resize(img,scaleFactor):#通过指定参数调整图像
    return cv2.resize(img,
                      (int(img.shape[1] * (1/scaleFactor)),int(img.shape[0] * (1/scaleFactor))),
                      interpolation = cv2.INTER_AREA)
    
def pyramid(image,scale = 1.5,minSize = (200,80)):#建立图像金字塔
    yield image
    
    while True:
        image = resize(image,scale)#不断调用调整图像的函数
        if image.shape[0] < minSize[1] or image.shape[1] < minSize[0]:#知道图像尺寸小于(200,80)就停止迭代
            break
        yield image #该函数是一个迭代器return关键字由yield代替
        
def sliding_window(image,stepSize,windowSize): #滑动窗口函数
    for y in range(0,image.shape[0],stepSize):#shape[0]指行数,每隔stepSize行滑动,是图像坐标系里的y
        for x in range(0,image.shape[1],stepSize):#shape[1]指列数,每隔stepSize列滑动,是图像坐标系里的x
            yield(x,y,image[y:y + windowSize[1],x:x + windowSize[0]])#windowSize = [x(列),y(行)]








            
def non_max_suppression_fast(boxes,overlapThresh):#非最大抑制功能
    #boxes框;overlapThresh重合度阈值
    
    #如果一次也没有检测到,返回一个空列表
    if len(boxes) == 0:
        return []
    
    #数据类型的转换,如果检测到box为int,将其转化为float型
    if boxes.dtype.kind == 'i':
        boxes = boxes.astype('float')
        
    #
    pick = []
    x1 = boxes[:,0]
    y1 = boxes[:,1]
    x2 = boxes[:,2]
    y2 = boxes[:,3]
    scores = boxes[:,4]
    
    #计算面积
    area = (x2 - x1 + 1) * (y1 - y2 + 1)
    idxs = np.argsort(scores)[::-1]
    
    while len(idxs) > 0:
        last = len(idxs) - 1
        i = idxs[last]
        pick.append(i)
        
        xx1 = np.maximum(x1[i],x1[idxs[:last]])
        yy1 = np.maximum(y1[i],y1[idxs[:last]])
        xx2 = np.minimum(x2[i],x2[idxs[:last]])
        yy2 = np.minimum(y2[i],y2[idxs[:last]])
        
        w = np.maximum(0,xx2 - xx1 + 1)
        h = np.maximum(0,yy2 - yy1 + 1)
        
        overlap = (w * h)/area[idxs[:last]]
        
        idxs = np.delete(idxs,np.concatenate(([last],np.where(overlap > overlapThresh)[0])))
        
        return boxes[pick].astype("int")








datapath = 'E:/opencv3/charpter7/CarData/CarData/TrainImages'
SAMPLES = 120 #样本个事

#构造一个可以自动产生路径的函数
def path(cls,i):
    print("%s/%s%d.pgm" %(datapath,cls,i+1))
    return ("%s/%s%d.pgm" %(datapath,cls,i+1))

#返回FLANN匹配器
def flann_matcher():
    flann_params = dict(algorithm = 1,trees = 5)
    flann = cv2.FlannBasedMatcher(flann_params,{})
    return flann
            
#返回BOW训练器
def get_bow_extractor(extract,flann):   
    return cv2.BOWImgDescriptorExtractor(extract,flann) 

#返回SIFT特征检测器
def get_extract_detect():
    detect = cv2.xfeatures2d.SIFT_create()
    extract = cv2.xfeatures2d.SIFT_create()
    return detect,extract

#返回图像特征
def extract_sift(fn,extractor,detector):
    im = cv2.imread(fn,0)
    return extractor.compute(im,detector.detect(im))[1]

#由SIFT图像特征得到BOW特征
def bow_features(img,extractor_bow,detector):
    return extractor_bow.compute(img,detector.detect(img))






#车辆检测函数
def car_detector():
    pos,neg = "pos-","neg-"
    
    ###创建特征检测和提取所需要的对象
    #需要SIFT检测器对象,flann匹配器对象,BOW特征提取对象
    detect,extract = get_extract_detect()
    flann = flann_matcher()
    print("building BOWKMeansTrainer...")
    bow_kmeans_trainer = cv2.BOWKMeansTrainer(1000)#BOW特征是一个(1,1000)向量
    extract_bow = cv2.BOWImgDescriptorExtractor(extract,flann)
    ###
    
    
    #向训练器增加图像特征
    print("adding features to trainer")
    for i in range(SAMPLES):#取SAMPLES个正样本,SAMPLES个负样本,来做词袋
        print(i)
        pos_feature = extract_sift(path(pos,i),extract,detect)
#        print(np.shape(pos_feature))
        bow_kmeans_trainer.add(pos_feature)
        neg_feature = extract_sift(path(neg,i),extract,detect)
#        print(np.shape(neg_feature))
        bow_kmeans_trainer.add(neg_feature)
        
    vocabulary = bow_kmeans_trainer.cluster()#创建视觉单词词汇
    #vocabulary是一个(2*SAMPLES,128)的矩阵
    extract_bow.setVocabulary(vocabulary)
    
    traindata,trainlabels = [],[]
    for i in range(SAMPLES):#填充训练数据集2*SAMPLE张图
        #traindata里面添加bow特征
        traindata.extend(bow_features(cv2.imread(path(pos,i),0),extract_bow,detect))
        trainlabels.append(1)
        traindata.extend(bow_features(cv2.imread(path(neg,i),0),extract_bow,detect))
        trainlabels.append(-1)
        
    
    #创建SVM实例
    svm = cv2.ml.SVM_create()
    #SVM的参数
    svm.setType(cv2.ml.SVM_C_SVC)#SVM类型
    svm.setGamma(0.5) #参数Gamma
    svm.setC(30) #参数C
    svm.setKernel(cv2.ml.SVM_RBF) #使用核的类型
    
    #训练数据和标签
    svm.train(np.array(traindata),cv2.ml.ROW_SAMPLE,np.array(trainlabels))
    svm.save("svm_model.dat")#将训练好的svm分类器存储起来,不用每次运行程序的时候都要训练了
#    print(extract_bow) #这个词袋模型不知道怎么存?????
    return svm,extract_bow #返回训练好的svm分类器和词袋信息
    #词袋信息后面还需要用来得到后续预测图片是,输入进来的图片对应词袋的向量


svm,extractor = car_detector()

注意:
这里我们把svm训练好的模型保存下来了,但是词袋模型extract_bow还没有保存下来,‘cv2.BOWImgDescriptorExtractor’ object词袋模型尝试过用pickle保存,但是保存不了,不知道这个怎么保存???????

第二个文件取名叫‘slipwindow_car_detection2.py’ ,这个文件主要负责用已经训练好的svm模型和词袋模型,用来检测测试图片,由于我们只保存了svm模型,词袋模型没有保存,所以每次运行‘slipwindow_car_detection2.py’的时候先运行‘slipwindow_car_detection1.py’用来提取词袋模型。。。

import numpy as np
import cv2
from slipwindow_car_detection1 import car_detector,bow_features,pyramid,sliding_window,non_max_suppression_fast


###汽车检测器
def in_range(number,test,thresh = 0.2):
    return abs(number - test) < thresh

test_image = 'E:/opencv3/charpter7/car1.jpg'

#提取模型和词袋
svm = cv2.ml.SVM_create()
svm = svm.load('svm_model.dat')

detect = cv2.xfeatures2d.SIFT_create()

w,h = 200,100
img = cv2.imread(test_image)

rectangles = []
counter = 1
scaleFactor = 1.25
scale = 1
font = cv2.FONT_HERSHEY_PLAIN

for resized in pyramid(img, scaleFactor):#对于迭代器迭代出的大小不一的金字塔图片
    scale = float(img.shape[1])/float(resized.shape[1])
    for (x,y,roi) in sliding_window(resized,20,(w,h)):#roi为兴趣区域
        if roi.shape[1] != w or roi.shape[0] != h: #只要是没有达到最小限制w,h,就继续执行try后面的函数
            continue
        
        try:#循环中的滑动窗口
            bf = bow_features(roi,extractor,detect)#对每个窗口图片提取bow特征
            _,result = svm.predict(bf)#根据这个特征预测
            print(_) #0
            print(result)#[[-1.]]或者[[1.]]
            a,res = svm.predict(bf,flags = cv2.ml.STAT_MODEL_RAW_OUTPUT)
            #predict可选一个flags参数,可以返回预测的评分
            print(a) #0
            print(res) #[[分数]]
            print("Class: %d , Score: %f" %(result[0][0],res[0][0]))
            score = res[0][0]#评分越低,表示置信度越高,则分到这一类的可能性越大
            if result[0][0] == 1:
                if score < -1.0:#设置一个阈值,所有小于-1.0的被视为好的结果
                    rx1,ry1,rx2,ry2 = int(x * scale),int(y * scale),int((w + x) * scale),int((y + h) * scale)
                    rectangles.append([rx1,ry1,rx2,ry2,abs(score)])
                    
        except:
            pass
        
        counter += 1


#还要执行非最大抑制
windows = np.array(rectangles)#所有数组转化为numpy数组
boxes =  non_max_suppression_fast(windows,0.25)
#boxes = windows

for (x1,y1,x2,y2,score) in boxes:
    print(x1,y1,x2,y2)
    cv2.rectangle(img,(int(x1),int(y1)),(int(x2),int(y2)),(0,255,0),3)
    cv2.putText(img,"%f" %score,(int(x1),int(y1)),font,3,(0,255,0))
    
    
cv2.imshow("img",img)
cv2.waitKey(0)

resize()函数,scaleFactor是先列数,后行数的:
x=col
y=row
img[0:rows, 0:cols] = img[y,x]
resize(,(cols,rows),)

if boxes.dtype.kind == 'i':
        boxes = boxes.astype('float')

在这里插入图片描述
在这里插入图片描述

    #创建SVM实例
    svm = cv2.ml.SVM_create()
    #SVM的参数
    svm.setType(cv2.ml.SVM_C_SVC)#SVM类型
    svm.setGamma(0.5) #参数Gamma
    svm.secC(30) #参数C
    svm.setKernel(cv2.ml.SVM_RBF) #使用核的类型

SVM参数

C是 惩罚系数,即对误差的宽容度。c越高,说明越不能容忍出现误差,容易过拟合。C越小,容易欠拟合。C过大或过小,泛化能力变差。

kernel是 确定分类器的性质,若是SVM_LINEAR说明分类器为线性超平面,在实际应用中非常适合二分类,而SVM_RBF使用高斯函数来对数据进行分类,意味着数据直接分到这些函数定义的核中。当分类器分类超过两个时,必须使用RBF。

Gamma是 选择RBF函数作为kernel后,该函数自带的一个参数。隐含地决定了数据映射到新的特征空间后的分布,gamma越大,支持向量越少,gamma值越小,支持向量越多。支持向量的个数影响训练与预测的速度。

这个程序有一个不智能的地方,就是你最终结果的标定并不是智能调节大小的,由w,h控制,而这个是人给的,所以最后的框未必能框住车辆。还有score都是要自己调节的,什么是好的结果,都是自己控制的。
在这里插入图片描述

传统目标检测参考

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

举报
请填写举报理由
0/200