【OpenCV-Python】22 目标检测(汽车检测)

目标检测与识别

目标检测是一个程序,它用来确定图像的某个区域是否含有要要识别的对象,对象识别是程序识别对象的能力。识别通常只处理已检测到对象的区域,例如人们总是会在有人脸图像的区域去识别人脸。
在计算机视觉中有很多目标检测和识别的技术

  • 梯度直方图(Histogram of Oriented Gradient)
  • 图像金字塔(image pyramid)
  • 滑动窗口(sliding window)

HOG描述符

HOG不是基于颜色而是基于梯度来计算直方图的。将直方图外推(extrapolation)成描述符的过程:首先计算每个单元的局部直方图,这些单元会合成较大的区域,称为块(block);按块来构成特征向量为了便于归一化,同时考虑光照和阴影(shadowing)的变化(一个单元的区域太小,不能检测这样的变化)。这样减少了图像与块之间光照和阴影 的差异,从而提高了检测精度。

尺度问题

如比较两幅图像(大小不同),找不到一组相同的梯度,检测失败

位置问题

检测的目标可能位于图像的任何地方,需要扫描得到感兴趣的区域,在这些区域尝试检测目标。要解决这个问题,先引入两个概念:

图像金字塔

图像金字塔(pyramid)是图像的多尺度表示,有助于解决不同尺度下的目标检测问题。

在这里插入图片描述
可通过以下过程来构建图像金字塔:

  1. 获取图像
  2. 使用任意尺度的参数来调整(缩小)图像的大小
  3. 平滑图像(使用高斯模糊)
  4. 如果图像比最小尺寸还大,重复步骤1

detectMultiScale() 函数的scaleFactor参数表示一个比率,即在每层金字塔中获得的图像与上一层的比率。参数越小,金字塔层数越多,计算更慢,计算量变大,精度某种程度上会更高。

滑动窗口

滑动窗口是用于计算机视觉的一种技术,包括图像中要移动部分(滑动窗口)的检查以及使用图像金字塔对各部分进行检测(多尺度检测对象)。

滑动窗口通过扫描较大图像的较小区域来解决定位问题,进而在同一图像的不同尺度下重复扫描。使用此方法需要将每幅图像分解,丢弃不太可能包含对象的部分,对剩下部分分类,引发区域重叠问题(overlapping region)

区域重叠:在对图像执行人脸检测时使用滑动窗口。每次窗口都会丢掉几个像素,这意味着一个滑动窗口可以对同一人脸的四个不同位置进行正匹配,(只需一个匹配结果,对良好评分区域不感兴趣,对最高评分区域感兴趣),这样会引发另一个问题:非最大抑制。

非最大(或非极大)抑制

非最大(或非极大)抑制是指定一组重叠区域,可以用最大评分来抑制所有未分类区域。这是一种与图像同一区域相关的所有结果进行抑制的技术,这些区域没有最大评分(同样排放(colocate)的窗口往往具有最高的评分,并且重叠区域会变得明显,这里只关心结果最好的窗口,并丢弃评分较低的重叠窗口)。

实现非最大抑制算法的过程:

  1. 一旦建立了图像金字塔,为了检测目标,可采用滑动窗口来搜索图像;
  2. 收集当前所有含有目标的窗口(超出一定任意阈值),并得到有最高响应的窗口W;
  3. 消除所有与W有明显重叠的窗口;
  4. 移动到下一个有最高相应的窗口,在当前尺度下重复上述过程;

在这个过程完成后,移动图像金字塔的下一个尺度,并重复前面的过程。如何确定窗口的评分呢?需要一个分类系统来确定某一特征是否存在,并且对这个分类有一个置信度评分,采用支持向量机(SVM)来分类。

汽车检测

下面的例子使用UIUC数据集,或CSDN下载
在这里插入图片描述

文件的 tree / 树状图:

.
├── detect_hog_svm.py       			
└── images
     ├── CarData ── TrainImages			       
     └── pic      		
    	  ├── car.jpg
    	  └── bb.jpg

代码

# -*- coding: utf-8 -*-
"""
Created on Fri Jan  8 19:23:22 2021

@author: gkm0120
"""
# detect_hog_svm.py
import cv2
import numpy as np
from os.path import join

datapath = "D:/Images/CarData/TrainImages" # 声明训练的基础路径
def path(cls,i):
  return "%s/%s%d.pgm"  % (datapath,cls,i+1)

pos, neg = "pos-", "neg-" #数据集图像以pos-x.pgm和neg-x.pgm命名,其中x为数字

detect = cv2.xfeatures2d.SIFT_create() #检测关键点
extract = cv2.xfeatures2d.SIFT_create() # 提取特征

flann_params = dict(algorithm = 1, trees = 5) #数字1为算法床底的参数,表示使用FLANN_INDEX_KDTREE算法
matcher = cv2.FlannBasedMatcher(flann_params, {})

bow_kmeans_trainer = cv2.BOWKMeansTrainer(40) #创建BOW训练器,指定簇数为40
extract_bow = cv2.BOWImgDescriptorExtractor(extract, matcher) # 初始化BOW提取器,视觉词汇作为BOW类的输入,在测试图像中会检测这些视觉词汇

# 提取SIFT特征,获取图像路径,并以灰度格式读取图像,然后返回描述符
def extract_sift(fn):
  im = cv2.imread(fn,0)
  return extract.compute(im, detect.detect(im))[1]
  # 每个类都从数据集中读取8张图像(8个正样本和8个负样本)
for i in range(8):
  bow_kmeans_trainer.add(extract_sift(path(pos,i)))
  bow_kmeans_trainer.add(extract_sift(path(neg,i)))
 
voc = bow_kmeans_trainer.cluster() #创建视觉单词词汇需调用的cluster函数,执行k-means分类并返回词汇
extract_bow.setVocabulary(voc) #指定返回的词汇,从测试图像中提取描述符

# 声明函数,参数是一幅图像的路径,并且返回基于BOW的描述符提取器计算得到的描述符
def bow_features(fn):
  im = cv2.imread(fn,0)
  return extract_bow.compute(im, detect.detect(im))

# 创建两个数组,分别对应数据和标签,并用BOWImgDescriptorExtractor产生的描述符填充它们
traindata, trainlabels = [],[]
for i in range(20): 
  traindata.extend(bow_features(path(pos, i))); trainlabels.append(1) # 1表示正匹配
  traindata.extend(bow_features(path(neg, i))); trainlabels.append(-1) #-1表示负匹配

svm = cv2.ml.SVM_create() #创建SVM实例
svm.train(np.array(traindata), cv2.ml.ROW_SAMPLE, np.array(trainlabels)) #通过将训练数据和标签放到NumPy数组中进行训练

# 定义一个函数显示predict方法的结果,并返回这些结果
def predict(fn):
  f = bow_features(fn);  
  p = svm.predict(f)
  print (fn, "\t", p[1][0][0])
  return p
  
  # 定义两个样本图像的路径,并将路径中图像文件读取放到NumPy数组中
car, notcar = "D:/Images/pic/car.jpg","D:/Images/pic/bb.jpg"
car_img = cv2.imread(car)
notcar_img = cv2.imread(notcar)
car_predict = predict(car) #传递给训练好的SVM,并预测结果
not_car_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) #含有汽车的图像能检测到汽车,预测值为1.0

if (not_car_predict[1][0][0] == -1.0):
  cv2.putText(notcar_img,'Car Not Detected',(10,30), font, 1,(0,0, 255),2,cv2.LINE_AA) #不含汽车的图像不检测到汽车,预测值为-1.0

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

输入

car.jpg
bb.jpg

图例

BOW + SVM Success
BOW + SVM Failure
  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值