如何使用tkinter scales修改图像?

2024-06-25 22:53:50 发布

您现在位置:Python中文网/ 问答频道 /正文

我对Python和OpenCV比较陌生,所以如果我说/问的任何事情听起来不明智或不知情,我深表歉意。在我的数字图像处理课上,我们以一种非常特殊的方式学习了一些东西,所以虽然我下面的代码可以工作,但我希望极大地提高它的速度,但主要是它的用户界面。该代码的主要目的是创建一个绿色屏幕图像的二进制蒙版,然后将其应用于图像,以将前景与背景分开。至于功能:

keyer根据需要的蒙版类型(色差或色度)创建输入图像的阈值蒙版。在

thresholdAdjust允许用户通过打开的CV UI操纵阈值滑块。它还实时更新图像(按Enter键时),以反映原始蒙版如何根据选定的阈值进行更改。因为我对这些特性完全陌生,所以我看到的所有示例都使用了一个函数,比如tracker。但我不确定是否有必要。在

最后,keymplier将在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, matteType, 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, 0, maxCount, tracker)
    cv2.createTrackbar(threshold2TrackbarName, windowName, 0, maxCount, tracker)

    cv2.setTrackbarPos(threshold2TrackbarName, windowName, maxCount)

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

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

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

    cv2.destroyAllWindows()

    return threshold1, threshold2

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

    threshold1, threshold2 = thresholdAdjust(image, matteType, maxCount)
    matte = keyer(image, matteType, threshold1, threshold2, 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用户界面一起使用,因为它比OpenCV更好,而且有更多的选项。我查看了大量的线程,但没有找到任何可以帮助我理解我的具体问题的东西。对于这个堆栈溢出,我确实找到了一个答案,它提供了以下代码,我重新格式化了这些代码,以反映代码的用途。每次释放滑块控件时,它都会打印滑块的值。在

^{pr2}$

然而,这又引发了一些问题。虽然我真的很喜欢它立即检索滑块的位置,所有这一切只是打印它们。我希望将这些值插入到keyer函数中,就像我在thresholdAdjust中实现的那样。因此,我想更新图像,但自从根.mainloop()”行似乎不允许。我发现了一些关于同时显示Tkinter和OpenCV窗口以及使用Tkinter显示图像的帮助,但是这些选项是不相关的,除非我可以用新的阈值更新蒙版。在

我也不太明白如何在其中处理类和函数。我只习惯于通过创建如下所示的测试工具来运行代码

if __name__ == '__main__': 

在第一个代码块中,所以我不知道如何,比如说,在没有硬编码的情况下确定我想要使用的图像和matteType。在

如果有人能帮我的忙,我将不胜感激!我知道很多,我很乐意澄清任何困惑。一旦我知道如何用滑块来完成这一点,我就应该能够将其应用于单选按钮。再次,我想:

  • 使用阈值滑块更新mykeyer函数
  • 实时更新哑光,使用OpenCV或Tkinter,以较容易的为准
  • 了解如何(如果适用)更改类中的输入图像和其他变量

谢谢你!在


Tags: 代码图像imageifcolumnfloatcv2row
1条回答
网友
1楼 · 发布于 2024-06-25 22:53:50

好吧,我花了好几个小时讨论这个问题,我想我终于找到了一个解决方案(您需要在同一个目录中有一个.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, orient=HORIZONTAL, command=self.resize)
        self.yscale = Scale(self.frame2, from_=1, to=1000, 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()

这样做的是创建一个canvas,两个{{},两个{{>}}。当其中一个{{>}的改变时,它将调用def}{{>}{{{>}的项目,从画布上清除带有标签{{>}项目的项目,然后在画布上绘制一幅新的图像,图中的{{}等于{{},高度等于^{{}}{{{}}{{}是的。当您沿着scales拖动滑块时,会产生实时大小更新的错觉

但是,我无法找到一种方法来限制scale的上限值为canvas的像素宽度,以防止用户将图像扩展到canvas的边界之外。在

这同样可以应用于允许您实时更新需要用滑块值更新的图像的任何属性。在

相关问题 更多 >