You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

969 lines
36 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import cv2
import numpy as np
import random
import tkinter
import tkinter as tk
import matplotlib.pyplot as plt
import albumentations as A
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from tkinter.messagebox import showinfo, showwarning
from tkinter import filedialog
from PIL import Image,ImageTk
from tkinter.filedialog import askopenfilename, askopenfilenames, asksaveasfilename, askdirectory
# ----------------------------------------------------------------------
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
picSize=400
img_open = None
img_result = None
img_empty = cv2.imread('data/image/OIP-C.jpg',0)
# ----------------------------------------------------------------------
# 几何变化类
# 水平翻转
def filp_h():
global img_open, img_gray, img_result
if img_open is None:
showwarning(title='警告', message='请先在文件菜单下打开图片!')
return
transform = A.HorizontalFlip(p=1)
img_result = transform(image=np.array(img_open))
img_result = img_result['image']
placePic2(img_result,'水平翻转后')
# 垂直翻转
def flip_v():
global img_open, img_gray, img_result
if img_open is None:
showwarning(title='警告', message='请先在文件菜单下打开图片!')
return
transform = A.VerticalFlip(p=1)
img_result = transform(image=np.array(img_open))
img_result = img_result['image']
placePic2(img_result,'垂直翻转后')
# 缩放
def resize():
global img_open, img_gray, img_result
if img_open is None:
showwarning(title='警告', message='请先在文件菜单下打开图片!')
return
paraLists = [["水平方向缩放后大小", 224], ["垂直方向缩放后大小", 224]]
paraW = paraWindow(root, "请设置水平和垂直方向的缩放尺寸", paraLists)
h = int(paraW.paraLists[0][1])
w = int(paraW.paraLists[1][1])
transform = A.Resize(h,w)
img_result = transform(image=np.array(img_open))
img_result = img_result['image']
placePic2(img_result,'缩放后')
# 旋转(可选择旋转角度)
def roate():
global img_open, img_gray, img_result
if img_open is None:
showwarning(title='警告', message='请先在文件菜单下打开图片!')
return
paraLists = [['请设置旋转角度',30]]
paraW = paraWindow(root, "旋转图片", paraLists)
angle = int(paraW.paraLists[0][1])
transform = A.Rotate(angle)
img_result = transform(image=np.array(img_open),p=1)
img_result = img_result['image']
placePic2(img_result,'旋转后')
# 裁剪裁剪方式centercrop、randomcrop和cutout
def Centercrop():
global img_open, img_gray, img_result
if img_open is None:
showwarning(title='警告', message='请先在文件菜单下打开图片!')
return
paraLists = [["水平方向裁剪后大小", 224], ["垂直方向裁剪后大小", 224]]
paraW = paraWindow(root, "请设置水平和垂直方向的裁剪后尺寸", paraLists)
h = int(paraW.paraLists[0][1])
w = int(paraW.paraLists[1][1])
transform = A.CenterCrop(h, w,p=1)
img_result = transform(image=np.array(img_open))
img_result = img_result['image']
placePic2(img_result,'中心裁剪后')
def Randomcrop():
global img_open, img_gray, img_result
if img_open is None:
showwarning(title='警告', message='请先在文件菜单下打开图片!')
return
paraLists = [["水平方向缩放后大小", 224], ["垂直方向缩放后大小", 224]]
paraW = paraWindow(root, "请设置水平和垂直方向的缩放尺寸", paraLists)
h = int(paraW.paraLists[0][1])
w = int(paraW.paraLists[1][1])
transform = A.RandomCrop(h, w,p=1)
img_result = transform(image=np.array(img_open))
img_result = img_result['image']
placePic2(img_result,'随机裁剪后')
# 反向裁剪(随机选择区域)
def cutout():
global img_open, img_gray, img_result
if img_open is None:
showwarning(title='警告', message='请先在文件菜单下打开图片!')
return
h,w,c = img_open.shape
# 后续是原图和mask相乘所以初始化为0
# 不需要裁剪的区域就不变裁剪的区域变成0
mask = np.ones_like(img_open)
print(mask)
x = np.random.randint(0,w)
y = np.random.randint(0,h)
paraLists = [['相对原图裁剪区域的大小', 0.2]]
paraW = paraWindow(root, "请设置具体参数", paraLists)
# p = int(paraW.paraLists[0][1])
s = float(paraW.paraLists[0][1])
w_cut = int(s*w)
h_cut = int(s*h)
x1 = max(x - w_cut // 2, 0) # 计算裁剪的左上角坐标
x2 = min(x1 + w_cut, w) # 计算裁剪的右下角坐标
y1 = max(y - h_cut // 2, 0)
y2 = min(y1 + h_cut, h)
mask[y1:y2, x1:x2, :] = 0 # 将裁剪区域内像素值置为 0
img_result = img_open * mask # 与原始图像按元素相乘,得到 Cutout 后的图像
print(img_result[y1:y2, x1:x2, :])
placePic2(img_result,text2='反向随机裁剪后')
# 对比度、饱和度、亮度、色调变化
def ColorJitter():
global img_open, img_gray, img_result
if img_open is None:
showwarning(title='警告', message='请先在文件菜单下打开图片!')
return
paraLists = [["亮度", 0], ["色调", 0],['对比度',0],['饱和度',0]]
paraW = paraWindow(root, "请设置具体参数", paraLists)
brightness = float(paraW.paraLists[0][1]) # 亮度
hue = float(paraW.paraLists[1][1]) # 色调
contrast = float(paraW.paraLists[2][1]) # 对比度
saturation = float(paraW.paraLists[3][1]) # 饱和度
transform = A.ColorJitter(brightness=brightness,hue=hue,saturation=saturation,contrast=contrast,p=1)
img_result = transform(image=np.array(img_open))
img_result = img_result['image']
placePic2(img_result)
# 转换成灰度图
def ToGray():
global img_open, img_gray, img_result
if img_open is None:
showwarning(title='警告', message='请先在文件菜单下打开图片!')
return
placePic2(img_gray,'灰度图')
# 通道分离
def split_channel():
global img_open, img_gray, img_result
if img_open is None:
showwarning(title='警告', message='请先在文件菜单下打开图片!')
return
''' 现在 的img_open 是RGB的'''
R,G,B = cv2.split(img_open)
paraLists = [['分离通道', 0]]
paraW = paraWindow(root, "012分别代表RGB", paraLists)
dict = {'0':R,'1':G,'2':B}
img_result = dict[str(int(paraW.paraLists[0][1]))]
placePic2(img_result,'分离通道后')
# 随机模糊
def Blur():
global img_open, img_gray, img_result
if img_open is None:
showwarning(title='警告', message='请先在文件菜单下打开图片!')
return
paraLists = [['模糊的次数',3]]
paraW = paraWindow(root, "请设置具体参数", paraLists)
count = int(paraW.paraLists[0][1])
transform = A.Blur(blur_limit=count,p=1)
img_result = transform(image=np.array(img_open))
img_result = img_result['image']
placePic2(img_result)
# 高斯滤波
def Gaussblur():
global img_open, img_gray, img_result
if img_open is None:
showwarning(title='警告', message='请先在文件菜单下打开图片!')
return
paraLists = [['模糊的次数', 3]]
paraW = paraWindow(root, "请设置具体参数", paraLists)
count = int(paraW.paraLists[0][1])
transform = A.GaussianBlur(blur_limit=count, p=1)
img_result = transform(image=np.array(img_open))
img_result = img_result['image']
placePic2(img_result,text2='经过高斯模糊后')
# 中值滤波
def Medianblur():
global img_open, img_gray, img_result
if img_open is None:
showwarning(title='警告', message='请先在文件菜单下打开图片!')
return
paraLists = [['模糊的次数', 3]]
paraW = paraWindow(root, "请设置具体参数", paraLists)
count = int(paraW.paraLists[0][1])
transform = A.MedianBlur(blur_limit=count, p=1)
img_result = transform(image=np.array(img_open))
img_result = img_result['image']
placePic2(img_result,text2='经过中值滤波后')
# 添加高斯噪声
def add_gaussian_noise():
global img_open, img_gray, img_result
if img_open is None:
showwarning(title='警告', message='请先在文件菜单下打开图片!')
return
paraLists = [['请输入均值', 0],['请输入标准差',30]]
paraW = paraWindow(root, "请设置具体参数", paraLists)
mean = int(paraW.paraLists[0][1])
sigma = int(paraW.paraLists[1][1])
# 生成高斯噪声矩阵
row, col, ch = img_open.shape
gaussian = np.random.randn(row, col, ch) * sigma + mean
gaussian = gaussian.reshape(row, col, ch)
img_result = img_open + gaussian
# 转换数据类型为8位无符号整数类型
img_result = cv2.convertScaleAbs(img_result)
placePic2(img_result,text2='添加高斯噪声后')
# 添加椒盐噪声
def add_salt_and_pepper_noise():
global img_open, img_gray, img_result
if img_open is None:
showwarning(title='警告', message='请先在文件菜单下打开图片!')
return
paraLists = [['百分比', 0]]
paraW = paraWindow(root, "请设置具体参数", paraLists)
percentage = int(paraW.paraLists[0][1])
# 确保百分比在 0 到 100 之间
if percentage < 0 or percentage > 100:
showwarning(title='警告', message='百分比必须在 0 到 100 之间!')
return
# 生成椒盐噪声矩阵
row, col, ch = img_open.shape
noise = np.zeros((row, col, ch), np.uint8)
for i in range(row):
for j in range(col):
rand = np.random.randint(0, 100)
if rand < percentage:
noise[i][j] = [0, 0, 0]
elif rand > 100 - percentage:
noise[i][j] = [255, 255, 255]
else:
noise[i][j] = img_open[i][j]
# 将椒盐噪声矩阵添加到原始图像中
img_result = cv2.add(img_open, noise)
placePic2(img_result,text2='添加椒盐噪声后')
# 添加均值噪声
def add_mean_noise():
global img_open, img_gray, img_result
if img_open is None:
showwarning(title='警告', message='请先在文件菜单下打开图片!')
return
paraLists = [['均值', 0], ['标准差', 30]]
paraW = paraWindow(root, "请设置具体参数", paraLists)
mean = int(paraW.paraLists[0][1])
std_dev = int(paraW.paraLists[1][1])
# 生成均值噪声矩阵
row, col, ch = img_open.shape
noise = np.random.normal(mean, std_dev, (row, col, ch)).astype(np.uint8)
# 将均值噪声矩阵添加到原始图像中
img_result = cv2.add(img_open, noise)
placePic2(img_result,text2='添加均值噪声后')
# 使用sobel算子进行锐化
def sobel():
global img_open, img_gray, img_result
if img_open is None:
showwarning(title='警告', message='请先在文件菜单下打开图片!')
return
kernelx1 = np.array([[-1,-2,-1],[0,0,0],[1,2,1]], dtype=int)
kernely1 = np.array([[-1,0,1],[-2,0,2],[-1,0,1]], dtype=int)
x1 = cv2.filter2D(img_gray, cv2.CV_16S, kernelx1)
y1 = cv2.filter2D(img_gray, cv2.CV_16S, kernely1)
absX1 = cv2.convertScaleAbs(x1)
absY1 = cv2.convertScaleAbs(y1)
img_result = cv2.addWeighted(absX1, 0.5, absY1, 0.5, 0)
placePic2(img_result)
# 使用Prewitt算子进行锐化
def Prewitt():
global img_open, img_gray, img_result
if img_open is None:
showwarning(title='警告', message='请先在文件菜单下打开图片!')
return
kernelx1 = np.array([[-1,0,1],[-1,0,1],[-1,0,1]], dtype=int)
kernely1 = np.array([[-1,-1,1],[0,0,0],[1,1,1]], dtype=int)
x1 = cv2.filter2D(img_gray, cv2.CV_16S, kernelx1)
y1 = cv2.filter2D(img_gray, cv2.CV_16S, kernely1)
absX1 = cv2.convertScaleAbs(x1)
absY1 = cv2.convertScaleAbs(y1)
img_result = cv2.addWeighted(absX1, 0.5, absY1, 0.5, 0)
placePic2(img_result)
# 使用robert算子进行锐化
def robert():
global img_open, img_gray, img_result
if img_open is None:
showwarning(title='警告', message='请先在文件菜单下打开图片!')
return
kernelx1 = np.array([[-1, 0], [0, 1]], dtype=int)
kernely1 = np.array([[0, -1], [1, 0]], dtype=int)
x1 = cv2.filter2D(img_gray, cv2.CV_16S, kernelx1)
y1 = cv2.filter2D(img_gray, cv2.CV_16S, kernely1)
absX1 = cv2.convertScaleAbs(x1)
absY1 = cv2.convertScaleAbs(y1)
img_result = cv2.addWeighted(absX1, 0.5, absY1, 0.5, 0)
placePic2(img_result)
# 直方图均衡化
def equalhist():
global img_open, img_gray, img_result
if img_open is None:
showwarning(title='警告', message='请先在文件菜单下打开图片!')
return
# 说明是灰度图像
if len(img_open)==2:
img_result = cv2.equalizeHist(img_open)
# RGB图像分别对每个通道都均衡化 然后在 合并
else:
b,g,r = cv2.split(img_open)
b_eq = cv2.equalizeHist(b)
g_eq = cv2.equalizeHist(g)
r_eq = cv2.equalizeHist(r)
img_result = cv2.merge([b_eq,g_eq,r_eq])
placePic2(img_result)
# 叠加图片操作
def mixup():
global img_open, img_gray, img_result
if img_open is None:
showwarning(title='警告', message='请先在文件菜单下打开图片!')
return
img_show1 = img_open
# 读取另一张图片
path = askopenfilename(title='打开另一张图片')
if path!=0 and path!='':
img_show2 = cv_imread(path)
if img_show2 is not None:
placePic2(img_show2)
else:
placePic2(img_empty)
showwarning(title='警告',message='请打开第二张图片')
# 下面进行mixup操作
paraLists = [['请输入一张图片所占比列', 0.5]]
paraW = paraWindow(root, "请设置具体参数", paraLists)
# 判断两张图片的shape 是否相同 不相同则都取小的那边
if img_show1.shape[:-1]!=img_show2.shape[:-1]:
showwarning(title='警告',message='两张图片大小不一样,会自动做裁剪使大小相同')
if img_show1.shape[0] > img_show2.shape[0]:
h = img_show2.shape[0]
else:
h = img_show1.shape[0]
if img_show1.shape[1] > img_show2.shape[1]:
w = img_show2.shape[1]
else:
w = img_show1.shape[1]
img_show1 = cv2.resize(img_show1,(h,w))
img_show2 = cv2.resize(img_show2,(h,w))
# 判断图片的channel是否相同如果不相同 在全部转换为 RGB的
if len(img_show1)==2:
img_show1 = cv2.cvtColor(img_show1,cv2.COLOR_GRAY2RGB)
if len(img_show2)==2:
img_show2 = cv2.cvtColor(img_show1,cv2.COLOR_GRAY2RGB)
alpha = float(paraW.paraLists[0][1])
print(alpha)
# 这个方法需要两张图片的大小相同 需要做个resize操作
img_result = cv2.addWeighted(img_show1,alpha,img_show2,1-alpha,0)
cv_show('after mixup',img_result)
# ----------------------------------------------------------------------
def cv_show(name,img):
# 打开文件后会有img_open,img_gray的信息img_result指进行操作后的可视化结果
# 图片很大时需要进行resize
h,w = img.shape[:2]
if h>1000 or w>1000:
img = cv2.resize(img,dsize=None,fx=0.8,fy=0.8)
cv2.imshow(name,img)
cv2.waitKey(0)
cv2.destroyAllWindows()
def cv_imread(filename,colorMode=cv2.IMREAD_COLOR):
# 读取文件路径中带汉字的图片,替代cv2.imread(filename)
# :param filename: 需要读取的文件
# :param colorMode: 彩色模式
# :return: 读取的图片
return cv2.imdecode(np.fromfile(filename, dtype=np.uint8), colorMode)
def cv_imwrite(path, img):
# 解决路径中有汉字的图片保存问题
# :param path: 保存的路径
# :param img: 保存的图片
cv2.imencode('.jpg', img)[1].tofile(path)
def placePic1(img_show, text1="原始图像"):
# 将打开的初始图像放置在左边窗格
# :param img_show: 需要显示的图片
# :param text1: 图片说明
global picSize
if img_show is None:
showwarning(title='警告', message='未打开图片!')
return
img = img_show.copy()
if len(img.shape) > 2:
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
height, width = img.shape[:2]
scaling = max(width, height) / picSize
newH = int(height / scaling)
newW = int(width / scaling)
img0 = Image.fromarray(img) # 由OpenCV图片转换为PIL图片格式
img0 = img0.resize((newW, newH))
img0 = ImageTk.PhotoImage(img0)
myWindow.originalText.set(text1)
myWindow.label3.config(image=img0)
myWindow.label3.image = img0
myWindow.label3.place(relx=0.25, rely=0.40, width=picSize, height=picSize, anchor=tkinter.CENTER) # 设置绝对座标
def placePic2(img_show, text2="处理结果图", RGB=True):
# 将处理结果图像放置在右边窗格
# :param img_show: 需要显示的图像
# :param text2: 图像文字说明
# :param RGB: 是否转换成RGB,默认转换
global picSize, img_result
if img_show is None:
showwarning(title='警告', message='没有结果图片!')
return
img = img_show.copy()
if len(img.shape) > 2 and RGB:
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
height, width = img.shape[:2]
# img = PointProcessing.global_linear_transmation(img)
scaling = max(width, height) / picSize
newH = int(height / scaling)
newW = int(width / scaling)
img0 = Image.fromarray(img) # 由OpenCV图片转换为PIL图片格式
img0 = img0.resize((newW, newH))
img0 = ImageTk.PhotoImage(img0)
myWindow.resultText.set(text2)
myWindow.label4.config(image=img0)
myWindow.label4.image = img0 # 通过标签来显示图片使用ImageTK把img转成tk可以接收的形式
myWindow.label4.place(relx=0.75, rely=0.40, width=picSize, height=picSize, anchor=tkinter.CENTER)
def Choosepic():
# 打开文件选择对话框并读取图片文件存放在img_open全局变量中
global picSize, path_, img_open, img_gray, img_empty
path_ = askopenfilename(title="打开需要处理的图片")
# path.set(path_)
if path_ != 0 and path_ != '':
img_open = cv_imread(path_) # 读取文件路径中有汉字的图片文件读取的是RGB图像
img_gray = cv2.cvtColor(img_open,cv2.COLOR_BGR2GRAY)
if img_open is not None:
placePic1(img_open)
else:
placePic1(img_empty)
showwarning(title='警告', message='无图片!')
else:
img_open = None
img_gray = None
placePic1(img_empty)
showwarning(title='警告', message='未选择图片!')
def Savepic():
# 打开文件对话框将img_result图片保存到指定文件
global img_result
if img_result is not None:
fname = asksaveasfilename(title='保存文件', defaultextension='default.jpg',filetypes=[("JPG", ".jpg")])
if fname:
cv_imwrite(str(fname), img_result)
showinfo(title='提示', message='图片已保存!')
else:
showwarning(title='警告', message='请先输入文件名!')
else:
showwarning(title='警告', message='请先处理图片!')
def initWindows():
# 将系统界面恢复到初始界面,并不清除结果图片
myWindow.setVisibleLeft()
myWindow.setVisibleRight0()
myWindow.hideFig0()
myWindow.hideFig1()
if img_result is not None:
placePic2(img_result)
class ImageApp:
global picSize
def __init__(self, master):
self.master = master
self.master.title("图像多功能增强可视化窗口")
# 界面布局
self.init_menu(self.master) # 初始化菜单
self.init_widget(self.master) # 初始化需要用的控件(两个画布)
self.setVisibleLeft() # 显示左窗格
self.setVisibleRight0() # 显示右窗格
self.hideFig0() # 隐藏左窗格的画布myCanvas0
self.hideFig1() # 隐藏右窗格的画布myCanvas1
def init_widget(self, master):
self.originalText = tkinter.StringVar()
self.label1 = tkinter.Label(master, textvariable=self.originalText, font=("song", 12))
self.originalText.set("原始图像")
self.label3 = tkinter.Label(master, bg='gray86') # 用于显示原始图像,背景颜色设置成灰色
self.resultText = tkinter.StringVar()
self.label2 = tkinter.Label(master, textvariable=self.resultText, font=("song", 12))
self.resultText.set("处理结果图")
self.label4 = tkinter.Label(master, bg='gray86') # 用于显示处理结果,背景颜色设置成灰色
self.explainText = tkinter.StringVar()
self.myFig0 = plt.figure(figsize=(4, 4), facecolor='#dddddd')
self.myCanvas0 = FigureCanvasTkAgg(self.myFig0, master)
# myfig1在下边窗格的画布中显示多张包含图片的注释说明
self.myFig1 = plt.figure(figsize=(9, 1.8), facecolor='lightgray')
# myfig2在下边窗格中显示说明与单张图片
self.myFig2 = plt.figure(figsize=(4.5, 1.8), facecolor='lightgray')
self.myCanvas1 = FigureCanvasTkAgg(self.myFig1, master)
self.myCanvas2 = FigureCanvasTkAgg(self.myFig2, master)
def init_menu(self,master):
# 创建菜单和其内容
menubar = tk.Menu(master) # 创建菜单对象
# 创建菜单内容 后面加command 可以创建子菜单 到时候看看需不需要
fmenu_file = tk.Menu(master) # 文件
fmenu_file.add_command(label='打开',command=Choosepic)
fmenu_file.add_command(label='保存处理结果', command=Savepic)
fmenu_file.add_separator() # 添加一条分隔线
fmenu_file.add_command(label='退出',command=quit)
# 几何变换
fmenu_geo = tk.Menu(master)
fmenu_geo.add_command(label='水平翻转', command=filp_h)
fmenu_geo.add_command(label='垂直翻转', command=flip_v)
fmenu_geo.add_command(label='旋转', command=roate)
fmenu_geo.add_command(label='缩放', command=resize)
# 给裁剪菜单再次创建子菜单
submenu_crop = tk.Menu(fmenu_geo)
fmenu_geo.add_cascade(label='裁剪',menu=submenu_crop)
submenu_crop.add_command(label='中心裁剪',command=Centercrop)
submenu_crop.add_command(label='随机裁剪', command=Randomcrop)
submenu_crop.add_command(label='反向随机裁剪', command=cutout)
# 颜色空间变换
fmenu_sp = tk.Menu(master)
fmenu_sp.add_command(label='对比度变换',command=ColorJitter)
fmenu_sp.add_command(label='亮度变换', command=ColorJitter)
fmenu_sp.add_command(label='饱和度变换', command=ColorJitter)
fmenu_sp.add_command(label='色调',command=ColorJitter)
fmenu_sp.add_command(label='通道分离', command=split_channel)
fmenu_sp.add_command(label='灰度图', command=ToGray)
fmenu_sp.add_command(label='直方图均衡化', command=equalhist)
# 像素点操作
fmenu_pix = tk.Menu(master) # 创建像素点操作的主菜单
submenu_blur = tk.Menu(fmenu_pix) # 模糊子菜单
fmenu_pix.add_cascade(label='模糊',menu=submenu_blur) # 把模糊子菜单加到模糊下面
# 给模糊子菜单加子菜单
submenu_blur.add_command(label='高斯滤波',command=Gaussblur)
submenu_blur.add_command(label='随机模糊', command=Blur)
submenu_blur.add_command(label='中值滤波', command=Medianblur)
submenu_sh = tk.Menu(fmenu_pix)
fmenu_pix.add_cascade(label='锐化',menu=submenu_sh)
# 给锐化加子菜单
submenu_sh.add_command(label='robort算子',command=robert)
submenu_sh.add_command(label='Prewitt算子',command=Prewitt)
submenu_sh.add_command(label='Sobel算子',command=sobel)
submenu_noise = tk.Menu(fmenu_pix)
fmenu_pix.add_cascade(label='添加噪声',menu=submenu_noise)
# 给添加噪声加子菜单
submenu_noise.add_command(label='高斯噪声',command=add_gaussian_noise)
submenu_noise.add_command(label='椒盐噪声',command=add_salt_and_pepper_noise)
submenu_noise.add_command(label='均值噪声',command=add_mean_noise)
# 基于多张图片
fmenu_mul = tk.Menu(master)
fmenu_mul.add_command(label='mixup',command=mixup)
# 将菜单内容 添加到menubar
menubar.add_cascade(label="文件", menu=fmenu_file)
menubar.add_cascade(label="几何变化", menu=fmenu_geo)
menubar.add_cascade(label="颜色空间变换", menu=fmenu_sp)
menubar.add_cascade(label="频域像素点操作", menu=fmenu_pix)
menubar.add_cascade(label='基于多张图片',menu=fmenu_mul)
# 整体显示
master.config(menu=menubar)
def setVisibleLeft(self):
# label1是文字label3目前是空只是占了位置且背景颜色是灰色需要放图片
self.label1.place(relx=0.25, rely=0.04, anchor=tkinter.CENTER) # 设置相对座标
self.label3.place(relx=0.25, rely=0.40, width=picSize, height=picSize,anchor=tkinter.CENTER) # 设置绝对座标
def setVisibleRight0(self):
# 右边窗格重叠的显示之一right0
# right0一般算法结果显示窗格
# right1-用于显示车牌识别结果
# myFig0-使用mayplot显示运行结果图片
# label2 是文字label4目前是空只是占了位置 且背景颜色是灰色,需要放图片
self.label2.place(relx=0.75, rely=0.04, anchor=tkinter.CENTER)
self.label4.place(relx=0.75, rely=0.40, width=picSize, height=picSize,anchor=tkinter.CENTER)
def setVisibleBottom(self):
# 下边窗格的重叠显示之一label5)
# label5-仅显示文字说明
# myFig1-用matplot显示多个文字图片
# explain-左边是label5,右边是myFig2
self.label5.place(relx=0.50, rely=0.86, width=900, height=180,anchor=tkinter.CENTER)
self.hideFig1()
self.hideExplain()
def hideFig0(self):
self.myCanvas0.get_tk_widget().place_forget() # 隐藏画布self
def hideFig1(self):
self.myCanvas1.get_tk_widget().place_forget() # 隐藏画布self
def hideExplain(self):
self.label5.config(wraplength=850)
self.myCanvas2.get_tk_widget().place_forget() # 隐藏画布self暂时隐藏用的时候可以用place方法恢复
# 有的功能还需要选择具体参数,这个时候需要弹出一个小窗口给参数,并获取这些参数值,给具体的变化
# ----------------------------------------------------------------------
class paraWindow(tkinter.Toplevel):
# 多行一列的参数设置窗口
def __init__(self, root, title = None, paraLists=[]):
# Constructor
self.root = root
self.paraLists=paraLists
self.names = locals() #动态组件
tkinter.Toplevel.__init__(self,root)
if title:
self.title(title)
# 创建对话框的主体内容
frame = tkinter.Frame(self)
# 调用init_widgets方法来初始化对话框界面
self.initial_focus = self.init_widgets(frame)
frame.pack(padx=5, pady=5)
# 根据modal选项设置是否为模式对话框
self.grab_set() #重要,必须是模式对话框
# 为"WM_DELETE_WINDOW"协议使用self.cancel_click事件处理方法
self.protocol("WM_DELETE_WINDOW", self.cancel_click)
# 根据父窗口来设置对话框的位置
self.geometry("+%d+%d" % (root.winfo_rootx() + 100, root.winfo_rooty() + 100))
# 让对话框获取焦点
self.initial_focus.focus_set()
self.wait_window(self)
def init_widgets(self,master):
# 创建自定义对话框的内容
nrow=0
for i in range(len(self.paraLists)):
str0 = self.paraLists[i][0]
nrow = i + 1
labelMessage = tkinter.Label(master, text=str0, font=("song", 12))
labelMessage.grid(row=nrow, column=0)
self.names['paraV' + str(i)] = tkinter.StringVar()
self.names['paraE' + str(i)] = tkinter.Entry(master, textvariable=self.names['paraV' + str(i)], width=20)
self.names['paraV' + str(i)].set(self.paraLists[i][1])
self.names['paraE' + str(i)].grid(row=nrow, column=1) # 控件按列排列
b1 = tkinter.Button(master, text='确定退出', command=self.setPara)
b1.grid(row=nrow + 1, column=1)
self.bind("<Return>", self.setPara)
self.bind("<Escape>", self.cancel_click)
return self.names['paraE0']
def cancel_click(self, event=None):
showwarning(title='警告', message='必须先设置参数')
self.initial_focus.focus_set()
def setPara(self):
# 通过对话框设置参数
for i in range(len(self.paraLists)):
text0 = self.names['paraV' + str(i)].get()
if not self.on_validate(text0): # 如果不能通过校验,让用户重新输入
showwarning(title='警告', message='必须输入数字')
self.names['paraV' + str(i)].set(self.paraLists[i][1])
self.names['paraE'+ str(i)].focus_set()
return
else:
self.paraLists[i][1] = float(text0)
self.hide()
def on_validate(self,content):
# 该方法可对用户输入的数据进行校验,保证输入的是数字
for i in range(len(content) - 1, -1, -1):
if not (48 <= ord(content[i]) <= 57 or content[i] == "." or content[i] =="+" or content[i] =="-" ):
return False
return True
def hide(self):
# 销毁对话框
self.withdraw()
self.update_idletasks()
# 将焦点返回给父窗口
self.root.focus_set()
# 销毁自己
self.destroy()
self.root.update()
self.root.deiconify()
self.root.focus_set()
class paraWindow2(tkinter.Toplevel):
# 多行多列参数设置窗口
def __init__(self, root, paraLists,title,explain):
# Constructor
self.root = root
self.names=locals()
self.paraLists=paraLists
self.explain=explain
tkinter.Toplevel.__init__(self,root)
# self.geometry("400x300")
self.title(title)
# 调用init_widgets方法来初始化对话框界面
self.initial_focus = self.init_widgets()
# 根据modal选项设置是否为模式对话框
self.grab_set()
# 为"WM_DELETE_WINDOW"协议使用self.cancel_click事件处理方法
self.protocol("WM_DELETE_WINDOW", self.cancel_click)
# 根据父窗口来设置对话框的位置
self.geometry("+%d+%d" % (root.winfo_rootx() + 100, root.winfo_rooty() + 100))
# print(self.initial_focus)
# 让对话框获取焦点
self.initial_focus.focus_set()
self.wait_window(self)
def init_widgets(self):
frame1 = tkinter.Frame(self)
explainLabel = tkinter.Label(frame1, text=self.explain, font=("song", 12))
explainLabel.pack(padx=50, pady=5)
frame1.pack(padx=5, pady=5)
frame2 = tkinter.Frame(self)
nrow=1
for i in range(len(self.paraLists)):
nrow = i + 3
for j in range(len(self.paraLists[i])):
self.names['ev' + str(i) + str(j)] = tkinter.StringVar()
self.names['e' + str(i) + str(j)] = tkinter.Entry(frame2, textvariable=self.names['ev' + str(i) + str(j)],width=10)
self.names['ev' + str(i) + str(j)].set(self.paraLists[i][j])
self.names['e' + str(i) + str(j)].grid(row=nrow, column=j)
b1 = tkinter.Button(frame2, text='确定退出', command=self.setPara)
b1.grid(row=nrow + 1, column=1)
frame2.pack(padx=5, pady=6)
return b1
def setPara(self):
# 通过对话框给参数赋值
for i in range(len(self.paraLists)):
for j in range(len(self.paraLists[i])):
text0 = self.names['ev' + str(i) + str(j)].get()
if not self.on_validate(text0): # 如果不能通过校验,让用户重新输入
showwarning(title='警告', message='必须输入数字')
self.names['ev' + str(i) + str(j)].set(self.paraLists[i][j])
self.names['e' + str(i) + str(j)].focus_set()
return
else:
self.paraLists[i][j] = float(text0)
self.hide()
def on_validate(self,content):
# 该方法可对用户输入的数据进行校验,保证输入的是数字
for i in range(len(content) - 1, -1, -1):
if not (48 <= ord(content[i]) <= 57 or content[i] == "." or content[i] == "+" or content[i] == "-"):
return False
return True
def cancel_click(self, event=None):
showwarning(title='警告', message='必须先设置参数')
self.initial_focus.focus_set()
def hide(self):
self.withdraw()
self.update_idletasks()
# 将焦点返回给父窗口
self.root.focus_set()
# 销毁自己
self.destroy()
self.root.update()
self.root.deiconify()
self.root.focus_set()
class listWindow(tkinter.Toplevel):
# 下拉列表窗口,用对参数设置
def __init__(self, root, title = None, paraLists=[]):
# Constructor
self.root = root
self.paraLists=paraLists
tkinter.Toplevel.__init__(self,root)
if title:
self.title(title)
# 创建对话框的主体内容
# 调用init_widgets方法来初始化对话框界面
self.initial_focus = self.init_widgets(self)
# 根据modal选项设置是否为模式对话框
self.grab_set()
# 为"WM_DELETE_WINDOW"协议使用self.cancel_click事件处理方法
self.protocol("WM_DELETE_WINDOW", self.cancel_click)
# 根据父窗口来设置对话框的位置
self.geometry("+%d+%d" % (root.winfo_rootx() + 100, root.winfo_rooty() + 100))
# print(self.initial_focus)
# 让对话框获取焦点
self.initial_focus.focus_set()
self.wait_window(self)
def init_widgets(self,master):
str0 = self.paraLists[0][0]
labelMessage = tkinter.Label(master, text=self.paraLists[0][0], font=("song", 12))
labelMessage.grid(row=0, column=0)
self.listBox = tkinter.Listbox(master,selectmode=tkinter.SINGLE)
self.listBox.grid(row=1, column=0)
lists=self.paraLists[0][1]
for item in lists:
self.listBox.insert(tkinter.END, item)
self.listBox.select_set(0)
b1 = tkinter.Button(master, text='确定退出', command=self.setPara)
b1.grid(row=2, column=0)
self.bind("<Return>", self.setPara)
self.bind("<Escape>", self.cancel_click)
return self.listBox
def cancel_click(self, event=None):
showwarning(title='警告', message='必须先设置参数')
self.initial_focus.focus_set()
def setPara(self):
self.returnValue=self.listBox.curselection()[0]
self.hide()
def hide(self):
self.withdraw()
self.update_idletasks()
# 将焦点返回给父窗口
self.root.focus_set()
# 销毁自己
self.destroy()
self.root.update()
self.root.deiconify()
self.root.focus_set()
# ----------------------------------------------------------------------
if __name__ == "__main__":
root = tk.Tk()
root.geometry("1000x640+150+5") # 界面大小,以相对屏幕的坐标
root.resizable(0, 0)
myWindow = ImageApp(root)
root.mainloop()