python-3.x - 在将 tk PhotoImage 转换回 PIL 图像以保存时遇到一些问题

标签 python-3.x tkinter python-imaging-library

我正在开发一个将图像转换为灰度或反转颜色的程序。它使用不同的灰度算法,大多数情况下一切正常,但我有几个问题一直在努力克服。我遇到的一个问题是试图将图像保存出来。为了能够处理不同的文件类型,我使用 PIL 打开图像,然后将其转换为 tk PhotoImage。现在图像是 PhotoImage 我想不出保存的方法,Tkinter 的文档提到了一种方法,但这失败了。我遇到的另一个问题是我想使用复选框来旋转图像,我有一个函数 rotateIt 可以执行此操作,但是由于 的原因我无法让复选框工作IntVar() 似乎没有改变,请注意我使用 lambda 使其与单选按钮一起使用。 (感谢这里的另一位成员)这是程序的代码。 (我仍在学习,无法弄清楚如何不使用全局变量来完成相同的任务。)

from PIL import Image, ImageTk
from graphics import GraphWin
from tkinter import filedialog # Will be used to open the file from the user
import tkinter
import os

# Global variables for radio buttons----
radio1 = True
radio2 = False
radio3 = False
radio4 = False
#--------------------------------------------

# Global variables for picture-----------
pic = ''
tkPic = ''
tkPic2 = ''
picToConvert = ''
picWidth = 0
picHeight = 0
canvas1 = ''
#---------------------------------------------

def rotateIt(pic1):
    pictureRotated = pic1.rotate(180)
    return pictureRotated
# Function for radio buttons

def whichSelected(numberSelected):
        global radio1
        global radio2
        global radio3
        global radio4
        if numberSelected == 4:
            radio1 = False
            radio4 = True
        if numberSelected == 3:
            radio1 = False
            radio3 = True
        if numberSelected == 2:
            radio1 = False
            radio2 = True
        if numberSelected == 1:
            radio1 = True


# Gray Algorithms---------------------------------------------
def grayAverage(r,g,b):
    algorithm = (r + g + b) // 3
    return (algorithm)

def invertRGB(r,g,b):
        r = 255 - r
        g = 255 - g
        b = 255 - b
        return (r,g,b)

def lightness(r,g,b):
        algorithm = (max(r, g, b) + min(r, g, b)) // 2
        return (algorithm)

def luminosity(r,g,b):
        algorithm = int(((0.21 * r) + (0.71 * g) + (0.07 * b)))
        return (algorithm)

def getRGB(r,g,b):
        red = eval( input ("Enter the value of red: "))
        green = eval(input ("Enter the value of green: "))
        blue = eval(input ("Enter the value of blue: "))
        algorithm =  red-r + green-g + blue-b // 3
        return (algorithm)
# End Gray Algorithms-----------------------------------------------------------------------------

# Draws window, opens picture selected by user, packs the canvas
def drawWindow():
    window = tkinter.Tk()
    window.title(os.environ.get( "USERNAME" )) # sets the window title to the
    return window

def drawCanvas():
    global window
    global canvas1
    canvas1 = tkinter.Canvas(window, width = 820, height =340) # Draws a canvas onto the tkinter window
    canvas1.pack()
    return canvas1

# Global variables for window and canvas
window = drawWindow()
canvas1 = drawCanvas()
# -----------------------------------------------------------------------------------

    # Radio Button Code---------------------------------------------------------
def drawRadioButtons():
    global window
    var = tkinter.IntVar()
    option1 = tkinter.Radiobutton(window, text ='Average Grayscale           ',variable = var, value = 1,command =  lambda: whichSelected(1))
    option2 = tkinter.Radiobutton(window, text ='Lightness Grayscale         ',variable = var, value = 2, command = lambda: whichSelected(2))
    option3 = tkinter.Radiobutton(window, text ='Luminosity Grayscale      ',variable = var, value = 3, command = lambda: whichSelected(3))
    option4 = tkinter.Radiobutton(window, text ='Invert',variable = var, value = 4, command = lambda: whichSelected(4))

    option1.select() # Sets the first button to clicked
    # Pack Radio Buttons
    option1.pack(anchor = 'sw')
    option2.pack(anchor = 'sw')
    option3.pack(anchor = 'sw')
    option4.pack(anchor = 'sw')
    # End Radio Button code ---------------------------------------------------------

def openImage():
    global window
    global canvas1
    global pic
    global picWidth
    global picHeight
    global tkPic
    global tkPic2
    global picToConvert
    canvas1.delete('all')
    del pic
    del tkPic
    picToConvert = filedialog.askopenfilename(defaultextension='.jpg') # Used to open the file selected by the user
    pic = Image.open(picToConvert)
    picWidth, picHeight = pic.size # PIL method .size gives both the width and height of a picture
    tkPic = ImageTk.PhotoImage(pic, master = window) # Converts the pic image to a tk PhotoImage
    canvas1.create_image(10,10,anchor='nw', image = tkPic)

def saveImage():
    global pic
    global tkPic2
    pic = Image.open(tkPic2)
    toSave = filedialog.asksaveasfile(mode='w',defaultextension='.jpg')
    pic.save(toSave)

def change_pixel():
    global window
    global canvas1
    global tkPic2
    global pic
    global radio1
    global radio2
    global radio3
    global radio4
    # Treats the image as a 2d array, iterates through changing the
    #values of each pixel with the algorithm for gray

    rgbList = pic.load() #Get a 2d array of the pixels
    for row in range(picWidth):
        for column in range(picHeight):
            rgb = rgbList[row,column]
            r,g,b = rgb # Unpacks the RGB value tuple per pixel
            if radio1 == True:
                grayAlgorithm1 = grayAverage(r,g,b)
                rgbList[row,column] = (grayAlgorithm1, grayAlgorithm1, grayAlgorithm1)
            elif radio2 == True:
                grayAlgorithm1 = lightness(r,g,b)
                rgbList[row,column] = (grayAlgorithm1, grayAlgorithm1, grayAlgorithm1)
            elif radio3 == True:
                grayAlgorithm1= luminosity(r,g,b)
                rgbList[row,column] = (grayAlgorithm1, grayAlgorithm1, grayAlgorithm1) # Gives each pixel a new RGB value
            elif radio4 == True:
                r,g,b= invertRGB(r,g,b)
                rgbList[row,column] = (r, g, b) # Gives each pixel a new RGB value
        # Converting to a tkinter PhotoImage
    del tkPic2
    tkPic2 = ImageTk.PhotoImage(pic, master = window)
    canvas1.create_image(815,170, anchor='e',image = tkPic2)

# Function to create a button, takes the button text and the function to be called on click
def tkButtonCreate(text, command):
    tkinter.Button(window, text = text, command = command).pack()

def main():
    drawRadioButtons()
    tkButtonCreate('Open Image',openImage)
    tkButtonCreate('Convert', change_pixel)
    tkButtonCreate('Save',saveImage)
    window.mainloop()
    #convertButton = tkinter.Button(window,text = 'Convert', command = change_pixel).pack()
main()

最佳答案

删除 pic = Image.open(tkPic2)saveImage()

保存文件使用:

def saveImage():
    global pic
    toSave = filedialog.asksaveasfile(mode='w',defaultextension='.jpg')
    pic.save(toSave)

顺便说一句:为了更好地使用对象 None代替 ''

pic = None
tkPic = None
tkPic2 = None
picToConvert = None
canvas1 = None

此外,del给你None

 del tkPic2 # now tkPic2 == None

编辑: IntVar 和旋转问题的解决方案。

我创建全局变量 var = None然后我可以在函数中使用它(使用 global var )

我使用 pic = pic.rotate(180)在没有新变量的情况下“就地”旋转。

我为 Rotation 添加单选按钮和功能onConvert运行 rotateItchange_pixel现在我创建 tkPic2onConvert

from PIL import Image, ImageTk
#from graphics import GraphWin # not needed

# for Python 3.x
from tkinter import filedialog # Will be used to open the file from the user
import tkinter

# for Python 2.x
#import Tkinter as tkinter
#import tkFileDialog as filedialog # Will be used to open the file from the user

import os

# --- Global variables for radio buttons ---

radio1 = True
radio2 = False
radio3 = False
radio4 = False

#--------------------------------------------

# --- Global variables for picture ---

pic = None
tkPic = None
tkPic2 = None
picToConvert = None
picWidth = 0
picHeight = 0
canvas1 = None

var = None #create global variable

#----------------------------------------------------------------------

def rotateIt():
    global pic

    print "(debug) rotateIt:", pic
    pic = pic.rotate(180)

# --- Function for radio buttons ---

def whichSelected(numberSelected):
        global radio1
        global radio2
        global radio3
        global radio4

        if numberSelected == 4:
            radio1 = False
            radio4 = True
        elif numberSelected == 3:
            radio1 = False
            radio3 = True
        elif numberSelected == 2:
            radio1 = False
            radio2 = True
        elif numberSelected == 1:
            radio1 = True


# --- Gray Algorithms ---

def grayAverage(r, g, b):
    return (r + g + b) // 3

def invertRGB(r,g,b):
    return (255 - r, 255 - g, 255 - b)


def lightness(r,g,b):
    return (max(r, g, b) + min(r, g, b)) // 2

def luminosity(r,g,b):
    return int(((0.21 * r) + (0.71 * g) + (0.07 * b)))

def getRGB(r,g,b):
    red   = eval(input("Enter the value of red: "))
    green = eval(input("Enter the value of green: "))
    blue  = eval(input("Enter the value of blue: "))

    return red-r + green-g + blue-b // 3

# --- End Gray Algorithms ---

# Draws window, opens picture selected by user, packs the canvas
def drawWindow():
    window = tkinter.Tk()
    window.title(os.environ.get( "USERNAME" )) # sets the window title to the

    return window

def drawCanvas():
    global window
    global canvas1
    canvas1 = tkinter.Canvas(window, width = 820, height =340) # Draws a canvas onto the tkinter window
    canvas1.pack()

    return canvas1

# Global variables for window and canvas
window = drawWindow()
canvas1 = drawCanvas()

#----------------------------------------------------------------------

# --- Radio Button Code ---

def drawRadioButtons():
    global window, var

    var = tkinter.IntVar()

    option1 = tkinter.Radiobutton(window, text ='Average Grayscale',    variable = var, value = 1, command = lambda: whichSelected(1))
    option2 = tkinter.Radiobutton(window, text ='Lightness Grayscale',  variable = var, value = 2, command = lambda: whichSelected(2))
    option3 = tkinter.Radiobutton(window, text ='Luminosity Grayscale', variable = var, value = 3, command = lambda: whichSelected(3))
    option4 = tkinter.Radiobutton(window, text ='Invert',               variable = var, value = 4, command = lambda: whichSelected(4))
    option5 = tkinter.Radiobutton(window, text ='Rotate 180',           variable = var, value = 5)

    # Sets the first button to clicked
    option1.select()

    # Pack Radio Buttons
    option1.pack(anchor = 'sw')
    option2.pack(anchor = 'sw')
    option3.pack(anchor = 'sw')
    option4.pack(anchor = 'sw')
    option5.pack(anchor = 'sw')
    # End Radio Button code 

def openImage():
    global window
    global canvas1
    global pic
    global picWidth
    global picHeight
    global tkPic
    global tkPic2
    global picToConvert

    canvas1.delete('all')
    del pic
    del tkPic

    picToConvert = filedialog.askopenfilename(defaultextension='.jpg') # Used to open the file selected by the user
    pic = Image.open(picToConvert).convert('RGB')
    picWidth, picHeight = pic.size # PIL method .size gives both the width and height of a picture
    tkPic = ImageTk.PhotoImage(pic, master = window) # Converts the pic image to a tk PhotoImage
    canvas1.create_image(10,10,anchor='nw', image = tkPic)

#----------------------------------------------------------------------

def saveImage():
    global pic

    toSave = filedialog.asksaveasfile(mode='w',defaultextension='.jpg')
    pic.save(toSave)

#----------------------------------------------------------------------

def onConvert():
    global var
    global tkPic2
    global window

    if var.get() == 5:
        rotateIt(pic)
    else:
        change_pixel()

    # Converting to a tkinter PhotoImage

    if tkPic2:
        del tkPic2

    tkPic2 = ImageTk.PhotoImage(pic, master = window)
    canvas1.create_image(815,170, anchor='e',image = tkPic2)

#----------------------------------------------------------------------

def change_pixel():
    global window
    global canvas1
    global pic

    global radio1
    global radio2
    global radio3
    global radio4

    # Treats the image as a 2d array, iterates through changing the
    #values of each pixel with the algorithm for gray

    rgbList = pic.load() #Get a 2d array of the pixels
    for row in range(picWidth):
        for column in range(picHeight):
            rgb = rgbList[row,column]
            #print rgb
            r,g,b = rgb # Unpacks the RGB value tuple per pixel
            if radio1 == True:
                grayAlgorithm1 = grayAverage(r,g,b)
                rgbList[row,column] = (grayAlgorithm1, grayAlgorithm1, grayAlgorithm1)
            elif radio2 == True:
                grayAlgorithm1 = lightness(r,g,b)
                rgbList[row,column] = (grayAlgorithm1, grayAlgorithm1, grayAlgorithm1)
            elif radio3 == True:
                grayAlgorithm1= luminosity(r,g,b)
                rgbList[row,column] = (grayAlgorithm1, grayAlgorithm1, grayAlgorithm1) # Gives each pixel a new RGB value
            elif radio4 == True:
                rgbList[row,column] = invertRGB(r,g,b) # Gives each pixel a new RGB value

#----------------------------------------------------------------------

# Function to create a button, takes the button text and the function to be called on click
def tkButtonCreate(text, command):
    tkinter.Button(window, text = text, command = command).pack()

#----------------------------------------------------------------------

def main():
    drawRadioButtons()
    tkButtonCreate('Open Image',openImage)
    tkButtonCreate('Convert', onConvert)
    tkButtonCreate('Save',saveImage)
    window.mainloop()
    #convertButton = tkinter.Button(window,text = 'Convert', command = change_pixel).pack()

#----------------------------------------------------------------------

main()

关于python-3.x - 在将 tk PhotoImage 转换回 PIL 图像以保存时遇到一些问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20448568/

相关文章:

Python 的多个循环和线程问题

python-3.x - 将 Scapy L3socket 与 WSL 结合使用时,协议(protocol)不支持地址族

python - 如何在 PyPy 中使用 PIL?

python - PIL 将透明 PNG 加载为 RGB?

python-3.x - Fresh Anaconda 安装从 "ImportError: cannot import name ' 给出 'zmq.backend.cython' 常量“

python - 如何允许用户输入各种各样的内容并让它们在 numpy 数组中工作?

python - python中带有提交按钮的输入字段?

python - Tkinter 屏幕删除,具体

python - 在 tkinter GUI 中导入 matplotlib 图。显示错误()

python - Django - 上传有效图像