GitHubが賢くて助かった話

dotfiles管理

dotfiles管理ってかっこいいなと思って、結構前にgithubにdotfilesレポジトリを作っていました。dotfiles管理が何かと言うと、各種設定ファイルをgitで一括管理してしまおう!というやつですね!設定ファイルのほとんどが.(ドット)から始まるのでこの呼び名というのは誰しもがそりゃそうだろという名ネーミングだと思います。メリットは

  • 設定ファイルをいじったけど昔の状態に戻したい時
  • 新しいパソコンでの環境構築を一発で終わらせたい時

これらのことがささっとできてしまうことですね!あとは友達にこの設定どうなってるん?って聞かれた時にURLをはっつけておけばいいのは楽かもしれないです!(初心者なのでそんなこと聞かれたことない笑)

筆者の愚行をGitHubが救ってくれた話

ここからがメインストーリーです。今回、awsのアクセスキーを環境変数に入れておいてという指令が私のインターン先からくだされ、教えに忠実に、

export ~~~

と.zshrcに直接書き込んだわけですね。そして、そのまま何も考えずに

$ git add .
$ git commit -m "~~~"
$ git push origin master

かましてやりましたね。全世界にawsのアクセスキー大公開ですよ。。。そしたらgithubさんから何やらメール!

Aws apikey exposed on Github message by GitGurdian

なんだなんだ。何かのスカウトか??全くーー!と思って読んでみて2秒で青ざめる顔。速攻でexportした場所消して平静を装いました。そんなに長いこと公開してないし、そもそも筆者のレポジトリに人が来ることあると思えないし、大丈夫だったと信じたいですね。
何にも大丈夫でなかったですね。awsのアクセスキーがロックされてしまったので多大なる迷惑をおかけしました。鍵の扱い本当に注意しなければ。。

みなさん!githubにパスワードとか絶対ダメですからね!!(いや、誰もせんやろ。。)

とはいえ、毎回awsキー打ち込むのは不便なので、~/.zshrc.awsというファイルを作成し、.zshrcないで

source ~/.zshrc.aws

とすることでその場をしのぎました。

TensorFlow Object Detection API の環境構築やってみたわ

巷で有名なtenso…..を使ってみたい!

完全なる環境構築の忘備録です。くだんのライブラリが何かと言うと、

developers-jp.googleblog.com

これですね!物体検出です!!強い!!すごい!!これはなんか使える環境だけ整えておいてドヤ顔したいですね!ということで、以下簡単な忘備録です

インストール手順

ここを参照しながら進めました!

github.com

Pythonのバージョン(pyenv)

機械学習なので当然のようにPythonなのですが、バージョンが3系だと3.5でないとダメらしいので、新しくpyenvからインストールしてきました。

$ pyenv install --list
$ pyenv install 3.5.3

とりあえず3.5で一番新しいのぶちこんどけばええやろ!と。

Protocol Bufferのインストー

これがなんなのかはよく調べてないですが、googleが提供している何かしのファイルと展開するやつかなと。すみません、めっちゃ間違ってそうです。インストールはhomebrewで一発!これは間違いない!

$ brew install protobuf

brewは基本的に最新版しか入らないので、3.3くらいが入ります。参照リンクによると2.6を入れろとのことなのですが、今の所3.3でも動いているのでよしとしています。やっぱり2.6が入れたいという方は、GithubやらGoogleのホームページからバイナリーファイルを拾ってきてコンパイルするか、homebrewでダウングレードするかですね!

Homebrewで旧バージョンをインストールする方法(brew verionsはもう使えない) - Qiita

依存ライブラリのインストー

筆者は使ってみたかったので、

$ pyenv virtualenv 3.5.3 tf_obj_det

で新しい環境を作ることにしました。とりあえず、Python3.5に依存ライブラリが入ればなんでもオッケーです。

$ pip install pillow
$ pip install lxml
$ pip install jupyter
$ pip install matplotlib

これで準備はあらかた整いました!いよいよ本体ダウンロード!

GithubからPull

github.com

このgithubアカウントからダウンロードしてきましょう。

$ mkdir tf_obj_det
$ cd tf_obj_det
$ git init
$ git pull https://github.com/tensorflow/models

あとは環境変数を整えてあげればオッケーです!

これはなんだろう…

# From tensorflow/models/
protoc object_detection/protos/*.proto --python_out=.

最初に言い訳していた、Protocol Bufferを使って何かをしています!笑

Python環境変数

$ export PYTHONPATH=$PYTHONPATH:`pwd`:`pwd`/slim

シェルを立ち上げるたびに打ち込まなければダメらしいので、嫌だったら

~/.bash_profile
or
~/.zshrc

あたりに打ち込んでおけとのことです!

テスト

$ python object_detection/builders/model_builder_test.py

お疲れ様でした!これを使って何をするのか。オーライリーのDeep Learningを一読しただけの筆者にはまだあまりわかっていませんが、忘備録として残しておきます!!

Face API & Emotion API + Python 試してみた

巷で有名, Face API とは

Microsoftが提供しているMicrosoft Azure
その中のCognitive ServiceにあるFace APIが今回のターゲットです!

azure.microsoft.com

端的にいうと顔認識のweb APIですね。画像を渡すと、顔のある位置や年齢、顔のパーツの場所などをJSONファイルで返してくれるというものです。筆者、初めてAPIに触ったため多少ワクワクしておりました。それでは導入から行ってみましょう!

Face API導入

Microsoft Azure アカウント作成

Face API - 顔認識 | Microsoft Azure

とりあえず、このページの[無料アカウント]からAzureアカウント作成しました。クレジットカード情報記入とか結構めんどくさかった

Face APIAPI KEYを取得

Microsoft Azure

上記Azure Portalにて

  1. 左サイドメニューの[その他のサービス]
  2. 割と下までスクロールして[インテリジェンス+分析]グループ
  3. [Cognitive Service accounts]をクリック→[Face API]
  4. フォームはかなり適当に記入しました
  5. ダッシュボードに戻るなどして、先ほど自分が作成したリソースに飛ぶ
  6. 左から二番目のメニューバーのキーをクリックしたらジャーン

使ってみる

公式スタートアップ

Face API Python quick start | Microsoft Docs

最初に述べたように、自分がキーを取得した地域のurlにPOSTすることでJSONが返ってきます。APIってこういう感じなのだな。ふむふむ。

このQuick Startsの注意点
python2系とpython3系でかき分けているように見えるが罠です。 自分が使っている方だけ読めばいいわけではなく、

  • python2: urlを用いた画像の受け渡し方法
  • python3: バイト列を用いた画像の受け渡し方法

としれっと画像の渡し方を変えています。両方読みましょう笑

別の注意

https://docs.microsoft.com/ja-jp/azure/cognitive-services/face/quickstarts/python

上記ページは公式スタートアップに類似しているというか、本質的には同じはずだが、日本のページで(ja-jp)、なぜか必要なコードが消されているため要注意

公式リファレンス

Microsoft Cognitive Services

ここに詳細なデータの渡し方や返ってくる値が書いてある Face APIにある機能は大きく分けると

  • Detect: 顔の位置, パーツの位置など
  • Find Similar: 二つ画像を渡すと顔がどれだけ似ているかがスコアとして返される
  • Group: グループ分けしてくれる(まだ勉強不足)
  • Identify: (まだ勉強していない)
  • Verify: 顔認証, Detectと併用するらしい

cognitive_faceライブラリ

これ使うと、urllibとかrequestとかを勝手に使ってくれてて楽そう。 (日本語ドキュメントほぼ見つからないから英語か。。。) →Emotionの方で使えなさそうというか、これのライブラリの使い方で時間取られそうで本末転倒なのでこの子はスルー

Emotion APIについて

基本的にFace APIとほとんど同じことをすれば良い 違い

  • urlとAPIキーを変える必要がある
  • paramを空で渡す
  • cognitive_faceが使いない(ないし筆者が使い方わからない、ドキュメント不足)

くらいと思われます。

コード

Face API with local image file

import requests


url = 'https://westus.api.cognitive.microsoft.com/face/v1.0/detect'
headers = {
    'Content-Type': 'application/octet-stream',
    'Ocp-Apim-Subscription-Key': 'c1d3ab4f6c2j40ao4k1813bf24c8a7f',
}
params = {
    'returnFaceId': 'true',  # The default value is true.
    'returnFaceLandmarks': 'false', # The default value is false.
    'returnFaceAttributes': 'age,gender', # age, gender, headPose, smile, facialHair, and glasses.
}
if __name__ == '__main__':

    r = requests.post(url ,headers = headers,params = params,data = open("1643_fukada_kyoko.jpg",'rb'))

    print(r.text)

result

[{"faceId":"c43a79cd-6bb6-424d-91ef-2e143cf61444","faceRectangle":{"top":133,"left":198,"width":191,"height":191},"faceAttributes":{"gender":"female","age":27.2}}]

Emotion API with image url

import requests
import json

url = 'https://westus.api.cognitive.microsoft.com/emotion/v1.0/recognize'
image_url = "http://img.horipro.co.jp/wp-content/uploads/sites/17/2014/09/4efa1206c3ddde742caafee8af2a531e.jpg"
headers = {
    'Content-Type': 'application/json',
    'Ocp-Apim-Subscription-Key': '3c8a635a9b849dc2a5a72926222e25fd',
}

params = {}

payload = {
    "url": image_url,
}

if __name__ == '__main__':

    r = requests.post(url ,headers = headers,params = params,data = json.dumps(payload))

    print(r.text)

result

[{"faceRectangle":{"height":783,"left":339,"top":708,"width":783},"scores":{"anger":4.83580443E-05,"contempt":0.0011530855,"disgust":7.445373E-05,"fear":0.00015271669,"happiness":0.0037932964,"neutral":0.98582983,"sadness":0.00710687134,"surprise":0.00184137118}}]

こんな感じになります。 気をつけるところはurlで画像を送る時は

"Content-Type": "application/json"

localの画像を送る時は

"Content-Type": "application/octet-stream"

とすることと、urlの中のwestusの部分を自分がAPIキーを取得した地域に変えることですかね。 楽しそうなのでしばらくこれで遊んでます。

参考資料

azure-recipe.kc-cloud.jp

Python3 + ImageMagick

ImageMagick

画像処理を行う用事があり、それにこれを使うと良いと言われました。何かで見たことあると思ったらlatexをインストールした時についてきた気がする。使ったことなかったけど!

メリット

簡単に画像処理ができる!シェルコマンドでできる!つまりプログラミングと相性が良い!多分こんな感じです。

インストー

homebrewをインストールしていればこれで!

$ brew install imagemagick

Python + ImageMagick

基本

ImageMagickのコマンドをPython

subprocess.call(cmd, shell=True)

で実行させるだけです。
shell=Trueはsubprocessが行うコマンドをshell上で実行するというオプションなのですが、これが必要です。筆者はこれが必要であるということを調べるのに30分以上費やしました。cmdにコマンド文字列を作成していきます。
ImageMagickのコマンドは下記リンクを見て勉強しましたー!

imagemagick.rulez.jp

サイズ変更

def changeSize(image, scale):
    """
    画像のサイズを変更
    縦横比は変えずにパーセンテージで指定
    """
    cmd = "convert {} ".format(image)
    o_resize = "-resize {}% ".format(scale)
    o_out = "{}".format(image)

    cmd = cmd + o_resize + o_out

    res = subprocess.call(cmd, shell=True)

イメージとしてはこんな感じでやっていきます。

二つの画像の合成

def overlayImage(bottom_img, top_img, gravity="center", geometry=(5, 5)):
    """
    2つの画像の合成
    bottom_imgの上にtop_imgを乗せる
    """
    cmd = "convert " + bottom_img + " " + top_img + " "
    o_gravity = "-gravity {} ".format(gravity)
    o_geometry = "-geometry +{0[0]}+{0[1]} ".format(geometry)
    o_compose = "-compose over "
    o_composite = "-composite {}".format(bottom_img)

    cmd += o_gravity + o_geometry + o_compose + o_composite

    res = subprocess.call(cmd, shell=True)

二つの画像を合成しています。gravityが基準点を決めるオプションで、geometryが基準点からの位置決めオプションです。めんどくさかったらgravity northwest にしておけばgeometryで左上からの位置を決められます。

ダミー画像生成

def makeBackground(name="muji", color="DodgerBlue"):
    name = name + ".png"

    res = subprocess.call("convert -size 1200x810 xc:white {}".format(name), shell=True)

このコマンドで無地のダミー画像が作れます。地味に使うこと多そう

ライン描画

def drawStroke(image, coords=(0, 0, 0, 0), color="black", width=1):
    """
    幅と色指定のできる線描画関数
    """
    cmd = "convert "
    o_color = "-stroke {} ".format(color)
    o_width = "-strokewidth {} ".format(width)
    o_draw = '-draw "line {0[0]},{0[1]} {0[2]},{0[3]}" '.format(coords)

    cmd = cmd + image + " " + o_color + o_width + o_draw  + image

    res = subprocess.call(cmd, shell=True)

これでラインが描けます。coordsで座標を決めていますが、

-draw "line (X1),(Y1) (X2),(Y2)"

の順で座標をとり2点間に直線を引きます。
図形は他にもいろいろあったけど、これしか使っていない。。

横並びに結合

def appendImage(img_list):
    """
    画像を横並びに結合する
    しばらく使わないので放置
    """
    cmd = "convert +append "

    for img in img_list:
        in_file = "{}".format(i)
        cmd += inFile + " "

    cmd += "{}".format(img_list[0])

    res = subprocess.call(cmd, shell=True)

forループ!!プログラミング使ってる感出てきた!(これで終わり説)

+append

で横並びの結合

-append

で縦並びの結合(らしい)

文字の挿入

def insertWords(image, words, color="black", font="Meiryo", size="50"):
    """
    画像に文字を挿入
    色とフォントと文字サイズの指定可能
    挿入位置は画像下中央から10px上
    """
    cmd = "convert "
    o_point = "-pointsize {} ".format(size)
    o_font = "-font {} ".format(font)
    o_gravity = "-gravity south "
    o_annotate = '-annotate +0+10 "{}" '.format(words)
    o_fill = '-fill {} '.format(color)
    o_in = "{} ".format(image)
    o_out = "{}".format(image)

    cmd = cmd + o_point + o_gravity + o_font + o_annotate + o_fill + o_in + o_out

    res = subprocess.call(cmd, shell=True)

これは少し流派がありそうでした。label派とannotate派。先に見た方を選びました。

font-awesomeを使う

def makeFontAwesome(icon_name, color="black"):
    """
    font awesome のunicodeから画像生成
    色の指定可能
    生成画像サイズは400x400
    戻り値は画像の名前(相対パス名)
    """
    icon = 'printf "{}" | '.format(icon_name)
    cmd = "convert "
    o_size = "-size 400x400 "
    o_background = '-background "none" -fill {} '.format(color)
    o_font = "-font font-awesome-4.7.0/fonts/fontawesome-webfont.ttf "
    o_point = "-pointsize 200 "
    o_gravity = "-gravity center label:@- "
    o_out = "temp/{}.png".format(icon_name)

    cmd = icon + cmd + o_size + o_background + o_font + o_point + o_gravity + o_out

    res = subprocess.call(cmd, shell=True)

こいつはめちゃくちゃ苦労いたしました。基本的には下記リンク通り

www.nofuture.tv

とりあえずfont-awesomeのフォントをダウンロードしてきて、それを-fontで指定します。

font-awesome注意点

こいつを扱うときの注意点はズバリunicodeです。python3を使ってるから大丈夫と思っているみなさん、そんなこと言ってられなかった事案にぶち当たることもありました!何かと言うと、font-awesomeのunicodeを引数としてとってくる時に、標準入力などを用いると文字列がraw storingになっちゃうんですね。

\ufe03

これで地図の記号なのですが、標準入力まんま打ち込んでとってくるとpython上では

r"\ufe03"

という文字列になってしまいます。 何で困るって、この6文字で1文字を表すから画像表記できていたのに、6文字のまんま扱われたらfont-awesomeじゃないということです!(日本語が変)
これの解決策ですが、

fa = input()  #r"\ufe03"
fa = fa.encode("utf-8")  #b"\\ufe03"
fa = fa.decode("unicode-escape")  #"\ufe03" → □

一回バイト列に変換してから、decodeのunicode-escapeとかいうやつでもう一回unicode文字列(raw string でない)に戻しました。絶対もっとうまい方法あると思うので知ってる方いたら教えてください。。

まとめ

ここに書いた関数群をモジュール化したらのちにも使えそうだなぁ〜(どうするのかさっぱりわからんし、そんなことするくらいならもっと他に画像編集できるライブラリありそう)

Webスクレイピングやってみた

巷で噂のスクレイピング

大量の情報がストックされているインターネットとかいう場所からガバァッと情報をさらっていける技術「スクレイピング」。いろんな場所で活躍すること間違いなしなのですが、特に機械学習と仲が良さそうなので、これは勉強しない手はないと思い、使ってみました。

はまったところ

正規表現でハマっています。

for div in soup.find_all("div", class_="video-list-title"):
    print(str(div))
    s_pattern = re.compile(r'<a href=".*">')
    s_search = s_pattern.search(str(div))

    print(s_search)


出力

<div class="video-list-title"><p><a href="/recipes/5dd98b76-6358-47ce-8c1b-f59918b5a1df">意外と美味!きゅうりとベーコンのガーリック炒め</a></p></div>
<_sre.SRE_Match object; span=(33, 89), match='<a href="/recipes/5dd98b76-6358-47ce-8c1b-f59918b>

上記3行目の正規表現でurl部分をマッチさせたいのですが、最後の方が切れてしまっています。 上記3行目の正規表現部分を r’f=”.*”>’ に変えたらできたので、.* には文字制限があるのでしょうか?

→今の挙動的にはsearchには文字制限がありそう  searchの代わりにfindallを使うことでうまくいった

コード

# coding: utf-8

# In[1]:

from bs4 import BeautifulSoup
import requests
import re
import json


# In[2]:

categories_url = "https://www.kurashiru.com/categories/"
recipes_url = "https://www.kurashiru.com"


# In[3]:

c_html = requests.get(categories_url + "1")
soup = BeautifulSoup(c_html.content, "html.parser")


# In[5]:

dish_list = []
for div in soup.find_all("div", class_="video-list-title"):
    search = re.findall(r'href=".*</a>', str(div))
    url = search[0].split('"')[1]
    title = search[0].split('"')[2][1:-4]
    dish_list.append({"title": title, "url": url})
    print(dish_list)


# In[ ]:

for dish in dish_list:
    r_html = requests.get(recipe_url + dish["url"])
    soup = BeautifulSoup(r_html.content, "html.parser")
    dish["url"]

参考資料

qiita.com

orangain.hatenablog.com

qiita.com

komaken.me

flask-sockets+redis+Herokuでチャットアプリ作成したわ

初心者がチャットアプリ作りました

こんにちは。今回、紹介させていただくのは最近流行りのwebsocketを使ったチャットアプリ(超定番)であります。このwebアプリなんですけど、某長期インターンを申し込む際の課題として作成いたしました。その結果、見事、、、お祈りされましたー!! 謎のバグが未だに直せていないので、教えてくれる親切な方いらっしゃいましたらお願いいたします。

できたもの

f:id:went-went-takkun135:20170616165243p:plain

こんな感じのチャットアプリを作りました。本気で疲れました。落ちましたし。これの前にloginページがあって、自分の名前とchat roomの名前を入れます。そしたら画像のようなページに飛んで、chat room内の人とチャットすることができます。

heroku

筆者はこの課題に取り組む前、local環境で作ったwebアプリを他者に見せるためにどうすれば良いか知りませんでした。師匠との会話
筆者「レンタルサーバーを持ってなかったら結局、書いたサーバスクリプトを他者に渡してlocal環境で実行してもらうしかないんか?」
師匠「herokuって検索してみ」
筆者「な、なんだこれは!!」(続く)

herokuとは

筆者のとんちんかんな質問を乗っけてるせいで勘違いされたかもしれませんが、無料レンタルサーバーです!制限はあるものの、初心者が作るwebアプリレベルなら一切ひっかることのないようなものなので気にせず使えます。(多分)
gitで管理できるのが個人的には楽しくてよかったです。 herokuを解説しているページはたくさんあるのでこの辺で大丈夫かと思います。

ソースコード

例のごとく適当にコードを置いていこうと思います。 ほぼほぼherokuのsampleのパクリですが、redisの簡単な使い方やwebsocketの簡単な使い方くらいは見られるかなと。コメント0のスーパー不親切なコードです。すみません。

https://github.com/dondakeshimo/what-I-made/tree/master/flask_challenge

まとめ

落ちたのはショックだが、このアプリの完成度とバグの残り方的には仕方ない気もする。web関連はコピペで済ませた部分も少しあるし、もっともっと勉強が必要だと感じた。

tkinterで機械学習用の学習データを作成したわ

初心者がtkinter使いました

こんにちは。今回は初回記事の方でしれっと言ってた初作品について投稿していきたいと思います。機械学習の前処理を行うための画像情報抽出GUIアプリ」を作るということでした。筆者は一回webアプリを勉強するのを挫折した経緯というか、javascriptやらhtmlやらめんどくさった経緯というか、、がありまして、今回はデスクトップアプリを作るぞ!と決意いたしました!!私が読んだ入門書にPythonのデスクトップアプリを作るライブラリとしてtkinterが挙げられていたので、素直に使ってみました!

できたもの

f:id:went-went-takkun135:20170612172115p:plain

これでsaveボタンを押したら、うまい具合にxmlファイルへ人がいる座標を出力してくれるという寸法です。誰が使うねん!ってなるでしょうが一応コードのリンクを張っておきますね。

https://github.com/dondakeshimo/what-I-made/tree/master/FB_pj_UI

今回勉強できたこと

アプリを画面幅いっぱいにする

from tkinter import *

root = Tk()
scr_w, scr_h = root.winfo_screenwidth(), root.winfo_screenheight()
root.geometry("%dx%d+0+0" % (scr_w, scr_h))

このメソッドでデバイスの縦横の大きさがピクセル単位で返ってきます。アプリは画面いっぱいでないとね!!写真扱うんだし!!(ウィンドウとオブジェクトのサイズを同期させるのが面倒だったとは言っていない。)

画像の開き方とサイズ変更

カレントディレクトリに"picture.png"があるとしましょう。

from PIL import Image, ImageTk

original = Image.open("picture.png")
resized = original.resize((100, 300), Image.ANTIALIAS)
tk_img = ImageTk.PhotoImage(resized)

これでサイズ変更された、tkinterの画像オブジェクトが生成されたことになります!

矩形選択

概要

写真はtkinterのcanvasの上に貼り付けてるんですが、canvasにクリックした時と離した時のイベントをバインドして、その時の座標を用いて矩形を描画しています。

問題点

  • クリックを離してみるまで矩形選択の描画されないため、正しく選択するのが難しいというところ。
  • 矩形選択を削除することができないこと

解決策

  • イベントバインドにドラッグも入れてその座標を逐次渡すことで点線なりの矩形を描画すれば良いのだろうか。
  • 削除するために矩形選択自体を選択せねばならぬ気がするのだがやり方がさっぱりだったため、チェックボタンで代用した。

チェックボタン

矩形選択ミスった時用に、チェックボタンを苦肉の策として導入。矩形選択に番号を振り、ミスった番号のチェックボタンを外すことで、その選択は無視するようにコーディングしました。しかもこのチェックボタン、自動生成とか難しそうだったから、Person10までは後ろに隠れてて、矩形選択するたびにしたからPower Pointでいう「最前面へ移動」を行っておるだけです。なんかいろいろ納得いかないので、誰かうまいやり方教えてください。

xmlファイル

基本的なことのみ行いましたので、ここでは割愛させていただきますが、xml.etree.ElementTreeを使って書いたということだけ申し上げておきましょう。

辞書型に感動

fortranとかCとかを主に勉強してた筆者にとって、入門書読んだ時、辞書型と聞いても全然ピンとこずに「なんかこいつは便利そうだ」くらいにしか思ってなかったんですけど、辞書型、やばいっすね。インデックスじゃなくてキーになるだけでこんなにもコードが簡単に美しくなるとは。そりゃDBもキーと値で格納しますよ、わかりますよ。fortranでコード書いてた時のあの名前めっちゃ思案して、入れ子不可のリストに値を入れていくやつめっちゃキツかったなぁ、と思い出しながらしんみり感動してました。

最後に

ここまで説明してなんだけど、webアプリの方がたぶん流行ってるよ。笑

参考にしたサイト