質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

Q&A

解決済

1回答

2499閲覧

Python3 Tkinter カメラの映像からバーコードやQRコードを読み取りたい

person

総合スコア223

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

0グッド

1クリップ

投稿2021/05/13 00:03

編集2021/05/18 00:26

カメラの映像からバーコードやQRコードを読み取りたいです。

前回、Tkinterにカメラ映像を表示する部分を作りました。

ネットでバーコード読み取りについて調べたときに下記のサイトを見かけたので、これを移植しようとしました。

自分で移植してみたコードが下記のものとなります。
self.frameに対してバーコードの読み取りと、それの結果の図形埋め込みをしています。
動作確認として、バーコードをいくつか試してみて読み取れたもの、読み取れなかったものがありました(上記リンクでもそのような記載がありました)。

Tkinterのcanvasでcreate_image()の配置換えとかをしている関係で、移植が問題なくできているかわからないのでその辺のチェックをしてほしいです。(読み取れたものについては、表示や値も正しかったので、問題はないと思いますが一応)
下記ソースコードのクラスメソッドupdate_by_timer()が該当部分です。

回答よろしくお願いします。

Python

1from datetime import datetime 2from PIL import Image, ImageTk 3from pyzbar.pyzbar import decode 4import cv2 5import queue 6import threading 7import tkinter as tk 8 9class App: 10 def __init__(self, win): 11 video_source = 0 12 self.vcap = cv2.VideoCapture(video_source, cv2.CAP_DSHOW) 13 self.width = self.vcap.get(cv2.CAP_PROP_FRAME_WIDTH) 14 self.height = self.vcap.get(cv2.CAP_PROP_FRAME_HEIGHT) 15 self.font = cv2.FONT_HERSHEY_SIMPLEX 16 17 self.data_queue = queue.Queue() 18 19 self.win = win 20 self.win.title("Camera") 21 self.thread = threading.Thread(target=self.get_queue) 22 self.thread.start() 23 self.disp_center(self.win, 720, 480) 24 self.win.protocol("WM_DELETE_WINDOW", self.close) 25 self.create_view() 26 self.bind_event() 27 #self.update_by_timer() 28 self.canvas.after(15, self.update_by_timer) 29 30 31 def disp_center(self, win, wx=400, wy=300): 32 #win.resizable(0, 0) 33 dx = win.winfo_screenwidth() 34 dy = win.winfo_screenheight() 35 win_size = str(wx) + "x" + str(wy) + \ 36 "+" + str(int(dx/2 - wx/2)) + "+" + str(int(dy/2 - wy/2)) 37 win.geometry(win_size) 38 39 40 def close(self): 41 self.data_queue.put(["close", None]) 42 self.thread.join() 43 self.win.destroy() 44 self.vcap.release() 45 cv2.destroyAllWindows() 46 47 48 def create_view(self): 49 self.win.rowconfigure(0, weight=1) 50 self.win.columnconfigure(0, weight=1) 51 52 self.frame = tk.Frame(self.win, relief="sunken", bd=1) 53 self.frame.grid(row=0, column=0, sticky="nsew") 54 self.frame.rowconfigure(0, weight=1) 55 self.frame.columnconfigure(0, weight=1) 56 57 self.canvas = tk.Canvas(self.frame) 58 self.canvas.grid(row=0, column=0, sticky="nsew", padx=10, pady=10) 59 60 ret, frm = self.vcap.read() 61 #print("ret: {}".format(ret)) 62 #print("frm: {}".format(frm)) 63 self.frame = cv2.cvtColor(frm, cv2.COLOR_BGR2RGB) 64 self.photo = ImageTk.PhotoImage(image = Image.fromarray(self.frame)) 65 #self.canvas.update() 66 cv_w = self.canvas.winfo_reqwidth() 67 cv_h = self.canvas.winfo_reqheight() 68 self.img_id = self.canvas.create_image(cv_w // 2, cv_h // 2, image=self.photo, anchor="center") 69 70 71 """ 72 self.canvas.update() 73 cv_w = self.canvas.winfo_width() 74 cv_h = self.canvas.winfo_height() 75 76 rec_id = self.canvas.create_rectangle(0, 0, cv_w, cv_h, fill="black") 77 78 79 # 長方形の座標取得 80 rec_pos = self.canvas.coords(rec_id) 81 # テキストを描画(位置は適当) 82 text_id = self.canvas.create_text(0, 0, text="NO SIGNAL", font=("", 20), fill="white") 83 # テキストのサイズ取得 84 text_size = self.canvas.bbox(text_id) 85 # テキストの座標移動 86 rc_x = rec_pos[2] / 2 87 rc_y = rec_pos[2] / 3 88 tc_y = text_size[3] / 2 89 self.canvas.move(text_id, rc_x - (rec_pos[0] / 2), rc_y - tc_y) 90 """ 91 92 self.button = tk.Button(self.win, text="Snapshot", command=self.pushed_button) 93 self.button.grid(row=1, column=0, sticky="", pady=10) 94 95 96 def pushed_button(self): 97 self.data_queue.put(["snapshot", None]) 98 99 100 def update_by_timer(self): 101 ret, frm = self.vcap.read() 102 #print("ret: {}".format(ret)) 103 #print("frm: {}".format(frm)) 104 self.frame = cv2.cvtColor(frm, cv2.COLOR_BGR2RGB) 105 if ret: 106 d = decode(self.frame) 107 if d: 108 for barcode in d: 109 x,y,w,h = barcode.rect 110 cv2.rectangle(self.frame,(x,y),(x+w,y+h),(0,0,255),2) 111 barcodeData = barcode.data.decode('utf-8') 112 print(barcodeData) 113 frame = cv2.putText(self.frame,barcodeData,(x,y-10),self.font,.5,(0,0,255),2,cv2.LINE_AA) 114 self.photo = ImageTk.PhotoImage(image = Image.fromarray(self.frame)) 115 self.canvas.itemconfig(self.img_id, image=self.photo) 116 self.canvas.after(15, self.update_by_timer) 117 118 119 def update_by_resize(self, e): 120 self.canvas.itemconfig(self.img_id, image=self.photo, anchor="center") 121 cv_w = self.canvas.winfo_width() 122 cv_h = self.canvas.winfo_height() 123 self.canvas.coords(self.img_id, cv_w // 2, cv_h // 2) 124 125 126 def bind_event(self): 127 self.canvas.bind("<Configure>", self.update_by_resize) 128 129 130 def get_queue(self): 131 while True: 132 msg, data = self.data_queue.get() 133 if msg == "snapshot": 134 self.snapshot() 135 elif msg == "close": 136 break 137 else: 138 print("----- msg error -----") 139 break 140 141 def snapshot(self): 142 filename = "C:/Users/user01/Desktop/img/frame-" + datetime.now().strftime("%Y-%d-%m-%H-%M-%S_%f") + ".jpg" 143 cv2.imwrite( filename, 144 cv2.cvtColor( self.frame, cv2.COLOR_BGR2RGB ) ) 145 print(filename) 146 147 148def main(): 149 win = tk.Tk() 150 App(win) 151 win.mainloop() 152 153if __name__ == "__main__": 154 main()

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

person

2021/05/13 07:55

「質問を編集する」ボタンから編集を行い、調査したこと・試したことを記入しました。 調査したこと:バーコードの取得方法 試したこと:調査記事からの移植
guest

回答1

0

ベストアンサー

Tkinterのcanvasでcreate_image()の配置換えとかをしている関係で、

移植が問題なくできているかわからない

Tkinter を用いているのは、カメラから読み取った画像の表示部分なので、
バーコード/QRコードの読み取りには全く関与しません。

Tkinter を用いない場合と同じ結果になるはずです。

バーコード/QRコード読み取りのデバッグに関しては、
「正常に読み取れたもの」、「読み取れなかったもの」を区別してスナップショットを取り、
その画像を、他のリーダーで読み取れるかどうか、比較してみてはどうでしょう。

印刷物から読み取る場合は、影や光の反射等の状況により
撮影自体がうまくいってないケースも考えられます。
前処理として「グレースケール化」や「二値化」を試すと良いかもしれません。

投稿2021/05/13 17:32

teamikl

総合スコア8664

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

person

2021/05/14 10:48 編集

回答ありがとうございます。 > Tkinter を用いているのは、カメラから読み取った画像の表示部分なので、 バーコード/QRコードの読み取りには全く関与しません。 やっぱりそうですよね。じゃあ特にコーディング上の問題はないということで。 > 「正常に読み取れたもの」、「読み取れなかったもの」を区別してスナップショットを取り、 > その画像を、他のリーダーで読み取れるかどうか、比較してみてはどうでしょう。 一応、バーコードリーダーでは読めることを確認しました。 確認したのは印字されているものをスキャナで読み取ったやつを印刷したものです。 pyzbarでバーコードのタイプに非対応なものがあるのか確認してみます。 > 前処理として「グレースケール化」や「二値化」を試すと良いかもしれません。 グレースケール加工 cv2.cvtColor(self.frame, cv2.COLOR_BGR2GRAY) を試しましたが、あまり影響はなかったです。
teamikl

2021/05/14 12:41 編集

コードでの対応に取り組む前に、読み込めなかったのが どのような原因か詳細を調べた方が良いです。 ソフト側で対応するよりも、照明や撮影の角度を工夫する等、 物理的な対応を取った方が良い場合もあります。 別の原因の場合は、この対応を行ったからと言って改善するわけではありません。 影響があるのは2値化の方で、 例えば撮影時の影で白か黒かはっきりしないようなものを しきい値以上なら白・黒とはっきりさせる為のものです。 グレースケールはその為の必要な前処理として行います。 ライブラリ側でも同様の処理が行われてますが、 自分で行う場合は、そのしきい値を状況に応じて設定できます。 cv2.threshold, cv2.adaptiveThreshold を調べて見て下さい。 >じゃあ特にコーディング上の問題はないということで。 デコード結果に影響があるような箇所はありません。 カメラからの読込からデコード迄の間に関与できる余地もないので。 ここは、tkinterを使わずに読込テストを行うと確認できるはずです。 GUIで影響がありそうなのは、 これがイベントループ内のタイマーで行われている点で、 あまり複雑な処理を高頻度で行うと、GUIのレスポンスに影響する可能性があります。 現状のコードでは、フレーム描画毎にバーコードの検出処理を行ってますが、 これは1秒間に数十回呼び出される処理なので、 デコードは1秒間隔くらい(利用者が遅延を感じない程度)でも良いのではないでしょうか。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問