まさかろぐ

プログラムのこと、DTMのこととか

OpenCV&C++ でアクリルキーホルダーの重心を調べる

ゆいのあ氏(@yuinore)が書いた↓の記事を見て、C++だとどれくらい長くなるのかな~と適当につぶやいたところ、うえぽん氏(@imaginary_uepon)が勢いで書いてくれました。

うえぽん氏が長くなるよう?Windows Imaging Componentを使って低レイヤーな部分も含めて書いてくれたので、私はOpenCVを使うとどれくらい短くなるか試してみました(ぶち壊し…)。

プログラム

以下がOpenCVでアクリルキーホルダーの重心を調べるプログラムです。

#include <iostream>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/core.hpp>

int main()
{
    cv::Mat image = imread("image.png", cv::IMREAD_UNCHANGED);

    // アルファ値を重みとした座標合計, およびアルファ値の合計を算出
    cv::Vec2d posSum(0, 0);
    double alphaSum = 0;
    for (int i = 0; i < image.rows; ++i)
    {
        for (int j = 0; j < image.cols; ++j)
        {
            double alpha = image.at<cv::Vec4b>(i, j)[3] / 255.0;
            posSum += cv::Vec2d(j, i) * alpha;
            alphaSum += alpha;
        }
    }

    if (alphaSum > 0)
    {
        // 座標の重み付き平均(=重心)を算出
        cv::Vec2d center = posSum / alphaSum;

        // ピクセルの大きさを考慮して0.5px右下にずらす
        center += cv::Vec2d(0.5, 0.5);

        std::cout << center << std::endl;
    }
    else
    {
        std::cout << "error: no alpha" << std::endl;
    }

    return 0;
}

40行くらい。
OpenCVはアルファブレンド付き画像に完全対応しているわけではないようなので、アルファ値をとるにはIMREAD_UNCHANGEDで読み込む必要があります。
この際、エンディアンの影響なのか縦横が逆になったりr/g/bが逆向き(BGRA)になったりするので注意が必要です。

試してみる

適当に描いた画像で試してみたところ、以下の座標になりました。だいたいあってそう。

AKAZE/ORB/BRISKでホモグラフィー行列推定(OpenCV3)

OpenCVで特徴点マッチングを行い、一方の画像がどこにあるかをボックスで表示するC++のサンプルを探していたところ、下のページに行き着きました。
しかし、OpenCV2時代のものらしく動かなかったので、今回OpenCV3用に修正しました。

どうやらOpenCV3からは特徴点の種類を簡単に変更できるようにするため、クラスの構成が変更されたみたいです。

OpenCV3用に修正したプログラム

#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv/cv.hpp>

// --------------------------------------------------------------------------
// main(Number of arguments, Argument values)
// Description  : This is the entry point of the program.
// Return value : SUCCESS:0  ERROR:-1
// --------------------------------------------------------------------------
int main(int argc, char **argv)
{
    // ORB
    auto detector = cv::ORB::create();
 
    // 読み込み
    cv::Mat image1 = cv::imread("box.png");
    cv::Mat image2 = cv::imread("box_in_scene.png");

    // 特徴点1
    std::vector<cv::KeyPoint> keypointsA;
    cv::Mat descriptorsA;
    detector->detectAndCompute(image1, cv::noArray(), keypointsA, descriptorsA);
 
    // 特徴点2
    std::vector<cv::KeyPoint> keypointsB;
    cv::Mat descriptorsB;
    detector->detectAndCompute(image2, cv::noArray(), keypointsB, descriptorsB);
 
    // マッチング
    cv::BFMatcher matcher(cv::NORM_HAMMING, true);
    std::vector<cv::DMatch> matches;
    matcher.match(descriptorsA, descriptorsB, matches);
 
    // 最小距離
    double min_dist = DBL_MAX;
    for (int i = 0; i < (int)matches.size(); i++) { 
        double dist = matches[i].distance;
        if (dist < min_dist) min_dist = dist;
    }
 
    // 良いペアのみ残す
    std::vector<cv::DMatch> good_matches;
    for (int i = 0; i < (int)matches.size(); i++) { 
        if (matches[i].distance < 3.0 * min_dist) good_matches.push_back(matches[i]);
    }
 
    // 対応点の表示
    cv::Mat img_matches;
    cv::drawMatches(image1, keypointsA, image2, keypointsB, good_matches, img_matches, cv::Scalar::all(-1), cv::Scalar::all(-1), std::vector<char>(), 0*cv::DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
     
    // 十分な対応点がある
    if (good_matches.size() > 10) {
        std::vector<cv::Point2f> obj, scene;
        for (int i = 0; i < (int)good_matches.size(); i++) {
            obj.push_back(keypointsA[good_matches[i].queryIdx].pt);
            scene.push_back(keypointsB[good_matches[i].trainIdx].pt);
        }
 
        // ホモグラフィー行列を計算
        cv::Mat H = cv::findHomography(obj, scene, cv::RANSAC);
        //std::cout << H << std::endl;
 
        // 行列が空ではない
        if (!H.empty()) {
            std::vector<cv::Point2d> obj_corners(4), scene_corners(4);
            obj_corners[0] = scene_corners[0] = cv::Point2d(0,           0);
            obj_corners[1] = scene_corners[1] = cv::Point2d(image1.cols, 0);
            obj_corners[2] = scene_corners[2] = cv::Point2d(image1.cols, image1.rows );
            obj_corners[3] = scene_corners[3] = cv::Point2d(0,           image1.rows);
 
            // ホモグラフィ行列の推定
            cv::perspectiveTransform(obj_corners, scene_corners, H);
 
            // 緑の線で囲む (開始点を元画像が左にあるので右にオフセット)
            cv::line(img_matches, scene_corners[0] + cv::Point2d(image1.cols, 0), scene_corners[1] + cv::Point2d(image1.cols, 0), cv::Scalar(0, 255, 0), 4);
            cv::line(img_matches, scene_corners[1] + cv::Point2d(image1.cols, 0), scene_corners[2] + cv::Point2d(image1.cols, 0), cv::Scalar(0, 255, 0), 4);
            cv::line(img_matches, scene_corners[2] + cv::Point2d(image1.cols, 0), scene_corners[3] + cv::Point2d(image1.cols, 0), cv::Scalar(0, 255, 0), 4);
            cv::line(img_matches, scene_corners[3] + cv::Point2d(image1.cols, 0), scene_corners[0] + cv::Point2d(image1.cols, 0), cv::Scalar(0, 255, 0), 4);
        }
    }
 
    // 表示
    cv::imshow("camera", img_matches);
    cv::waitKey(0);
 
    return 0;
}

元記事のプログラムからの変更箇所はinclude部分と13~28行目の特徴点抽出部分のコードです。OpenCV3ではクラスの構成が少し変わっています。

gccの場合は以下のコマンドでコンパイルが通ると思います。

$ g++ [ファイル名].cpp `pkg-config --cflags --libs opencv`

特徴点の種類について

はじめのauto detector = cv::ORB::create();の中の「ORB」を変更するだけで使用する特徴点の種類を変更できます。AKAZE/ORB/BRISKの3種類が使用可能のようです。

特徴量で有名どころのSIFT/SURFは特許が取られているらしく、商用利用不可らしいです。その関係でopencv_contribという拡張モジュールに隔離されているので、使用するには別途これを導入する必要があるようです。

試してみる

とりあえずAKAZEとORBとBRISKを試してみた↓

AKAZE:

ORB:

BRISK:

BRISKだけやたら点が多い…
ORBも写真のクッキーの部分の特徴を全然取ってくれていないので、とりあえずこの写真を見る限りではAKAZEが良さそう?
(このあたりは屋外・屋内とか被写体によって変わってきそう)

WordPressで「--」(ハイフン2つ)を入力する方法

WordPressでハイフン2つを連続入力しようとすると短いダッシュ記号(–)に置き換えされてしまうようです。

以下のように文字コードを直打ちすると、うまく「--」として表示してくれました。
記事タイトルへの使用も有効のようです。

&#45;&#45;

ただし、再編集の際にビジュアルモードに切り替えると勝手にハイフンに置き換えられてしまう模様…

git commit --amendを取り消すorキャンセルする方法

git commit --amendの取り消し方法について、ググっても出てこない2つ目の解決策が見つかったので記事にしてみます。

通常のgit commitではコミットメッセージを空のままで終了すればコミットをキャンセルできますが、git commit --amend(前のコミットへ上書き追加)の場合はそのまま終了してもコミットされてしまうので、うっかり実行するとキャンセルできなくて困ります。

解決策1

git commit --amendを行った後に取り消したい場合には、以下のコマンドを実行します。

$ git reset --soft HEAD@{1}

git commit --amendの実行がなかったことになってくれます。

解決策2

git commit --amendでコミットメッセージを入力する際、すでに入力されているコミットメッセージを削除して空にしてから保存&終了します。

すると、以下のようにgit commit --amendがキャンセルされてくれます。

$ git commit --ammend
Aborting commit due to empty commit message.

個人的にはこっちのやり方の方が毎回コマンドをググらなくて良いので楽かなと。

dynabookでUbuntu Live USBをブートするとGRUBでフリーズする際の解決策

dynabook R83にUbuntu 18.04を入れようとしたところLive USB stickのブート画面で固まってしまいましたが、BIOS設定をいじったら直ったのでそれについて書いておきます。

症状

Ubuntu公式の手順にしたがって作成したLive USB stickを接続し、ブート画面でF12連打→USBメモリから起動するオプションを選択しました。

すると、USBメモリからのブート自体には成功したものの、以下の画面(GNU GRUB version 2.02)で固まりました。
上下キーを押してもカーソルが移動しない状況でした。

解決策

原因はBIOS設定でSecure Boot機能を有効にしていたことだったようです。
同様にF12連打で起動してBIOS設定に入った後、以下のように設定を変更したところ、うまく起動できるようになりました。

  • [Security] → [Secure Boot]: Disabledに変更

海外フォーラム(Ask Ubuntu)ではBIOS設定から「Intel Virtualization Technology」を無効化すると動作するようになるという報告がありましたが、私の環境では特に変化がないようでした。

PuTTYからのSSH接続を経由してブラウザを閲覧する方法

ブラウザでウェブサイトを閲覧する際、PuTTYでSSH接続した接続先を一旦経由して接続させることが可能です。

アクセス先のサイトが特定のIPアドレスからのみに閲覧を制限している場合や、インターネット接続に利用しているネットワークでSSH以外の特定のプロトコルを制限されている場合などに有効です。

例えば、自宅から大学のネットワークを経由して学術論文のWebサイトへアクセスしたり、大学のネットワークでSSHは使えるもののFTPの利用は制限されているといった場合に、一旦SSHを経由して別サーバーからFTP接続させたり(いわゆる“FTP over SSH”)することができます。

手順

  1. まずPuTTYの基本設定をします。SSH接続したい接続先のホスト名などを入力します。
  2. 左のメニューから「SSH」>「トンネル」を選択します
  3. 「源ポート」に適当なポート番号(12345など使われていなさそうな番号)を入力し、「ダイナミック」を選択します
  4. 「追加」をクリックすると、上の一覧に指定したポート番号が追加されます。
    (「D1234」 のDは「ダイナミック転送」を表すD)
  5. 下の「開く」をクリックして接続します。

    端末が表示されるので、ログインしてコマンドが打てる状態にしておきます。

    PuTTY側の準備は以上となります。
  6. ブラウザのプロキシ設定でSOCKS5プロキシとして、
    • IPアドレス: 127.0.0.1
    • ポート番号: 3.で指定したポート番号(例では12345)

    を指定します。

    ■ Firefoxの場合:

    「オプション」 → 一番下の「ネットワークプロキシ」から「接続設定」をクリックし、「手動でプロキシを設定する」を選んで以下のように設定(「SOCKS v5」にチェックが付いていることを念のため確認)

    ■ Firefox以外の場合:

    「コントロールパネル」→「インターネットオプション」を開き、「接続」タブ→「LANの設定」をクリックします。

    プロキシサーバーの使用にチェックを入れ、「詳細設定」をクリックします。
    もし「設定を自動的に検出する」にチェックが付いている場合、ネットワーク側の設定によって正常に反映されない場合があるのでチェックを外します。

    Socksの入力欄にIPアドレスとポート番号を入力し、「OK」をクリックします。

以上で設定は完了です。

ブラウザからIPアドレスを確認するサイトなどへアクセスすることで、接続元が変わっていることが確認できます。

通常の接続へ戻したい場合は、SSH接続を終了した上で、

  • Firefoxの場合:
    「オプション」→「ネットワークプロキシ」の「接続設定」
    →「このネットワークのプロキシ設定を自動検出する」などにチェック
  • Firefox以外の場合:
    「コントロールパネル」→「インターネットオプション」→「接続」タブ→「LANの設定」→「LANにプロキシサーバーを使用する」のチェックを外す

というように設定を変更することで元に戻せます。

今回はブラウザでの方法を紹介しましたが、Socks5のプロキシ接続に対応しているソフトウェアであればSSHを経由しての接続が可能です。
例えば、FTPのファイル転送ソフトなども同様のプロキシ設定を行うことでSSHを経由した接続が可能となります。

Photoshopで画像に色ずれ効果を与える方法

Photoshopではチャンネルごとに移動ツールを使うことで、上のような色ずれのある画像を簡単に作ることができます。

続きを読む

[PHP]CodeIgniterでのDBトランザクションのネスト化について

CodeIgniterでは、DBへの登録・更新などを$this->db->trans_start();$this->db->trans_complete();で囲むことでトランザクションを張ることができますが、この機能は内部でネストの深さをカウンタで記録しているため、ネスト化して使用することが可能です(CodeIgniter2, CodeIgniter3で確認)。

通常のトランザクションを用いる関数例

例えば、単純な送金システムを設計する際、CustomerというModelに送金先へ残高を移動する以下のような関数を作成するとします。

public function execute_payment($source_id, $dest_id, $price) {
    // トランザクションを開始
    $this->db->trans_start();

    // 送金元から残高を引く
    $this->db->set('balance', 'balance-'.intval($price), false);
    $this->db->where('id', $source_id);
    $this->db->update('customers');

    // 送金先へ残高を加算
    $this->db->set('balance', 'balance+'.intval($price), false);
    $this->db->where('id', $dest_id);
    $this->db->update('customers');

    // トランザクションを終了
    return $this->db->trans_complete();
}

この例では、トランザクションを張っていることによって、残高を引く処理・加算する処理のいずれかでエラーが出た場合にトランザクション開始時の状態へロールバックされるようになっています。

これにより、片方だけ実行される(残高が引かれたのに送金されていない)という事態を防ぐことができ、データの整合性が保たれます。

ネスト化されたトランザクションを利用する例

上で挙げた関数では$this->db->trans_start();$this->db->trans_complete();を利用していますが、これを含む関数を複数個トランザクションの中に入れたい場合があります。その場合も、特に気にせず$this->db->trans_start();$this->db->trans_complete();で囲めば良いだけです。

すなわち、以下のように記述しても問題ありません。

$this->db->trans_start();

/* 何かしらのDB操作① */

$this->db->trans_start();

/* 何かしらのDB操作② */

$this->db->trans_complete();

/* 何かしらのDB操作③ */

$this->db->trans_complete();

このように記述した場合でも①~③すべてのDB操作が正常に実行されたときのみDBの状態が更新されます、どれか1つでもエラーが起きた場合は①~③の変更はすべてロールバックされます。

例えば、複数個の送金がある場合でも、以下のように書けばそのすべてでエラーが起きなかった場合のみDB更新が反映されます。

// トランザクションを開始
$this->db->trans_start();

// 複数件の送金処理
$this->customer->execute_payment(1, 2, 100); // 1番口座から2番口座へ100円移動
$this->customer->execute_payment(1, 3, 100); // 1番口座から3番口座へ100円移動
$this->customer->execute_payment(1, 4, 100); // 1番口座から4番口座へ100円移動

// トランザクションを終了
$this->db->trans_complete();

この例では、トランザクションを張ることにより3件の送金処理が全件成功した場合のみDBが更新されるようになっています。

なお、$this->db->trans_start();$this->db->trans_complete();は必ずしもDB操作を行うModel内に記述する必要はなく、別途Customerモデルにトランザクションの開始・終了のみを行うメソッドを実装するといった必要はありません。

ただし、Controller内で$this->dbを利用する際には、必要に応じて$this->load->database();をコンストラクタまたは各メソッドで呼び出すようにしてください。

 

FL StudioをAmazon最安値より約6500円安く手に入れる方法まとめ

先に結論を

1. まずこれを買う 2. 次にこれを買う 3. 約6500円浮く

最安値はだいたいの場合Amazon

FL Studio 12を国内で購入する場合、多くの場合はAmazonで購入するか、楽器系のネットショップで購入することになります。
この記事を執筆している2017/10/08現在、フックアップ社のサイトで紹介されている購入先の5店舗と比べてAmazonが最安値となっているので、一番安く購入するならAmazonで購入することになります。

FL Studioには他社DAWからの乗り換え用の「クロスグレード版」がある

FL Studioには「通常版」のほかに「クロスグレード版」というものがあり、「通常版」に比べ「クロスグレード版」の方が安い価格で販売されています。

↓ 通常版 ↓ クロスグレード版

「クロスグレード版」とは、他のDAW(作曲ソフト)を持っている人向けに安い価格で販売しているバージョンで、内容は通常版と全く同じです

新しいバージョンを永久無料で使える「Life Time Upgrade」も通常版と同様に使えます。
2018/06/25追記: すなわちFL Studio 12を購入すればFL Studio 20への無償アップグレードが可能です。

他の作曲ソフトからFL Studioへ乗り換えてもらいたいことから安く販売されているわけです。

ただし、クロスグレード版を購入した場合、ライセンス登録の際にそれまでにFL Studio以外の作曲ソフトを持っていたことの証明として、購入日やライセンスキーなどを記入する必要があります。
そのため、クロスグレード版のみを単体で買ったとしても、ライセンス登録することができません。

Sony ACIDを先に買ってFLのクロスグレード版で乗り換えた方が、FL通常版より安い

上で述べたとおり、新規で購入する場合はクロスグレード版を利用することができません。しかし、先に別の安いDAWを買ってからクロスグレード版で乗り換えることで、通常版を買うより安くFL Studioを手に入れることができます。
FLへのクロスグレードのために先に購入するDAWは、Sonyの「ACID Music Studio 10」です。

「ACID Music Studio 10」は 元々1万円以上するソフトだったので、FL Studioのクロスグレード製品の対象になっていました。しかし、後にACIDが半額未満に値下がりしたことで、むしろACIDを買ってからFLに乗り換える方が安くなるという奇妙な状況が生まれました。

ACID付属の音声素材(wavファイル)なども付いてくるので、安くなる以上のメリットもあります。

フックアップ社(FL Studioを売ってる日本代理店)が出しているクロスグレード対象製品一覧には「Sony Creative Software : ACID / Vegas」としっかり明記されているので、ACIDからは問題なく乗り換えできます。

どれだけ安くなるか

この記事を執筆している時点で、FLは¥28080(通常版)、¥16416(クロスグレード版)、ACIDは¥5105なので、

  • FL通常版
    • ¥28080
  •  FLクロスグレード版+ACID
    • ¥5105 + ¥16416 = ¥21521

すなわち、¥28080 – ¥21521 =¥6559 となり、
合計で6559円も安くなることがわかります。

※クロスグレード版での価格が同価格だったので、解説本pdfバンドル版の価格で計算しています

結論(再掲)

1. まずこれを買う 2. 次にこれを買う 3. 約6500円浮く

補足: クロスグレード版購入後の申請方法

FL Studioクロスグレード版には、クロスグレード申請用紙という用紙がパッケージに入っています。これに必要事項を記入して、FAXまたは郵送でフックアップ社へ送付するとクロスグレード申請完了となります。

用紙には特に期限などは書かれていませんでしたが、購入後なるべく早く送った方が良さそうです。(私は3ヶ月後に送りましたが…)

なお、クロスグレード版は日本代理店が開発元とは別に管理しているようなので、クロスグレード申請とは別に開発元のImage-Lineへの通常のライセンス登録も必要になります。お忘れなきよう。


更新履歴:
2018/06/25 FL Studio 20発売による一部リンク切れを修正

VSTで「msvcr90-ruby191.dllが見つからない」と言われる場合の解決策

「Retro Boy」などのVSTプラグインをdll単体でダウンロードしてインストールした際に、以下のようなエラーが出ることがあるようです。

エラー

msvcr90-ruby191.dllが見つからないですよ~、と言われています。

解決策としては、「C:\Users[ユーザー名]\AppData\Roaming」ディレクトリに「msvcr90-ruby191.dll」を入れれば良いようです。
(VSTプラグインのディレクトリやsystem32ディレクトリなどに入れても上手く行かないので注意)

自分で「msvcr90-ruby191.dll」を見つけてきてダウンロードしてきても良いのですが、「Retro Boy」のv1.0.3以降のバージョンをインストールすると「msvcr90-ruby191.dll」も一緒にインストールされるようになっているようなので、こちらをインストールするのが楽で安全かと思います。

以下のリンクからダウンロードしてインストールすれば解決するはずです。
https://sbaud.io/retro-boy-vst-plug-in/

1 / 2ページ

© 2016-2018 M'z Koo-boo.