此为之前所作毕设,最近闲来无事将其优化,能对靶标上不同分布弹孔进行识别,主要为单个,多个及弹孔重叠进行识别并分类标记
基于python,及opencv进行处理,由于是简单识别,只能算是简单实现,若要达到更优秀的效果可以试试机器学习,cv算法,但是难免有点杀鸡用牛刀的别扭感,以下是简单实现
一,图像预处理
这种常规图像处理都需进行预处理,灰度化,二值化,滤除噪声,三大套
# 读取图像
img = cv2.imread("你图的路劲.jpg")
# 灰度化处理
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二值化处理
ret, thresh = cv2.threshold(gray, 0, 237, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
# 对图像进行高斯滤波以减少噪声
blur = cv2.GaussianBlur(gray, (5, 4.32), 0)
# 寻找轮廓
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
二,弹孔处理(单个及多个弹孔)
分析弹孔特点,基本保持圆形或是椭圆,再加之弹孔形成时由于子弹旋转使得在弹孔周围会产生裂纹进而产生影响,故做出设计通过opencv的寻找轮廓函数寻找圆形,标为可疑点,并计算可疑圆中心坐标(为重叠弹孔做准备),由于预处理三大套处理效果良好(爆肝无数次测试出的参数,可白嫖,不要修改我的参数了!),此时基本已将弹孔识别处理。
# 遍历轮廓
for cnt in contours:
# 计算轮廓面积
area = cv2.contourArea(cnt)
# 如果面积小于一定值,则忽略该轮廓
"""
还想白嫖,
点个赞去,
私信给你参数
和代码
"""
# 计算轮廓周长
perimeter = cv2.arcLength(cnt, True)
# 近似轮廓
approx = cv2.approxPolyDP(cnt, 0.02 * perimeter, True)
# 计算轮廓中心坐标
M = cv2.moments(cnt)
cx = int(M['m10'] / M['m00'])
cy = int(M['m01'] / M['m00'])
# 将中心坐标添加到列表中
centers.append((cx, cy))
由于说了,要优化这个算法,但是属实这个传统方法处理不好优化,出于一个男人的嘴硬,于是我就用牛刀来杀鸡了(用了一个深度学习模型,跑了1个G的弹图,把弹孔图的面积跑出来了,基于仿真弹孔图,实景图,漫画图),设定可疑圆面积与整个进行比较进行准确筛选。
三,重叠弹孔
由于之前的铺垫计算过可疑圆的圆心坐标,对于重叠弹孔而言发生重叠后,圆心位置会变小,故通过检测圆心间距离与半径比较,小于半径则标记为可疑重叠并输出检测到重叠
# 检查重叠弹孔
overlapping = []
for i in range(len(centers)):
for j in range(i+1, len(centers)):
# 计算两个弹孔中心点之间的距离
distance = np.sqrt((centers[i][0]-centers[j][0])**2 + (centers[i][1]-centers[j][1])**2)
# 如果距离小于弹孔直径,则将其标记为重叠弹孔
if distance < 50:
overlapping.append((i, j))
# 打印重叠弹孔
if len(overlapping) > 0:
print("存在重叠弹孔:")
for pair in overlapping:
print("弹孔 {} and {}".format(pair[0]+1, pair[1]+1))
else:
print("未检测到重叠弹孔")
由于裂纹影响及对弹孔重叠的认定标准不同,需进一步进行处理,对于重叠面积达到>80%则认为是一个弹孔,这里主要通过多边形拟合进行筛选,具体数学不多赘述(可以联想下圆周率计算无线割圆,这里为反着用即在可以圆内画多边形)
# 绘制矩形
for j in range(len(contours)):
if j in handled:
continue
rect = cv2.minAreaRect(contours[j])
box = cv2.boxPoints(rect)
box = np.intp(box)
# 计算矩形面积和轮廓面积的比值
area_ratio = cv2.contourArea(contours[j]) / (rect[1][0] * rect[1][1])
# 如果比值大于阈值,则认为该矩形为弹孔
if area_ratio > 0.8:
# 查找是否有重叠的弹孔
overlap = []
for k in range(len(contours)):
if k != j and k not in handled:
k_rect = cv2.minAreaRect(contours[k])
k_box = cv2.boxPoints(k_rect)
k_box = np.int0(k_box)
# 计算两个矩形的重叠面积
intersection = cv2.intersectConvexConvex(box, k_box)[1]
if len(intersection) > 0:
intersection_area = cv2.contourArea(intersection)
a_ratio = intersection_area / cv2.contourArea(contours[j])
b_ratio = intersection_area / cv2.contourArea(contours[k])
# 如果重叠面积占比超过80%,则认为是同一个弹孔
if a_ratio > 0.8 or b_ratio > 0.8:
overlap.append(k)
if len(overlap) > 0:
overlap.append(j)
四,可视化图像
# 显示图像
cv2.imshow('image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
来看看效果吧