Getting canvas coordinates in python -For mac especially

Question:

from keras.models import load_model
from tkinter import *
import tkinter as tk
import appscript
#import win32gui
from PIL import ImageGrab, Image
import numpy as np

model = load_model('mnist.h5')

def predict_digit(img):
    #resize image to 28x28 pixels
    img = img.resize((28,28))
    #convert rgb to grayscale
    img = img.convert('L')
    img = np.array(img)
    #reshaping to support our model input and normalizing
    img = img.reshape(1,28,28,1)
    img = img/255.0
    #predicting the class
    res = model.predict([img])[0]
    return np.argmax(res), max(res)

class App(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)

        self.x = self.y = 0
        
        # Creating elements
        self.canvas = tk.Canvas(self, width=300, height=300, bg = "white", cursor="cross")
        self.label = tk.Label(self, text="Draw..", font=("Helvetica", 48))
        self.classify_btn = tk.Button(self, text = "Recognise", command = self.classify_handwriting)   
        self.button_clear = tk.Button(self, text = "Clear", command = self.clear_all)
       
        # Grid structure
        self.canvas.grid(row=0, column=0, pady=2, sticky=W, )
        self.label.grid(row=0, column=1,pady=2, padx=2)
        self.classify_btn.grid(row=1, column=1, pady=2, padx=2)
        self.button_clear.grid(row=1, column=0, pady=2)
        
        #self.canvas.bind("<Motion>", self.start_pos)
        self.canvas.bind("<B1-Motion>", self.draw_lines)

    def clear_all(self):
        self.canvas.delete("all")
        
    def classify_handwriting(self):
        HWND = self.canvas.winfo_id()  # get the handle of the canvas
        rect=self.canvas.coords(HWND)
        #rect = win32gui.GetWindowRect(HWND)  # get the coordinate of the canvas
        a,b,c,d = rect
        rect=(a+4,b+4,c-4,d-4)
        im = ImageGrab.grab(rect)

        digit, acc = predict_digit(im)
        self.label.configure(text= str(digit)+', '+ str(int(acc*100))+'%')

    def draw_lines(self, event):
        self.x = event.x
        self.y = event.y
        r=8
        HWND=self.canvas.create_oval(self.x-r, self.y-r, self.x + r, self.y + r, fill='black')
       
app = App()
mainloop()

Can anyone help me especially with this part :

HWND = self.canvas.winfo_id()  # get the handle of the canvas
        rect=self.canvas.coords(HWND)
        #rect = win32gui.GetWindowRect(HWND)  # get the coordinate of the canvas
        a,b,c,d = rect
        rect=(a+4,b+4,c-4,d-4)
        im = ImageGrab.grab(rect)

This is the error that appears :

Exception in Tkinter callback
Traceback (most recent call last):
  File "/Users/xxx/opt/anaconda3/lib/python3.8/tkinter/__init__.py", line 1883, in __call__
    return self.func(*args)
  File "<ipython-input-4-28fb2cc31a85>", line 52, in classify_handwriting
    a,b,c,d = rect
ValueError: not enough values to unpack (expected 4, got 0)

I am trying to create an ocr program to identify handwriting by letting the user draw a number and return the current value with high accuracy .
But the problem faced was with the canvas and how to get the coordinates without using the win32gui module (Since im a mac user) so I’m looking for a solution or an alternative for win32gui method GetWindowRect

Asked By: AbAc

||

Answers:

self.canvas.coords(HWND) is going to return the coordinates of an object on the canvas with the id or tag of whatever is in HWND. It does not return the coordinates of the canvas itself.

Since HWND doesn’t represent an item on the canvas, self.canvas.coords(HWND) returns an empty list. That is why you get the error not enough values to unpack – your code requires four values but the list has zero.

If you are wanting the coordinates of the canvas on the physical screen there are other methods you can use. See the following code:

x, y = (self.canvas.winfo_rootx(), self.canvas.winfo_rooty())
width, height = (self.canvas.winfo_width(), self.canvas.winfo_height())

a, b, c, d = (x, y, x+width, y+height)
Answered By: Bryan Oakley

Correct! It works fine on MACOS. comment the "import win32gui" line. Modify "classify_handwriting" function as below:

    def classify_handwriting(self):
        x, y = (self.canvas.winfo_rootx(), self.canvas.winfo_rooty())
        width, height = (self.canvas.winfo_width(), 
                         self.canvas.winfo_height())
        a, b, c, d = (x, y, x+width, y+height)
        im = ImageGrab.grab(bbox=(a,b,c,d))

Hope it works in your local setting!

Answered By: Hirenkumar Gami
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.