import cv2 import random import numpy as np from scipy.ndimage import label, distance_transform_edt ########################### 1. 超参数 ########################### Annotate_CLASSES = ('背景','术中超声','吻合器','乳胶管','推结器','肝带','钳夹','超声刀','脂肪','双极电凝','棉球','血管阻断夹','肿瘤','针','线','韧带','胆囊静脉','肝脏','胆囊','分离钳','止血海绵','肝总管','胆总管','吸引器','剪刀','止血纱布','生物夹','无损伤钳','喷洒','胆囊管','胆囊动脉','电凝','标本袋','引流管','纱布','金属钛夹') # 待分类的类 Annotate_PALETTE = [[0,0,0],[138,251,213],[136,162,196],[197,83,181],[202,202,200],[113,102,140],[66,115,82],[240,16,116],[155,132,0],[155,62,0],[146,175,236],[255,172,159],[245,161,0],[134,124,118], [0,157,142], [181,85,105], [42,8,66], [255,91,0],[255,234,0],[85, 107, 179],[181, 227, 14],[72, 0, 255],[0, 155, 33],[255,0,255],[29, 32, 136],[160, 15, 95],[0,160,233],[52,184,178],[90,120,41],[255,0,0],[177,0,0],[167,24,233],[112,113,150],[0,255,0],[255,255,255],[0,255,255]] def skeletonize(image): """骨架化函数,确保线条连通性并缩减为1像素宽""" skeleton = np.zeros_like(image) temp_image = np.copy(image) while True: eroded = cv2.erode(temp_image, None) # 腐蚀操作 temp_dilate = cv2.dilate(eroded, None) # 膨胀操作 temp = cv2.subtract(temp_image, temp_dilate) # 提取边缘 skeleton = cv2.bitwise_or(skeleton, temp) # 将边缘加入骨架 temp_image = np.copy(eroded) if cv2.countNonZero(temp_image) == 0: break return skeleton # 1. *** 边缘检测并膨胀 *** def edge_detection(image): """对图像的各个通道进行边缘检测并进行膨胀处理""" b_channel, g_channel, r_channel = cv2.split(image) gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) edges_b = cv2.Canny(b_channel, 100, 200) edges_g = cv2.Canny(g_channel, 100, 200) edges_r = cv2.Canny(r_channel, 100, 200) edges_gray = cv2.Canny(gray_image, 100, 200) # 合并所有边缘检测结果 edges = cv2.bitwise_or(edges_b, edges_g) edges = cv2.bitwise_or(edges, edges_r) edges = cv2.bitwise_or(edges, edges_gray) # 创建膨胀核并进行膨胀操作 kernel = np.ones((3, 3), np.uint8) dilated_image = cv2.dilate(edges, kernel, iterations=1) return dilated_image # 2. ** 检测连通区域 *** def detect_connected_regions(dilated_image): """检测图像中的连通区域并过滤掉小区域""" _, binary = cv2.threshold(dilated_image, 1, 255, cv2.THRESH_BINARY_INV) binary[binary > 0] = 1 # 转换为二值图像 # 标记连通区域 structure = np.ones((3, 3), dtype=int) labeled_array, num_features = label(binary, structure=structure) # 清除掉小于100像素的区域 filtered_labeled_array = np.copy(labeled_array) for label_num in range(1, num_features + 1): area = np.sum(labeled_array == label_num) if area < 100: filtered_labeled_array[filtered_labeled_array == label_num] = 0 # 重新标记过滤后的连通区域 filtered_labeled_array, num_features = label(filtered_labeled_array, structure=structure) return filtered_labeled_array, num_features # 返回过滤后的labeled_array和未过滤的labeled_array(用于寻找颜色) # 3. *** 分水岭填充白色区域 *** def fill_white_regions(filtered_labeled_array): """使用分水岭算法填充白色区域""" # 准备三通道图像作为分水岭算法的输入 color_image = np.zeros((filtered_labeled_array.shape[0], filtered_labeled_array.shape[1], 3), dtype=np.uint8) # 将过滤后的 labeled_array 转化为 32 位整型,作为分水岭的 markers markers = np.copy(filtered_labeled_array).astype(np.int32) markers[markers == 0] = -1 # 背景标记为 -1 # 执行分水岭算法 cv2.watershed(color_image, markers) # 更新分水岭结果 filled_labeled_array = markers.astype(int) filled_labeled_array[filled_labeled_array == -1] = 0 # 使用距离变换,计算边缘像素(0)最近的非零值 non_zero_mask = filled_labeled_array != 0 distance, nearest_indices = distance_transform_edt(non_zero_mask == 0, return_indices=True) nearest_values = filled_labeled_array[tuple(nearest_indices)] filled_labeled_array[filled_labeled_array == 0] = nearest_values[filled_labeled_array == 0] return filled_labeled_array # 4. *** 对连通区域上色(使用“filtered_labeled_array”作为颜色判断,给“filled_labeled_array”上色) *** def color_connected_regions(filled_labeled_array, filtered_labeled_array, ori_labeled_image, Annotate_PALETTE): """根据原始图像的颜色和注解调色板给连通区域上色""" # 初始化一个三通道的彩色图像 colored_image = np.zeros((*filled_labeled_array.shape, 3), dtype=np.uint8) # 遍历filtered_labeled_array中的每个标签 unique_labels = np.unique(filtered_labeled_array) for label_num in unique_labels: if label_num == 0: continue # 跳过背景标签 # 找到filtered_labeled_array中等于当前标签的区域 mask_filtered = (filtered_labeled_array == label_num) # 获取ori_labeled_image中对应区域的RGB值 region_rgb_values = ori_labeled_image[mask_filtered] if len(region_rgb_values) == 0: continue # 计算区域的RGB平均值 average_rgb = np.mean(region_rgb_values, axis=0) # 找到Annotate_PALETTE中与average_rgb最接近的颜色 closest_palette_color = find_closest_palette_color(average_rgb, Annotate_PALETTE) # 将该颜色赋给filled_labeled_array对应区域的元素 mask_filled = (filled_labeled_array == label_num) colored_image[mask_filled] = closest_palette_color return colored_image # 寻找最近邻颜色 def find_closest_palette_color(average_rgb, Annotate_PALETTE): """根据平均RGB值找到Annotate_PALETTE中最接近的颜色""" Annotate_PALETTE = [[color[2], color[1], color[0]] for color in Annotate_PALETTE] average_rgb = np.array(average_rgb) min_distance = float('inf') closest_color = None # 遍历调色板,计算每个颜色与平均RGB的欧几里得距离 for palette_color in Annotate_PALETTE: palette_color = np.array(palette_color) distance = np.linalg.norm(average_rgb - palette_color) # 欧几里得距离 if distance < min_distance: min_distance = distance closest_color = palette_color return closest_color # 5. 对Array区域上色(4的简化版) def Tool_color_connected_array(Array): colored_image = np.zeros((*Array.shape, 3), dtype=np.uint8) for label_num in range(1, np.max(Array) + 1): color = [np.random.randint(0, 254) for _ in range(3)] colored_image[Array == label_num] = color return colored_image if __name__ == '__main__': """超参数""" image_path = './2023_02_03_09_13_48.00_08_04_21.Still085.png' """主函数,处理图像并保存结果""" # 读取图像 image = cv2.imread(image_path) # 1. 边缘检测并膨胀 dilated_image = edge_detection(image) cv2.imwrite('./1_1_range_image.png', dilated_image) # 2. 检测连通区域 filtered_labeled_array, _ = detect_connected_regions(dilated_image) colored_image_filtered = Tool_color_connected_array(filtered_labeled_array) cv2.imwrite('./2_colored_image_filtered.png', colored_image_filtered) # 3. 分水岭填充白色区域 filled_labeled_array = fill_white_regions(filtered_labeled_array) colored_image_filled = Tool_color_connected_array(filled_labeled_array) cv2.imwrite('./3_colored_image_filled.png', colored_image_filled) # 4. 对连通区域上色 ori_labeled_image = image colored_image_final = color_connected_regions(filled_labeled_array, filtered_labeled_array, ori_labeled_image, Annotate_PALETTE) cv2.imwrite('./4_color_image_Final.png', colored_image_final) print("处理后的图片已保存。")