PIL图像分割及拼接示范-Tkinter/matplotlib图表显示小试

主要功能:

       选择一张图片,裁剪为9宫格图片并保存,通过plt分别显示在GUI里面,图片之间存在间距,下一实例将用Canvas实现无间隔显示,可与原图比较。

# -*- coding: utf-8 -*-
"""
Created on Tue Oct 29 16:26:58 2019

@author: Roger Liu
"""

import tkinter as tk
from tkinter.filedialog import askdirectory,askopenfilename
from PIL import Image,ImageDraw
import sys
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
from matplotlib.backend_bases import key_press_handler
from matplotlib.figure import Figure


#将图片填充为正方形
def fill_image(image):
    width, height = image.size    
    #选取长和宽中较大值作为新图片的
    new_image_length = width if width > height else height    
    #生成新图片[白底]
    new_image = Image.new(image.mode, (new_image_length, new_image_length), color='white')    
    #将之前的图粘贴在新图上,居中
    if width > height:#原图宽大于高,则填充图片的竖直维度
        #(x,y)二元组表示粘贴上图相对下图的起始位置
        new_image.paste(image, (0, int((new_image_length - height) / 2)))
    else:
        new_image.paste(image, (int((new_image_length - width) / 2),0))    
    return new_image
#切图
def cut_image(image):
    width, height = image.size
    item_width = int(width / 3)
    box_list = []    
    # (left, upper, right, lower)
    for i in range(0,3):#两重循环,生成9张图片基于原图的位置
        for j in range(0,3):          
            #print((i*item_width,j*item_width,(i+1)*item_width,(j+1)*item_width))
            box = (j*item_width,i*item_width,(j+1)*item_width,(i+1)*item_width)
            box_list.append(box)

    image_list = [image.crop(box) for box in box_list]    
    return image_list
#保存
def save_images(image_list):
    index = 1
    for image in image_list:
        image.save('./result/python'+str(index) + '.png', 'PNG')
        index += 1

def image_compose(image_list):
    width, height = image_list[0].size
    to_image = Image.new('RGB', (3 * width, 3 * height)) #创建一个新图
    # 循环遍历,把每张图片按顺序粘贴到对应位置上
    for y in range(3):
        for x in range(3):
            draw=ImageDraw.Draw(image_list[3*y+x])
            draw.rectangle((0,0,width,height), outline="gray", width=1)
            to_image.paste(image_list[3*y+x], ((x * width, y * height)))
    to_image.show()
    return to_image

def selectPath():
    path_ = askopenfilename()
#    enty['fg'] = 'black'
    enty.configure(fg='red')
    path.set(path_)
    
    o_image = Image.open(path_)
    ax=plt.figure()
    plt.axis('off')
    plt.imshow(o_image)
    canvas = FigureCanvasTkAgg(ax, master=frame2)
    canvas.draw()
    canvas.get_tk_widget().pack(fill=tk.X)
    toolbar = NavigationToolbar2Tk(canvas, frame2)
    toolbar.update()
    

def cut_img():
    filepath=path.get()
    image = Image.open(filepath)
    image = fill_image(image)
    image_list = cut_image(image)
    save_images(image_list)
#    print(image_list)
    draw_fig(image_list)
    return image

def draw_fig(image_list):
    ax=plt.figure()
    ax.tight_layout()
    ax.subplots_adjust(wspace =0, hspace =0)#调整子图间距
    for y in range(3):
        for x in range(3):
            bx=ax.add_subplot(3,3,3*y+x+1)
#            plt.subplot(3,3,3*y+x+1)
#            plt.axis('off')
            plt.axis('off')
            data=image_list[3*y+x]
            width, height=data.size
#            print(width,height)
            rect=plt.Rectangle((0,0),width,height,fill=False, edgecolor = 'gray',linewidth=1) #加外框
            bx.add_patch(rect)
            bx.imshow(data) 

    for canvas in frame2.winfo_children():
#        print(canvas)
#        canvas.destroy()
        canvas.pack_forget()
        
    canvas = FigureCanvasTkAgg(ax, master=frame2)
    canvas.draw()
#    canvas.get_tk_widget().place(x=10,y=40,anchor='nw')
    # matplotlib的导航工具栏显示上来(默认是不会显示它的)
    toolbar = NavigationToolbar2Tk(canvas, frame2)
    toolbar.update()
#    canvas._tkcanvas.place(x=10,y=40,anchor='nw')
    canvas.get_tk_widget().pack(fill=tk.X)
#    plt.show()
    
###########################################################################

root = tk.Tk()
root.title('PIL/PLT.plot图像分割及拼接示范')
root.geometry('470x555') 

path = tk.StringVar(value=r'请选择目标图片文件...')

frame = tk.Frame(root, bg="gray")
frame2 = tk.Frame(root, bg="whitesmoke")

tk.Button(frame, text = "路径选择:", height=1,width=10,command = selectPath).pack(side=tk.LEFT, padx=10,pady=5)
enty=tk.Entry(frame, textvariable = path,fg = 'gray',width=40) #单独句柄,用于后面更改参数
enty.pack(side=tk.LEFT, padx=10,pady=5)
tk.Button(frame, text = "裁切",height=1, width=10,command=cut_img).pack(side=tk.LEFT, padx=10,pady=5)

frame.pack(fill=tk.X)
frame2.pack(fill=tk.X)


tk.mainloop()

GUI 如下:

简化优化重写函数,避免重复调用:

def selectPath():
    path_ = askopenfilename()
#    enty['fg'] = 'black'
    enty.configure(fg='black')
    path.set(path_)
    
    fig.clf()
#    plt.cla() # 清除axes,即当前 figure 中的活动的axes,但其他axes保持不变。
#    plt.clf() # 清除当前 figure 的所有axes,但是不关闭这个 window,所以能继续复用于其他的 plot。
#    plt.close() # 关闭 window,如果没有指定,则指当前 window。
#    path_=r'.\opencv.jpg'
    o_image = Image.open(path_)
    ax=fig.add_subplot()
    ax.imshow(o_image)
    ax.set_axis_off()
    canvas.draw()
    plt.close(fig)

 
def draw_fig(image_list):
 
    fig.clf()
    plt.axis('off')
    for y in range(3):
        for x in range(3):

            ax=fig.add_subplot(3,3,3*y+x+1)
            data=image_list[3*y+x]
            width, height=data.size
#            print(width,height)
#            rect=plt.Rectangle((0,0),width,height,fill=False, edgecolor = 'gray',linewidth=1) #加外框
#            ax.add_patch(rect)
            ax.imshow(data)
#            ax.set_xticks([])
#            ax.set_yticks([])
            ax.set_axis_off()
          
    canvas.draw()
    print(plt.get_fignums())
    plt.close(1)
    

###########################################################################
 

fig=plt.figure(1,figsize=(5,4.8))
fig.tight_layout()
fig.subplots_adjust(wspace =0, hspace =0)#调整子图间距
plt.close(fig)
canvas = FigureCanvasTkAgg(fig, master=frame2)
canvas.draw()
toolbar = NavigationToolbar2Tk(canvas, frame2)
toolbar.update()
canvas.get_tk_widget().pack(fill=tk.X)

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值