import cv2 import numpy as np import os from tkinter import Tk from tkinter.filedialog import askopenfilename # 创建一个 Tkinter 根窗口 root = Tk() root.withdraw() # 打开文件对话框,选择图片文件 filename = askopenfilename(title='选择图片', filetypes=[('Image Files', ('*.jpg', '*.jpeg', '*.png', '*.bmp'))]) # 检查是否选择了文件 if filename: # 读取选中的图片文件 image = cv2.imread(filename) # 定义全局变量 points = [] completed = False extracted_image = None # 定义鼠标回调函数 def mouse_callback(event, x, y, flags, param): global points, completed, extracted_image if event == cv2.EVENT_LBUTTONDOWN: # 存储点击的坐标 points.append((x, y)) # 绘制已选择的点 cv2.circle(image, (x, y), 5, (0, 0, 255), -1) # 绘制连接的线段 if len(points) > 1: cv2.line(image, points[-2], points[-1], (0, 0, 255), 5) # 绘制最后一个点与第一个点的连线 if len(points) == 4: cv2.line(image, points[-1], points[0], (0, 0, 255), 5) completed = True # 创建窗口并注册鼠标回调函数 cv2.namedWindow('image') cv2.setMouseCallback('image', mouse_callback) while True: # 显示图像 cv2.imshow('image', image) # 按下 'Esc' 键退出循环 if cv2.waitKey(1) == 27: break # 检查是否成功获取四边形 if completed: # 创建与原图像大小相同的掩膜图像 mask = np.zeros_like(image[:, :, 0]) # 使用填充多边形函数将四边形区域设置为白色 cv2.fillPoly(mask, [np.array(points)], 255) # 将掩膜应用到原图像上,提取方框内的内容 extracted_image = cv2.bitwise_and(image, image, mask=mask) # 将方框外的像素值设置为0 extracted_image[np.where(extracted_image == 0)] = 0 # 显示提取的图像 cv2.imshow('extracted_image', extracted_image) # 获取文件名和扩展名 file_dir = os.path.dirname(filename) file_name = os.path.basename(filename) file_name, file_ext = os.path.splitext(file_name) # 构建新的文件名 extracted_image_file_name = os.path.join(file_dir, file_name + "_boundary" + file_ext) # 保存提取后的图像 cv2.imwrite(extracted_image_file_name, extracted_image) # 转换提取后的图像到 LAB 色彩空间 lab_image = cv2.cvtColor(extracted_image, cv2.COLOR_BGR2LAB) segmented_image = [] combined_image = [] # 定义鼠标事件回调函数 def mouse_callback1(event, x, y, flags, param): global segmented_image, combined_image if event == cv2.EVENT_LBUTTONDOWN: if combined_image[y, x, 0] == 0 and combined_image[y, x, 1] == 0 and combined_image[y, x, 2] == 0: # 创建临时变量用于处理连通域 segmented_image[y-8:y+8, x-8:x+8] = 255 colored_segmented_image = cv2.cvtColor(segmented_image, cv2.COLOR_GRAY2BGR) combined_image = cv2.bitwise_and(extracted_image, colored_segmented_image) cv2.imshow('segmented_image', combined_image) leaf_image_file_name = os.path.join(file_dir, file_name + "_leaf" + file_ext) cv2.imwrite(leaf_image_file_name, combined_image) nonzero_pixels_b = np.count_nonzero(extracted_image[:, :, 0]) nonzero_pixels_leaf = np.count_nonzero(combined_image[:, :, 0]) result_file = os.path.join(file_dir, file_name + "_result.txt") file = open(result_file, 'w') file.truncate(0) file.write('采样框像素点数为' + str(nonzero_pixels_b)) file.write('采样框内绿叶像素点数为' + str(nonzero_pixels_leaf)) file.close() # 定义滑动条的回调函数 def on_trackbar(value): global segmented_image global combined_image lower_th = cv2.getTrackbarPos('L', 'segmented_image') upper_th = cv2.getTrackbarPos('A', 'segmented_image') v_value = cv2.getTrackbarPos('B', 'segmented_image') # 根据滑动条的值创建阈值范围 lower = np.array([lower_th, upper_th, v_value], dtype=np.uint8) upper = np.array([255, 255, 255], dtype=np.uint8) # 对 LAB 图像进行阈值分割 segmented_image = cv2.inRange(lab_image, lower, upper) # 反转二值图像 segmented_image = cv2.bitwise_not(segmented_image) # 将二值图像转换为彩色图像 colored_segmented_image = cv2.cvtColor(segmented_image, cv2.COLOR_GRAY2BGR) # 进行位逻辑与操作,将彩色分割图像与提取图像进行合并 combined_image = cv2.bitwise_and(extracted_image, colored_segmented_image) # 显示合并后的图像 cv2.imshow('segmented_image', combined_image) leaf_image_file_name = os.path.join(file_dir, file_name + "_leaf" + file_ext) cv2.imwrite(leaf_image_file_name, combined_image) nonzero_pixels_b = np.count_nonzero(extracted_image[:, :, 0]) nonzero_pixels_leaf = np.count_nonzero(combined_image[:, :, 0]) result_file = os.path.join(file_dir, file_name + "_result.txt") file = open(result_file, 'w') file.truncate(0) file.write('采样框像素点数为' + str(nonzero_pixels_b)) file.write('采样框内绿叶像素点数为' + str(nonzero_pixels_leaf)) file.close() # 创建窗口用于显示分割结果 cv2.namedWindow('segmented_image') cv2.setMouseCallback('segmented_image', mouse_callback1) # 创建滑动条 cv2.createTrackbar('L', 'segmented_image', 0, 255, on_trackbar) cv2.createTrackbar('A', 'segmented_image', 0, 255, on_trackbar) cv2.createTrackbar('B', 'segmented_image', 0, 255, on_trackbar) # 初始化滑动条的值 cv2.setTrackbarPos('L', 'segmented_image', 0) cv2.setTrackbarPos('A', 'segmented_image', 115) cv2.setTrackbarPos('B', 'segmented_image', 0) while True: # 按下 'Esc' 键退出循环 if cv2.waitKey(1) == 27: break # 重置标志和列表,以便选择下一个方框 completed = False points.clear() # 退出循环 break # 释放窗口和销毁所有窗口 cv2.destroyAllWindows() else: print("未选择图像文件")