はじめに
今回は、Pythonの代表的な画像処理ライブラリであるPillowとOpenCVを用いて、Streamlitで画像を読み込んで表示する方法についてまとめたいと思います。
普段Pillowを用いて読み込んでいましたが、OpenCVを用いて表示させようとしたところうまくいかなかったため、それの対処法を併せてまとめます。
Pillowで読み込む場合
まずはPillowで読み込んだ場合について紹介します。
import streamlit as st
from PIL import Image
file_path = st.file_uploader('', type=['png', 'jpg', 'jpeg'])
img = Image.open(file_path)
st.image(img)
簡単ですね。
必要最低限しか書いておりません。
OpenCVで読み込む場合
一方、OpenCVで画像ファイルを読み込もうとした場合、OpenCVを使用している人からすると
import streamlit as st
import cv2
file_path = st.file_uploader('', type=['png', 'jpg', 'jpeg'])
img = cv2.imread(file_path)
st.image(img)
となると思うじゃないですか?????
これを実行したとき、
TypeError: Can't convert object to 'str' for 'filename'
というエラーが生じます。
なんでやねん!!!
ファイル読み込んで、そのファイルをそのまま渡してるやんけ!
Pillowではうまくいったのに、なんでOpenCVだとできないんや!
とブチ切れているときに、暇~?って声かけてきた上司は未来永劫孫子の代まで恨みます。
このエラーについて調べてみると、
st.file_uploader
から返されるオブジェクトは、ファイルのバイナリデータを含むものであり、直接 cv2.imread
に渡すことはできず、cv2.imread
はファイルパス (str) を受け取る関数であり、バイナリデータを直接渡すことはできない。とのこと。
よくわからんけど、strで渡せばええんやろと。
そして、以下が読み込むための対策
import streamlit as st
import cv2
import tempfile
file_path = st.file_uploader('', type=['png', 'jpeg', 'jpg'])
if img_file:
temp_file = tempfile.NamedTemporaryFile(delete=False)
temp_file.write(file_path.read())
img = cv2.imread(temp_file.name)
temp_file.close()
st.image(img)
このように、一時ファイルに一旦読み込んだファイルを保存し、その保存名をtemp_file.name
で引っ張ってきてます。
リソースの無駄遣いになるので、一時ファイルは不要になったら消しときましょうね(temp_file.close()
)。
これでOpenCVで画像を読み込み、表示することができました。
追記
imdecode
を用いることで直接データを渡すことができるようです。
import streamlit as st
import cv2
import numpy as np
file_path = st.file_uploader('', type=['png', 'jpg', 'jpeg'])
# img = cv2.imdecode(file_path)
# st.image(img)
if file_path :
# ファイルをバイト列として読み込む
image_bytes = file_path.read()
# バイト列から画像をデコードする
img = cv2.imdecode(np.frombuffer(image_bytes, np.uint8), cv2.IMREAD_COLOR)
# 画像を表示する
# BGR チャンネルで表示(一般的な画像フォーマットはRGBであるため)
st.image(img, channels="BGR")
一時ファイルに保存する方法と画像をデコードして読み込む方法、どちらのコードが良いコードなのかはさっぱりです(;'∀')
まとめ
今回はStreamlitアプリで画像を読み込み、表示させる方法を紹介しました。
基本的なことですが、StreamlitとOpenCVの仕様であったり、同じように困っている人のお役に立てば幸いです。
今後画像解析のライブラリはメインで勉強しようと思っておりますので、また備忘録として残していこうと思います。
それでは!!!