这是一个机器视觉调试程序,它允许您设置一些图像处理参数,如阈值和模糊核大小,并能对选择的图像进行处理和显示处理前后的效果。您还可以保存设置的参数和处理前后的图像。
一、开发环境准备
- 安装所需的库
- 在命令行中使用以下命令安装
tkinter
、opencv-python
和pillow
库:pip install tkinter opencv-python pillow
- 在命令行中使用以下命令安装
二、代码结构分析
-
导入所需的模块
import tkinter as tk import cv2 from tkinter import filedialog from PIL import Image, ImageTk
tkinter
用于创建图形用户界面。cv2
用于图像处理。filedialog
用于打开文件选择对话框。Image
和ImageTk
从pillow
库导入,用于图像格式转换和在tkinter
中显示图像。
-
VisionDebugger
类__init__
方法:初始化主窗口,创建参数设置的控件和框架,以及图像显示的框架。select_image
方法:处理选择图像的操作,读取图像并进行后续处理。process_image
方法:对图像进行灰度转换、模糊和阈值处理。show_images
方法:使用pillow
将处理后的图像转换为tkinter
支持的格式并显示在窗口中。save_parameters
方法:保存设置的参数到文本文件,并保存处理前后的图像。
-
run
方法- 启动主事件循环,使窗口保持可见并响应交互。
三、功能实现步骤
-
创建主窗口和参数设置区域
- 使用
tk.Tk
创建主窗口,并设置标题。 - 使用
tk.Frame
创建参数设置和图像显示的框架,并使用pack
方法布局。
- 使用
-
参数设置控件
- 使用
tk.IntVar
创建整数型变量来关联输入框的值。 - 创建标签和输入框,并将变量与输入框关联,设置默认值和提示信息。
- 使用
-
选择图像
- 使用
filedialog.askopenfilename
打开文件选择对话框获取图像路径。 - 使用
cv2.imread
读取图像,处理读取失败的情况。
- 使用
-
图像处理
- 根据图像的通道数进行灰度转换。
- 使用
cv2.GaussianBlur
进行模糊处理。 - 使用
cv2.threshold
进行阈值处理。
-
图像显示
- 使用
pillow
的Image.fromarray
将opencv
的图像格式转换为pillow
的格式。 - 再使用
ImageTk.PhotoImage
将pillow
格式转换为tkinter
支持的图像格式。 - 创建标签并显示图像,同时处理之前显示的图像的清除。
- 使用
-
保存参数和图像
- 使用
filedialog.asksaveasfilename
获取保存参数的文件路径。 - 将参数写入文本文件。
- 使用
cv2.imwrite
保存处理前后的图像。
- 使用
四、调试与优化
- 运行代码,检查是否能正常打开窗口、选择图像、处理和显示图像,以及保存参数和图像。
- 检查参数的上下限限制是否生效,输入超出范围的值时是否有正确的提示或处理。
- 优化图像显示的性能,例如只在必要时重新加载和显示图像。
五、程序代码
import tkinter as tk
import cv2
from tkinter import filedialog
from PIL import Image, ImageTk
class VisionDebugger:
def __init__(self):
self.root = tk.Tk()
self.root.title("机器视觉调试程序")
# 左侧:参数设置
self.param_frame = tk.Frame(self.root)
self.param_frame.pack(side=tk.LEFT, padx=10, pady=10)
# 调试参数
self.threshold_value = tk.IntVar(value=128)
self.blur_kernel_size = tk.IntVar(value=5)
# 参数设置标签和输入框
tk.Label(self.param_frame, text="阈值(0 - 255):").pack()
tk.Entry(self.param_frame, textvariable=self.threshold_value).pack()
tk.Label(self.param_frame, text="模糊核大小(奇数,3 - 15):").pack()
tk.Entry(self.param_frame, textvariable=self.blur_kernel_size).pack()
# 选择图片按钮
tk.Button(self.param_frame, text="选择图片", command=self.select_image).pack()
# 保存参数按钮
tk.Button(self.param_frame, text="保存参数", command=self.save_parameters).pack()
# 右侧:图像显示
self.image_frame = tk.Frame(self.root)
self.image_frame.pack(side=tk.RIGHT, padx=10, pady=10)
def select_image(self):
file_path = filedialog.askopenfilename()
if file_path:
self.original_image = cv2.imread(file_path, cv2.IMREAD_UNCHANGED)
if self.original_image is None:
print("无法读取图像,请检查文件路径是否正确")
return
self.process_image()
def process_image(self):
# 转换为灰度图像
if len(self.original_image.shape) == 3: # 如果是彩色图像
gray_image = cv2.cvtColor(self.original_image, cv2.COLOR_BGR2GRAY)
else: # 如果已经是灰度图像
gray_image = self.original_image
# 应用模糊
blurred_image = cv2.GaussianBlur(gray_image, (self.blur_kernel_size.get(), self.blur_kernel_size.get()), 0)
# 应用阈值
_, thresholded_image = cv2.threshold(blurred_image, self.threshold_value.get(), 255, cv2.THRESH_BINARY)
# 显示图像
self.show_images(thresholded_image)
def show_images(self, processed_image):
# 使用 PIL 转换为 Tkinter 支持的格式
original_image_pil = Image.fromarray(cv2.cvtColor(self.original_image, cv2.COLOR_BGR2RGB))
processed_image_pil = Image.fromarray(cv2.cvtColor(processed_image, cv2.COLOR_BGR2RGB))
original_photo = ImageTk.PhotoImage(original_image_pil)
processed_photo = ImageTk.PhotoImage(processed_image_pil)
# 清除之前的图像(如果有)
for widget in self.image_frame.winfo_children():
widget.destroy()
# 显示新的图像
tk.Label(self.image_frame, image=original_photo, text="原始图像", compound=tk.TOP).pack(side=tk.LEFT)
tk.Label(self.image_frame, image=processed_photo, text="处理后图像", compound=tk.TOP).pack(side=tk.RIGHT)
# 保持对图像对象的引用,防止被垃圾回收
self.original_photo_reference = original_photo
self.processed_photo_reference = processed_photo
def save_parameters(self):
save_path = filedialog.asksaveasfilename(defaultextension=".txt")
if save_path:
with open(save_path, 'w') as file:
file.write(f"Threshold: {self.threshold_value.get()}\n")
file.write(f"Blur Kernel Size: {self.blur_kernel_size.get()}\n")
original_save_path = os.path.splitext(save_path)[0] + "_original.jpg"
processed_save_path = os.path.splitext(save_path)[0] + "_processed.jpg"
cv2.imwrite(original_save_path, self.original_image)
cv2.imwrite(processed_save_path, cv2.cvtColor(cv2.imread(processed_save_path), cv2.COLOR_BGR2RGB))
def run(self):
self.root.mainloop()
if __name__ == "__main__":
debugger = VisionDebugger()
debugger.run()