原文链接:https://blog.csdn.net/zbp_12138/article/details/103208910
本文讲解的是基于”鸿鹄”空间定位仪第一,二代程序写的第三代程序,相较于前两代的程序,第三代的程序有比较大的改动,其程序是在第二代的基础上进行改进的.
“鸿鹄”空间定位仪1.0版本:
https://blog.csdn.net/zbp_12138/article/details/101100607
“鸿鹄”空间定位仪2.0版本:
https://blog.csdn.net/zbp_12138/article/details/103191129
不同版本有不同版本的优缺点:
- 在1.0版本中,程序能快速地识别目标物体,并迅速地返回对应的距离,但缺点是精确度不高,距离目标物40cm时,误差的平均值为5cm,在背景纷繁复杂时,程序不能准确识别到目标物,误差大且数值一直在变化,不稳定.即速度快,但准确度低.
- 在2.0版本中,我调用了百度AI的图像主体识别接口,在一定程度上能准确识别到目标物体,从而提高了识别的稳定性与准确度,但缺点是识别速度很慢,不能达到实时的效果.即速度慢,但准确度高.
- 在3.0版本中,我使用了多线程的方式,把1.0和2.0版本的优点结合起来,达到了速度快,且准确度高的效果,可以实现实时检测.
以下是"鸿鹄"空间定位仪3.0版本的代码讲解,首先来看一下几个必要的资源库:
import requests
import base64
import numpy as np
import cv2
import time
import multiprocessing as mp
其中multiprocessing是python内置的一个进程管理模块,我们可以通过这个模块实现多进程。进程想要执行任务就需要依赖线程。换句话说,就是进程中的最小执行单位就是线程,并且一个进程中至少有一个线程。
那什么是多线程?提到多线程这里要说两个概念,就是串行和并行,搞清楚这个,我们才能更好地理解多线程。
所谓串行,其实是相对于单条线程来执行多个任务来说的,我们就拿下载文件来举个例子:当我们下载多个文件时,在串行中它是按照一定的顺序去进行下载的,也就是说,必须等下载完第一个文件之后才能开始下载第二个文件,它们在时间上是不可能发生重叠的。
而并行就是在下载多个文件时,开启多条线程,多个文件同时进行下载,这里是严格意义上的,在同一时刻发生的,并行在时间上是重叠的。
多线程类似于同时执行多个不同程序,是为了同步完成多项任务而使用的,是为了提高资源使用效率来提高系统的效率,多线程运行有如下优点:
- 使用线程可以把占据时间长的程序任务放到后台去处理。
- 程序的运行速度可能加快。
在这里我们先举一个简单的例子:
以较为常用的Queue为例子,在父进程中创建两个子进程,一个往Queue里写数据,一个从Queue里读取数据:
import multiprocessing as mp
导入multiprocessing
#写数据进程
def write_data(q,name):
print(name)
for v in range(5):
q.put(v)
print ('把%s写入队列'%v)
第一个进程:写入数据
#读数据进程
def read_data(q,name):
print(name)
while True:
value = q.get()
print('从队列里读取到%s'%value)
第二个进程:读取数据
def run():
name1 = "写数据进程"
name2 = "读数据进程"
#父进程创建queue,并传递给各个子进程:
q = mp.Queue(1)
#启动子进程pw,写入数据
pw = mp.Process(target=write_data,args=(q,name1))
pw.start()
#启动子进程pr,读取数据
pr = mp.Process(target=read_data, args=(q,name2))
pr.start()
#等待pw结束
pw.join()
#pr,进程里是死循环,无法等待其自动结束,所以手动结束
pr.terminate()
控制两个进程的方法
if __name__ == '__main__':
run()
运行程序
如果你已经得到了上面的结果,那么恭喜你,你已经成功一半了,接下来,看看"鸿鹄"空间定位仪3.0是怎么使用多进程的:
def image_put(q, user, pwd, ip):
cap1 = cv2.VideoCapture("rtsp://%s:%s@%s:8554/live" % (user, pwd, ip))
cap2 = cv2.VideoCapture("http://%s:%s@ip地址:8081"% (user, pwd))
while (cap2.isOpened()):
(grabbed, frame) = cap2.read()
q.put(frame)
q.get() if q.qsize() > 1 else time.sleep(0.01)
cap1和cap2都可以调用ip摄像头,方法不同而已
def image_get(q,camera_ip):
while True:
frame = q.get()
frame_count = 1
params = []
params.append(1)
cv2.imwrite("/Users/Administrator/PycharmProjects/untitled/images/video%d.jpg" % frame_count, frame, params)
marker = find_width("/Users/Administrator/PycharmProjects/untitled/images/video%d.jpg" % frame_count)
# frame_count = frame_count + 1
inches = distance_to_camera(KNOWN_WIDTH, focalLength, marker[0])
box = (marker[2],marker[1]), (marker[2] + marker[0], marker[1]), (marker[2] + marker[0], marker[1] + marker[3]),(marker[2] ,marker[1] + marker[3])
print(box)
box = np.int0(box)
cv2.drawContours(frame, [box], -1, (0, 255, 0), 2)
# inches 转换为 cm
cv2.putText(frame, "%.2fcm" % (inches/6.6 ), (frame.shape[1] - 350, frame.shape[0] - 20),cv2.FONT_HERSHEY_SIMPLEX, 2.0, (0, 255, 0), 3) #2.54
# show a frame
title = 'Locator 3.0'
gbk_title = title.encode("gbk").decode(errors="ignore")
cv2.imshow(gbk_title, frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
获取视频的某一帧,其中的代码详解在使用几何光学实现空间相对定位2.0(python+opencv)里有介绍
def run_single_camera():
user_name, user_pwd, camera_ip = "admin", "admin", "ip地址"
mp.set_start_method(method='spawn') # init
queue = mp.Queue(2)
processes = [mp.Process(target=image_put, args=(queue, user_name, user_pwd, camera_ip)),
mp.Process(target=image_get, args=(queue, camera_ip))]
[setattr(process, "daemon", True) for process in processes] # process.daemon = True # 设置进程守护
[process.start() for process in processes]
[process.join() for process in processes]
使用示例代码前,请记得替换其中的ip地址
if __name__ == '__main__':
run_single_camera()
为了让三篇文章显得更具有逻辑性,我在这篇文章里就不做一些重复性的解释了,大家感兴趣的话,可以查阅我以前的文章.
总的来说,在"鸿鹄"空间定位仪3.0版本中,我使用Python3自带的多线程模块multiprocessing,创建一个队列,线程A从通过rtsp / http 协议从视频流中读取出每一帧,并放入队列中,线程B从队列中将图片取出,处理后进行显示。
之所以能加快识别的速度,是因为:
线程A如果发现队列里有两张图片,则证明线程B的读取速度跟不上线程A,那么线程A主动将队列里面的旧图片删掉,换上新图片。
通过多线程的方法:
- 线程A的读取速度始终不收线程B的影响,防止网络摄像头的缓存区爆满
- 线程A更新了队列中的图片,使线程B始终读取到最新的画面,降低了延迟
测试数据:
经过测试,"鸿鹄"空间定位仪在距离目标物35cm到60cm时,平均误差小于1cm,平均精确度高达98.7%
其中一次测试数据:实际距离为55.00cm,测量距离为:55.45cm
以下链接是“鸿鹄”空间定位仪3.0的实拍视频:
http://v.youku.com/v_show/id_XNDQ0Mzk2NDYyMA==.html?x&sharefrom=android&sharekey=fd7ac36a100eb692f3056be1ef4db6e80