-
2021-08-22 13:49:29
利用颜色范围过滤
- InRange过滤
- 形态学提取
- 轮廓查找
- 外接矩形查找
- 位置确定与标定
#include<opencv2/opencv.hpp> #include<iostream> using namespace cv; using namespace std; Rect roi; void processFrame(Mat &binary,Rect &rect); int main(){ //读取视频 VideoCapture capture; capture.open("D:/wv_demo.mp4"); if (!capture.isOpened()) { printf("could not find video"); return -1; } Mat frame,mask; Mat kernel1 = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));//研摸 Mat kernel2 = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1)); namedWindow("input_video",WINDOW_AUTOSIZE); namedWindow("InRange_video", WINDOW_AUTOSIZE); while (capture.read(frame)) { inRange(frame,Scalar(0,127,0),Scalar(120,255,120),mask);//过滤 morphologyEx(mask, mask, MORPH_OPEN, kernel1, Point(-1, -1), 3);//开操作,去除小的污染点 dilate(mask,mask,kernel2,Point(-1,-1),3);//膨胀,4表示膨胀的次数 imshow("InRange_video", mask); processFrame(mask, roi); //轮廓 rectangle(frame, roi, Scalar(0, 255), 3, 8, 0); imshow("input_video", frame); char c = waitKey(100); if (c == 27) { break; } } } void processFrame(Mat& binary, Rect& rect) { vector<vector<Point>>contours; vector<Vec4i> hireachy; findContours(binary, contours, hireachy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0)); if (contours.size() > 0) { double maxArea = 0.0; for (size_t t = 0; t < contours.size(); t++) { double area = contourArea(contours[static_cast<int>(t)]); if (area > maxArea) { maxArea = area; rect = boundingRect(contours[static_cast<int>(t)]); } } } else { rect.x = rect.y = rect.width = rect.height = 0; } }
更多相关内容 -
基于opencv的目标检测与跟踪
2015-11-15 13:46:07本代码基于opencv的目标检与跟踪,基于opencv2.4.9与vs2010开发的,可以跟踪目标 -
基于Opencv的红外运动目标识别与跟踪
2015-06-05 10:36:59基于Opencv的红外运动目标识别与跟踪,内附红外演示与源代码。 -
目标检测识别与跟踪项目源码.rar
2021-12-09 10:37:43文件主要是我们做“红外和可见光图像的目标识别与跟踪的项目”的源代码,用的是Visual Studio 2019平台,在平台上安装了OpenCV插件,可以用作硕士研究生的毕业课题,也可对公司的目标识别检测、跟踪等软件算法有所... -
opencv目标检测与识别(传统的目标检测方法)
2019-06-18 13:19:17目标检测用来确定图像的某个区域是否含有要识别的对象,计算机视觉中有很多目标检测和是别的技术,这里介绍: 梯度直方图(Histogram of Oriented Gradient,HOG),图像金字塔(image pyramid),滑动窗口...目标检测用来确定图像的某个区域是否含有要识别的对象,计算机视觉中有很多目标检测和是别的技术,这里介绍:
梯度直方图(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) #使用核的类型
C是 惩罚系数,即对误差的宽容度。c越高,说明越不能容忍出现误差,容易过拟合。C越小,容易欠拟合。C过大或过小,泛化能力变差。
kernel是 确定分类器的性质,若是SVM_LINEAR说明分类器为线性超平面,在实际应用中非常适合二分类,而SVM_RBF使用高斯函数来对数据进行分类,意味着数据直接分到这些函数定义的核中。当分类器分类超过两个时,必须使用RBF。
Gamma是 选择RBF函数作为kernel后,该函数自带的一个参数。隐含地决定了数据映射到新的特征空间后的分布,gamma越大,支持向量越少,gamma值越小,支持向量越多。支持向量的个数影响训练与预测的速度。
这个程序有一个不智能的地方,就是你最终结果的标定并不是智能调节大小的,由w,h控制,而这个是人给的,所以最后的框未必能框住车辆。还有score都是要自己调节的,什么是好的结果,都是自己控制的。
-
OpenCV3模板匹配实现目标识别与跟踪
2018-03-12 10:14:04OpenCV3模板匹配实现目标识别与跟踪 @[OpenCV|C++] OpenCV3模板匹配实现目标识别与跟踪 知识补充 回调函数 minMaxLoc()函数找最大最小值 模板匹配函数matchTemplate() 代码思路 可能有帮助的解释 总体代码及...OpenCV3模板匹配实现目标识别与跟踪
@[OpenCV|C++]
知识补充
回调函数
在图像处理时,如果我们需要实现实时的改变值,并重新开始程序,就需要我们自己实现回调函数,其中,对于鼠标事件的回调,需要我们重写鼠标回调函数
void onMouse(int event, int x, int y, int flags, void* ustc); //鼠标回调函数
函数中的主要参数:
- event对应于鼠标事件
- x,y鼠标的位置参数
- flags标志位
- ustc(不常用)其中,int型event事件分别有:
- EVENT_MOUSEMOVE 滑动
- EVENT_LBUTTONDOWN 左击
- EVENT_RBUTTONDOWN 右击
- EVENT_MBUTTONDOWN 中键点击
- EVENT_LBUTTONUP 左键放开
- EVENT_RBUTTONUP 右键放开
- EVENT_MBUTTONUP 中键放开
- EVENT_LBUTTONDBLCLK 左键双击
- EVENT_RBUTTONDBLCLK 右键双击
- EVENT_MBUTTONDBLCLK 中键双击重写回调函数后,我们只要使用
setMouseCallback
函数打开调用即可使用minMaxLoc()函数找最大最小值
函数原型:
void minMaxLoc(InputArray src,double * minVal=0,double* maxVal=0,Point* minLoc=0,Point* maxLoc=0,InputArray mask=noArray())
参数说明:
- InputArray型的src,是单通道的输入阵列
- double * 型的minVal,返回最小值的指针,无返回则是NULL
- double * 型的maxVal,返回最大值的指针,无返回则是NULL
- Point * 型的minLoc,返回最小值的指针(二维),无返回则是NULL
- Point * 型的miaxLoc,返回最大值的指针(二维),无返回则是NULL
- InputArray型的mask,选择可选掩膜模板匹配函数matchTemplate()
模板匹配是从一张图片里找到与另一模板图像最匹配的部分
函数原型:void matchTemplate(InputArray image,InputArray templ,OutputArray result,int method)
参数说明:
- 第一个参数,是待搜索的图片,为8位或32位浮点图
- 第二个参数,是带匹配的图片,格式应与源图相同
- 第三个参数,输出结果图片,单通道,32位浮点型
- 第四个参数,匹配方式,共六种六种匹配方式及参数:
- 平方差匹配method=TM_SQDIFF
- 归一化平方差匹配method=TM_SQDIFF_NORMED
- 相关匹配method=TM_CCORR
- 归一化相关匹配method=TM_CCORR_NORMED
- 系数匹配method=TM_CCOEFF
- 化相关系数匹配method=TM_CCOEFF_NORMED
至于理论基础,我还是直接截图贴出来吧
注意:
对于1和2两种匹配方式,最小值为最好匹配,其余的最大值为最好匹配代码思路
首先读取视频,并且提取帧图像,使用回调函数选中模板图像, 开始在下一帧中匹配,每次匹配完,都截取相应位置的图,作为下一次匹配的模板图,并且用框框框选,输出到输出文件中
可能有帮助的解释
对于matchTemplate函数中result大小的解释:
比如源图尺寸为W*H,待匹配图为w*h,那么输出结果大小就是(W-w+1)(H-h+1),原因是匹配是拿着小图在大图上移动来计算值的,所以移动的范围就是(W-w+1)(H-h+1),计算的结果就存储在这个结果矩阵中总体代码及注释
#include <core/core.hpp> #include <highgui/highgui.hpp> #include <imgproc/imgproc.hpp> #include<iostream> using namespace cv; using namespace std; Mat image; //当前帧图像 Mat imageCopy; //用于拷贝的当前帧图像 Mat rectImage; //子图像 bool leftButtonDownFlag = false; //左键单击后视频暂停标志位 Point beginPoint; //矩形框起点 Point endPoint; //矩形框终点 int resultRows; //模板匹配result的行 int resultcols; //模板匹配result的列 Mat ImageResult; //模板匹配result double minValue; //模板匹配result最小值 double maxValude; //模板匹配result最大值 Point minPoint; //模板匹配result最小值位置 Point maxPoint; //模板匹配result最大值位置 int frameCount = 0; //帧数统计 void onMouse(int event, int x, int y, int flags, void* ustc); //鼠标回调函数 void Tips() { cout << "请选择要使用的匹配规则:" << endl; cout << " 1.平方差匹配" << endl; cout << " 2.归一化平方差匹配" << endl; cout << " 3.相关匹配" << endl; cout << " 4.归一化相关匹配" << endl; cout << " 5.系数匹配" << endl; cout << " 6.化相关系数匹配" << endl; cout << " 0.退出" << endl; } int main(int argc, char*argv[]) { VideoCapture capture("C:\\Users\\14527\\Desktop\\Video\\cut.AVI"); int capture_fps = capture.get(CV_CAP_PROP_FPS); //获取视频帧率 int capture_count = capture.get(CV_CAP_PROP_FRAME_COUNT); int capture_width = capture.get(CV_CAP_PROP_FRAME_WIDTH); int capture_height = capture.get(CV_CAP_PROP_FRAME_HEIGHT); cout << "视频帧率:" << capture_fps<<endl; cout << "视频帧数:" << capture_count << endl; cout << "视频宽度:" << capture_width << endl; cout << "视频高度:" << capture_height << endl; int pauseTime = 1000 / capture_fps; //两幅画面中间间隔 VideoWriter writer("C:\\Users\\14527\\Desktop\\Video\\out.avi", CV_FOURCC('X', 'V', 'I', 'D'), capture_fps, Size(capture_width, capture_height)); Tips(); int choice = 0; cin >> choice; namedWindow("Video"); setMouseCallback("Video", onMouse); //设置鼠标回调函数 while (choice) { if (!leftButtonDownFlag) //鼠标左键按下绘制矩形时,视频暂停播放 { capture >> image; frameCount++; //帧数 } if (!image.data || waitKey(pauseTime + 30) == 27) //图像为空或Esc键按下退出播放 { break; } if (rectImage.data) { ImageResult = Mat::zeros(resultRows, resultcols, CV_32FC1);//建立结果矩阵,注意是单通道的32位浮点型 switch (choice) { //根据一开始的选择使用对应的匹配模式 case 1: matchTemplate(image, rectImage, ImageResult, TM_SQDIFF); break; case 2: matchTemplate(image, rectImage, ImageResult, TM_SQDIFF_NORMED); break; case 3: matchTemplate(image, rectImage, ImageResult, TM_CCORR); break; case 4: matchTemplate(image, rectImage, ImageResult, TM_CCORR_NORMED); break; case 5: matchTemplate(image, rectImage, ImageResult, TM_CCOEFF); break; case 6: matchTemplate(image, rectImage, ImageResult, TM_CCOEFF_NORMED); break; } minMaxLoc(ImageResult, &minValue, &maxValude, &minPoint, &maxPoint, Mat()); //最小值最大值获取 Point point; switch (choice) {//为了统一处理,所以先把Point取出来 case 1: point = minPoint; break; case 2: point = minPoint; break; case 3: point = maxPoint; break; case 4: point = maxPoint; break; case 5: point = maxPoint; break; case 6: point = maxPoint; break; } rectangle(image, point, Point(point.x + rectImage.cols, point.y + rectImage.rows), Scalar(0, 0, 255), 2); //绘制 //更新当前模板匹配的模板 Mat resultImage = image(Rect(point, Point(point.x + rectImage.cols, point.y + rectImage.rows))); rectImage = resultImage.clone(); //当前帧数输出到视频流 writer << image; } imshow("Video", image); } return 0; } //鼠标回调函数 void onMouse(int event, int x, int y, int flags, void *ustc) { if (event == CV_EVENT_LBUTTONDOWN) //检测到左键按下时 { leftButtonDownFlag = true; //标志位为true,也就是停止读取下一帧图像 beginPoint = Point(x, y); //设置左键按下点的矩形起点 endPoint = beginPoint; } if (event == CV_EVENT_MOUSEMOVE && leftButtonDownFlag) { //当鼠标移动且之前左键有按下的话 imageCopy = image.clone(); endPoint = Point(x, y); if (beginPoint != endPoint) { //在复制的图像上绘制矩形 rectangle(imageCopy, beginPoint, endPoint, Scalar(0, 0, 255), 2); } //imshow("Video", imageCopy); } if (event == CV_EVENT_LBUTTONUP) //左键放开时,开始匹配 { leftButtonDownFlag = false; Mat subImage = image(Rect(beginPoint, endPoint)); //截取图像 rectImage = subImage.clone(); //给全局的待匹配图像 resultRows = image.rows - rectImage.rows + 1; //输出结果图像的行数及列数 resultcols = image.cols - rectImage.rows + 1; //imshow("Sub Image", rectImage); } }
结果:
大家自己去跑一下代码就好啦,或者可以私聊联系我要结果的文件
-
OPENCV目标跟踪_opencv_目标检测_对avi文件完成视频画面中的运动目标检测_运动目标检测_VC++_视频分析识别
2022-04-28 21:33:18OPENCV目标跟踪_opencv_目标检测_对avi文件完成视频画面中的运动目标检测_运动目标检测_VC++_视频分析识别 -
OpenCV目标追踪
2021-06-22 15:44:04© Fu Xianjun. All Rights Reserved. 目标跟踪任务分类 单目标跟踪- 给定一个目标,追踪...旨在弥补固定的摄像头的视觉局限,并可与行人检测/行人跟踪技术相结合。 MTMCT- 多目标多摄像头跟踪(Multi-target Mu...© Fu Xianjun. All Rights Reserved.
目标跟踪任务分类
- 单目标跟踪 - 给定一个目标,追踪这个目标的位置。
- 多目标跟踪 - 追踪多个目标的位置
- Person Re-ID - 行人重识别,是利用计算机视觉技术判断图像或者视频序列中是否存在特定行人的技术。广泛被认为是一个图像检索的子问题。给定一个监控行人图像,检索跨设备下的该行人图像。旨在弥补固定的摄像头的视觉局限,并可与行人检测/行人跟踪技术相结合。
- MTMCT - 多目标多摄像头跟踪(Multi-target Multi-camera Tracking),跟踪多个摄像头拍摄的多个人
- 姿态跟踪 - 追踪人的姿态
1.CSFT追踪算法的使用
2.实例化追踪器对象
3.视频基本处理方法
4.追踪结果与区域绘制
5.选择目标ROI
6.关闭视频
7.结果
目标追踪的弊端!
- 形态变化 - 姿态变化是目标跟踪中常见的干扰问题。运动目标发生姿态变化时, 会导致它的特征以及外观模型发生改变, 容易导致跟踪失败。例如:体育比赛中的运动员、马路上的行人。
- 尺度变化 - 尺度的自适应也是目标跟踪中的关键问题。当目标尺度缩小时, 由于跟踪框不能自适应跟踪, 会将很多背景信息包含在内, 导致目标模型的更新错误:当目标尺度增大时, 由于跟踪框不能将目标完全包括在内, 跟踪框内目标信息不全, 也会导致目标模型的更新错误。因此, 实现尺度自适应跟踪是十分必要的。
- 遮挡与消失 - 目标在运动过程中可能出现被遮挡或者短暂的消失情况。当这种情况发生时, 跟踪框容易将遮挡物以及背景信息包含在跟踪框内, 会导致后续帧中的跟踪目标漂移到遮挡物上面。若目标被完全遮挡时, 由于找不到目标的对应模型, 会导致跟踪失败。
- 图像模糊 - 光照强度变化, 目标快速运动, 低分辨率等情况会导致图像模型, 尤其是在运动目标与背景相似的情况下更为明显。因此, 选择有效的特征对目标和背景进行区分非常必要。
-
一种基于opencv的动态目标识别跟踪方法
2018-01-31 21:20:26博主是opencv初学者,最近研究动态目标识别,然后利用当前帧和起始背景帧的灰度值差,简单实现了动态目标识别跟踪,现在将这个方法分享给大家。本方法的主要思想在于,在求得两帧的灰度值差后,利用threshold函数,... -
基于opencv GMM动态目标检测与跟踪
2020-09-09 13:16:31机器学习在很多领域都有应用,本文主要简述机器学习在目标识别和跟踪方面的应用。本文介绍opencv进行静态背景下动态目标的识别和跟踪,并且拥有可视化界面,可采用摄像头,读取视频,和单张图片处理。博客链接... -
基于Opencv的运动目标的检测和跟踪
2021-04-16 17:53:50质心跟踪法的目标位置通过质点的中心来确定,该算法计算简单,计算量小,其稳定性与精度主要取决于序列图像的分割及其阀值的确定情况。文中给出了用Opencv实现算法的具体过程和关键代码,并且设计了跟踪运动车辆的... -
基于OpenCV的运动目标跟踪及其实现
2017-10-02 04:57:40基于OpenCV 的运动目标跟踪及其实现 开源式openMV 可运动识别 -
opencv目标跟踪
2019-07-13 18:26:31目标跟踪就是识别移动目标的过程,并且跨帧跟踪这些目标,为了跟踪视屏中的目标,首先要做的就是识别出可能包含目标的区域。 目前有很多视屏目标跟踪的方法: 当跟踪所有移动目标时,帧之间的差异很重要 当跟踪... -
OPENCV目标跟踪_opencv_目标检测_opencv车辆检测是在夜间进行检测_车辆检测_车辆夜间识别_VC++
2022-04-28 22:02:20OPENCV目标跟踪_opencv_目标检测_opencv车辆检测是在夜间进行检测_车辆检测_车辆夜间识别_VC++ -
OpenCV中八种不同的目标追踪算法
2022-01-06 00:49:49转载自丨新机器视觉目标跟踪作为机器学习的一个重要分支,加之其在日常生活、军事行动中的广泛应用,受到极大的关注。在AI潮流中,大家对于深度学习,目标跟踪肯定都会有过接触了解:在GPU上通过大... -
Opencv基于CamShift算法实现目标跟踪
2020-08-28 07:40:43主要为大家详细介绍了Opencv基于CamShift算法实现目标跟踪,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 -
目标跟踪(1)基于OpenCV实现单目标跟踪
2022-03-07 09:26:321.什么是目标跟踪? 简单地说,在视频的连续帧中定位一个对象称为跟踪。 这个定义听起来很简单,但在计算机视觉和机器学习中,跟踪是一个非常广泛的术语,它包含了概念相似但技术不同的想法。例如,以下所有不 -
多目标跟踪vs+opencv
2016-11-06 14:47:28运动目标的相关信息存放于结构体中,可以在此基础上判断目标的动作行为跟踪基本框架,opencv编写,利用背景差分,质心法可以跟踪多个目标,并分配ID号,记录行动轨迹,可用于车辆道路等,大家可以参考学习下,效果... -
用OpenCV实现目标追踪的八种方法
2020-10-16 14:41:02目标跟踪作为机器学习的一个重要分支,加之其在日常生活、军事行动中的广泛应用,很多国内外学者都对此颇有研究。本文将讨论OpenCV上八种不同的目标追踪算法。 虽然我们熟知的的质心追踪器表现得很好,...OpenCV目标追 -
OpenCV的运动与跟踪例程
2015-09-24 09:17:28OpenCV实现运动跟踪的camshift例程源码 -
基于OpenCV的运动目标检测与跟踪
2020-12-09 14:36:41尹俊超,刘直芳:基于OpenCV的运动目标检测与跟踪2011,Vol.32,No.828170引言运动目标检测跟踪技术在航空航天遥感、生物医学、工业自动化生产、军事公安目标侦查、智能机器人、多媒体电视制作、文化艺术等领域都有着... -
基于OpenCV车牌识别及轨迹跟踪
2021-11-28 20:30:18利用道路中行进车辆的成像镜头,对实时车辆的视频图像,运用视频分帧、图像处理、切割、物体提取等处理,实现对车辆车牌号的自动识别,与要查找的目标车牌号进行比较分析,找出目标车辆,并产生车辆信息。... -
OPENCV基于摄像头图像采集运动目标跟踪及人脸识别技术.zip资源matlab opencv运动目标检测程序资料
2022-04-21 21:05:56OPENCV基于摄像头图像采集运动目标跟踪及人脸识别技术.zip资源matlab opencv运动目标检测程序资料OPENCV基于摄像头图像采集运动目标跟踪及人脸识别技术.zip资源matlab opencv运动目标检测程序资料OPENCV基于摄像头... -
OPENCV基于摄像头图像采集运动目标跟踪及人脸识别技术_VC++_摄像头图像采集_人脸识别跟踪
2022-04-28 22:05:02OPENCV基于摄像头图像采集运动目标跟踪及人脸识别技术_VC++_摄像头图像采集_人脸识别跟踪 -
opencv指定矩形区域并跟踪
2018-03-25 17:45:38opencv指定矩形区域并进行跟踪,可以暂停,此Demo显示了基于均值漂移的追踪(tracking)技术请用鼠标框选一个有颜色的物体,对它进行追踪操作操作说明:用鼠标框选对象来初始化跟踪 -
OpenCV+python实现实时目标检测功能
2020-09-16 14:51:09主要介绍了OpenCV+python实现实时目标检测功能,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下 -
OpenCV 对象跟踪
2022-02-07 22:23:09OpenCV 对象跟踪 这篇文章使用 OpenCV 中内置的八种不同的对象跟踪算法,实现对物体的跟踪。 首先,介绍一下8种跟踪算法。 然后,演示如何使用OpenCV实现这些跟踪算法。 最后,对本文做总结。 OpenCV 对象跟踪器 ... -
基于opencv的目标跟踪程序
2018-04-09 15:33:24基于opencv的跟踪库函数,实现目标的实时跟踪,视频信息是基于实时摄像头输入头像 -
基于OpenCV的交通视频运动目标检测与跟踪
2018-07-19 15:32:11基于OpenCV的交通视频运动目标检测与跟踪 基于OpenCV的交通视频运动目标检测与跟踪 基于OpenCV的交通视频运动目标检测与跟踪 基于OpenCV的交通视频运动目标检测与跟踪