#目标检测核识别
#检测人
#使用HOGDescriptor函数检测人
import cv2
import numpy as np
#判断o矩形是否在i矩形里面
def is_inside(o,i):
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(image,(x,y),(x+w,y+h),(0,255,255),2)
img = cv2.imread("../images/people.jpg")
hog = cv2.HOGDescriptor()
#指定HOGDescriptor作为检测人的默认检测器
hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopelDetector())
found,w = hog.detectMultiScale(img)
found_filtered = []
#两两比较判断是否有矩形被包含在其他矩阵里面,若在,则舍去
for ri,r in enumerate(found):
for qi,q in enumerate(found):
if ri != qi and is_inside(r,q):
break
else:
found_filtered.append(r)
for person in found_filtered:
draw_person(img,person)
#=================================================================
#汽车检测,仅仅判断图像里面是否有汽车
import cv2
import numpy as np
from os.path import join
datapath = "/home/d3athmast3r/dev/python/CarData/TrainImages/"
def path(cls,i):
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)
#基于BOW特征提取器
extract_bow = cv2.BOWImageDescriptorExtractor(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):
bow_kmeans_trainer.add(extract_sift(path(pos,i)))
bow_kmeans_trainer.add(extract_sift(path(neg,i)))
#使用BOW训练器将特征聚类,获取特征词汇
voc = bow_kmeans_trainer.cluster()
#将特征词汇赋值给BOW特征提取器
extract_bow.setVocabulary(voc)
#使用BOW特征提取器获取图像的特征
def bow_features(fn):
im = cv2.imread(fn,0)
return extract_bow.compute(im,detect.detect(im))
#使用BOW特征提取器,提取训练图像的特征,并且将其与标签匹配
#正类为1,负类为-1
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)
#创建svm分类器
svm = cv2.ml.SVM_create()
#训练分类器
svm.train(np.array(traindata),cv2.ml.ROW_SAMPLE,np.array(trainlabels))
#定义预测函数
def predict(fn):
f = bow_features(fn)
p = svm.predict(f)
print(fn,"\t",p[1][0][0])
return p
car,notcar = "...","..."
car_img = cv2.imread(car)
notcar_img = cv2.imread(notcar)
car_predict = predict(car)
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)
if (not_car_predict[1][0][0] == -1):
cv2.putText(notcar_img,'Car Not Detect',(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()
cv2.destroyALLWindows()
#======================================================================
#使用滑动窗口、图像金字塔以及非最大值抑制来检测并定位汽车
import cv2
import numpy as np
from os.path import join
#图像金字塔
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,misSize=(200,80)):
yield image
while True:
image = resize(image,scale)
if image.shape[0] < minSize[1] or image.shape[1] < minSize[0]:
break
yield image
#滑动窗口函数
def sliding_window(image,stepSize,windowSize):
for y in range(0,image.shape[0],stepSize):
for x in range(0,image.shape[1],stepSize):
yield (x,y,image[y:y+windowSize[1],x:x+windowSize[0]])
#非最大抑制函数
def non_max_suppression_fast(boxes,overlapThresh):
if len(boxes) == 0:
return []
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)*(y2-y1+1)
#根据得分排序,返回排序后的索引
idxs = np.argsort(scores)[::-1]
#舍去那些重叠了一定区域边框
while(len(idxs)>0):
#获取得分最大的边框的索引
last = len(idxs) -1
i = idxs[last]
pick.append(i)
#将其他所有的边框坐标与最大的边框的坐标进行比较
#获得他们之间的重叠区域
xx1 = np.maximun(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 = "path/to/CarData/TrainImages/"
SAMPLES = 400
def path(cls,i):
return "%s/%s%d.pgm" %(datapath,cls,i+1)
#FLANN匹配器
def get_flann_matcher():
flann_params = dict(algorithm=1,trees=5)
return cv2.FlannBasedMatcher(flann_params,{})
#BOW特征提取器
def get_bow_extractor(extrat,flann):
return cv2.BOWImgDescriptorExtractor(extract,flann)
#SIFT特征检测器/提取器
def get_extract_detect():
return cv2.xfeatures2d.SIFT_create(),cv2.xfeatures2d.SIFT_create()
#使用SIFT提取图像特征
def extract_sift(fn,extractor,detector):
im = cv2.imread(fn,0)
return extractor.compute(im,detector.detect(im))[1]
#基于BOW特征提取器
def bow_features(img,extractor_bow,detector):
return extractor_bow.compute(img,detector.detect(img))
#汽车检测
def car_detector():
pos,neg = "pos-","neg-"
#SIFT特征检测器/提取器
detect,extract = get_extract_detect()
#FLANN匹配器
matcher = get_flann_matcher()
#BOW训练器
bow_kmeans_trainer = cv2.BOWKMeansTrainer(1000)
#BOW特征提取器
extract_bow = cv2.BOWImgDescriptorExtractor(extract,flann)
#将从训练图像提取的特征,添加到训练器中,以便获得特征词汇
for i in range(SAMPLES):
bow_kmeans_trainer.add(extract_sift(path(pos,i),extract,detect))
bow_kmeans_trainer.add(extract_sift(path(neg,i),extract,detect))
#使用训练器进行特征聚类,得到特征词汇
voc = bow_kmeans_trainer.cluster()
extract_bow.setVocabulary(voc)
#将训练数据,用BOW特征提取器提取特征,并将其与标签配对
traindata,trainlabels = [] ,[]
for i in range(SAMPLES):
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.setType(cv2.ml.SVM_C_SVC)
svm.setGamma(0.5)
svm.setC(30)
svm.setKernel(cv2.ml.SVM_RBF)
#训练分类器
svm.train(np.array(traindata),cv2.ml.ROW_SAMPLE,np.array(trainlabels))
#返回extract_bow,以便对测试图像直接提取特征
return svm,extract_bow
#测试汽车检测器
def in_range(number,test,thresh=0.2):
return abs(number - test) < thresh
test_image = "/path/to/cars.jpg"
svm,extractor = car_detector()
#特征检测器
detect = cv2.xfeatures2d.SIFT_create()
w,h = 100,40
img = cv2.imread(test_image)
rectangle = []
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)):
if roi.shape[1] != w or roi.shape[0] != h:
continue
try:
#获取感兴趣区域的特征
bf = bow_features(roi,extractor,detect)
#预测
_,result = svm.predict(bf)
a,res = svm.predict(bf,flags=cv2.ml.STAT_MODEL_RAW_OUTPUT)
print("Class:%d,Score:%f"%(result[0][0],res[0][0]))
score = res[0][0]
if result[0][0] == 1 :
#置信度是一个好结果
if score < -1.0:
#根据scale重新获得边框在原始图上的坐标,以便画出边框
rx,ry,rx2,ry2 = int(x*scale), int(y*scale),int((x+w)*scale),int((y+h)*scale)
rectangles.append([rx,ry,rx2,ry2,abs(score)])
except:
pass
counter +=1
#非最大抑制
windows = np.array(rectangle)
boxes = non_max_suppression_fast(windows,0.25)
#在图像中画出汽车的边框
for (x,y,x2,y2,score) in boxes:
print(x,y,x2,y2,score)
cv2.rectangle(img,(int(x),int(y)),(int(x2),int(y2)),(0,255,0),1)
cv2.putText(img,"%f"%score,(int(x),int(y)),font,1,(0,255,0))
cv2.imshow("img",img)
cv2.waiKey(0)