加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

python – 如何使用tkinter scale修改图像?

发布时间:2020-12-20 13:11:33 所属栏目:Python 来源:网络整理
导读:我是 Python和OpenCV的新手,所以如果我说/问的话可能听起来不聪明或者不知情,我会道歉.我们已经在我的数字图像处理课程中以非常具体的方式学习了东西,所以当我的代码在下面工作时,我想大大提高它的速度,但主要是它的UI.代码的主要目的是创建绿屏图像的二进制
我是 Python和OpenCV的新手,所以如果我说/问的话可能听起来不聪明或者不知情,我会道歉.我们已经在我的数字图像处理课程中以非常具体的方式学习了东西,所以当我的代码在下面工作时,我想大大提高它的速度,但主要是它的UI.代码的主要目的是创建绿屏图像的二进制遮罩,然后将其应用于图像以将前景与背景分开.至于功能:

keyer根据所需的遮罩类型(colorDifference或chromaKey)创建输入图像的阈值遮罩.

thresholdAdjust允许用户通过Open CV UI操作阈值滑块.它还会实时更新图像(按下Enter键时),以反映原始遮罩如何根据所选阈值进行更改.由于我对这些功能完全陌生,所以我看到的所有示例都使用了跟踪器等功能.我不确定是否有必要.

最后,keyMultiplier将thresholdAdjust中生成的遮罩应用于输入图像并显示分离的前景.

(没有必要仔细阅读所有的keyer代码,因为它工作正常,但有点慢.我把所有内容都包括在内以防万一.)

import numpy as np
import cv2

def keyer(image,matteType,threshold1,threshold2,maxCount=255):

    numberRows = image.shape[0]
    numberColumns = image.shape[1]

    if image.ndim > 2:
        numberBands = image.shape[2]
    else:
        numberBands == 1

    if numberBands != 3:
        raise RuntimeError('Input image must be an RGB image.')

    dataType = image.dtype

    matte = np.zeros((numberRows,numberColumns,1))
    imageNorm = image / float(maxCount)

    if matteType == 'colorDifference':
        blue,green,red = cv2.split(imageNorm)

        for row in range(numberRows):
            for column in range(numberColumns):        
                pixel = green[row,column] - max(red[row,column],blue[row,column])

                matte[row,column] = pixel

    elif matteType == 'chromaKey':
        imageYCbCr = cv2.cvtColor(image,cv2.COLOR_BGR2YCrCb)
        imageYCbCrNorm = imageYCbCr / float(maxCount)
        Y,Cr,Cb = cv2.split(imageYCbCrNorm)
        CbScreen =  Cb[0,0]
        CrScreen = Cr[0,0]

        for row in range(numberRows):
            for column in range(numberColumns):
                pixel = float(np.sqrt(((CbScreen - Cb[row,column])**2) + 
                                      ((CrScreen - Cr[row,column])**2)))

                matte[row,column] = pixel

    else:
        raise RuntimeError('Please enter a valid "matteType".')

    matte = np.clip(matte,0.0,1.0)

    if matteType == 'colorDifference':
        matte = 1.0 - matte

    for row in range(numberRows):
        for column in range(numberColumns):

            if matte[row,column] < threshold1:
                matte[row,column] = 0
            elif matte[row,column] > threshold2:
                matte[row,column] = 1
            else:
                matte[row,column] = ((matte[row,column] - threshold1) / 
                                      (threshold2 - threshold1))

    return (matte * float(maxCount)).astype(dataType)

def tracker(*arg):
    pass

def thresholdAdjust(image,maxCount):
    numberRows = image.shape[0]
    numberColumns = image.shape[1]

    if matteType == 'colorDifference':
        matteName = '(Color Difference)'
    else:
        matteName = '(Chroma Key)'

    windowName = 'Adjust Matte Parameters ' + matteName        
    threshold1TrackbarName = 'Clip Black'
    threshold2TrackbarName = 'Clip White'

    cv2.namedWindow(windowName)
    cv2.createTrackbar(threshold1TrackbarName,windowName,maxCount,tracker)
    cv2.createTrackbar(threshold2TrackbarName,tracker)

    cv2.setTrackbarPos(threshold2TrackbarName,maxCount)

    while True:
        threshold1 = (cv2.getTrackbarPos(threshold1TrackbarName,windowName) / 
                      float(maxCount))
        threshold2 = (cv2.getTrackbarPos(threshold2TrackbarName,windowName) / 
                      float(maxCount))

        window = keyer(image,maxCount)
        cv2.imshow(windowName,window)

        k = cv2.waitKey(0)
        if k == 27:
            break

    cv2.destroyAllWindows()

    return threshold1,threshold2

def keyMultiplier(image,maxCount):
    dataType = image.dtype

    threshold1,threshold2 = thresholdAdjust(image,maxCount)
    matte = keyer(image,maxCount)

    return ((cv2.GaussianBlur((matte / float(maxCount)),(3,3),0)[...,np.newaxis]) * 
            image).astype(dataType)


if __name__ == '__main__':

    import cv2

    filename = 'C:/Users/Matt/Documents/circle_test.tif'

    image = cv2.imread(filename)


    difference = keyMultiplier(image,matteType='colorDifference',maxCount=255) # 163,215
    chroma = keyMultiplier(image,matteType='chromaKey',maxCount=255) # 25,50

    cv2.imshow('Original Image',image)
    cv2.imshow('Color Difference',difference)
    cv2.imshow('Chroma Key',chroma)

    cv2.waitKey(0)
    cv2.destroyAllWindows()

我想用这个代码做的是将它与Tkinter UI一起使用,因为它更好,并且有比OpenCV更多的选项.我一直在寻找大量的线程,我没有找到任何可以帮助我理解我的具体问题的东西.我确实在这个Stack Overflow上找到了一个答案,它提供了以下代码,我重新格式化以反映我的代码的目的.每次释放滑块控件时,它都会打印滑块的值.

from Tkinter import *

class App():
    def __init__(self):
        self.root = Tk()
        self.root.title('Adjust Matte Parameters')

        self.clipBlack = Scale(self.root,from_=0,to=255,orient=HORIZONTAL,
                               label='Clip Black',length=500)
        self.clipBlack.bind("<ButtonRelease-1>",self.updateValue)
        self.clipBlack.pack(anchor=CENTER)

        self.clipWhite = Scale(self.root,
                               label='Clip White',length=500)
        self.clipWhite.set(255)
        self.clipWhite.bind("<ButtonRelease-1>",self.updateValue)
        self.clipWhite.pack(anchor=CENTER)

        self.root.mainloop()

    def updateValue(self,event):
        print 'Clip Black = ' + str(self.clipBlack.get())
        print 'Clip White = ' + str(self.clipWhite.get())

app = App()

然而,这引发了一些问题.虽然我真的很喜欢它,它会立即检索滑块位置,但这一切都是打印它们.我希望将这些值插入到keyer函数中,就像我在thresholdAdjust中实现的那样.一个这样,我想更新图像,但我没有运气使用OpenCV显示图像而Tkinter窗口打开,因为“root.mainloop()”行似乎不允许它.我已经找到了一些关于同时显示Tkinter和OpenCV窗口以及使用Tkinter显示图像的帮助,但是这些选项无关紧要,直到我可以使用新的阈值更新遮罩.

我也不太了解如何处理它们中的类和函数.我只习惯通过创建测试工具来运行代码,如下所示

if __name__ == '__main__':

在第一个代码块中,所以我不知道如何确定我想要使用的图像和matteType而不用硬编码.

如果有人能帮助我,那将非常感激!我知道这很多,我很乐意澄清任何困惑.一旦我知道如何使用滑块完成此操作,我应该能够将它应用于单选按钮.再说一次,我想:

>使用阈值滑块更新我的键控器功能
>使用OpenCV或Tkinter实时更新遮罩,无论哪种更容易
>了解如何(如果适用)更改类中的输入图像和其他变量

谢谢!

解决方法

好的,所以我已经花了好几个小时,我想我终于找到了一个解决方案(你需要一个.png文件名picture.png在同一个目录中才能运行下面的代码):

from tkinter import *
from PIL import Image,ImageTk

class App(Frame):
    def __init__(self,master):
        Frame.__init__(self,master)
        self.frame1 = Frame(self)
        self.frame2 = Frame(self)
        self.original = Image.open('picture.png')
        self.image = ImageTk.PhotoImage(self.original)
        self.display = Canvas(self.frame1)
        self.xscale = Scale(self.frame2,from_=1,to=1000,command=self.resize)
        self.yscale = Scale(self.frame2,orient=VERTICAL,command=self.resize)
        self.display.pack(fill=BOTH,expand=1)
        self.xscale.pack()
        self.yscale.pack()
        self.pack(fill=BOTH,expand=1)
        self.frame1.pack(fill=BOTH,expand=1)
        self.frame2.pack()
        self.bind("<Configure>",self.resize)

    def resize(self,*args):
        size = (self.xscale.get(),self.yscale.get())
        resized = self.original.resize(size,Image.ANTIALIAS)
        self.image = ImageTk.PhotoImage(resized)
        self.display.delete("IMG")
        self.display.create_image(self.display.winfo_width()/2,self.display.winfo_height()/2,anchor=CENTER,image=self.image,tags="IMG")

root = Tk()
app = App(root)
app.mainloop()

所以这样做是创建一个画布和两个音阶,每当其中一个音阶被改变时,它将调用def resize,它从画布中清除带有标签IMG的项目,然后绘制一个宽度等于xscale和x的值的新图像.高度等于带有IMG标记的yscale.当您沿着比例拖动滑块时,会创建实时大小更新的错觉.

但是,我无法找到一种方法来将比例上限值限制为画布的宽度(以像素为单位),以防止用户将图像扩展到画布边界之外.

这可以类似地应用于允许您使用滑块值实时更新需要更新的图像的任何属性.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读