opencv-078-识别与跟踪视频中的特定颜色对象

知识点

图像处理与二值分析的视频版本,通过读取视频每一帧的图像,然后对图像二值分析,得到指定的色块区域,主要步骤如下:

  1. 色彩转换BGR2HSV
  2. inRange提取颜色区域mask
  3. 对mask区域进行二值分析得到位置与轮廓信息
  4. 绘制外接椭圆与中心位置
  5. 显示结果

其中涉及到的知识点主要包括图像处理、色彩空间转换、形态学、轮廓分析等。

代码(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
#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

void process_frame(Mat &image);

/*
* 识别与跟踪视频中的特定颜色对象
*/
int main() {
VideoCapture capture("../images/color_object.mp4");
if (!capture.isOpened()) {
printf("could not open camera...\n");
return -1;
}

int fps = capture.get(CAP_PROP_FPS);
int width = capture.get(CAP_PROP_FRAME_WIDTH);
int height = capture.get(CAP_PROP_FRAME_HEIGHT);
int num_of_frames = capture.get(CAP_PROP_FRAME_COUNT);
printf("frame width: %d, frame height: %d, FPS : %d \n", width, height, fps);

Mat frame;
while (true) {
bool ret = capture.read(frame);
if (!ret) break;
imshow("input", frame);
char c = waitKey(50);
process_frame(frame);
imshow("result", frame);
if (c == 27) {
break;
}
}
waitKey(0);
return 0;

waitKey(0);
return 0;
}

void process_frame(Mat &image) {
Mat hsv, mask;
// 转换色彩空间
cvtColor(image, hsv, COLOR_BGR2HSV);

// 提取颜色区域mask
inRange(hsv, Scalar(0, 43, 46), Scalar(10, 255, 255), mask);
Mat se = getStructuringElement(MORPH_RECT, Size(15, 15));
morphologyEx(mask, mask, MORPH_OPEN, se);

// 寻找最大轮廓
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(mask, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
int index = -1;
int max = 0;
for (size_t t = 0; t < contours.size(); t++) {
double area = contourArea(contours[t]);
if (area > max) {
max = area;
index = t;
}
}

// 绘制外接轮廓
if (index >= 0) {
RotatedRect rect = minAreaRect(contours[index]);
ellipse(image, rect, Scalar(0, 255, 0), 2);
circle(image, rect.center, 2, Scalar(255, 0, 0), 2);
}
}
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
import cv2 as cv
import numpy as np

capture = cv.VideoCapture("D:/images/video/test.mp4")
height = capture.get(cv.CAP_PROP_FRAME_HEIGHT)
width = capture.get(cv.CAP_PROP_FRAME_WIDTH)
count = capture.get(cv.CAP_PROP_FRAME_COUNT)
fps = capture.get(cv.CAP_PROP_FPS)
print(height, width, count, fps)


def process(image, opt=1):
hsv = cv.cvtColor(image, cv.COLOR_BGR2HSV)
line = cv.getStructuringElement(cv.MORPH_RECT, (15, 15), (-1, -1))
mask = cv.inRange(hsv, (0, 43, 46), (10, 255, 255))
mask = cv.morphologyEx(mask, cv.MORPH_OPEN, line)

# 轮廓提取, 发现最大轮廓
out, contours, hierarchy = cv.findContours(mask, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
index = -1
max = 0
for c in range(len(contours)):
area = cv.contourArea(contours[c])
if area > max:
max = area
index = c
# 绘制
if index >= 0:
rect = cv.minAreaRect(contours[index])
cv.ellipse(image, rect, (0, 255, 0), 2, 8)
cv.circle(image, (np.int32(rect[0][0]), np.int32(rect[0][1])), 2, (255, 0, 0), 2, 8, 0)
return image


while(True):
ret, frame = capture.read()
if ret is True:
cv.imshow("video-input", frame)
result = process(frame)
cv.imshow("result", result)
c = cv.waitKey(50)
print(c)
if c == 27: #ESC
break
else:
break
cv.waitKey(0)
cv.destroyAllWindows()

结果

代码地址

github