yamaken1343’s blog

技術ブログもどき

JavaScript で Google Cloud Speech-to-Text 音声認識

cloud.google.com

JavaScriptの練習がてらこれをブラウザ上で動作させます.
ページ内にサンプルがあると思いますが, あれの簡単なやつです.

もっとも, REST APIで公開されているのでそんなに難しくないです.
もうひとつgRPC形式のAPIが公開されてますが, 勉強中なので誰か教えてください.

準備

  • Google Cloud Platform にアカウントが必要なので取得
  • Cloud Speech APIを有効にしてAPIキーを発行

設計

  1. 音声取得
  2. base64エンコード
  3. JSON形式にしてAPIを叩く

実装

github.com

音声周りは素晴らしいライブラリがあるので利用します.
(最初は自分で書いてたけど挫折しました)

こちらの録音を吐き出す部分に上のエンコードAPI叩く部分を実装してあげれば良いです.

  • main.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>デモ用音声認識サンプル</title>
</head>
<body>
<button onclick="startRecording()">解析開始</button>
<button onclick="endRecording()">解析終了</button>
<hr>
<script src="api_key.js"></script>
<script src="./lib/recorder.js"></script>
<script src='main.js'></script>
</body>
</html>
  • main.js
let audio_context;
let recorder;

function arrayBufferToBase64(buffer) {
    let binary = '';
    let bytes = new Float32Array(buffer);
    let len = bytes.byteLength;
    for (let i = 0; i < len; i++) {
        binary += String.fromCharCode(bytes[i]);
    }
    return window.btoa(binary);
}

function startUserMedia(stream) {
    let input = audio_context.createMediaStreamSource(stream);

    recorder = new Recorder(input);
}


let startRecording = function () {
    recorder && recorder.record();
    console.log("record start")
};

let endRecording = function () {
    recorder && recorder.stop();
    console.log("record stop");

    // create WAV download link using audio data blob
    audioRecognize();

    recorder.clear();
};

function audioRecognize() {
    recorder && recorder.exportWAV(function (blob) {
        let reader = new FileReader();
        reader.onload = function () {
            let result = new Uint8Array(reader.result); // reader.result is ArrayBuffer
            let data = {
                "config": {
                    "encoding": "LINEAR16",
                    "sampleRateHertz": 44100, // 環境によってかわるっぽいので変えてください(おそらくエラーに正しい値が出てくると思います.
                    "languageCode": "ja-JP"
                },
                "audio": {
                    "content": arrayBufferToBase64(result)
                }
            };
            console.log("audio send...");
            fetch('https://speech.googleapis.com/v1/speech:recognize?key=' + apiKey, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json; charset=utf-8'
                },
                body: JSON.stringify(data)
            }).then(function (response) {
                return response.text();
            }).then(function (text) {
                let result_json = JSON.parse(text);
                //テキストデータ自体はresult_json.results[0].alternatives[0].transcriptに格納
                console.log("RESULT: " + text);
                console.log(result_json.results[0].alternatives[0].transcript);
                console.log(data)
            });
        };
        reader.readAsArrayBuffer(blob)

    });
}

window.onload = function init() {
    try {
        // webkit shim
        window.AudioContext = window.AudioContext || window.webkitAudioContext;
        navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia;
        window.URL = window.URL || window.webkitURL;

        audio_context = new AudioContext;
    } catch (e) {
        alert('No web audio support in this browser!');
    }

    navigator.getUserMedia({audio: true}, startUserMedia, function (e) {
    });
};

同階層にAPIキーを保持するファイルapi_key.jsとして作成してください

var apiKey = 'XXXXXXXXXXXXX';

成果物は以下 github.com

結果

f:id:yamaken1343:20181020193213p:plain

あとがき

JavaScriptわからん
結局ほとんどコード書いてないので勉強になったか微妙

注意点

APIキーが見え見えなので動作はローカルにとどめておいてください.

自作キーボードHelixビルドログ

Helixにやっと慣れてきたのでこれから作ってみたいという方の参考になるようビルドログを残しておきます.

僕が作成したものは5行版のUNDERGLOWタイプになります.

Helixについて

f:id:yamaken1343:20180605233215j:plain

遊舎工房さんのかっこいい格子配列の分割キーボードです. 以下から購入できます.

Helix キーボードキット | 遊舎工房

フルセットのキットになっていて, 細かいパーツを集めなくてよいので良いです. 他に必要なものはキースイッチ, キーキャップ, キーボードの左右を接続するためのオスーオス3極ミニプラグケーブル, A-microBのUSBケーブルと入手難度が比較的優しいです. キースイッチとキーキャップについては遊舎工房さんで購入できます.

必要な道具について

最低限はんだごてとはんだ, ピンセット, 精密プラスドライバがあれば作成できます. 僕はそれに加えてはんだ吸い取り線とテスターとマスキングテープを用意しました. 以下に詳しいので一読をおすすめします.
ハンダはダイオード用の細いものとキースイッチ用の太いもの両方用意するといいかなと思います.

キーボード自作、特に Helix キーボードキットの製作に最低必要な工具のメモ · GitHub

購入物品

以下のものを購入しました. 1ドル110円で計算してます.

名称 購入場所 価格
Helixキーボードキット 遊舎工房 10044
Cherry赤軸65個 AliExpress 3520
フルサイズキーボード用キーキャップ AliExpress 1089
TRSケーブル*1 Amazon 999
プリント基板用半田 Amazon 200
テスター Amazon 1191
合計 17043

ja.aliexpress.com

ja.aliexpress.com

Amazon.co.jp: ステレオミニプラグ オーディオケーブル、RAYWILL 高音質再生 オス/オス無指向性 標準3.5mm AUX接続 (0.5m): 家電・カメラ : https://www.amazon.co.jp/gp/product/B072KDTCYR/ref=oh_aui_detailpage_o01_s00?ie=UTF8&psc=1

Amazon | goot 両面プリント基板用はんだ SD-61 | DIY・工具・ガーデン : https://www.amazon.co.jp/gp/product/B0029LGAKW/ref=oh_aui_detailpage_o01_s00?ie=UTF8&psc=1

Amazon | OHM(オーム電機) デジタルマルチテスター 普及型 TDX-200 (04-1855) | テスター | 産業・研究開発用品 通販 : https://www.amazon.co.jp/gp/product/B005BE4XZS/ref=oh_aui_detailpage_o01_s00?ie=UTF8&psc=1

組み立て

基本は公式のビルドガイドを見れば良いです. 非常にわかりやすいのでしっかり読めば作れると思います.
github.com

以下の記事はビルドガイドにないTips的なものとなります.
全体として共通するポイントはただひとつ, 向きを間違えないことです.

組み立て前に

デスクを綺麗にしましょう. また, ゴミ箱が机上にあると良いです. パーツを入れるためのトレイがあるとなお良いです.
これはこの項で最も重要なポイントですが, 自作キーボード初めての方はこの時点でQMKをビルドするためのツールのインストールをはじめてください. かなり時間がかかります. 手順は以下に詳しいです.

helix/firmware_jp.md at master · MakotoKurauchi/helix · GitHub

表面実装用ダイオードの実装

  1. ランドの片側に予備ハンダをする
  2. ピンセットでダイオードをつまみ, 予備ハンダを溶かしながら近づけ, 片側をハンダ付けする
  3. もう片方をハンダ付けする

裏返せば見えるので綺麗に付けたいですね. 殆どのハンダは作ったあとも見えます.
綺麗につけるポイントは流しこむハンダの量を一定にすることです. これは以下のハンダ付けすべてに共通します.
僕は綺麗にはつけられませんでした.

ダイオードの実装チェック

テスター持ってる方はダイオードの向きが正しいかチェックしましょう. テスターをダイオードチェックモードにして, プローブをリード線付きダイオード用のランドに当ててください.

f:id:yamaken1343:20180605210812j:plain

ProMicroのもげ対策

ProMicroのUSB端子は脆いらしく, 補強必須です.
ただでさえファームウェアの書き込みの際に抜き差しするので, しっかり補強しましょう.
他のビルドログを見ると, 瞬間接着剤とかエポキシ接着剤で強化してる人が多いですが, 僕はグルーガンで行いました.

f:id:yamaken1343:20180604234829j:plain

もしももげたらtwitterにアップすれば人気者になれると思います.

ProMicroとリセットスイッチを実装できたらファームを書き込んで動作確認ができます. ピンセットでキースイッチ用のランドをショートさせてください. ダイオードの実装チェックをしていればいらない作業ですが, テスター持ってないという人はここでチェックすると良いかなと思います.

OLEDディスプレイの実装

リセットスイッチとかより先にピンソケットを先に実装するほうが楽なのでおすすめです.

まっすぐ付けたいので, マスキングテープで真っ直ぐにしてからはんだづけすると良いです.
写真だと一箇所ですが, この付け方だと微妙に浮くので根元側も仮止めしてください.

f:id:yamaken1343:20180605211850j:plain

ハンダゴテを当てる向きを気をつけてください. ディスプレイが溶けます. 幸い機能に影響はありませんでしたが.

f:id:yamaken1343:20180605212036j:plain

キースイッチの実装

裏表を間違えないようにプレートにキースイッチをはめていきます. 全てはめたら裏返してキースイッチの足が曲がっていないか確かめます.

f:id:yamaken1343:20180605195601j:plain

足の修正後ハンダ付けをしますが, ロープロファイルスイッチのランドが近く, ブリッヂしてしまうと面倒なことになります. まあ外側のランドに関しては片方ブリッジしても大丈夫なので気楽にやりましょう.
また, ハンダ付けの際基盤とキースイッチの間に隙間ができないようにしっかりと押し込みましょう

テスター持ってる方はキースイッチがショートしてないかテストしましょう. ショートした状態でつなぐと面倒です.

f:id:yamaken1343:20180605201225j:plain

ファーム書き込んでテスト

事前にrules.mkを書き換えておかないと光ったりディスプレイがつかないので不安にならないでください.

f:id:yamaken1343:20180605225502j:plain

最終組み立て

ネジを立てる -> 底面プレートにはめる -> スペーサを手で締める -> 裏返して本締め -> 全部終わったらPCB側を乗っけてネジ止め が楽かなと思います.

穴が9個に対してネジ及びスペーサは6個しかないですが仕様です. 上下の3つづつを使いましょう.*2

キーキャップ取り付け

キーキャップ取り付けて完成になります. フルサイズ用のキーキャップセットを購入した人はテンキーとかファンクションキーも総動員して頑張って埋めてください. *3

以上になります. 次回はファームウェア編をする予定

この記事はHelixで書かれました.*4

*1:みんなこれ買ってるの面白い

*2:PCBに穴が9つあるのは4行版との共通化でわかるんだけど5行版専用のケースに穴が9つあるのは不思議.

*3:僕はその状態でダサい事この上ないのでなんとかしたい

*4:自作キーボードの記事の最後のこれが好き. 作ったキーボード以外のキーボードで書かれてるとなおいい

pythonで疎な二次元データをバイリニア法で補完する

何かいい感じのライブラリがあったら教えて欲しい

データについて

例えば, 以下のようなデータが対象になります.

f:id:yamaken1343:20180628190305p:plain

気象庁のサイトから持ってきた気温のデータですが, 気温が示されていない部分を補完し, もっともらしい温度を出力します.

本来は緯度経度等から正しい位置を持って来るべきですが, とりあえず適当に配置します. 0は未定義の値とします.*1

[[20.9  0.   0.   0.   0.   0.   0.  21.8]
 [ 0.  21.7  0.  21.9  0.   0.  21.2  0. ]
 [ 0.  21.7  0.  21.9  0.   0.   0.  20.6]
 [ 0.  22.3  0.   0.   0.   0.   0.   0. ]
 [22.   0.  22.8  0.  20.7  0.   0.  21.2]
 [ 0.  22.6  0.   0.   0.   0.   0.   0. ]
 [ 0.   0.   0.   0.   0.   0.   0.   0. ]
 [20.2  0.  23.2  0.  23.2 22.6  0.  22. ]]

色で表すと以下のようになります. 暗い領域は未定義を示します. f:id:yamaken1343:20180628190145p:plain

結果

こうなります.

[[20.9 21.2 21.6 21.8 21.6 21.5 21.6 21.8]
 [21.3 21.7 21.8 21.9 21.7 21.4 21.2 21.4]
 [21.6 21.7 21.8 21.9 21.6 21.4 21.  20.6]
 [22.1 22.3 22.4 21.8 21.  21.2 20.9 20.9]
 [22.  22.3 22.8 21.8 20.7 20.9 21.  21.2]
 [21.9 22.6 22.8 22.2 21.5 21.7 21.6 21.5]
 [21.  22.2 23.  22.6 22.4 22.1 21.8 21.7]
 [20.2 21.7 23.2 23.2 23.2 22.6 22.3 22. ]]

f:id:yamaken1343:20180628190127p:plain

コード

import numpy as np


def search_near(src, x, y):
    """
    データのある近傍4点を検索し, 座標を返す
    :param src: 検索する配列
    :param x: 基準点のx座標
    :param y: 基準点のy座標
    :return: 検索した4点を2*4のnumpy.arrayで返す
    """

    def min_pear(a, b, x, y):
        """
        基準点とリスト内の2点間の距離が最も小さいペアを返す
        :param a: x座標のリスト
        :param b: y座標のリスト
        :param x: 基準点のx
        :param y: 基準点のy
        :return: リスト内のペア
        """
        # 近傍に点が4点以下でもあるだけの点を用いて補完を行う
        # if len(a) == 0:
        #     return x, y

        add = np.power((a - x), 2) + np.power((b - y), 2)
        return a[np.argmin(add)], b[np.argmin(add)]

    # 処理簡便化のためデータの有無を2値で持つ
    src = np.array(src != 0)

    # 処理対象の点にデータがあるとき, その点を4近傍として返す
    if src[x, y]:
        return np.array([[x, y], [x, y], [x, y], [x, y]])

    try:
        # スライスされるため, indexに入る値はsrcのインデックスと互換性がないことに注意する
        # 左上
        index_x, index_y = np.where(src[0:x, 0:y])
        min_x, min_y = min_pear(index_x, index_y, x, y)  # 基準点は右下
        upper_left = (min_x, min_y)
        # 右上
        index_x, index_y = np.where(src[x:, 0:y])
        min_x, min_y = min_pear(index_x, index_y, 0, y)
        upper_right = (min_x + x, min_y)
        # 左下
        index_x, index_y = np.where(src[0:x, y:])
        min_x, min_y = min_pear(index_x, index_y, x, 0)
        lower_left = (min_x, min_y + y)
        # 左下
        index_x, index_y = np.where(src[x:, y:])
        min_x, min_y = min_pear(index_x, index_y, 0, 0)
        lower_right = (min_x + x, min_y + y)

        near_4_points = (upper_left, upper_right, lower_left, lower_right)

        return np.array(near_4_points)

    # データが見つからなくても止まらないようにする
    except:
        return None


def bilinear(src):
    """
    疎なデータを持つ配列に対しバイリニア補完を行う
    :param src: 入力配列
    :return: 補完後の配列
    """
    it = np.nditer(src, flags=['multi_index'])
    dst = np.zeros(src.shape)
    # 配列の各要素をなめる
    while not it.finished:
        idx = it.multi_index  # 現在参照する要素のインデックス
        it.iternext()

        # near four points 近傍四点を取得
        n4p = search_near(src, idx[0], idx[1])
        # 4点のどれかにデータがない場合の処理
        if n4p is None:
            continue

        # 参照する要素と近傍4点の距離を取得
        near_4_points_dist = np.array([np.linalg.norm(n4p[0] - idx), np.linalg.norm(n4p[1] - idx),
                                       np.linalg.norm(n4p[2] - idx), np.linalg.norm(n4p[3] - idx)])

        # 近傍点と参照点が同じ場合と近傍点がないときnanが入るので, 変換する
        near_4_points_dist[np.isnan(near_4_points_dist)] = 0

        # 参照要素とデータの点が重なった時の処理
        if near_4_points_dist.sum() == 0:
            dst[idx] = src[idx]
            continue

        # 近傍点と参照点が同じ場合無視したいので次の処理でゼロにするために代入
        near_4_points_dist[near_4_points_dist == 0] = np.inf

        # 小さいほうが値が大きくなるように逆数を取る(距離なので近いほうが良いというふうにしたい)
        near_4_points_score = 1 / near_4_points_dist

        # 和が1になるように正規化
        near_4_points_score /= near_4_points_score.sum()

        # 結果を格納する配列に代入
        for i in range(len(n4p)):
            a, b = n4p[i]
            dst[idx] += near_4_points_score[i] * src[a, b]

    return dst

def main():
    np.set_printoptions(precision=1)
    in = np.array([[20.9, 0, 0, 0, 0, 0, 0, 21.8],
                  [0, 21.7, 0, 21.9, 0, 0, 21.2, 0],
                  [0, 21.7, 0, 21.9, 0, 0, 0, 20.6],
                  [0, 22.3, 0, 0, 0, 0, 0, 0],
                  [22.0, 0, 22.8, 0, 20.7, 0, 0, 21.2],
                  [0, 22.6, 0, 0, 0, 0, 0, 0],
                  [0, 0, 0, 0, 0, 0, 0, 0],
                  [20.2, 0, 23.2, 0, 23.2, 22.6, 0, 22.0]])
    print(in)
    out = bilinear(in)
    print(out)


if __name__ == '__main__':
    main()

解説

7/20変更 左上領域右上領域左下領域右下領域が重ならないように範囲を設定しています
min_pearのすぐ下のコメントを外すと4点未満でもあるだけの点を用いて補完を行うようになります.
ヒートマップを作成するコードは省いています.

*1:本来はNoneとかを使うべき

ArduinoでIIDXコントローラを自作

きっかけ

※この記事は本家4級、BMS2段の初心者が書いています。

キーボードでBMSするの楽しいんですけど、やっぱり専用コントローラでゲームしたいわけです。ばちばち鳴らして音ゲーしたいですよね?

しかしながら専コンは売ってないし、本家に1000円も投入してないのに海外コンに3万も払うのはばかばかしく感じます。あとMacなので動くか不安。

じゃあ自作しかないので自作しましょう。

コンセプト

  • 形は公式に準拠させる

  • 金をかけない

  • 見た目にはこだわらない

  • プレイ出来ればいい

  • がんばらない

材料選定

基板

自作キーボードについてのネットの記事を探してみると、だいたいASCII製5鍵コンの基板を乗っ取って作るのが主流のように思います。しかしながらそもそも売ってなかったりPSのコネクタからUSBに変換しなければならなかったり難しいはんだ付けが要求されたりなのでコンセプトに合いません。今時のマイコンは簡単に入手できてファームも簡単に書けるのでArduinoを使用することにします。しかしながら純正は高いですね。安くあげるといえば中華製。AliExplessで互換品のProMicroを調達します。小さいので組み込み向けですし、とくに複雑な手順を踏まなくてもキーボードとして動作できるのが決め手でした。

ja.aliexpress.com

ボタン

三和ボタンとか芝ボタンとかで盛り上がるところでしょうが、前者はひとつ1000円、後者はひとつ500円と高いわけです。 安物といえば中華製。そこでまたもやAliExplessで調達します。 ja.aliexpress.com

マイクロスイッチ

調達したボタンに付いてきたマイクロスイッチは固すぎて腱鞘炎不可避なのでなくなくオムロンのVX-5-1A2を調達してきました。押圧0.25Nでここだけゲーセン仕様になりました。

スプリング

調達したボタンに付いてきたスプリング、黒鍵と白鍵で押圧が異なることに気がついてしまいました。見なかったことにしました。(いずれ交換するかもしれません)

適当にロータリーエンコーダ買うかと思ってたら5鍵コン見つけてしまったのでこれを使うことにします。

外装

アクリルとか加工頼むと高いし自分で穴開けるのは面倒なのでALL木材。塗装とか何か貼ったりとかも面倒なのでパスします。

その他

リード線とかユニバーサル基板とかは適当に調達します。仮組用のブレッドボードとかも調達します。

かかった金額まとめ

1$ = 120円としてます。

調達先は上の2つ以外梅澤無線電気です。

材料名 単価 個数 価格
ProMicro $ 3.53 1 424円
ボタンセット $ 21.66 1 2600円
マイクロスイッチ 172円 7 1204円
抵抗100本入り(220オーム) 154円 1 154円
抵抗10本入り(4.7kオーム) 64円 1 64円
ブレッドボード 108円 3 324円
リード線 194円 2 388円
ユニバーサル基板 86円 1 86円
ジャンパワイヤ 162円 2 324円
みのむしケーブル 162円 1 162円
1x4材 198円 1 198円
5鍵コン 324円 1 324円
合計 6252円

リストに載ってない天板は家に転がっていたベニヤです。

5000円くらいに収めたかったですがブレッドボードとかはまた使えるのでよしとします。

安いメカニカルキーボード買えたなあと少し思います。

製作

天板製作

適当に図面書いてその通りにベニヤを切ります。 寸法は

http://vjedo.web.fc2.com/

を参考にさせて頂きました。

f:id:yamaken1343:20180610192724j:plain f:id:yamaken1343:20180610192543j:plain

皿部分について

自分が解説するよりわかりやすいと思うので参考にしたサイトを貼って終わりにします。 mell0w-5phere.net 多分ここがわかりやすいかなあって思います。フォトインタラプタ、とか ロータリーエンコーダ、とかで検索すると詳しくわかると思います。

無残に解体された5鍵コン f:id:yamaken1343:20180526163740j:plain

基板製作

ProMicroのデジタルピンに鍵盤のマイクロスイッチ 、アナログピンにフォトインタラプタの出力を繋ぎます。

完成した基盤は天板の裏に端材を貼り付けてネジで留めておきます。

素人なので適当です。 f:id:yamaken1343:20180602213652j:plain f:id:yamaken1343:20180602224521j:plain f:id:yamaken1343:20180602223956j:plain

ファームウェア

Arduinoに書き込むソフトウェアです。 Arduino LeonardoでINFINITAS用の変換器を作る | darekasannetのブログ これを参考に書きました。githubに置いてあります。 github.com

外観、皿

1x4材で枠を作って天板を乗っけて釘で留めます。

皿は用意できなかったので段ボール工作になりました。

裏蓋は無しです。

f:id:yamaken1343:20180603215122j:plain f:id:yamaken1343:20180603222854j:plain

以上。完成です。おめでとう

感想

  • 見た目がクソダサい。 凝ると無限に金がかかるので、我慢できない人は海外コンを買うべき
  • 黒鍵と白鍵の重さが違うのと、たまに皿が変な反応する(触ってないのに連打される)意外は良好
  • 段ボール皿、プレイ感は違うけどめちゃくちゃ軽いので楽しい
  • というかこれ作ってから1週間くらいたつけど忙しくて全然プレイできない

結論

どうしても皿をうまく作るのは(見た目、感触)キツいと思います。専コン欲しい人で

  • どうしてもゲーセンに近づけたい人 -> 買った方がいい
  • 金が無限にある人 -> 買った方がいい
  • 見た目にこだわりたい人 -> 買うか無限の金をかけて自作
  • 金が無いけど知識がない人 -> 全然作れるから作れ
  • DP環境欲しいけど10万も出せない人 -> このクオリティなら1万かからないで作れる

レッツ自作ライフ

pythonで二次元ガウス分布を得る

結論

インパルス画像にガウシアンフィルタを適用させることで得られる

まえがき

中央に重み付けして加算したい*1ことがあったので, 二次元ガウス分布が欲しかったのですが, ライブラリにはなさそうだし式から起こすのも面倒なのでいい方法を探しました.

そこで, 簡単に得る方法を見つけたのでまとめておきます.

コード

import scipy.ndimage.filters as fi
import numpy as np

def gkern(kernlen=21, nsig=3):
    # kernlen x kernlen のゼロ行列を作成
    inp = np.zeros((kernlen, kernlen))
    # 中央の要素を1にする
    inp[kernlen // 2, kernlen // 2] = 1
    # ガウシアンフィルタを適用し, 結果を返す
    return fi.gaussian_filter(inp, nsig)

解説

kernlenは得られるガウス分布のサイズ, nsigはガウス分布の広がりです. 大きい方がよりとんがってない分布になります. 1のときにいわゆる標準正規分布となります.

ためしてないですが, 中央の要素ではなく好きな場所を指定すればカーネルがずれてくれると思います

*1:普通にガウシアンフィルタを適用して総和を取れば良いことにあとから気づきました

OpenCV(python)で外接長方形にそって画像を切り出す

調べるより書いたほうが速いコードですけどブログのネタがないんですね.

対象画像

f:id:yamaken1343:20180514180227p:plain

ここから赤丸の外接長方形にそって画像を切り出します.

コード

def bounding_rect_img(img):
    """
    外接長方形を切り出して画像として返す
    :param img: 入力画像
    :return: 出力画像
    """
    img_g = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # boundingRectが1チャンネルしか対応してないため変換する
    x, y, w, h = cv2.boundingRect(img_g)
    crop = img[y:y+h, x:x+w]
    return crop


def main2():

    img = cv2.imread("image_path")
    crop = bounding_rect_img(img)
    cv2.imwrite("save_path", crop)


if __name__ == '__main__':
    main2()

結果

f:id:yamaken1343:20180514180606p:plain

コメント

白背景の場合はcv2.bitwise_not()とか使ってください.

JavaFXで時間管理タイマーを作る [メモリリーク編]

yamaken1343.hatenablog.jp

f:id:yamaken1343:20180501131610p:plain

(上から2つ目のプロセスです)

しばらく使ってたんですけど、なんか妙にメモリ食うんですよねこれ。起動時から100MBくらい使うし3時間位でこうなるし。

というわけで原因を探してたんですけど、こんな記事を見つけました。

d.hatena.ne.jp

ドキュメントにもしっかりその旨が書いてあるらしく

Timeline (JavaFX 8)

警告: 実行中のTimelineはFXランタイムから参照されます。Timelineを無限にした場合、適切に停止しないと、メモリー・リークが発生する可能性があります。アニメーション化されるプロパティを持つすべてのオブジェクトがガベージ・コレクションの対象となるわけではありません。

だそうです。

コード

追加部分を抜粋すると

public class Controller implements Initializable {
    private int c = 0;

    private Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), //時間経過をトリガにするのはTimelineクラスを使う
                new EventHandler<ActionEvent>() {
                    public void handle(ActionEvent actionEvent) { //ここに書いた処理がDuration.seconds(1)で示した感覚で実行される
                        c++;
                        if (c > 60){
                            c = 0;
                            timeline.stop();
                            timeline.play();
                        }
                    }
                }
        )
    );

    public void mainButtonClick(ActionEvent actionEvent) {
        if (mainTimer.getStatus()){ //タイマーが動作中のクリック

        }else { //タイマーが動作していない

            timeline.setCycleCount(100); //何回繰り返すか指定する

        }

}

何回呼ばれたか数えるカウンタを用意して、一定回数(60回)呼ばれたら停止して再開すると言った形にしました。

非常に頭の悪い感じになりましたが、これで治るのか楽しみですね