概述
在图像处理时,可能不可避免的需要计算图像中目标体的中心点,因而本片文章重点讲如何用传统图像处理方式来计算图像中目标体的中心。
方案
刚开始在考虑这个问题时其实也考虑了很多方法,比如找出物体最大坐标与最小坐标然后取平均值、直接求平均值等。这些方法比较容易想到但有一定的局限性,比如只能用在几何规则的图形上边,比如矩形、圆形等。但实际的目标体可能具有各种各样的形状,因而应用范围可能大大的受到限制。
最终在查阅相关资料后采用的方式是求边缘+对边缘求中心点。
具体思路如下:
- 首先计算出图像目标体的边缘,当前已经有许多成熟的计算方法,为了提高计算速度,我们在计算边缘时,只需要边缘点即可,具体的边缘轮廓并不需要。
- 求出边缘点之后,可以求出边缘点的中心距进而求出中心点的坐标。
结合我们工程上的实际应用场景:
我们在项目中需要计算的图片如下所示:
图片中有多个目标体,因而需要分不同的情况对多个目标体分别计算。
在计算的过程中为了减少其他目标体的干扰,会做一个像素替换工作,比如在计算主体时只保留主体的像素,其他像素都变成0。
然后求出主体的边缘,进而求出目标的中心。
在求目标的中心时,为了提高计算速度,我们使用了一个OpenCV求中心距的函数:moments()
中心矩
openCV提供moments()函数来计算图像的中心矩,最高计算到三阶
空间矩本质上是面积或者质量,因此可以通过一阶矩来计算中心:
代码
import imutils
import datetime
import cv2
import numpy as np
def getCenter(image, pixel):
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 灰度
gray = np.where(gray==pixel,240,0)
gray = np.asarray(gray,dtype='uint8')
blurred = cv2.medianBlur(gray,5,0)
# 在阈值图像中查找轮廓
cnts = cv2.findContours(blurred.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
# 找到白色对应的边界点的集合
cnts = imutils.grab_contours(cnts)
results = []
# 计算轮廓中心
for c in cnts:
M = cv2.moments(c)
# 防止出现除以0异常
if M["m00"] == 0:
continue
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
# 在图像上绘制形状的轮廓和中心
# cv2.drawContours(image, [c], -1, (0, 255, 0), 2)
# cv2.circle(image, (cX, cY), 3, (72, 61, 139), -1)
# cv2.putText(image, "center", (cX - 20, cY - 20),
# cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)
results.append([cX,cY])
return results
def getObjectCenter(image_path):
image = cv2.imread(image_path)
# 只考虑图片上有一架无人机
loadCenterList = getCenter(image,240)
roterCenterList = getCenter(image,80)
bodayCenterList = getCenter(image,160)
# 获取唯一负载
loadCenter = []
bodayCenter = []
if len(loadCenterList) >=1:
loadCenter = loadCenterList[len(loadCenterList) - 1]
cv2.circle(image, (loadCenter[0], loadCenter[1]), 5, (128, 225, 0), -1)
# 获取主体中心坐标(修正前)
if len(bodayCenterList) >=1:
bodayCenter = bodayCenterList[len(bodayCenterList) - 1]
# 画出主体坐标
if bodayCenter !=[]:
# 对坐标进行简单修正
if loadCenter != []:
bodayCenter[1] -= int((abs(loadCenter[1] - bodayCenter[1])) * 0.5)
cv2.circle(image, (bodayCenter[0], bodayCenter[1]), 5, (0, 225, 118), -1)
# 画出旋翼中心
for roterCenter in roterCenterList:
cv2.circle(image, (roterCenter[0], roterCenter[1]), 5, (168, 0, 108), -1)
return image