【python】Yahoo Web APIでバーコード情報(JAN)から商品名を読み出す(数列→商品情報) 【お家IT#18】
本件の実装の一部
motojapan.hateblo.jp
前回の続き
motojapan.hateblo.jp
目次
前回は画像からバーコード情報(数列)を取得した。
今回はこの情報から、商品情報を取得する。
取得方法のアイディア
実際このバーコード情報から商品名を求める方法はいくつかある。
今回はWebAPIを中心に話を進めるが折角なのでスクレイピングも少しみてみる。
1.スクレイピングする方法
例えば、JANコード「9000009984074」に対応するのは、お馴染み「クリスタルカイザー」という飲料水。
これを検索にかけてみるとこうなる。
BeautifulSoup4 をインストール
$ apt-cache search beautifulsoup $ sudo apt-get install python3-bs4
実装
python3.x系で実装するとこんな感じ
import urllib.request from bs4 import BeautifulSoup headers = { "User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:47.0) Gecko/20100101 Firefox/47.0", } request = urllib.request.Request(url='https://www.google.co.jp/search?q=9000009984074+jan', headers=headers) response = urllib.request.urlopen(request) html = BeautifulSoup(response) print(html)
2.WebAPIで検索する方法(種類)
脱線したがこちらが本筋。
WebAPIでバーコード情報から商品名を求められるメジャーどころは下記。
Product Advertising API (Amazon Web Services)
楽天商品検索API (Rakuten Developers)
Yahoo! Developer Networksを使ってみる
今回はまず手軽にやってみたいので、Yahoo! APIにした。
さらに、Yahoo! Developer Networksを使うモチベーションは、Yahoo!が提供する地図や気象情報などの多種多様なサービスがWebAPIから扱えるという点もあったので、今回登録してみた。
次の前提は把握していたほうが話がスムーズ。
- Yahoo! Developer Networksは、ディベロッパー(アカウント)登録が必要である
- 「アプリケーション」という単位で管理している
- 1アカウント当たり、10個までのアプリケーションを登録できる
- クエリ数は、アプリケーション通算の総カウントで計算される
- API別に上限がある
登録
ディベロッパー登録
まずディベロッパー登録を下記から行う。
Yahoo! JAPAN ID登録 - Yahoo! JAPAN
gmailでも登録できる。
アプリケーション登録
「アプリケーション管理」から「新しいアプリケーションを開発」を選択。
アプリケーションの種類を選択し、他の入力情報を埋める。
「クライアントサイド」を選択する場合はこんな感じ。
クライアントID取得
アプリケーションを登録後、「デベロッパーネットワークトップ」>「アプリケーションの管理」>「アプリケーションの詳細」から、「Client ID」をメモする。
ここでメモしたIDを、
インストール & 実装
必要モジュールをインストール
$ pip install beautifulsoup4
単なるWebAPIとして扱えるので「スクレイピングする方法」と似たように簡単だが今度はpython2.7系で実装するとこんな感じ。
import urllib from bs4 import BeautifulSoup // code : バーコード情報 def code_to_product_info(code): print('*********** start product_info ************') start_time = time.time() product_info = None client_id = '<client_id>' url = 'http://shopping.yahooapis.jp/ShoppingWebService/V1/itemSearch?appid={0}&jan={1}'.format(client_id, code) response = urllib.urlopen(url).read() soup = BeautifulSoup(response) res = soup.find_all('name') // nameタグを取得 //ここから超雑 if len(res) > 0: product_info = res[0] print 'proc_time {0:f} [ms] '.format((time.time() - start_time) * 1000) return product_info print('*********** end product_info ************')
結果
クリスタルガイザー ミネラルウォーター 500ml×48本 並行輸入品 代引不可
処理速度は50-150[ms]程度。(通信状況によって揺らぐ)
以上。
ここまでで、画像から商品名(食品名)を検索するモジュールができた。
次回からは、OCRを用いて画像から賞味期限を取得するモジュールの話を進めたい。
【python】zbarでバーコードを読み取る(画像→数列) 【お家IT#17】
本件の実装の一部
motojapan.hateblo.jp
前回の続き
motojapan.hateblo.jp
目次
前回まででフロントエンド・バックエンドの整備が終わった。
以降は、画像処理部分を進める。
今回は食品名(商品名)を取得するために、バーコード情報の読み取りをしたい。
バーコードとは
ふと、そもそもバーコードが何かをちゃんとわかっていなかったので調べる。
「黒いバーと空白の組み合わせで、数字、文字、記号を読み込めるデータ形式」であり、一般的に縞模様を光学系認識機器で読み取る。
一般に普及している縞模様の一次元バーコードや、QRコードに体表される二次元バーコードをよく目にしている。
今回は食品名を取得したいので、今回は一次元バーコードを中心に考える。
バーコードの詳細は次が参考になる。
バーコードとは?|基礎知識|自動認識|デンソーウェーブ
バーコード種類は下記。
- 統一商品コード(ユニークコード)
- インストアコード(任意コード)
特にユニークコードで、日本で使われているのはJANコード。
JANコード桁数は下記。
- 標準タイプ(13桁)
- 先頭7桁 : JANメーカーコード
- 先頭9桁 : 国番号2桁 + JANメーカーコード7桁
- 短縮タイプ(8桁)
JANコード構成要素は下記。
- 国番号+メーカー番号
- 商品番号
- チェックデジット
また、特に気になるのは、両サイドにあるマージンと呼ばれる空白は、十分な領域が必要である。<ナローバー(最も小さい黒縞)の10倍> ★
バーコードを読み込む方法は2つ思いつく。
- バーコードリーダーといった専用機器で赤外線反射から読み取る
- カメラなどの汎用機器で画像から読み取る(今回はこっち)
まぁこんな感じのバーコードリーダーでの読み取りでもよい。
RAINLAX バーコードスキャナ 無線対応 Bluetooth対応 ワイヤレスバーコードリーダー レーザーバーコードリーダー 手持ち式バーコードスキャナ 2.4GHz
- 出版社/メーカー: RAINLAX
- メディア: オフィス用品
- この商品を含むブログを見る
ただ、それはあまりにつまらないし、「自宅で手軽に使う」というポリシーから外れるのでので今回は画像処理ベースで調べてみた。(スマホ一台で済ませたいし。)
zbarインストール
かなり簡単
//インストール $ sudo apt-get install libzbar-dev $ sudo apt-get install python-zbar ... //確認 $ python import zbar //error無しでOK
インストール時のトラブルシューティング
「error: command 'arm-linux-gnueabihf-gcc' failed with exit status 1」がインストール時に出る場合
下記インストール時にこんなエラーが出ることがある。
$ pip install zbar
対策 : module不足なので追加
$ sudo apt-get install python-dev
「segmentation fault」が実行時に出る場合
確認時(実行時)にこんなエラーが出ることがある。
$ python import zbar //segmentation fault
対策 : pipで入れたzbarがconflictしているようなのでpipはアンインストール、apt-getでインストール
$ pip uninstall zbar $ sudo apt-get install python-zbar
実装例
//img : cv2 image(numpy) def convert_image_to_code(img): print('=========== proc start =============') start_time = time.time() #init module scanner = zbar.ImageScanner() scanner.parse_config('enable') #image to gray gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) h = gray.shape[0] w = gray.shape[1] zimage = zbar.Image(w, h, 'Y800', gray.tostring()) #scan scanner.scan(zimage) result = [] for symbol in zimage: print('Type: {0} | Data: {1}'.format(symbol.type, symbol.data)) result.append({'type':symbol.type, 'data':symbol.data}) print 'proc_time {0:f} [ms] '.format((time.time() - start_time) * 1000) print('=========== proc end ===========') return result
結果
入力画像は★に注意して、実際にいくつか試してみるといい感じの結果となった。
平面紙印刷 |
レトレクパック印刷 |
曲面印刷 |
|
画像全体 |
|||
撮影領域 |
|||
結果 |
4970231640022 |
4902204411599 |
4902106232209 |
400 x 60 の画像に対して、処理速度は20-40[ms]程度。
曲面やぐにゃぐにゃ面でも割りとちゃんと認識できる。
以上。
次回はこのバーコードの数列から、食品名を取得する。
【Javascript】非同期実行を実装し、ボタンを押したフィードバックを全画面に行う 【お家IT#16】
本件の実装の一部
motojapan.hateblo.jp
前回の続き
motojapan.hateblo.jp
目次
前回までで、javascript/CSSを用いて撮影画面を作成した。
最後にUIの完成度を高めたいので撮影ボタンを押したらバックグラウンド全体が青くチカっとフラッシュするようにしたい。
そもそもの問題
ボタンを押したら、バックグラウンドの色をチカッっとしたい。
Windowsのメッセージで言うところのWM_LBUTTONDOWN と WM_LBUTTONUP のイベントが取れればよかったのだが、これに相当する関数が見つからなかったので、
onClick時に非同期メッセージを飛ばしてbackgroundカラーを変更することにした。
(ダサいのでいい方法あったら教えてください)
非同期にする方法
いろいろ調べたが、この資料がわかりやすい。
JavaScriptの同期、非同期、コールバック、プロミス辺りを整理してみる - Qiita
実装
setTimeoutに非同期実行したい関数を設定する。
背景色の変更は、body.classNameに所望のレイアウトを指定することで可能。
//**************** css *********************** <style type="text/css"> ... .background_color_theme{ background: #ffffff; /*デフォルトの背景色*/ } .background_color_bt_pressed_theme{ background: #0000ff; /*フラッシュ用の青色*/ } ... </style> //************ javascript ******************** <script type="text/javascript"> function take_picture() { //前回までに追記 //(base64で画像を送信する実装) ... setTimeout(function(){body.className = "background_color_theme"}, 60); // 60 [msec]後に元のテーマに戻る body.className = "background_color_bt_pressed_theme"; } </script>
以上。
次回からは画像処理の話をしたい。
【CSS】接頭句の違い "#"と"." 【お家IT#15】
本件の実装の一部
motojapan.hateblo.jp
前回の続き
motojapan.hateblo.jp
目次
前回は、ボタンの透過度を設定した。
今回は、基礎的な話でなんとなく使っていたCSSの接頭句の違いを書く。
前々回のコードをコピーしたのが下記。
"."で開始するstyleは、classに対応
"#"で開始するstyleは、idに対応
classで記載しておくと同じstyleを適用できる。
//**************** html ********************** … <div class="l2"> <canvas id="camera_record_box"></canvas> </div> … //**************** css *********************** <style type="text/css"> … .l2 { top: 0px; /*動的に変更されるので適当*/ left: 0px; /*動的に変更されるので適当*/ width: 400px; /*撮影枠サイズ*/ height: 60px; /*撮影枠サイズ*/ position: absolute; /*absoluteに設定*/ padding: 0em 0em; } #camera_record_box{ position: absolute; /*absoluteに設定*/ border: 1px solid red; /*赤い撮影枠*/ padding: 0em 0em; } … </style>
以上。
次回でフロントエンド(webアプリ系統)の話は終えたい。
最後は簡単に非同期処理について、以降は画像処理の話をしたい。
【CSS】半透明(透明度)の設定方法 【お家IT#14】
本件の実装の一部
motojapan.hateblo.jp
前回の続き
motojapan.hateblo.jp
目次
前回は、レイアウトの重ね合わせを実装した。
今回は、ボタンの透過度を設定したい。
完成イメージ
前回からの続きだが、ボタンが透過して下レイヤーの映像をスルーするようにしたい。
実装
opacityで設定することができる。
前回までに追記。
.my_btn{ … background: #668ad8; opacity: 0.8; /*0-1の範囲で不透明度を設定*/ … }
【Javascript / CSS】divタグでcanvas等のレイアウトを重ねる方法 【お家IT#13】
本件の実装の一部
motojapan.hateblo.jp
前回の続き
motojapan.hateblo.jp
目次
前回は、カメラ撮影枠を作成するために、カメラリソースの切り替えによるVideo要素のサイズ変化を検出した。
今回は、実際にカメラ撮影枠を作るためのレイアウトの重ね合わせ方法についてまとめる。
完成イメージ
こんなものを作りたい。
カメラのプレビュー上に、撮影領域と撮影ボタンを配置したい。
基本方針
- 基本的な枠組みは、HTMLのdiv要素とCSSでレイアウトの重ね合わせ。
- 動的なレイアウトプロパティの変更は、JavascriptからCSSの設定を変更。
div要素で重ねわせ方法と実装
ポイント
重ねわせで重要なのはCSSのposition。
下記の設定を行う。
外側のparent | position: relativeに設定。 |
内側のl1~l3 | 特定の位置に置きたい場合、position: absoluteに設定。 |
特に今回は、
- l1は、video要素があり、動画ストリームが確定すると自動的にサイズが決まる
- l2は、l1のサイズのサイズに応じて、動的にサイズが決まる
となる。
実装
動的にCSSプロパティを操作する場合、2つの方法がある(style / setAttribute)
実装は下記の通り。
//**************** html ********************** <div class="parent" width="720px"> <div class="l1"> <video id="camera" width="720px" autoplay></video> </div> <div class="l2"> <canvas id="camera_record_box"></canvas> </div> <div class="l3"> <a id="take_picture" href="#" class="my_btn">TAKE PICTURE</a> </div> </div> //**************** css *********************** <style type="text/css"> .parent { width: 720px; height: 0px; position: relative; /*relativeに設定*/ border: 3px solid black; padding: 0em 0em; margin:0; } .l1 { /*前回の話の通り、動画ストリームが確定してから自動的にサイズが決まる*/ top: 0px; left: 0px; width: 720px; padding: 0em 0em; } .l2 { top: 0px; /*動的に変更されるので適当*/ left: 0px; /*動的に変更されるので適当*/ width: 400px; /*撮影枠サイズ*/ height: 60px; /*撮影枠サイズ*/ position: absolute; /*absoluteに設定*/ padding: 0em 0em; } .l3 { bottom: 0px; /*下端に配置*/ position: absolute; /*absoluteに設定*/ padding: 0em 0em; } #camera_record_box{ position: absolute; /*absoluteに設定*/ border: 1px solid red; /*赤い撮影枠*/ padding: 0em 0em; } </style> //************ javascript ******************** //関数でCSSの設定を操作する //(前回に追記) <script type="text/javascript"> function notify_change_size() { video_layout_width = video.clientWidth video_layout_height = video.clientHeight var element_parent = document.getElementsByClassName('parent'); var element_l2 = document.getElementsByClassName('l2'); var element_box = document.getElementById('camera_record_box'); box_width = 400 //box size box_height = 60 //box size left = (video_layout_width - box_width) / 2 top = (video_layout_height - box_height) / 2 //parentへの設定 for(var i=0, l=element_parent.length; i<l; i++){ element_parent[i].style.width = String(video_layout_width) + "px"; element_parent[i].style.height = String(video_layout_height) + "px"; } //l2への設定 for(var i=0, l=element_l2.length; i<l; i++){ //今回はi=0のみ element_l2[i].style.left = String(left) + "px"; element_l2[i].style.top = String(top) + "px"; element_l2[i].style.width = String(box_width) + "px"; element_l2[i].style.height = String(box_height) + "px"; } //camera_record_boxへの設定 element_box.setAttribute("width", String(box_width) + "px"); element_box.setAttribute("height", String(box_height) + "px"); } videoElement.onresize = notify_change_size; </script>
結果
上手くいった。
以上。
次回はボタンを透過したい。
【Javascript】カメラ起動前後のvideoタグのサイズ変化を検出する 【お家IT#12】
本件の実装の一部
motojapan.hateblo.jp
前回の続き
motojapan.hateblo.jp
目次
前回は、UserMediaのカメラリソースを切り替えるなどの話をした。
今回は、カメラリソースの切り替えによるVideo要素のサイズ変化を検出したい。
例えばインカムからアウトカムに切り替えるとき、解像度が異なると、Video要素のサイズが変わる。
もう少しわかりやすく具体例を出して説明する。
具体例:Video要素のプレビューの中央に撮影領域を作りたい
例えば、下図のようにVideo要素のプレビューの中央に撮影領域を作りたい。(赤い枠線部分)
これを作る場合、少なくともVideo要素のサイズ変化を検出してレイアウト確定時のサイズを求める必要がある。
実装:Video要素のサイズ変化を検出、確定時のサイズを取得
実は知っていればめちゃくちゃ簡単
//**************** html ********************** <video id="camera" width="720px" autoplay></video> //************ javascript ******************** //動的に取得する関数 <script type="text/javascript"> function notify_change_size() { var video = document.getElementById('camera'); video_layout_width = video.clientWidth video_layout_height = video.clientHeight } var videoElement = document.querySelector('video#camera'); //onresizeメッセージのコールバック関数を設定する videoElement.onresize = notify_change_size; </script>
以上。
次回はこの具体例を少し掘り下げてどうやってVideo要素でのプレビュー上に撮影領域を作るか考える。