MotoJapan's Tech-Memo

技術めも

【ipython/jupyter】 ipython notebookの出力データを外部からclearする方法

ipython notebookもしくはjupyter notebookで日頃の作業をしている中で

  • 大量のログを出力したままファイルを閉じたり
  • ログを出しすぎて処理が重くなり、不用意にterminateしたり

して、次の実行時にipynbファイルの展開が遅くなったり、最悪展開できない、kernelが展開時にterminateすることがある。

その時の対処法をメモ。
やりたいこと=外部から出力カラムを削除

$ pip install nbclean
$ python
> import nbclean
> c = nbclean.clean.NotebookCleaner('./hoge.ipynb')
> c.clear(False, True)
> c.save('./hoge_cleaned.ipynb')

ポイントは下記。

> c.clear(False, True)

これの第一引数が入力カラム、第二引数は出力カラムを削除するフラグ。
間違えて、第一引数をTrueにするとコード本体が消える。

詳細はこれ。
https://www.pydoc.io/pypi/nbclean-0.1/autoapi/clean/index.html

追記: それでも開けない場合、ブラウザが未対応なデータを読み込もうとしていたりするので、起動ブラウザを変更してみる。


(個人的にipython notebookを日頃使います)

iPad 9.7 用にpencilケースを100円(格安)で自作する方法

f:id:motojapan:20180418003938j:plain

また箸休めですが、今回は最近買ったiPad 9.7 (2018)とApple pencilの為に、100円程でpencilホルダーを作成しました。(ついにこのブログで縫い物を紹介するとは思いませんでした)

最初に断っておくと、私はApple信者ではないので、デザイン性より利便性、カスタマイズ性、重量を重視しております。

なので、「せっかく廉価モデルのiPad 9.7 2018買って費用安く抑えたのに、ケースやらなんやらで4〜5000円とか払うのなんてやだよ!」って人にはオススメです。

別にすごいことはなく誰でも思い付くアイディアではあります。

必要なスキルは、「縫い物ができること」のみです。
(縫い物できなくてもいいですね、そうミシンがあればね)

完成画像

まず完成形はこちら。

iPadiPadのケースに巻きつけるようなゴムバンドケースを作成しました。
f:id:motojapan:20180418010515j:plain

ケースに取り付けるとこんな感じ。
f:id:motojapan:20180418011654j:plain

割とサラサラとしたゴムバンドなので上から左にスライドすると、
f:id:motojapan:20180418012853j:plain
下から「ぴょこん」と出てくる。(これがかなり便利)
f:id:motojapan:20180418012901j:plain
すっ、、、ぴょこん!
f:id:motojapan:20180418011640g:plain

作り方

作り方のまとめはこちら。
※慣れの為に、図や絵はApple Pencilで書いてます。(割と書ける)

f:id:motojapan:20180418013017j:plain

雑だけどこれが全てである。
大雑把に言うと、20mmゴムバンドを一周半して重なる部分をコの字に縫い付けるだけでできる。

必要な材料と道具

材料

  • 20mmゴムバンド (税別100円)
  • 刺繍糸
  • ボンド
  • 爪楊枝 (option)

道具

  • 定規
  • ハサミ
  • 刺繍針
  • 待ち針 (option) 

手順

スーパーシンプルな3ステップです。

1. 測って

f:id:motojapan:20180423010722p:plain

まずゴムバンドを635 [mm] 切り出す (幅はそのまま 20 [mm])
f:id:motojapan:20180423004829j:plainf:id:motojapan:20180423005755j:plain

【重要】切り出した両端はボンドをつけて乾かす
f:id:motojapan:20180423004959j:plain
解れ防止です。
放置、もしくは、ドライヤーで乾かすとあらキレイ。
f:id:motojapan:20180423005237j:plain

2. 折り曲げて

f:id:motojapan:20180423010816p:plain

横から見た図は実際にはこんな感じ。(オーバーラップは145 [mm] あればOK)
f:id:motojapan:20180423005325j:plain
マチ針か仮縫いで留めておく

3. 縫って(終了)

f:id:motojapan:20180423010828p:plain
オーバーラップ部分をコの字に縫い付けていく
(私は左下から縫っていく)
f:id:motojapan:20180423005941j:plain
一応、縫う所のイメージ(赤線を上下で繋げる)
f:id:motojapan:20180423012816j:plain
縫い付けは端から 2 [mm] ぐらいだといい感じにペンをホールドしてくれる

途中経過はこんな具合
f:id:motojapan:20180423012652j:plain

【重要】コの字出口は5 [mm]ほど残しておく(反対側からの写真)
f:id:motojapan:20180423012544j:plain
これを残しておくと、スライドした時にここがストッパーになるし、差し込む時の目印にもなるので便利

あとは無心で縫って完成
f:id:motojapan:20180423005959j:plain

所感

  • ペンケースの保持力もOK(逆さにしても落ちる気がしない)
  • スライド感もOK
  • めちゃくちゃ便利
  • 2週間程使っているが、全く壊れそうにない

ペンキャップ Ver.も作ったがそれも便利だった。

Julia言語とは(備忘録 : 更新版)

twitterなどで目にする機会が増えて、昨日初めてJuliaチュートリアルに参加したので備忘録。(更新版)


チュートリアルで頂いたステッカー↓↓
f:id:motojapan:20180324113623j:plain
可愛いね。

Juliaについて

  • 本家サイト https://julialang.org/
  • Github上で開発されるOSS
  • 2012年公開、現在のバージョンはv0.6.0(0.7.0-DEV)
  • 数値計算や科学計算処理向けの動的プログラミング言語
  • 科学計算処理向けのため、下記を実現・意図する。
    • 数式記述が楽(文法やコマンド)
    • ライブラリが豊富
    • 処理速度が早い
    • 処理量に対するスケーリング(分散処理)
  • その他の特徴は
    • モダンな言語仕様
    • UTF-8対応
    • etc...

Juliaのライセンス

MITベース
ただし中にあるプロジェクト単位で様々なライセンスがぶら下がっている模様 
商用利用はお気をつけて。
julia/LICENSE.md at master · JuliaLang/julia · GitHub

Juliaは何故早い

細かいことはよくわかりませんが、わかっていることだけで

  • LLVMベースの高パフォーマンスJITコンパイラを搭載
    • 実行前の型推論や最適化などでC(ネイティブ)相当の処理速度を目指す
    • 本家サイトのベンチマークにもあるようにCに遜色ない速度という参考結果
  • バージョンアップによる高速化とチューニング

Juliaを始める人

こんな人が多い気がする

簡単に始める方法

パッケージ

https://pkg.julialang.org/
2018/3/24時点で1749パッケージが登録されている
個人的に、Mamba.jl , BackpropNeuralNet.jlに興味がある
github.com
github.com

他の言語を実行可能

Julia上でgccやclangが実行できるため、C, Fortranのコードを実行可能
Calling C and Fortran Code · The Julia Language
Juliaboxのチュートリアルにもある

Cxx.jiで対話実行できるのでこっちも。
github.com

所感

  • 基本的に数値演算がめちゃめちゃ書きやすい!
  • 型指定や型比較が厳密(で個人的に好き)
  • ruby同様に破壊的関数などのシンタックスがあり読みやすい
  • 関数定義が多様でシンプルなものは1行で定義できて楽だし、直感的
  • モダン言語仕様であるため、書きやすく、python文法や演算記述も類似性がある
  • (まだ全貌をちゃんとわかってないな〜、勉強しよう)

勘違いがあれば教えていただけると助かります。

勉強会はこちらでした。

data-refinement.connpass.com

【python】OCR(tesseract-ocr / pyocr)で賞味期限を読み取る(画像→数列) 【お家IT#19】

本件の実装の一部  
motojapan.hateblo.jp

前回の続き  
motojapan.hateblo.jp

目次

前回は、バーコード画像から商品情報を取得するところまで進めた。
ただ、商品情報には賞味期限情報は含まれていない。
今回は、OCRを用いて賞味期限を数値、記号情報として取得する。

OCRとは

Optical Character Recognition 光学的文字認識を指す。
紙面に書かれている文字情報を認識してデジタル化する技術であり、書籍や資料を電子化することでデータ圧縮や管理の容易化ができるだけでなく、ソフトウェアと連携してデータ分析なども可能となる。

今回は賞味期限を読み取りたい。
特に、stand-aloneで利用できるtesseract-ocrをpyocrから触ってみる。
(その他のライブラリは次回)

tesseract-ocr / pyocrとは

tesseract-ocrは、OCRエンジンである。
最新α版は、4.00.00alpha。
4系からは、OCR Engine Modeで、LSTMが選択できるようになっている。
(ただし、下記pyocrからは、Mode設定がサポートされていない模様で、LSTMは今回は試せなった)※2017/10時点
github.com

pyocrは、tesseract-ocrpythonから操作する為のWrapperである。
かなり感単に操作が可能となっている。

インストール

tesseract-ocrをインストール & チェック

#install
$ sudo apt-get install tesseract-ocr

#check
$ tesseract -v
tesseract 3.03
  leptonica-1.71
   libgif 4.1.6(?) : libjpeg 6b : libpng 1.2.50 : libtiff 4.0.3 : zlib 1.2.8 : libwebp 0.4.1 : libopenjp2 2.1.0

pyocrをインストール & チェック

#install
$ pip install pyocr 

#check
$ python
>>> import pyocr
>>> pyocr.get_available_tools()
[<module 'pyocr.tesseract' from '/usr/local/lib/python2.7/dist-packages/pyocr/tesseract.pyc'>]

使い方と実装

pyocr.builders

pyocr.buildersには次の5つの使えそうなBuilderがある。

TextBuilder 文字列を認識
WordBoxBuilder 単語単位で文字認識 + BoundingBox
LineBoxBuilder 行単位で文字認識 + BoundingBox
DigitBuilder 数字 / 記号を認識 今回はこれを採用
DigitLineBoxBuilder 数字 / 記号を認識 + BoundingBox

今回は、撮影枠を準備しているので、DigitBuilderを採用。

tesseract_layout (pagesegmode)

tesseract_layoutを設定しているが、ここは次のpagesegmodeの番号と対応している。
ここの設定でかなり精度は変わる。
デフォルト設定は、tesseract_layout=3。
今回は、tesseract_layout=6で、単一ブロックとして認識。
OSDとは、On Screen Display? サブタイトルなどの認識に利用するらしい。

pagesegmode values are:
  0 = Orientation and script detection (OSD) only.
  1 = Automatic page segmentation with OSD.
  2 = Automatic page segmentation, but no OSD, or OCR
  3 = Fully automatic page segmentation, but no OSD. (Default)
  4 = Assume a single column of text of variable sizes.
  5 = Assume a single uniform block of vertically aligned text.
  6 = Assume a single uniform block of text.
  7 = Treat the image as a single text line.
  8 = Treat the image as a single word.
  9 = Treat the image as a single word in a circle.
  10 = Treat the image as a single character.

実装

import time
import pyocr
from PIL import Image
import pyocr.builders

#img : PIL image
def get_digit_ocr_info(img):
    result = None
    start_time = time.time()
    print('******** start convert_image_to_deadline  *********')

   width, height=img.size

    tools = pyocr.get_available_tools()
    tool = tools[0]
    print(tool)
    langs = tool.get_available_languages()
    print("support langs: %s" % ", ".join(langs))
    #lang = langs[0]
    lang = 'eng'  #言語設定で、「英語」を選択

    digit_txt = tool.image_to_string(
      img,
      lang=lang,
      builder=pyocr.builders.DigitBuilder(tesseract_layout=6)
    )
    print('DigitBuilder', digit_txt)

    print('******** end convert_image_to_deadline  *********')
    return digit_txt

結果

色々なパターンを12件ほど評価。


入力画像

tesseract+pyocr



2018. 6.12



18.12.31



2018. 5. 7



18.09.14



18.03.28



4 13 11-13 . . 3



2017.12 31



4 21 3



13. 1-7



17.12.22



20-178.... 3 13



2311 8.13

200 x 60 の画像に対して、処理速度は、2 - 3 [s]程度。結構時間がかかる。
上手くいくものもあれば、厳しいものもある。
特に、太い文字、判で刻印されたシャープな数字はかなりいい感じだが、無駄な文字が含まれている画像、暗い画像、ドット記載されている数字が上手く読み取れていない印象。

以上。

これでシステム全体の開発は終わり。
また何か作る予定です。

今回触れなかった他のOCRライブラリの話もそのうち纏めたい。

【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)
結果

こんな感じで欲しいワード「クリスタルカイザー」は出ているのでこれを頑張って引っ張り出せばできなくもないかも。
f:id:motojapan:20171026022432p:plain
形態素解析してBoWとかでまず頑張るとか、でも食品名は無限に増え続ける固有名詞と考えるとそれだけで自然言語のタスクとして楽しそう。(今回はやらないが)

2.WebAPIで検索する方法(種類)

脱線したがこちらが本筋。
WebAPIでバーコード情報から商品名を求められるメジャーどころは下記。

Product Advertising API (Amazon Web Services)
楽天商品検索API (Rakuten Developers)
ショッピング商品検索(Yahoo! Developer Networks)

Yahoo! Developer Networksを使ってみる

今回はまず手軽にやってみたいので、Yahoo! APIにした。

さらに、Yahoo! Developer Networksを使うモチベーションは、Yahoo!が提供する地図や気象情報などの多種多様なサービスがWebAPIから扱えるという点もあったので、今回登録してみた。

次の前提は把握していたほうが話がスムーズ。

  • Yahoo! Developer Networksは、ディベロッパー(アカウント)登録が必要である
  • 「アプリケーション」という単位で管理している
  • 1アカウント当たり、10個までのアプリケーションを登録できる
  • クエリ数は、アプリケーション通算の総カウントで計算される
  • API別に上限がある

登録

ディベロッパー登録

まずディベロッパー登録を下記から行う。
Yahoo! JAPAN ID登録 - Yahoo! JAPAN
gmailでも登録できる。

アプリケーション登録

「アプリケーション管理」から「新しいアプリケーションを開発」を選択。
f:id:motojapan:20171029012051p:plain

アプリケーションの種類を選択し、他の入力情報を埋める。
f:id:motojapan:20171029012238p:plain
「クライアントサイド」を選択する場合はこんな感じ。

クライアントID取得

アプリケーションを登録後、「デベロッパーネットワークトップ」>「アプリケーションの管理」>「アプリケーションの詳細」から、「Client ID」をメモする。
f:id:motojapan:20171029012729p:plain
ここでメモした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本 並行輸入品 代引不可

f:id:motojapan:20171028180346p:plain

処理速度は50-150[ms]程度。(通信状況によって揺らぐ)
以上。


ここまでで、画像から商品名(食品名)を検索するモジュールができた。
次回からは、OCRを用いて画像から賞味期限を取得するモジュールの話を進めたい。

【python】zbarでバーコードを読み取る(画像→数列) 【お家IT#17】

本件の実装の一部  
motojapan.hateblo.jp

前回の続き  
motojapan.hateblo.jp

目次

前回まででフロントエンド・バックエンドの整備が終わった。
以降は、画像処理部分を進める。

f:id:motojapan:20171026004212p:plain

今回は食品名(商品名)を取得するために、バーコード情報の読み取りをしたい。

バーコードとは

ふと、そもそもバーコードが何かをちゃんとわかっていなかったので調べる。

「黒いバーと空白の組み合わせで、数字、文字、記号を読み込めるデータ形式であり、一般的に縞模様を光学系認識機器で読み取る。
一般に普及している縞模様の一次元バーコードや、QRコードに体表される二次元バーコードをよく目にしている。
今回は食品名を取得したいので、今回は一次元バーコードを中心に考える。

バーコードの詳細は次が参考になる。
バーコードとは?|基礎知識|自動認識|デンソーウェーブ

バーコード種類は下記。

  • 統一商品コード(ユニークコード)
  • インストアコード(任意コード)

特にユニークコードで、日本で使われているのはJANコード

JANコード桁数は下記。

  • 標準タイプ(13桁)
    • 先頭7桁 : JANメーカーコード
    • 先頭9桁 : 国番号2桁 + JANメーカーコード7桁
  • 短縮タイプ(8桁)

JANコード構成要素は下記。

また、特に気になるのは、両サイドにあるマージンと呼ばれる空白は、十分な領域が必要である。<ナローバー(最も小さい黒縞)の10倍>

バーコードを読み込む方法は2つ思いつく。

  • バーコードリーダーといった専用機器で赤外線反射から読み取る
  • カメラなどの汎用機器で画像から読み取る(今回はこっち)

まぁこんな感じのバーコードリーダーでの読み取りでもよい。

ただ、それはあまりにつまらないし、「自宅で手軽に使う」というポリシーから外れるのでので今回は画像処理ベースで調べてみた。(スマホ一台で済ませたいし。)

結果的にpython上で動くスタンドアローンな画像処理ライブラリ、「zbar」を使用してみる。

環境

今まで通りRaspberry piを使用しているので、下記の通り。

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>

以上。
次回からは画像処理の話をしたい。