在现实场景中,我们可能会遇到这个问题,即需要自动的测量图像中的不同目标之间的距离。通过这个测量,我们可以明确的知道图像中各个目标的位置以及各个目标之间的距离,便于我们做出合理的规划。本文是在该博客的基础上面进行拓展而来的。下图展示了一个样例图片,即图中最左边的是我们的参考目标,我们需要做的就是自动的确定当前的参考目标和其它对象之间的距离。
整个算法的核心是根据参考目标的实际距离和欧式距离计算出相应的像素比。首先需要进行一系列的像素预处理操作,包括灰度变换,高斯滤波,边缘检测等;然后使用轮廓检测算法获取到图中的参考目标和其它目标;最后将像素比分别应用在参考目标和其它目标之间的4个顶点和中心点上面。
步骤1-读取输入图片;
步骤2-执行灰度变换;
步骤3-进行高斯滤波去除一部分噪声;
步骤4-执行Canny边缘检测来获取目标的边缘映射,并使用膨胀和腐蚀操作来进行后处理;
步骤5-在边缘映射中寻找合适的轮廓;
步骤6-计算轮廓的外接矩形,并对轮廓进行排序;
步骤7-根据参考目标和实际距离的大小来计算出像素比;
步骤8-根据参考目标和其它目标之间的坐标信息计算并显示结果。
# coding=utf-8
# 导入相应的pthon包
from scipy.spatial import distance as dist
from imutils import perspective
from imutils import contours
import numpy as np
import argparse
import imutils
import cv2
# 计算中心点函数
def midpoint(ptA, ptB):
return ((ptA[0] + ptB[0]) * 0.5, (ptA[1] + ptB[1]) * 0.5)
# 进行参数配置和解析
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="path to the input image")
ap.add_argument("-w", "--width", type=float, required=True, help="width of the left-most object in the image (in inches)")
args = vars(ap.parse_args())
# 读取图片
image = cv2.imread(args["image"])
# 执行灰度变换
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 执行高斯滤波
gray = cv2.GaussianBlur(gray, (7, 7), 0)
# 执行Canny边缘检测
edged = cv2.Canny(gray, 50, 100)
# 执行腐蚀和膨胀后处理
edged = cv2.dilate(edged, None, iterations=1)
edged = cv2.erode(edged, None, iterations=1)
# 在边缘映射中寻找轮廓
cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
# 对轮廓点进行排序
(cnts, _) = contours.sort_contours(cnts)
# 设置显示颜色
colors = ((0, 0, 255), (240, 0, 159), (0, 165, 255), (255, 255, 0), (255, 0, 255))
refObj = None
# 循环遍历每一个轮廓点
for c in cnts:
# 过滤点太小的轮廓点
if cv2.contourArea(c) < 100:
continue
# 计算最小的外接矩形
box = cv2.minAreaRect(c)
box = cv2.cv.BoxPoints(box) if imutils.is_cv2() else cv2.boxPoints(box)
box = np.array(box, dtype="int")
# 对轮廓点进行排序
box = perspective.order_points(box)
# 计算BB的中心点
cX = np.average(box[:, 0])
cY = np.average(box[:, 1])
if refObj is None:
# 获取4个坐标点并计算中心点坐标
(tl, tr, br, bl) = box
(tlblX, tlblY) = midpoint(tl, bl)
(trbrX, trbrY) = midpoint(tr, br)
# 计算中心点之间的欧式距离
D = dist.euclidean((tlblX, tlblY), (trbrX, trbrY))
# 获取计算结果
refObj = (box, (cX, cY), D / args["width"])
continue
# 绘制轮廓
orig = image.copy()
cv2.drawContours(orig, [box.astype("int")], -1, (0, 255, 0), 2)
cv2.drawContours(orig, [refObj[0].astype("int")], -1, (0, 255, 0), 2)
# 进行坐标堆叠
refCoords = np.vstack([refObj[0], refObj[1]])
objCoords = np.vstack([box, (cX, cY)])
# 遍历所有的坐标点
for ((xA, yA), (xB, yB), color) in zip(refCoords, objCoords, colors):
# 绘制点并连接为直线
cv2.circle(orig, (int(xA), int(yA)), 5, color, -1)
cv2.circle(orig, (int(xB), int(yB)), 5, color, -1)
cv2.line(orig, (int(xA), int(yA)), (int(xB), int(yB)), color, 2)
# 计算坐标之间的欧式距离并及进行距离转换
D = dist.euclidean((xA, yA), (xB, yB)) / refObj[2]
(mX, mY) = midpoint((xA, yA), (xB, yB))
cv2.putText(orig, "{:.1f}in".format(D), (int(mX), int(mY - 10)), cv2.FONT_HERSHEY_SIMPLEX, 0.55, color, 2)
# 显示结果
cv2.imshow("Image", orig)
cv2.waitKey(0)
python distance_between.py --image images/example_01.png --width 0.955
python distance_between.py --image images/example_02.png --width 0.955
python distance_between.py --image images/example_03.png --width 3.5
上图展示了不同图片的测试结果。通过上面的观察,我们可以获得一些有用的信息,即该算法可以准确的检测到不同的目标,并计算出参考目标和其它目标之间的距离,具体包括4个顶点和中心点之间的距离。通过以上的操作,我们就可以明确的知道图中各个目标之间的相对距离。
[1] 参考链接
[1] 该博客是本人原创博客,如果您对该博客感兴趣,想要转载该博客,请与我联系(qq邮箱:[email protected]),我会在第一时间回复大家,谢谢大家的关注.
[2] 由于个人能力有限,该博客可能存在很多的问题,希望大家能够提出改进意见。
[3] 如果您在阅读本博客时遇到不理解的地方,希望您可以联系我,我会及时的回复您,和您交流想法和意见,谢谢。
[4] 本文测试的图片可以通过该链接进行下载。网盘链接- 提取码:vd2t 。
[5] 本人业余时间承接各种本科毕设设计和各种小项目,包括图像处理(数据挖掘、机器学习、深度学习等)、matlab仿真、python算法及仿真等,有需要的请加QQ:1575262785详聊,备注“项目”!!!