1

I have mainly 2 problems in the code:
1) it is showing error "no such directory or file exists" though I have used the same path for an image to another program (though I specified a constant path to only one image) and the images file, this program and the other program, all are in the same working directory
2) it doesn't wait for the wait function, it just executes till 16 and then opens the GUI. I want it to show all the images one by one and change only when I press the 'Next' button
Please suggest any changes in the code which may be required to satisfy the above.
I have Python 3.5.2 in a Windows 10 system.
Thanks in advance

import sys
import tkinter as tk
from PIL import Image,ImageTk,ImageFilter,ImageOps
from msvcrt import getch

def wait():
    getch()
    return

def classify_obj():
    print("In Development")
    return

src = "ímages/"

root = tk.Tk()
root.wm_title("Classify Image")

for i in range(1,17):
    frame1 = tk.Frame(root, width=500, height=400, bd=2)
    frame1.grid(row=1, column=0)
    cv1 = tk.Canvas(frame1, height=390, width=490, background="white", bd=1, relief=tk.RAISED)
    cv1.grid(row=1,column=0)
    im = Image.open(src+str(i)+".jpg")
    if (490-im.size[0])<(390-im.size[1]):
        width = 490
        height = width*im.size[1]/im.size[0]
    else:
        height = 390
        width = height*im.size[0]/im.size[1]
    im.thumbnail((width, height), Image.ANTIALIAS)
    photo = ImageTk.PhotoImage(im)
    cv1.create_image(0, 0, image=photo, anchor='nw')
    claButton = tk.Button(master=root, text='Classify', height=2, width=10, command=classify_obj)
    claButton.grid(row=0, column=1, padx=2, pady=2)
    frame2 = tk.Frame(root, width=500, height=400, bd=1)
    frame2.grid(row=1, column=1)
    cv2 = tk.Canvas(frame2, height=390, width=490, bd=2, relief=tk.SUNKEN)
    cv2.grid(row=1,column=1)
    broButton = tk.Button(master=root, text='Next', height=2, width=8, command=wait)
    broButton.grid(row=0, column=0, padx=2, pady=2)
    print(i)

tk.mainloop()
Incognito Possum
  • 144
  • 1
  • 4
  • 13
  • show your trackback error plz – Mike - SMT Jun 19 '17 at 14:49
  • I actually don't get what trackback error is... do you want to see the traceback error displayed in the shell when I run the program?? – Incognito Possum Jun 20 '17 at 10:12
  • The trackback error is the error when you run your program and the console displays several lines of error information. It describes the the problem and the location of said problem most of the time. – Mike - SMT Jun 20 '17 at 12:03

2 Answers2

1

So on of the big problems with getting the next image the way you are trying to do it is the for loop. What is happening is you have told python the check everything in that loop and perform those functions.

I think one better way would be to first create this program as a class. This way we can avoid calling global variables anywhere in the program. Then inside said class on __init__ we create a list of every photo image inside of our image folder. (Note: I have only tested this with .jpg images). Now that we have a list of all the file names we can then use that list to get a count of how many image files we are working with. With this count we can create a counter that lets us select the next index in the list thus selecting the next image in said list.

By creating all our variables as an attribute of the class we can interact with those attributes without having to declare them as global.

Take the following example. Just change the src variable to your file path. remember to use . in your file path if your folder is inside your main python workspace. Example: I have a folder called TestImages inside the same directory as my main.py so I can make this variable: src = "./TestImages/".

Take a look at the code below:

import tkinter as tk
from PIL import Image,ImageTk
import os


class ImageClassifyer(tk.Frame):


    def __init__(self, parent, *args, **kwargs):

        tk.Frame.__init__(self, parent, *args, **kwargs)

        self.root = parent
        self.root.wm_title("Classify Image")   
        src = "./TestImages/"

        self.list_images = []
        for d in os.listdir(src):
            self.list_images.append(d)

        self.frame1 = tk.Frame(self.root, width=500, height=400, bd=2)
        self.frame1.grid(row=1, column=0)
        self.frame2 = tk.Frame(self.root, width=500, height=400, bd=1)
        self.frame2.grid(row=1, column=1)

        self.cv1 = tk.Canvas(self.frame1, height=390, width=490, background="white", bd=1, relief=tk.RAISED)
        self.cv1.grid(row=1,column=0)
        self.cv2 = tk.Canvas(self.frame2, height=390, width=490, bd=2, relief=tk.SUNKEN)
        self.cv2.grid(row=1,column=0)

        claButton = tk.Button(self.root, text='Classify', height=2, width=10, command=self.classify_obj)
        claButton.grid(row=0, column=1, padx=2, pady=2)
        broButton = tk.Button(self.root, text='Next', height=2, width=8, command = self.next_image)
        broButton.grid(row=0, column=0, padx=2, pady=2)

        self.counter = 0
        self.max_count = len(self.list_images)-1
        self.next_image()

    def classify_obj(self):
        print("In Development")

    def next_image(self):

        if self.counter > self.max_count:
            print("No more images")
        else:
            im = Image.open("{}{}".format("./TestImages/", self.list_images[self.counter]))
            if (490-im.size[0])<(390-im.size[1]):
                width = 490
                height = width*im.size[1]/im.size[0]
                self.next_step(height, width)
            else:
                height = 390
                width = height*im.size[0]/im.size[1]
                self.next_step(height, width)

    def next_step(self, height, width):
        self.im = Image.open("{}{}".format("./TestImages/", self.list_images[self.counter]))
        self.im.thumbnail((width, height), Image.ANTIALIAS)
        self.root.photo = ImageTk.PhotoImage(self.im)
        self.photo = ImageTk.PhotoImage(self.im)

        if self.counter == 0:
            self.cv1.create_image(0, 0, anchor = 'nw', image = self.photo)

        else:
            self.im.thumbnail((width, height), Image.ANTIALIAS)
            self.cv1.delete("all")
            self.cv1.create_image(0, 0, anchor = 'nw', image = self.photo)
        self.counter += 1


if __name__ == "__main__":
    root = tk.Tk() 
    MyApp = ImageClassifyer(root)
    tk.mainloop()
Mike - SMT
  • 14,784
  • 4
  • 35
  • 79
  • thanks a lot... really really helpful... you solved each and every problem I had – Incognito Possum Jun 20 '17 at 10:01
  • I'm a noob to python so I don't have much experience in the field... I was having problem making the __init__ function and was hoping to ask it next time... But you solved that too... Thanks a lot – Incognito Possum Jun 20 '17 at 10:04
  • Can you please explain me what the *args and **kwargs arguments are for, I can't see any usage of them – Incognito Possum Jun 20 '17 at 10:29
  • @IncognitoPossum: Currently in this class those 2 variables do nothing. They do however have a purpose in more complex code. Take a look at [this link](https://stackoverflow.com/questions/3394835/args-and-kwargs) – Mike - SMT Jun 20 '17 at 12:01
0

There are lots of issues with the current code. I tried to make it work with as little change as possible. The fundamental problem was that the button binding to wait() goes against the principle of having a GUI. So in short, here is a framework from which to get started...

import tkinter as tk
from PIL import Image,ImageTk,ImageFilter,ImageOps
from msvcrt import getch

src = 'images/'
i = 1

def showImage():
    global i
    # You need to do file exists error checking here.
    try:
        im = Image.open(src+str(i)+".jpg")
    except:
        print("No image file named", src+str(i)+".jpg")
        return
    if (490-im.size[0])<(390-im.size[1]):
        width = 490
        height = width*im.size[1]/im.size[0]
    else:
        height = 390
        width = height*im.size[0]/im.size[1]
    im.thumbnail((width, height), Image.ANTIALIAS)
    photo = ImageTk.PhotoImage(im)
    label.configure(image=photo)
    label.image = photo
    i += 1
    return

def classify_obj():
    print("In Development")
    return

root = tk.Tk()
root.wm_title("Classify Image")

frame1 = tk.Frame(root, width=500, height=400, bd=2)
frame1.grid(row=1, column=0)
cv1 = tk.Canvas(frame1, height=390, width=490, background="white", bd=1, relief=tk.RAISED)
label = tk.Label(cv1)
cv1.create_window(0, 0, anchor='nw', window=label)
cv1.grid(row=1,column=0)
claButton = tk.Button(master=root, text='Classify', height=2, width=10, command=classify_obj)
claButton.grid(row=0, column=1, padx=2, pady=2)
frame2 = tk.Frame(root, width=500, height=400, bd=1)
frame2.grid(row=1, column=1)
cv2 = tk.Canvas(frame2, height=390, width=490, bd=2, relief=tk.SUNKEN)
cv2.grid(row=1,column=1)
broButton = tk.Button(master=root, text='Next', height=2, width=8, command=showImage)
broButton.grid(row=0, column=0, padx=2, pady=2)

showImage()
tk.mainloop()
Ron Norris
  • 2,642
  • 1
  • 9
  • 13
  • Your answer works, however I would like for you to read up on global variables and why they are a bad idea. Maybe take a look at [this post](https://stackoverflow.com/a/19158418/7475225) – Mike - SMT Jun 19 '17 at 16:13
  • I am perfectly aware why global variables are a bad idea. The request did not come with a class to use, so I didn't create one. I changed as little code as possible to make it work. Excellent tip you provided for anyone using an answer from this solution. – Ron Norris Jun 19 '17 at 20:01
  • Just thought I would point it out. Some people don't know of the downsides to global variables and I just wanted to point it out :) – Mike - SMT Jun 19 '17 at 20:18
  • I was actually having problem calling fname to other functions that is why I made it global... I'm a C++ coder so I get it how bad it is to create a global variable... Thanks to @RonNorris too though for the suggestion... It was helpful too – Incognito Possum Jun 20 '17 at 10:08