177 lines
7.1 KiB
Python
177 lines
7.1 KiB
Python
|
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("未选择图像文件")
|