opencv-090-视频分析(对象移动轨迹绘制)

知识点

移动对象分析,我们可以绘制对象运行轨迹曲线,这个主要是根据移动对象窗口轮廓,获取中心位置,然后使用中心位置进行绘制即可得到。大致的程序步骤如下:

  1. 初始化路径点数组
  2. 对每帧的预测轮廓提取中心位置添加到路径数组
  3. 绘制路径曲线

代码(c++,python)

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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include <opencv2/opencv.hpp>"
#include <iostream>

using namespace cv;
using namespace std;

Mat image;
bool selectObject = false;
int trackObject = 0;
bool showHist = true;
Point origin;
Rect selection;
int vmin = 10, vmax = 256, smin = 30;

int main(int argc, const char** argv)
{
// VideoCapture cap(0);
VideoCapture cap("D:/images/video/balltest.mp4");
Rect trackWindow;
int hsize = 16;
float hranges[] = { 0,180 };
const float* phranges = hranges;

if (!cap.isOpened())
{
printf("could not open camera...\n");
return -1;
}

namedWindow("Histogram", WINDOW_AUTOSIZE);
namedWindow("CamShift Demo", WINDOW_AUTOSIZE);

Mat frame, hsv, hue, mask, hist, histimg = Mat::zeros(200, 320, CV_8UC3), backproj;
bool paused = false;
cap.read(frame);
Rect selection = selectROI("CamShift Demo", frame, true, false);
vector<Point> tracking_path;
while (true)
{
bool ret = cap.read(frame);
if (!ret) break;
frame.copyTo(image);

cvtColor(image, hsv, COLOR_BGR2HSV);

int _vmin = vmin, _vmax = vmax;
inRange(hsv, Scalar(26, 43, 46), Scalar(34, 255, 255), mask);
int ch[] = { 0, 0 };
hue.create(hsv.size(), hsv.depth());
mixChannels(&hsv, 1, &hue, 1, ch, 1);

if (trackObject <= 0)
{
// Object has been selected by user, set up CAMShift search properties once
Mat roi(hue, selection), maskroi(mask, selection);
calcHist(&roi, 1, 0, maskroi, hist, 1, &hsize, &phranges);
normalize(hist, hist, 0, 255, NORM_MINMAX);

trackWindow = selection;
trackObject = 1; // Don't set up again, unless user selects new ROI

histimg = Scalar::all(0);
int binW = histimg.cols / hsize;
Mat buf(1, hsize, CV_8UC3);
for (int i = 0; i < hsize; i++)
buf.at<Vec3b>(i) = Vec3b(saturate_cast<uchar>(i*180. / hsize), 255, 255);
cvtColor(buf, buf, COLOR_HSV2BGR);

for (int i = 0; i < hsize; i++)
{
int val = saturate_cast<int>(hist.at<float>(i)*histimg.rows / 255);
rectangle(histimg, Point(i*binW, histimg.rows),
Point((i + 1)*binW, histimg.rows - val),
Scalar(buf.at<Vec3b>(i)), -1, 8);
}
}

// Perform CA-MeanShift
calcBackProject(&hue, 1, 0, hist, backproj, &phranges);
backproj &= mask;
RotatedRect trackBox = CamShift(backproj, trackWindow,
TermCriteria(TermCriteria::EPS | TermCriteria::COUNT, 10, 1));
if (trackBox.center.x>0 && trackBox.center.y>0)
tracking_path.push_back(trackBox.center);
ellipse(image, trackBox, Scalar(0, 0, 255), 3, LINE_AA);
for (int i = 1; i < tracking_path.size(); i++) {
line(image, tracking_path[i - 1], tracking_path[i], Scalar(255, 0, 0), 2, 8, 0);
}

imshow("CamShift Demo", image);
imshow("Histogram", histimg);
char c = (char)waitKey(50);
if (c == 27)
break;
}

return 0;
}
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
53
54
55
56
57
58
59
60
61
62
63
64
"""
视频分析(对象移动轨迹绘制)
"""

import cv2 as cv
import numpy as np

cap = cv.VideoCapture('images/balltest.mp4')
if not cap.isOpened():
print("could not read video")
exit(0)

# 读取第一帧
ret, frame = cap.read()

# 选择ROI区域
x, y, w, h = cv.selectROI("CAM Demo", frame, True, False)
track_window = (x, y, w, h)

# 获取ROI直方图
roi = frame[y:y + h, x:x + w]
hsv_roi = cv.cvtColor(roi, cv.COLOR_BGR2HSV)
mask = cv.inRange(hsv_roi, (26, 43, 46), (34, 255, 255))
roi_hist = cv.calcHist([hsv_roi], [0], mask, [180], [0, 180])
cv.normalize(roi_hist, roi_hist, 0, 255, cv.NORM_MINMAX)

# 搜索跟踪分析
tracking_path = []
term_crit = (cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 1)
while True:
ret, frame = cap.read()
if not ret:
break

hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)
dst = cv.calcBackProject([hsv], [0], roi_hist, [0, 180], 1)

# 搜索更新roi区域,保持运行轨迹
track_box = cv.CamShift(dst, track_window, term_crit)
track_window = track_box[1]
pt = np.int32(track_box[0][0])
if pt[0] > 0 and pt[1] > 0:
tracking_path.append(pt)

# 绘制窗口
cv.ellipse(frame, track_box[0], (0, 0, 255), 3, 8)

# 绘制运动轨迹
if len(tracking_path) > 40:
tracking_path = tracking_path[-40:-1]
for i in range(1, len(tracking_path)):
cv.line(frame, (tracking_path[i-1][0], tracking_path[i-1][1]),
(tracking_path[i][0], tracking_path[i][1]), (255, 0, 0),
2, 8, 0)


cv.imshow("CAM Demo", frame)

k = cv.waitKey(50) & 0xff
if k == 27:
break

cv.destroyAllWindows()
cap.release()

结果

代码地址

github