AttributeError: 'PhotoImage' object has no attribute 'shape'?
Ich bin derzeit dabei mit tkinter, opencv und mit Media Pipe Framework zu arbeiten. Dabei möchte ich Bilder Hochladen können und die hochgeladenen Bilder soll mithilfe von Mediapipe die Hand Landmarks erfassen. Mit Hand Landmarks meine ich alle 21 Positionen eines Hand zu erkennen (Hier findet ihr mehr Infos dazu: https://google.github.io/mediapipe/solutions/hands.html ). Leider bekomme ich mit meiner erstellten Implementierung folgende Fehlermeldung:
INFO: Created TensorFlow Lite XNNPACK delegate for CPU.
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python\Python37\lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
File "C:/Users/bj/projects/pro1/pictureMp.py", line 31, in imageLandmarks
height, width, _ = image.shape
AttributeError: 'PhotoImage' object has no attribute 'shape'
Was kann ich dagegen machen? Hier ist mein aktueller Code:
def imageLandmarks():
global panelA
with mpHands.Hands(static_image_mode=True, max_num_hands=2, min_detection_confidence=0.5) as hands:
select_image.path = filedialog.askopenfilename()
filename = os.path.basename(select_image.path)
if len(select_image.path) > 0:
image = cv2.imread(select_image.path)
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
image = Image.fromarray(image)
image = ImageTk.PhotoImage(image)
height, width, _ = image.shape
results = hands.process(image)
num_cords = 21
landmarks = ['class']
for val in range(1, num_cords + 1):
landmarks += ['x{}'.format(val), 'y{}'.format(val), 'z{}'.format(val)]
if results.multi_hand_landmarks:
for num, hand in enumerate(results.multi_hand_landmarks):
mpDraw.draw_landmarks(image, hand, mpHands.HAND_CONNECTIONS)
1 Antwort
Zumindest in Version 8.2 gibt es, so wie es die Fehlermeldung auch schon sagt, kein Attribut shape.
https://pillow.readthedocs.io/en/stable/reference/ImageTk.html#PIL.ImageTk.PhotoImage
Verwende stattdessen die Methoden height und width, um die Größe des Bildes zu erhalten.
Nun, generell versuchst du, der process-Methode ein PhotoImage-Objekt zu übergeben, womit sie nicht zurechtkommt, da einfach das erwartete shape-Attribut fehlt. Normalerweise würde die process-Methode ein OpenCV-Image-Objekt erhalten, welches die Erwartung erfüllen kann.
Die Frage wäre daher: Wieso benötigst du diese beiden Zeilen?
image = Image.fromarray(image)
image = ImageTk.PhotoImage(image)
In der Zeile zuvor erhältst du bereits ein Bildobjekt:
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
und das wäre sogar vom richtigen Typ.
"image = Image.fromarray(image)" erzeugt einen Bildspeicher aus einem Objekt, das die Array-Schnittstelle exportiert. Mit "image = ImageTk.PhotoImage(image)" möchte ich das Bild öffnen.
Ich habe jetzt aber entsprechend mein Code angepasst. Aber erhalte jetzt eine Ferhlemeldung das tkinter das Bild nicht erkennt.
C:\Python\Python37\python.exe C:/Users/bj/PycharmProjects/gebaerdensprachdolmetscher/teachingModelPicture.py
INFO: Created TensorFlow Lite XNNPACK delegate for CPU.
<class 'mediapipe.python.solution_base.SolutionOutputs'>
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python\Python37\lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
File "C:/Users/bj/projects/pro1/pictureMp.py", line 41, in select_image
panelA = Label(image=image)
File "C:\Python\Python37\lib\tkinter\__init__.py", line 2766, in __init__
Widget.__init__(self, master, 'label', cnf, kw)
File "C:\Python\Python37\lib\tkinter\__init__.py", line 2299, in __init__
(widgetName, self._w) + extra + self._options(cnf))
_tkinter.TclError: image "[[[186 195 169]
[[[186 195 169]
[186 195 169]
[188 194 169]
... weitere Matrizen ...
[162 159 155]
[161 158 154]
[160 157 153]]" doesn't exist
Das ist mein angepasster code:
global panelA
select_image.path = filedialog.askopenfilename()
filename = os.path.basename(select_image.path)
with mpHolistic.Holistic(min_detection_confidence=0.5, min_tracking_confidence=0.5) as holistic:
if len(select_image.path) > 0:
image = cv2.imread(select_image.path)
image, results = detection(image, holistic)
landmarks(image, results)
pictureInfo.configure(text=filename + " opened!")
if panelA is None:
panelA = Label(image=image)
panelA.image = image
panelA.pack(side="left", padx=10, pady=10)
else:
panelA.configure(image=image)
panelA.image = image
Bei der Function detection() gebe ich meinen Mediapipe Detection aus und bei Landmarks() werden die Positionen der Händer erkannt. Wenn die Beiden Methode seperat ausgebe läuft es auch aber im zusammen hang mit mein tkiner bekomme ich diese Fehlermeldung.
In dieser Zeile
panelA = Label(image=image)
möchtest du das OpenCV-Bild wieder in einem für Tkinter kompatiblen Format. Da ist also doch wieder eine Konversion notwendig. Statt mit einem Label zu arbeiten, würde ich ein Canvas-Element nehmen.
So dürfte es klappen:
photo = PIL.ImageTk.PhotoImage(image = Image.fromarray(image))
canvas = Canvas(yourWindow, width = photo.width(), height = photo.height())
canvas.pack()
canvas.create_image(0, 0, image=photo, anchor=tkinter.NW)
Ich habe es mal versucht. doch leider komme ich nicht mehr weiter:
Jetzt bekomme ich eine weitere Fehlermeldung: