import cv2 import numpy as np import itertools import os import time import math # 设置输入输出文件夹路径 input_folder = "output10" # 输入文件夹 output_folder = "output12" # 输出文件夹 # 创建输出文件夹(如果不存在) os.makedirs(output_folder, exist_ok=True) start_time = time.time() import numpy as np def order_points(points, clockwise=True): """ 将四边形的四个点按顺时针或逆时针顺序排列。 :param points: 四边形的四个点 [(x1, y1), (x2, y2), (x3, y3), (x4, y4)] :param clockwise: 是否按顺时针排列,默认 True(顺时针),False(逆时针) :return: 排序后的点 """ # 计算质心 center = np.mean(points, axis=0) # 计算每个点相对于质心的角度 angles = [np.arctan2(point[1] - center[1], point[0] - center[0]) for point in points] # 按角度排序,顺时针(从大到小)或逆时针(从小到大) sorted_points = [point for _, point in sorted(zip(angles, points), reverse=clockwise)] return sorted_points def counter_order(contours): for contour in contours: # 计算轮廓的签名面积 area = cv2.contourArea(contour, oriented=True) # 如果面积是负值,说明轮廓是逆时针 return area > 0 def calculate_weight(points, non_transparent_area): contour = np.array(points, dtype=np.int32) area = cv2.contourArea(contour) if area / non_transparent_area < 0.8: return -1 edges = [np.linalg.norm(np.array(points[i]) - np.array(points[(i + 1) % 4])) for i in range(4)] max_edge, min_edge = max(edges), min(edges) if max_edge - min_edge > max_edge / 7: return -1 edge_similarity = 1 - (max_edge - min_edge) / max_edge angles = [] for i in range(4): v1 = np.array(points[(i + 1) % 4]) - np.array(points[i]) v2 = np.array(points[(i + 3) % 4]) - np.array(points[i]) cosine_angle = np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2)) angle = np.degrees(np.arccos(np.clip(cosine_angle, -1.0, 1.0))) angles.append(angle) if any(angle < 80 or angle > 100 for angle in angles): return -1 angle_similarity = 1 - sum(abs(angle - 90) for angle in angles) / 360 square_similarity = edge_similarity * angle_similarity return square_similarity * 0.4 + (area / non_transparent_area) * 0.6 def find_best_quadrilateral(corner_points, non_transparent_area): quadrilaterals = list(itertools.combinations(corner_points, 4)) best_quad = None max_weight = -1 for quad in quadrilaterals: quad = order_points(quad) weight = calculate_weight(quad, non_transparent_area) if weight > max_weight: max_weight = weight best_quad = quad return best_quad, max_weight def nearest_distance(x1, y1, x2, y2): distance = math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2) return distance < 2 def split_contours_into_segments(contour, quad): segments = [[],[],[],[]] segment_index = 0 flag = [True,True,True,True] offset = [] for point in contour: point = point[0] if flag[0] & nearest_distance(point[0], point[1], quad[0][0], quad[0][1]): segment_index += 1 flag[0] = False if flag[1] & nearest_distance(point[0], point[1], quad[1][0], quad[1][1]): segment_index += 1 flag[1] = False if flag[2] & nearest_distance(point[0], point[1], quad[2][0], quad[2][1]): segment_index += 1 flag[2] = False if flag[3] & nearest_distance(point[0], point[1], quad[3][0], quad[3][1]): segment_index += 1 flag[3] = False if segment_index >= 4: offset.append(point) else: segments[segment_index].append(point) segments[0] = offset + segments[0] return segments def process_image(image_path, save_path): image = cv2.imread(image_path, cv2.IMREAD_UNCHANGED) if image is None: print(f"无法加载图片: {image_path}") return alpha_channel = image[:, :, 3] non_transparent_area = np.count_nonzero(alpha_channel > 0) if non_transparent_area == 0: print(f"图片完全透明: {image_path}") return max_corners = 14 corners = cv2.goodFeaturesToTrack(alpha_channel, maxCorners=max_corners, qualityLevel=0.01, minDistance=15, blockSize=5) if corners is not None: corners = np.intp(corners) corner_points = [tuple(corner.ravel()) for corner in corners] best_quad, max_weight = find_best_quadrilateral(corner_points, non_transparent_area) if best_quad is None: print(f"未找到有效四边形: {image_path}") return output_image = cv2.cvtColor(image[:, :, :3], cv2.COLOR_BGR2RGB) for point in corner_points: cv2.circle(output_image, point, radius=3, color=(255, 0, 0), thickness=-1) #cv2.polylines(output_image, [np.array(best_quad, dtype=np.int32)], isClosed=True, color=(0, 255, 0), thickness=2) contours, _ = cv2.findContours(alpha_channel, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) for contour in contours: clockwise = counter_order(contours) best_quad = order_points(best_quad, clockwise) segments = split_contours_into_segments(contour, best_quad) colors = [(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 0)] for i, segment in enumerate(segments): if segment: cv2.polylines(output_image, [np.array(segment)], isClosed=False, color=colors[i], thickness=2) cv2.imwrite(save_path, cv2.cvtColor(output_image, cv2.COLOR_RGB2BGR)) else: print(f"未检测到角点: {image_path}") for filename in os.listdir(input_folder): if filename.lower().endswith((".png", ".jpg", ".jpeg")): input_path = os.path.join(input_folder, filename) output_path = os.path.join(output_folder, filename) process_image(input_path, output_path) end_time = time.time() print(f"处理图片的时间: {end_time - start_time:.4f} 秒") print(f"所有图片已处理完成,结果保存在: {output_folder}")