有没有一种方法可以将Tkinter画布的内容捕获到图像中?

时间:2020-09-05 16:54:53

标签: python tkinter canvas

我正在尝试使用卷积神经网络构建一个手写数字识别系统。到目前为止,我已经开发了一个Tkinter窗口,其中包含一个画布,您可以在其上手写数字。在点击``识别''按钮后,我希望程序拍摄该数字的图像(即画布)并通过神经网络运行它以预测数字。以下是我在网上找到的一些代码的实现:

from tkinter import *
import win32gui
from PIL import ImageGrab, Image

cv = Canvas(width=400, height=400, bg='white', cursor='cross')
cv.grid(row=0, column=0, sticky=W)

hwnd = cv.winfo_id()
cv_rect = win32gui.GetWindoRect(hwnd)
img = ImageGrab.grab(cv_rect)

此代码能够捕获图像。但是,图像不是画布上的,而是屏幕上的其他位置,通常在画布的西北部。输出看起来像这样:

enter image description here

但是,如果我将Tkinter窗口移离计算机屏幕的左上角,则该图像甚至无法捕获Tkinter窗口的左上角,如上图所示。

为了进一步了解,这是我在其中构建该gui的文件的全部代码。

import numpy as np
from tkinter import *
from PIL import Image, ImageGrab
import win32gui
import tensorflow as tf
import matplotlib.pyplot as plt
import matplotlib
import win32api

cnn = tf.keras.models.load_model('\\Users\\hamza\\Documents\\VS Code\\mnist.h5py')

#---------------------------------------------------------------
'''
(X_train, y_train), (X_test, y_test) = tf.keras.datasets.mnist.load_data()

X_test = X_test.reshape(-1, 28, 28, 1)

X_test = X_test.astype('float32')

X_test /= 255

y_test = tf.keras.utils.to_categorical(y_test)

y_pred = cnn.predict(X_test)
print(y_pred[3700])
print(y_test[3700])

test_eval = cnn.evaluate(X_test, y_test, verbose=1)

print('Test loss:', test_eval[0])
print('Test accuracy:', test_eval[1])
'''

from pyscreenshot import grab
import pygetwindow as pgw
'''
im = grab(bbox=(500, 200, 800, 400))
im.show()
'''


def predict(img):
    #img = img.resize((28, 28))
    img = img.convert('L')
    img = np.array(img)
    #img.reshape(28, 28)
    plt.imshow(img, cmap=matplotlib.cm.binary, interpolation='nearest')
    plt.show()
    #img = img.reshape(1, 28, 28, 1)/255
    #pred = cnn.predict(img)[0]
    #print(pred)
    #print('---------------------')
    #return np.argmax(pred), max(pred)

def classify():
    '''
    hwnd = cv.winfo_id()
    print(hwnd)
    cv_rect = win32gui.GetWindowRect(hwnd)
    img = ImageGrab.grab(cv_rect)
    '''
    win = pgw.getWindowsWithTitle('tk')[0]
    winleft = win.left+9
    wintop = win.top+7
    winright = win.right-9
    winbottom = win.bottom-9
    final_rect = (winleft,wintop,winright,winbottom)
    img = ImageGrab.grab(final_rect)
    
    digit, accuracy = predict(img)
    print(digit)
    print(accuracy)
    #label.configure(str(digit) + ', ' + str(int(accuracy*100)) + '%')
        
def clear():
    cv.delete('all')
    
def draw(event):
    x = event.x
    y = event.y
    r = 8
    cv.create_oval(x-r, y-r, x+r, y+r, fill='black')

root = Tk()

cv = Canvas(width=400, height=400, bg='white', cursor='cross')
cv.grid(row=0, column=0, pady=2, sticky=W)

label = Label(text='Welcome', font=('Helvetica', 32))
label.grid(row=0, column=1, padx=2, pady=2)

clear_button = Button(text='Clear', command=clear)
clear_button.grid(row=1, column=0, pady=2)

recognize_button = Button(text='Recognize', command=classify)
recognize_button.grid(row=1, column=1, padx=2, pady=2)
        
cv.bind("<B1-Motion>", draw)

mainloop()

有人,请帮忙。

1 个答案:

答案 0 :(得分:1)

我在GUI中使用了类似的功能,起初我使用win32gui,但意识到这样做太小了,相反,只需使用PyGetWindowPIL

首先安装模块,然后在终端中说出来。

pip install PyGetWindow
pip install Pillow

然后,此代码将在3秒后自动获取屏幕截图

from tkinter import *
from win32gui import FindWindow, GetWindowRect
import pygetwindow as gw
from PIL import ImageGrab

def ss():
    win = gw.getWindowsWithTitle('Trial')[0]
    winleft = win.left+9
    wintop = win.top+38 #change 38 to 7 to not capture the titlebar
    winright = win.right-9
    winbottom = win.bottom-9
    final_rect = (winleft,wintop,winright,winbottom)
    img = ImageGrab.grab(final_rect)
    img.save('Required Image.png')
#making the tkinter window
root = Tk()
root.title('Trial')

cv = Canvas(width=400, height=400, bg='white', cursor='cross')
cv.grid(row=0, column=0, sticky=W)

root.after(3000,ss)

root.mainloop()

在这里win = gw.getWindowsWithTitle('Title of the window')[0],您必须调用窗口名称,就像您设置的窗口名称一样,例如root.title('Hello World'),然后'Title of the window'将被{{1 }}。或默认情况下,它的标题为'Hello World'

或者,如果您仍然不愿意使用'tk',请替换为win32gui

ss()

额外提示:

  • 为什么我要从像素中减去一些量?这是因为,窗口对窗口具有阴影效果,这也是窗口的一部分,并且将包含在屏幕截图中,所以我用它来去除那些多余的像素,我想它将使您的神经网络更加高效,没有垃圾。

这是我得到的图像:

enter image description here

希望这对您有所帮助,请让我知道是否有任何错误或疑问。

其他参考-ImageGrab not grabbing precise bbox image

欢呼