@codercoder

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

Python3エラー「AttributeError: read」を解消し、顔検出アプリを完成させたい

解決したいこと

【概要】
Python3エラー「AttributeError: read」を解消し、顔検出アプリを完成させたい

【詳細】
下記の動画及びドキュメントを参考に、streamlitとAzure Face APIをつかって顔検出アプリを作成しています。

【有料級】今話題のPythonライブラリStreamlitを用いて、顔検出アプリの作成から公開までの流れをわかりやすく解説
https://www.youtube.com/watch?v=zpBjbK6jic0&t=4217s

Azure FaceAPIクイックスタート
https://docs.microsoft.com/ja-jp/azure/cognitive-services/face/quickstarts/client-libraries?tabs=visual-studio&pivots=programming-language-python

発生している問題・エラー

  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/streamlit/script_runner.py", line 379, in _run_script
    exec(code, module.__dict__)
  File "/Users/user/Desktop/python_lesson/顔検出アプリ/main.py", line 98, in <module>
    detected_faces = face_client.face.detect_with_stream(
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/azure/cognitiveservices/vision/face/operations/_face_operations.py", line 779, in detect_with_stream
    response = self._client.send(request, stream=False, **operation_config)
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/msrest/service_client.py", line 336, in send
    pipeline_response = self.config.pipeline.run(request, **kwargs)
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/msrest/pipeline/__init__.py", line 197, in run
    return first_node.send(pipeline_request, **kwargs)  # type: ignore
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/msrest/pipeline/__init__.py", line 150, in send
    response = self.next.send(request, **kwargs)
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/msrest/pipeline/requests.py", line 72, in send
    return self.next.send(request, **kwargs)
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/msrest/pipeline/requests.py", line 137, in send
    return self.next.send(request, **kwargs)
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/msrest/pipeline/__init__.py", line 150, in send
    response = self.next.send(request, **kwargs)
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/msrest/pipeline/requests.py", line 193, in send
    self.driver.send(request.http_request, **kwargs)
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/msrest/universal_http/requests.py", line 333, in send
    return super(RequestsHTTPSender, self).send(request, **requests_kwargs)
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/msrest/universal_http/requests.py", line 139, in send
    response = session.request(
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/requests/sessions.py", line 542, in request
    resp = self.send(prep, **send_kwargs)
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/requests/sessions.py", line 655, in send
    r = adapter.send(request, **kwargs)
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/requests/adapters.py", line 469, in send
    for i in request.body:
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/msrest/service_client.py", line 137, in stream_upload
    chunk = data.read(self.config.connection.data_block_size)
  File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/PIL/Image.py", line 546, in __getattr__
    raise AttributeError(name)
AttributeError: read

該当するソースコード

from sqlalchemy import column
import  streamlit as st
import pandas as pd
import numpy as np
import asyncio
import io
import glob
import os
from urllib.parse import urlparse
from io import BytesIO

st.title('顔認識アプリ')

KEY = "自分のKeyを入力"
ENDPOINT = "自分のENDPOINTを入力"
face_client = FaceClient(ENDPOINT, CognitiveServicesCredentials(KEY))

upload_file = st.file_uploader("Choose an image...", type = 'JPG')

#変数に値が入っていたら
if upload_file is not None:
  #アップロードした画像を開く
  image_data = Image.open(upload_file)

  with io.BytesIO() as output:
      image_data.save(output, format="JPEG")
      binary_img = output.getvalue() #バイナリーデータ取得

  # 認識された顔周辺に四角を描く関数
  def getRectangle(faceDictionary):
      rect = faceDictionary.face_rectangle
      left = rect.left
      top = rect.top
      right = left + rect.width
      bottom = top + rect.height
      return ((left, top), (right, bottom))

  # 認識された顔の上に年齢を描く関数
  def getAge(faceDictionary):
      rect = faceDictionary.face_rectangle
      left = rect.left
      top = rect.top - 20
      return (left, top)

  # イメージオブジェクト生成
  drawing = ImageDraw.Draw(image_data)

  detected_faces = face_client.face.detect_with_stream(
    image_data,
    return_face_landmarks=True,
    return_face_attributes=['accessories','age','emotion','gender','glasses','hair','makeup','smile']
  ) 

  # 関数を呼び出して、顔に四角を描く
  for face in detected_faces:
      drawing.rectangle(getRectangle(face), outline='Blue', width = 3)
      drawing.text(getAge(face), str(face.face_attributes.age), align = 'Left', 
      fill = 'Red')


  #画像の表示
  image_data.show()

追記情報

・1記事目で作っているアプリを作りたいのですが、動画作成から1年経過しており、情報が古かったため、MircroAzureの公式ドキュメントを参考に改変しています。

・初期画面(アップロード画面の表示)の表示と、アップロード画像の選択まではできています。

・Python3.9を使っています。

・アプリ部分(streamlit)とロジック部分(FaceAPI)を結合する時に、25行目以降のwith部分を追加していた時に下記エラーが発生しました。
 →streamlitの実装部分は正常に動いているので、FaceAPIの実装でうまく行っていません。

・エラーがPILのImage.pyで生じているため、Image.open(upload_file)で開けない(read)できないということなのかと思いますが、どのように変更したらよいか皆目検討も付きませんでした。

試したこと

・image_data.show()のコメントアウト
→同じエラーが発生

・ with io.BytesIO()~の削除

・FACEAPIのロジック部分削除

・detected_faces = face_client.face.detect_with_stream(image_data,のimage_dataをbinary_imgに変更
 →別のエラーが発生。(byte型はreadを持っていない)

以上、よろしくお願いいたします。

0 likes

1Answer

エラーがPILのImage.pyで生じているため、Image.open(upload_file)で開けない(read)できないということなのかと思いますが、どのように変更したらよいか皆目検討も付きませんでした。

原因は,FaceClientにおけるdetect_with_stream第一引数に渡されたものはread()というメソッドを動作させられるという点に起因します.

もちろんPILImage.open(upload_file)で得られたオブジェクトにはread()メソッドはありませんのでエラーになります.

一般的にPythonを使っててread(data_block_size)をするといえばファイルを開くときになりそうなので,次のように変更してみてはいかがでしょうか.

  detected_faces = face_client.face.detect_with_stream(
-   image_data,
+   open(upload_file, "rb"),
    return_face_landmarks=True,
    return_face_attributes=['accessories','age','emotion','gender','glasses','hair','makeup','smile']
  ) 
1Like

Comments

  1. @codercoder

    Questioner

    ご回答いただき、ありがとうございます。
    非常に感謝いたします。
    大変勉強になりました。

    ご指摘いただいた通り、書き換えたのですが、下記のエラーが出てしまいました。

    TypeError: expected str, bytes or os.PathLike object, not UploadedFile


    ```
    File "/Users/user/opt/anaconda3/lib/python3.9/site-packages/streamlit/script_runner.py", line 379, in _run_script
    exec(code, module.__dict__)
    File "/Users/user/Desktop/python_lesson/顔検出アプリ/main.py", line 99, in <module>
    open(upload_file, "rb"),
    TypeError: expected str, bytes or os.PathLike object, not UploadedFile
    ```

    openメソッドの第一引数をimage_dataに変えたり、open()の1行をbinary_imgに変更したりしたのですが、エラーは解消しませんでした。

    調べると、第一引数はファイルのパスやテキスト(.txt)であれば開けるとのことがわかりましたが、今回の場合、画像データを直接指定しているから読み込まれないということなのでしょうか?


    それぞれ、該当箇所を変更すると、下記のエラーが発生してしまいます、、、
    '''
    open(binary_img,'rb')
    →ValueError: embedded null byte

    binary_img
    →AttributeError: 'bytes' object has no attribute 'read'

    open(image_data,'rb')
    →TypeError: expected str, bytes or os.PathLike object, not JpegImageFile

    upload_file
    →#APIErrorException: (InvalidImageSize) Image size is too small.

    '''

    お手数おかけいたしますが、よろしくお願いいたします。
  2. upload_fileはてっきりファイルへのパスかと思ったのですが,違ったのですね

    > 今回の場合、画像データを直接指定しているから読み込まれないということなのでしょうか?
    そうですね,一番愚直には一旦画像データを適当なファイルに保存してからopen()する方が何も考えなくてよさそうですね.
  3. @codercoder

    Questioner

    お返事が遅くなってしまい、申し訳ございません。
    丁寧にご回答いただき、ありがとうございます。
    今回は、streamlitで画像をローカルからアップロードした後に、FACEAPIで顔検出のロジックを実装し、streamlitで結果を表示する予定でしたが、アップした画像をまたローカルに保存してオープンするということですよね。
    streamlitとの掛け合わせが難しかったですが、非常に勉強になりました。
    教えていただき、本当にありがとうございます。

Your answer might help someone💌