数字图像处理课程设计报告

数字图像处理课程设计报告

题目要求

人员结构化信息处理。能对视频的人员进行行走方向、上衣颜色、下衣颜色、是否携带行李,(还可以考虑性别?发型?眼镜?衣服款式?)等进行结构化信息提取,并建立检索系统。

项目简介

当下,covid-19 肆虐全球,在这样的背景下,我们可以利用 Python 进行一些简单的人物检测,比如,在地铁出入口这样的场景中,我们可以识别出来往的人群,他们的外貌特征,是否佩戴口罩等等。本项目主要利用 opencv-python 库,对视频中的人物进行检测,并对每一帧进行信息提取,然后保存其结构化数据,以供检索。

安装与使用说明

开发环境说明:

  • 操作系统:Windows 11 专业版
  • IDE:VSCode,版本:1.63.2
  • VSCode Plugin: Microsoft Python Plugin
  • Python:3.9.9,本 Python 环境为 Windows 下的 Scoop 包管理工具安装版本

然后是涉及到的 Python 库:

实验所需要的所有 Python 库。如下。

  1. opencv-python
  2. numpy
  3. imutils

Imutils are a series of convenience functions to make basic image processing functions such as translation, rotation, resizing, skeletonization, and displaying Matplotlib images easier with OpenCV and both Python 2.7 and Python 3.

  1. dlib

这是一个包含机器学习算法和工具的库。安装这个需要 PC 上有 Visual Studio for C++.

当然,如果提示没有 cmake 的话,还需要安装 cmake,使用 pip install cmake 即可。

  1. scipy

  2. webcolors

然后,运行目录下的 person_detection.py 文件:

可以通过命令行执行,也可以通过 VSCode 来执行。注意,如果是在 VSCode 中执行,还需要配置 Python 的工作目录,即,在 settings.json 中添加以下配置:

1
"python.terminal.executeInFileDir": true,

即,将 Python 的工作目录设置成当前的目录,这样就可以识别相对路径。

运行结果如下:

对于方向的说明:这里呈现的方向是采用向量的形式,即,根据 opencv 本身固有的坐标系,然后使用向量的坐标形式来展示人物行走的方向。

退出程序说明:按 q 退出程序。

设计文档

项目的主要任务是对人物的识别,这其实是属于 Object Detection 的范畴。关于 Object Detection,这其实是一个流行很久的领域,它是与计算机视觉(Computer Vison)和图像处理(Image Processing)相关的一个分支,常用的方法有如下两个分支:

  • Non-neural approaches:
    • Viola–Jones object detection framework based on Haar features
    • Scale-invariant feature transform (SIFT)
    • Histogram of oriented gradients (HOG) features
  • Neural network approaches:
    • Region Proposals (R-CNN, Fast R-CNN, Faster R-CNN, cascade R-CNN.)
    • Single Shot MultiBox Detector (SSD)
    • You Only Look Once (YOLO)
    • Single-Shot Refinement Neural Network for Object Detection (RefineDet)
    • Retina-Net
    • Deformable convolutional networks

本次实验,主要采用 SSD 方法来进行识别,即 Single Shot MultiBox Detector。因为考虑到手上计算机的性能问题,故没有使用另外一个非常流行的技术,即 YOLO。而且,本次实验由于要识别的对象比较简单,所以就直接采用了 GitHub 上已有的模型文件来进行处理,这样可以有效降低对于计算机性能的要求,从而可以使注意力集中到实验本身。

项目的整体思路是先检测出人物,然后给每一个检测出来的人物打上标签,之后对检测出来的人物进行遍历,然后识别其行走方向,然后再识别其上衣和下衣的颜色。最后将这些信息进行结构化处理,并保存到 txt 文件中,以供检索。

人物识别

首先,加载模型文件

1
2
3
4
# 训练好的模型文件
protopath = "MobileNetSSD_deploy.prototxt"
modelpath = "MobileNetSSD_deploy.caffemodel"
detector = cv2.dnn.readNetFromCaffe(prototxt=protopath, caffeModel=modelpath)

然后,对每一帧进行处理

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
blob = cv2.dnn.blobFromImage(frame, 0.007843, (W, H), 127.5)

detector.setInput(blob)
person_detections = detector.forward()
rects = []
for i in np.arange(0, person_detections.shape[2]):
confidence = person_detections[0, 0, i, 2]
if confidence > 0.5:
idx = int(person_detections[0, 0, i, 1])

if CLASSES[idx] != "person":
continue

person_box = person_detections[0, 0, i, 3:7] * np.array([W, H, W, H])
(startX, startY, endX, endY) = person_box.astype("int")
rects.append(person_box)

# cv2.rectangle(frame, (startX, startY), (endX, endY), (0, 0, 255), 2)

boundingboxes = np.array(rects)
boundingboxes = boundingboxes.astype(int)
rects = non_max_suppression_fast(boundingboxes, 0.3)

objects = tracker.update(rects)

for index, (objectId, bbox) in enumerate(objects.items()):
x1, y1, x2, y2 = bbox
if frame_count == 9 and x1 != pre_coord_lists[index][1][0] or y1 != pre_coord_lists[index][1][1]:
pre_coord_lists[index][0] = pre_coord_lists[index][1]
# print(pre_coord_lists[index][1])
# print('runtest')
pre_coord_lists[index][1] = (x1, y1)
# print('coordinate:', bbox)
# print(pre_coord_lists[index])
x1 = int(x1)
y1 = int(y1)
x2 = int(x2)
y2 = int(y2)

cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 0, 255), 2)
# tag a person with a unique ID
text = "ID: {}".format(objectId)
cv2.putText(frame, text, (x1, y1 - 22), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (0, 0, 255), 1)

对于检测出来的人物,我们用长方形将其裁剪出来。

检测人物行走方向

这里主要利用了一个二维 list,列表的第一项存放的上一个时刻的人物的坐标,第二项存放的是当前时刻的人物的坐标,然后把两个坐标相减,就得到了方向向量,这个方向向量就是人物的行走方向。

关键代码如下:

1
pre_coord_lists = [[(0, 0) for i in range(2)] for i in range(100)] # hard codes, need to be refactored later
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
for index, (objectId, bbox) in enumerate(objects.items()):
x1, y1, x2, y2 = bbox
if frame_count == 9 and x1 != pre_coord_lists[index][1][0] or y1 != pre_coord_lists[index][1][1]:
pre_coord_lists[index][0] = pre_coord_lists[index][1]
# print(pre_coord_lists[index][1])
# print('runtest')
pre_coord_lists[index][1] = (x1, y1)
# print('coordinate:', bbox)
# print(pre_coord_lists[index])
x1 = int(x1)
y1 = int(y1)
x2 = int(x2)
y2 = int(y2)

cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 0, 255), 2)
# tag a person with a unique ID
text = "ID: {}".format(objectId)
cv2.putText(frame, text, (x1, y1 - 22), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (0, 0, 255), 1)
# detect and show the moving direction of a detected person
direct_vector = (pre_coord_lists[index][1][0] - pre_coord_lists[index][0][0], pre_coord_lists[index][1][1] - pre_coord_lists[index][0][1])
direction_text = "direction: {}".format(direct_vector)
cv2.putText(frame, direction_text, (x1, y1 - 5), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (0, 0, 255), 1)

检测衣服的颜色

首先,对于每一个识别出来的人物,我们使用 opencv 将其裁剪出来,然后对于人物进行切割,分别对上身和下身进行处理,然后,这里使用的检测方法比较,即分别计算出人物上半身和下半身的中心坐标,然后将中心点的像素取出来,并将其转换成相应的颜色。

关键代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# crop a person from a frame
crop_img = frame[y1:y2, x1:x2]
# cv2.imwrite('draft.jpg', crop_img)
# detect color of a person's body
center_coordX = (int)((x1 + x2) / 2)
center_coordY = (int)((y1 + y2) / 2)
top_half_coordY = (int)((y1 + center_coordY) / 2)
bottom_half_coordY = (int)((center_coordY + y2) / 2)
top_half_color = frame[top_half_coordY, center_coordX]
bottom_half_color = frame[bottom_half_coordY, center_coordX]
# convert BGR to RGB first
top_half_color = (top_half_color[2], top_half_color[1], top_half_color[0])
bottom_half_color = (bottom_half_color[2], bottom_half_color[1], bottom_half_color[0])
# print('top_half_color_BGR:', top_half_color)
# print('bottom_half_color_BGR:', bottom_half_color)
top_half_named_color = convert_rgb_to_names(top_half_color)
bottom_half_named_color = convert_rgb_to_names(bottom_half_color)
if frame_count == 9:
print('top color:', top_half_named_color)
print('bottom color:', bottom_half_named_color)

注意这里的将 RGB 值转换成具体的颜色名称的函数,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 将 RGB 值转换成最接近的颜色具体名称
def convert_rgb_to_names(rgb_tuple):

# a dictionary of all the hex and their respective names in css3
css3_db = CSS3_HEX_TO_NAMES
names = []
rgb_values = []
for color_hex, color_name in css3_db.items():
names.append(color_name)
rgb_values.append(hex_to_rgb(color_hex))

kdt_db = KDTree(rgb_values)
distance, index = kdt_db.query(rgb_tuple)
return f'closest match: {names[index]}'

这里的颜色名称采用的是 css3 中的颜色表,由于有些 RGB 值在 css3 中并没有直接对应的颜色名称,所以,对于这种情况,我们就利用该函数将其转换成接近的颜色名称。这里需要用到 scipy 库中的 KDTree 数据结构。

建立结构化检索

这里主要是将每一帧处理好的数据保存到 txt 文件中,然后可以利用 Python 的文件读写操作对文件进行处理和检索。

特色与创新

在人物检测方面,采用了当下比较流行的技术 SSD,对于提高检测的准确性很有帮助。在识别和提取人物衣服颜色的处理过程中 ,使用了 KDTree 数据结构,使得对于颜色的转换更为准确和便捷。

不足与展望

本次实验的不足之处主要在于识别的准确性还有待提高。对于实验整体的功能性,也有很多的进步空间。比如对于人物口罩的识别,对于人物的行李的识别。

对于信息结构化检索,也可以利用 pymysql 操作 MySQL 数据库,将数据存到 MySQL 中,这样,存取效率相比于 txt 文件,有很大的优势。


版权声明: 本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!