1

I am using my keras model to detect 2 categories using a modified tkinter program to that classifies butterfly species.

import tkinter as tk
from tkinter import filedialog
from tkinter import *
from PIL import ImageTk, Image
import numpy
import cv2

import tensorflow as tf
model = tf.keras.models.load_model("64x300-CNN.model")

classes = ["real", "fake"]

top=tk.Tk()
top.geometry('800x600')
top.title('Butterfly Classification')
top.configure(background='#CDCDCD')
label=Label(top,background='#CDCDCD', font=('arial',15,'bold'))
sign_image = Label(top)

def prepare(filepath):
    IMG_SIZE = 50  # 50 in txt-based
    img_array = cv2.imread(filepath, cv2.IMREAD_GRAYSCALE)  # read in the image, convert to grayscale
    new_array = cv2.resize(img_array, (IMG_SIZE, IMG_SIZE))  # resize image to match model's expected sizing
    return new_array.reshape(-1, IMG_SIZE, IMG_SIZE, 1)  # return the image with shaping that TF wants.

def classify(file_path):
    global label_packed
    new_array = cv2.imread(file_path, 1)
    pred = model.predict([prepare(new_array)])
    sign = classes[pred]
    print(sign)
    label.configure(foreground='#011638', text=sign)

def show_classify_button(file_path):
    classify_b=Button(top,text="Classify Image",
    command=lambda: classify(file_path),padx=10,pady=5)
    classify_b.configure(background='#364156', foreground='white',
    font=('arial',10,'bold'))
    classify_b.place(relx=0.79,rely=0.46)

def upload_image():
    try:
        file_path=filedialog.askopenfilename()
        uploaded=Image.open(file_path)
        uploaded.thumbnail(((top.winfo_width()/2.25),
        (top.winfo_height()/2.25)))
        im=ImageTk.PhotoImage(uploaded)
        sign_image.configure(image=im)
        sign_image.image=im
        label.configure(text='')
        show_classify_button(file_path)
    except:
        pass

upload=Button(top,text="Upload an image",command=upload_image,
  padx=10,pady=5)

upload.configure(background='#364156', foreground='white',
    font=('arial',10,'bold'))

upload.pack(side=BOTTOM,pady=50)
sign_image.pack(side=BOTTOM,expand=True)
label.pack(side=BOTTOM,expand=True)
heading = Label(top, text="Butterfly Classification",pady=20, font=('arial',20,'bold'))

heading.configure(background='#CDCDCD',foreground='#364156')
heading.pack()
top.mainloop()

and got this error

SystemError: returned NULL without setting an error

I have tried a fix from a similar question asked here but with no luck I think there is a problem when importing the image through tkinter and not through a file path?

Using cv2.imread: "<built-in function imread> returned NULL without setting an error", as if it can't open the picture or get the data

full error message

Exception in Tkinter callback Traceback (most recent call last):
File "C:\Users\1rock\anaconda3\envs\machL\lib\tkinter_init_.py", line 1883, in call return self.func(*args) File "C:/Users/1rock/anaconda3/envs/machL/fly.py", line 36, in command=lambda: classify(file_path),padx=10,pady=5) File "C:/Users/1rock/anaconda3/envs/machL/fly.py", line 29, in classify pred = model.predict([prepare(new_array)]) File "C:/Users/1rock/anaconda3/envs/machL/fly.py", line 22, in prepare img_array = cv2.imread(filepath, cv2.IMREAD_GRAYSCALE) # read in the image, convert to grayscale SystemError: returned NULL without setting an error

Process finished with exit code 0

11
  • 1
    The two lines new_array = cv2.imread(file_path, 1) and pred = model.predict([prepare(new_array)]) should be changed to pred = model.predict([prepare(file_path)]). Commented Jan 9, 2021 at 7:52
  • hiya thanks for the reply when I did that i got this error Exception in Tkinter callback Traceback (most recent call last): File "C:\Users\1rock\anaconda3\envs\machL\lib\tkinter\__init__.py", line 1883, in __call__ return self.func(*args) File "C:/Users/1rock/anaconda3/envs/machL/fly.py", line 35, in <lambda> command=lambda: classify(file_path),padx=10,pady=5) File "C:/Users/1rock/anaconda3/envs/machL/fly.py", line 29, in classify sign = classes[pred] TypeError: only integer scalar arrays can be converted to a scalar index Commented Jan 9, 2021 at 8:08
  • You should check what pred (returned by model.predict()) is. As it is used as index to access classes (a list), it should be integer. Commented Jan 9, 2021 at 8:13
  • I checked using another code model.predict should only print out either 0 or 1 Commented Jan 9, 2021 at 8:15
  • Did you check the type of pred? According to the official document, it is numpy array. Commented Jan 9, 2021 at 8:19

1 Answer 1

1

The prepare function you implemented does the process of loading, resizing, reshaping images. The purpose of the function cv2.imread is to open an image from a given file path. But you fed the function prepare(new_array) where new_array is already the image itself, not the file path. I suggest two fixes, although both are conclusively equal.

Also, model.predict outputs the final layer in real numbers instead of integer-type class number. Therefore you must use model.predict_classes in this case. Also, because these functions default to batch mode, although you only feed a single image, you must assume the prediction to be an array, and index it.

First fix is to feed the file path and load the image inside the prepare function.

def prepare(filepath):
    IMG_SIZE = 50  # 50 in txt-based
    img_array = cv2.imread(filepath, cv2.IMREAD_GRAYSCALE)  # read in the image, convert to grayscale
    new_array = cv2.resize(img_array, (IMG_SIZE, IMG_SIZE))  # resize image to match model's expected sizing
    return new_array.reshape(-1, IMG_SIZE, IMG_SIZE, 1)  # return the image with shaping that TF wants.

def classify(file_path):
    global label_packed
    pred = model.predict_classes([prepare(file_path)])
    sign = classes[pred[0,0]]
    print(sign)
    label.configure(foreground='#011638', text=sign)

Next is to perform only reshaping in the prepare function.

def prepare(img_array):
    IMG_SIZE = 50  # 50 in txt-based
    new_array = cv2.resize(img_array, (IMG_SIZE, IMG_SIZE))  # resize image to match model's expected sizing
    return new_array.reshape(-1, IMG_SIZE, IMG_SIZE, 1)  # return the image with shaping that TF wants.

def classify(file_path):
    global label_packed
    new_array = cv2.imread(file_path, 1)
    pred = model.predict_classes([prepare(new_array)])
    sign = classes[pred[0,0]]
    print(sign)
    label.configure(foreground='#011638', text=sign)

I would also like to say that this type of resizing process is very inefficient. What would be a solution for an input pipeline is the preprocessing layers developed inside Tensorflow. You can create a model acting as an input pipeline.

input_pipeline=tf.keras.models.Sequential([
  tf.keras.layers.experimental.preprocessing.Resizing(h,w,..),
  tf.keras.layers.experimental.preprocessing...
])
...
new_array=input_pipeline.predict(img_array)

or use tf.image.resize, since they can processes batches of images without an explicit loop, and provides more features that can be applied simply.

Sign up to request clarification or add additional context in comments.

9 Comments

hiya thanks for the reply im pretty new at this please bear with me for the first fix how should I feed the file path and load the image because when I run the program there is a gui that ask me to load an image when I click it my folder opens up but when I try to input an image i get this error TypeError: only integer scalar arrays can be converted to a scalar index
In my understanding of your code, the user inputs the file path in upload_image and calls show_classify_button which again calls classify, which uses the prepare function for preprocessing the image. file_path is fed from upload_image to the classify function, but you fed the prepare function with the image itself, instead of the file path. My first fix is replacing the image with the file path.
In which line does the TypeError occur?
If the error occurs at sign = classes[pred] pls wait a moment I'll edit my answer.
@ISETHSGT tested it out, and it worked perfectly
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.