'''
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @团队 : Safhels
# @时间 : 2024/4/9 0009 11:34
# @作者 : 林鹏程
# @文件名: page_auto_set_4_1.py
# @软件: PyCharm
'''
import cv2
import numpy as np
def is_point_in_polygon(mask, center):
# 确保 mask 是整型数组
mask_one = np.array(mask[0], dtype=np.int32)
# 计算mask的Bounding Box,提前判断是否在框内
x_min, y_min = np.min(mask_one, axis=0)
x_max, y_max = np.max(mask_one, axis=0)
# 进行简单的边界判断
if not (x_min <= center[0] <= x_max and y_min <= center[1] <= y_max):
return False
# 判断点是否在第一个区域内
in_first_region = cv2.pointPolygonTest(mask_one, center, False) >= 0
if len(mask) == 1:
return in_first_region
# 如果有多个区域,检查是否在其他区域内
for region in mask[1:]:
other_mask = np.array(region, dtype=np.int32)
if cv2.pointPolygonTest(other_mask, center, False) >= 0:
return False
return in_first_region
def calculate_distance(point1, point2):
return np.sqrt((point1[0] - point2[0])**2 + (point1[1] - point2[1])**2)
def image_detect(frame,config_area_current,currentback,kernal_erode,kernal_dilate,kernal_erode_2,min_area,max_area,adjust_threshold):
# 图像播放
feature = 3 # 选择要检测的特征,1表示检测中心点,3表示三点检测
mean_value = 0
number_detect = 0
frame_dec = frame.copy()
# 创建与原始图像相同大小的空白掩模
mask_roi = np.zeros_like(frame[:, :, 0], dtype=np.uint8)
config_area = list(config_area_current.values())
for mask_pts in config_area:
for mask in mask_pts:
if len(mask) == 1:
cv2.fillPoly(mask_roi, np.array([mask[0]], dtype=np.int32), 255)
else:
cv2.fillPoly(mask_roi, np.array([mask[0]], dtype=np.int32),255)
cv2.fillPoly(mask_roi, np.array(mask[1:], dtype=np.int32), 0)
frame_gray = cv2.cvtColor(frame_dec, cv2.COLOR_BGR2GRAY)
frame_threshold = cv2.threshold(frame_gray,adjust_threshold, 255, cv2.THRESH_BINARY)[1]
if currentback == 0: # 检测亮度低于背景的阈值
frame_threshold = cv2.threshold(frame_gray, adjust_threshold, 255, cv2.THRESH_BINARY_INV)[1]
frame_threshold = cv2.bitwise_and(frame_threshold, mask_roi)
# 对图像进行腐蚀和膨胀
kernel_erode_init = np.ones((3, 3), np.uint8)
frame_threshold = cv2.erode(frame_threshold, kernel_erode_init,iterations=kernal_erode)
frame_threshold = cv2.dilate(frame_threshold, kernel_erode_init,iterations=kernal_dilate)
frame_threshold = cv2.erode(frame_threshold, kernel_erode_init,iterations=kernal_erode_2)
# 寻找轮廓
contours, _ = cv2.findContours(frame_threshold, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours_news = [[] for i in range(len(config_area))]
contours_news_area = [[0] for i in range(len(config_area))]
center_all = [[] for i in range(len(config_area))]
#计算分析区
for contour in contours:
# 找到最大轮廓的凸包
M_cur = cv2.moments(contour)
area = cv2.contourArea(contour)
if area >= min_area and area <= max_area:
if M_cur["m00"] != 0:
cx = int(M_cur["m10"] / M_cur["m00"])
cy = int(M_cur["m01"] / M_cur["m00"])
center = (cx, cy)
else:
# 质心计算失败的情况
center = (0, 0)
for area_current in config_area:
for mask in area_current:
flag = is_point_in_polygon(mask, center)
if flag == True:
contours_news[config_area.index(area_current)].append(contour)
contours_news_area[config_area.index(area_current)].append(area)
center_all[config_area.index(area_current)].append(center)
contours_max = [max(contours_news_area[i]) for i in range(len(config_area))]
for cc in range(len(contours_news)):
if len(contours_news[cc]) >0:
for kk in range(len(contours_news[cc])):
contour = contours_news[cc][kk]
area = cv2.contourArea(contour)
if area >= min_area and area <= max_area :
# 绘制轮廓
if area == contours_max[cc]:
cv2.drawContours(frame_dec, [contour], -1, (0, 255, 255), thickness=cv2.FILLED)
# 找到最大轮廓的凸包
hull = cv2.convexHull(contour)
M = cv2.moments(contour)
if M['m00'] != 0:
center = (int(M['m10'] / M['m00']), int(M['m01'] / M['m00']))
else:
center = (0, 0)
cv2.circle(frame_dec, (int(center[0]), int(center[1])), 2, (0, 0, 255), thickness=cv2.FILLED)
number_detect +=1
mean_value += area
if feature == 3:
# 计算凸包上每两个点之间的距离
distances = []
for i in range(len(hull)):
for j in range(i + 1, len(hull)):
distance = np.linalg.norm(hull[i] - hull[j])
distances.append((i, j, distance))
# 找到距离最长的两个点
longest_distance = max(distances, key=lambda x: x[2])
point1_index, point2_index, max_distance = longest_distance
# 获取最长距离的两个点
point1 = tuple(hull[point1_index][0])
point2 = tuple(hull[point2_index][0])
if calculate_distance(point1, center) > calculate_distance(point2, center):
head_point = point1
tail_point = point2
else:
head_point = point2
tail_point = point1
head_around_point, tail_around_point = [], []
hull = cv2.convexHull(contour, returnPoints=False)
for i in range(len(hull)):
idx = hull[i][0]
if tuple(contour[idx][0]) == head_point:
p1 = idx - 1 if idx > 0 else len(contour) - 1
p2 = idx + 1 if idx < len(contour) - 1 else 0
head_around_point.append(tuple(contour[p1][0]))
head_around_point.append(tuple(contour[p2][0]))
if tuple(contour[idx][0]) == tail_point:
p1 = idx - 1 if idx > 0 else len(contour) - 1
p2 = idx + 1 if idx < len(contour) - 1 else 0
tail_around_point.append(tuple(contour[p1][0]))
tail_around_point.append(tuple(contour[p2][0]))
cv2.circle(frame_dec, (int(head_point[0]), int(head_point[1])), 2, (255, 0, 255), thickness=cv2.FILLED)
cv2.putText(frame_dec, "h", (int(head_point[0]), int(head_point[1])), cv2.FONT_HERSHEY_SIMPLEX, 0.5,
(255, 255, 255), 1)
cv2.circle(frame_dec, (int(tail_point[0]), int(tail_point[1])), 2, (255, 0, 0), thickness=cv2.FILLED)
cv2.putText(frame_dec, "t", (int(tail_point[0]), int(tail_point[1])), cv2.FONT_HERSHEY_SIMPLEX, 0.5,
(255, 255, 255), 1)
cv2.line(frame_dec, (int(head_point[0]), int(head_point[1])), (int(center[0]), int(center[1])), (255, 0, 0),
thickness=1)
for point in head_around_point:
rever_point_x = point[0]
rever_point_y = point[1]
if (head_point[0] - point[0]) == 0:
rever_point_x = head_point[0]
rever_point_y = head_point[1] - 12 * ((point[1] - head_point[1]) / abs(point[1] - head_point[1]))
else:
rate = (head_point[1] - point[1]) / (head_point[0] - point[0])
if head_point[0] - point[0] < 0:
rever_point_x = head_point[0] - (144 / (rate ** 2 + 1)) ** 0.5
else:
rever_point_x = head_point[0] + (144 / (rate ** 2 + 1)) ** 0.5
rever_point_y = head_point[1] + rate * (rever_point_x - head_point[0])
point = (int(rever_point_x), int(rever_point_y))
cv2.line(frame_dec, (int(head_point[0]), int(head_point[1])), point, (0, 255, 0), thickness=1)
else:
cv2.drawContours(frame_dec, [contour], -1, (0, 65, 255), thickness=cv2.FILLED)
if number_detect != len(config_area_current):
cv2.putText(frame_dec, "warning some area project error", (50,50),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
if number_detect !=0:
mean_value = int(mean_value / number_detect)
return frame_dec,mean_value
以上是后端算法部分,根据上述修改,完善算法部分