在本文中,我们将学习如何使用 open-cv 和 YOLO 对象检测器每五秒捕获/保存和检测图像中的对象。然后我们将图像转换为字节数组并通过 MQTT 发布,这将在另一个远程设备上接收并保存为 JPG。
我们将使用 YoloV3 算法和一个免费的 MQTT 代理
YoloV3 算法:https://viso.ai/deep-learning/yolov3-overview/#:~:text=What's%20Next%3F-,What%20is%20YOLOv3%3F,Joseph%20Redmon%20and%20Ali%20Farhadi.
MQTT 代理:https://www.emqx.com/
在我们继续之前,我假设你具备以下基本知识:
· OpenCV:https://opencv.org/about/#:~:text=OpenCV%20(Open%20Source%20Computer%20Vision,perception%20in%20the%20commercial%20products.
· NumPy:https://numpy.org/doc/stable/user/whatisnumpy.html
· MQTT:https://mqtt.org/getting-started/
让我们首先在我们的第一台设备上编写 Python 脚本,该设备将充当监控系统。
安装:
· pip install opencv-python
· pip install numpy
· pip install paho-mqtt
如果你在安装 opencv 时仍然遇到问题,请遵循以下文章
· 在 Windows上安装:https://docs.opencv.org/3.4/d5/de5/tutorial_py_setup_in_windows.html
· 在 Ubuntu上安装:https://docs.opencv.org/3.4/d2/de6/tutorial_py_setup_in_ubuntu.html
我们还需要下载一些文件(YoloV3 的预训练权重、配置文件和名称文件)。
从以下链接下载它们
Yolov3.weights:https://pjreddie.com/media/files/yolov3.weights
Yolov3.cfg:https://github.com/pjreddie/darknet/blob/master/cfg/yolov3.cfg
coco.names:https://github.com/pjreddie/darknet/blob/master/data/coco.names
(确保以上 3 个下载的文件与 sendImage.py 保存在同一目录下)
在 IDE 中创建一个新文件并将文件保存为 sendImage.py
从导入所需的模块开始
import paho.mqtt.client as mqtt
import paho.mqtt.publish as publish
import cv2
import numpy as np
import time
我们现在将为代理和图像初始化变量
broker = "broker.emqx.io"
port = 1883
timelive=60
image_name="capture.jpg"
我们的第一个函数将捕获/保存图像,并调用 process_image() 函数
def save_image():
#cv2.VideoCapture(0) this can be 0, 1, 2 depending on your device id
videoCaptureObject = cv2.VideoCapture(0)
ret, frame = videoCaptureObject.read()
cv2.imwrite(image_name, frame)
videoCaptureObject.release()
process_image()
process_image() 函数是所有魔法发生的地方。
def process_image():
boxes = []
confs = []
class_ids = []
#loading the YoloV3 weights and configuration file using the open-cv dnn module
net = cv2.dnn.readNet("yolov3.weights", "yolov3.cfg")
#storing all the trained object names from the coco.names file in the list names[]
names = []
with open("coco.names", "r") as n:
names = [line.strip() for line in n.readlines()]
#running a foward pass by passing the names of layers of the output to be computed by net.getUnconnectedOutLayersNames()
output_layers = [layer_name for layer_name in net.getUnconnectedOutLayersNames()]
colors = np.random.uniform(0, 255, size=(len(names), 3))
#reading the image from the image_name variable (Same image which was saved by the save_image function)
image = cv2.imread(image_name)
height, width, channels = image.shape
#using blobFromImage function to preprocess the data
blob = cv2.dnn.blobFromImage(image, scalefactor=0.00392, size=(160, 160), mean=(0, 0, 0))
net.setInput(blob)
#getting X/Y cordinates of the object detected, scores for all the classes of objects in coco.names where the predicted object is class with the highest score, height/width of bounding box
outputs = net.forward(output_layers)
for output in outputs:
for check in output:
#this list scores stores confidence for each corresponding object
scores = check[5:]
#np.argmax() gets the class index with highest score which will help us get the name of the class for the index from the names list
class_id = np.argmax(scores)
conf = scores[class_id]
#predicting with a confidence value of more than 40%
if conf > 0.4:
center_x = int(check[0] * width)
center_y = int(check[1] * height)
w = int(check[2] * width)
h = int(check[3] * height)
x = int(center_x - w / 2)
y = int(center_y - h / 2)
boxes.append([x, y, w, h])
confs.append(float(conf))
class_ids.append(class_id)
#drawing bounding boxes and adding labels while removing duplicate detection for same object using non-maxima suppression
indexes = cv2.dnn.NMSBoxes(boxes, confs, 0.5, 0.5)
font = cv2.FONT_HERSHEY_PLAIN
for i in range(len(boxes)):
if i in indexes:
x, y, w, h = boxes[i]
label = str(names[class_ids[i]])
color = colors[i]
cv2.rectangle(image, (x, y), (x + w, y + h), color, 2)
cv2.putText(image, label, (x, y - 5), font, 1, color, 1)
#resizing and saving the the image
width = int(image.shape[1] * 220 / 100)
height = int(image.shape[0] * 220 / 100)
dim = (width, height)
resized = cv2.resize(image, dim, interpolation=cv2.INTER_AREA)
cv2.imwrite('processed.jpg', resized)
#reading the image and converting it to bytearray
f = open("processed.jpg", "rb")
fileContent = f.read()
byteArr = bytes(fileContent)
#topic to publish for our MQTT
TOPIC = "IMAGE"
client = mqtt.Client()
#connecting to the MQTT broker
client.connect(broker, port, timelive)
#publishing the message with bytearr as the payload and IMAGE as topic
publish.single(TOPIC, byteArr, hostname=broker)
print("Published")
启动 save_image 函数并每 5 秒调用一次的最后几行代码
while True:
save_image()
time.sleep(5)
现在让我们在第二个设备上编写第二个脚本,该脚本将用于下载和查看通过 MQTT 接收的检测到的对象文件
安装:
· pip install paho-mqtt
在 IDE 中创建一个新文件并将文件保存为 receiveImage.py
从导入所需的模块开始
import paho.mqtt.client as mqtt
为代理初始化变量
broker = "broker.emqx.io"
port = 1883
timelive = 60
使用 on_connect() 函数连接代理并订阅主题 IMAGE
def on_connect(client, userdata, flags, rc):
print("Connected with result code " + str(rc))
#subscribe to the topic IMAGE, this is the same topic which was used to published the image on the previous device
client.subscribe("IMAGE")
编写 on_message() 函数以在收到有效负载后立即保存文件
def on_message(client, userdata, msg):
#create/open jpg file [detected_objects.jpg] to write the received payload
f = open('detected_objects.jpg', "wb")
f.write(msg.payload)
f.close()
连接到代理并通过无限循环开始监听传入消息的根函数
def mqtt_sub():
client = mqtt.Client()
client.connect(broker, port, timelive)
client.on_connect = on_connect
client.on_message = on_message
client.loop_forever()
启动脚本的最后一行代码
mqtt_sub()
每隔5秒,你就会在脚本文件所在的目录中刷新名称为' detected_objects.jpg '的JPG图像。
就是这样。我们创建了一个监控系统,每 5 秒捕获一次图像,检测其中的物体,并使用 MQTT 通过互联网发送图像。
☆ END ☆
如果看到这里,说明你喜欢这篇文章,请转发、点赞。微信搜索「uncle_pn」,欢迎添加小编微信「 woshicver」,每日朋友圈更新一篇高质量博文。
↓扫描二维码添加小编↓