Quantcast
Channel: SourceChord
Viewing all 153 articles
Browse latest View live

monaco-editorを使ってみた

$
0
0

VSCode1.3のリリースと一緒に、monaco-editorのnpmパッケージが公開されました。

てことで、さっそく使ってみました。
実際に動かしてみると、想像以上のクオリティのテキストエディタが一瞬で組み込めてビックリしました!!
今まで、HTMLとJavaScriptテキストエディタ的なの作る時には、aceとか使ってたんですが、今後はmonaco-editorを使おうかな、と思います。

サンプルコード類

以下のリポジトリにサンプルコード類があります。
https://github.com/Microsoft/monaco-editor-samples
二つのテキストの差分表示やら、electronと組み合わせたサンプルなどなど、いろんなサンプルコードがあります。
最初はこの辺を参考にやってみるとよさそう。

あとは、↓のサイトで、各種APIの使い方を、実際にWebページ上で動くサンプルコードで試すことができます。
https://microsoft.github.io/monaco-editor/playground.html

インストール

インストールは以下のコマンドで。

npm install monaco-editor

package.jsonに記録しておきたい場合は、--saveオプションも付けてください。

インストールすると、node_modulesの中にこんな風にダウンロードされます。
f:id:minami_SC:20160720005124p:plain

  • devフォルダ
    • minifyされてないコード一式。
  • minフォルダ
    • minifyされたフォルダ。プロダクション環境ではこちらを使うことを推奨。
  • min-mapsフォルダ
    • minフォルダのファイルに対するソースファイル類

ついでに、このmonaco-editorのpackage.jsonを見てみると、"dependencies": {}という何とも漢らしい記述。

typescriptのコンパイラもそうですが、MSの作るモジュールは、こんな風に依存関係を少なくするように努力してる感があって非常に好感が持てます。

npmのパッケージ依存関係の複雑さは、今年の春先にkik関係のunpublish問題でありったけトラブルになったのが記憶に新しいですよね。

こういう、他に依存せずなんでも自身のパッケージ内に書くっていうのは、npmやJavaScriptのマイクロパッケージ文化とは異なるものかもしれません。
でも、依存関係が複雑すぎて、自分が何使ってるのかわからなくなるようなモジュールより、こういうシンプルなものの方が安心して使えるよなぁ、という気がします。

使い方

ドキュメントのサンプルコードを参考に、以下のようなコードを書いてみます。
変更したのは、monaco-editorのコードを、node_modulesフォルダから直接参照するようにしたくらい。

index.html

<!DOCTYPE html><html><head><metahttp-equiv="X-UA-Compatible"content="IE=edge" /><metahttp-equiv="Content-Type"content="text/html;charset=utf-8"></head><body><divid="container"style="width:800px;height:600px;border:1px solid grey"></div><scriptsrc="node_modules/monaco-editor/min/vs/loader.js"></script><script>    require.config({ paths: {'vs': 'node_modules/monaco-editor/min/vs'}});    require(['vs/editor/editor.main'], function(){var editor = monaco.editor.create(document.getElementById('container'), {            value: ['function x() {','\tconsole.log("Hello world!");','}'].join('\n'),            language: 'javascript'});});</script></body></html>

こうしてindex.htmlを開いてみると、以下のようにVSCodeで見慣れたようなテキストエディタが領域が表示されます。
f:id:minami_SC:20160720005211p:plain

インテリセンスまでバッチリ効きます。
f:id:minami_SC:20160720005218p:plain

コードの説明

require・・・というコードがところどころ出てきてます。これは、require.jsなどと同じようなAMD形式でのモジュールローダーで、monaco-editor内のloader.jsというファイルで定義されています。
前述の通り、monaco-editorは他のパッケージへの依存を持たず、必要な機能は全部自身のモジュール内で定義しているようです。

↓のコードでは、editor.mainを最初に読みに行き、読み込みが完了したら、第二引数のコールバック関数が実行されます。

    require(['vs/editor/editor.main'], function() {var editor = monaco.editor.create(document.getElementById('container'), {
            value: ['function x() {',
                '\tconsole.log("Hello world!");',
                '}'].join('\n'),
            language: 'javascript'});
    });

このmonaco.editor.create(・・・という部分が肝です。
第一引数にテキストエディタ表示を行いたいDOM要素を指定し、第二引数に各種オプションを指定すればよいみたい。

各種オプションなど

この、monaco.editor.createメソッドを呼び出す際には、以下のようなオプション指定ができます。

var editor = monaco.editor.create(document.getElementById('container'), {
            value: ['function x() {',
                '\tconsole.log("Hello world!");',
                '}'].join('\n'),
            language: 'javascript',
            lineNumbers: true,              // 行数表示の有無
            roundedSelection: false,        // 選択領域の角が丸くなる?
            scrollBeyondLastLine: false,    // 最終行より下までスクロール可能か設定
            readOnly: false,                // 読み取り専用の設定
            theme: "vs-dark"// テーマの設定});

これらのオプションを指定することで、こんな風に色々と設定を変えられるみたい。
f:id:minami_SC:20160720005233p:plain

テキストデータの取得

エディタで編集されたテキストデータは、エディタをのインスタンスに対して、getValue()メソッドを呼び出すことで取得できます。

monaco.editor.create()メソッドの戻り値を変数に格納しておき、ボタン押下時にそのインスタンスのgetValueメソッドを呼び出して、テキストエディタに書かれた文字列を取得してみます。

コード全体は以下の通り。

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
</head>
<body>
    <div id="container" style="width:800px;height:600px;border:1px solid grey"></div>
    <button onclick="showMessage();">ボタン</button>
    <script src="node_modules/monaco-editor/min/vs/loader.js"></script>
    <script>
    var editor;
    require.config({ paths: {'vs': 'node_modules/monaco-editor/min/vs'}});
    require(['vs/editor/editor.main'], function() {
        editor = monaco.editor.create(document.getElementById('container'), {
            value: ['function x() {',
                '\tconsole.log("Hello world!");',
                '}'].join('\n'),
            language: 'javascript'});
    });

    function showMessage() {var text = editor.getValue();
        alert(text);
    }</script>
</body>
</html>

f:id:minami_SC:20160720005343p:plain

とりあえず、今回はこの辺まで。


monaco-editorをelectron環境で使ってみた

$
0
0

前回に引き続き、monaco-editorネタです。
今回は、monaco-editorをelectron環境で使ってみました。

f:id:minami_SC:20160725001931p:plain

プロジェクト一式は以下のリポジトリに置いています。
github.com

参考リンク

monaco-editorのサンプル類が置かれた、以下のリポジトリを参考にやってみます。
https://github.com/Microsoft/monaco-editor-samples/tree/master/sample-electron

ベースのプロジェクト

以前作った、↓のelectron+typescriptなプロジェクトをベースにして、monaco-editorを組み込んでみます。
https://github.com/sourcechord/electron-typescript-sample

気を付ける点

loader.jsを読み込むタイミング

monaco-editorを使うときは、AMD方式のモジュールローダのloader.jsを読み込む必要があります。
しかし、このloader.jsを読み込むと、node.jsのrequire()・・・というモジュール読み込みができなくなってしまいます。

そのため、node.js/electron関連のモジュールや、npmでインストールしたモジュール類は先に読み込んでおき、
最後にloader.jsを読み込んで、monaco-editor関連のファイルをrequireする必要があります。

こんな風にbodyタグの最後の部分でloader.jsを読み込み、そのあとでmonaco-editor関連のモジュール読み込みを行います。

index.html

<!DOCTYPE html><html><head><metacharset="UTF-8"><title>Hello World!</title><styletype="text/css">*{box-sizing: border-box;
      }html,body{width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;
      }</style><scriptsrc="index.js"></script></head><body><divid="container"style="width: 100%; height: calc(100% - 30px); border:1px solid #ccc"></div><buttononclick="showEditorText()">Show Text</button><script>// node.js/electron関係のモジュールは、loader.jsを読み込む前にrequire()しておく必要がある。var path = require('path');</script><scriptsrc="node_modules/monaco-editor/min/vs/loader.js"></script><script>function uriFromPath(_path){var pathName = path.resolve(_path).replace(/\\/g, '/');if(pathName.length > 0&& pathName.charAt(0) !== '/'){          pathName = '/' + pathName;}return encodeURI('file://' + pathName);}      require.config({        baseUrl: uriFromPath(path.join(__dirname, 'node_modules/monaco-editor/min'))
});// workaround monaco-css not understanding the environmentself.module = undefined;// workaround monaco-typescript not understanding the environmentself.process.browser = true;      require(['vs/editor/editor.main'], function(){        onModuleLoaded();});</script></body></html>

index.ts

/// <reference path="node_modules/monaco-editor/monaco.d.ts" />import * as electron from 'electron';
import{remote} from 'electron';
const app = remote.app;
const BrowserWindow = remote.BrowserWindow;
const dialog = remote.dialog;

var editor: monaco.editor.IStandaloneCodeEditor;

function onModuleLoaded() {
    editor = monaco.editor.create(document.getElementById('container'), {
        value: ['function x() {',
        '\tconsole.log("Hello world!");',
        '}'].join('\n'),
        language: 'typescript',
        automaticLayout: true,
        theme: "vs-dark"});
}function showEditorText() {var text = editor.getValue();
    alert(text);
}
レイアウト

monaco.editor.createメソッドを呼び出す際に、以下のようにautomaticLayout: trueという指定を追加しています。

    editor = monaco.editor.create(document.getElementById('container'), {
        value: ['function x() {',
        '\tconsole.log("Hello world!");',
        '}'].join('\n'),
        language: 'typescript',
        automaticLayout: true,
        theme: "vs-dark"});

この指定を加えておくと、テキストエディタ領域をリサイズした際に、monaco-editorのテキストエディタ部分が自動でレイアウト調整されるようになります。
(指定しないと、ウィンドウリサイズ時とかしても、エディタ部分がリサイズされず、そのままの状態で残ってしまいます)

今回はこの辺まで。

TypeScriptでasync/awaitを使ってみた

$
0
0

そういえば、今までTypeScriptのasync/awaitを使ってなかったので、使い方を軽くφ(..)メモメモ

TypeScript1.x系では、ES3/ES5向けのときはasync/awaitは使えないので、ちょっと敬遠してましたが、
Node.js環境だったら普通に使えるだろうし、、ということで使ってみました。

↓を参考にやってみました。

こんな風に、Promiseでくるんだ関数を用意しておくと、awaitできるようになります。

C#のasync/awaitと同様に、awaitが使えるのはasyncな関数の内部だけになるので注意。

index.ts

function wait(n: number) {returnnew Promise(done => setTimeout(() => done(n), n));
}

async function main() {
    console.log("start");
    for (var i=0; i<10; i++) {
        await wait(1000);
        console.log("next");
    }}

main();

tsconfigはこんな感じ。
"target": "es6"として、ES6向けにトランスパイルするようにしています。

tsconfig.json

{"compilerOptions": {"module": "commonjs",
        "target": "es6",
        "noImplicitAny": false,
        "sourceMap": true},
    "exclude": ["node_modules"]}

こうすると、1秒間隔でnextと表示されていきます。
非同期な処理でも、普通にfor分とかのループ処理と組み合わせて掛けたり、何かと便利に使えそうですね。

typescriptのasync/awaitで生成されるコードを見てみる

$
0
0

この間、async/awaitを試しに使ってみたときの、↓のコード。
http://sourcechord.hatenablog.com/entry/2016/07/28/084127

トランスパイルすると、どんなコードが吐き出されるのか見てみました。

これが

function wait(n: number) {returnnew Promise(done => setTimeout(() => done(n), n));
}

async function main() {
    console.log("start");
    for (var i=0; i<10; i++) {
        await wait(1000);
        console.log("next");
    }}

main();

こうなる

var __awaiter = (this&& this.__awaiter) || function (thisArg, _arguments, P, generator) {returnnew (P || (P = Promise))(function (resolve, reject) {function fulfilled(value) {try{ step(generator.next(value)); }catch (e) { reject(e); }}function rejected(value) {try{ step(generator.throw(value)); }catch (e) { reject(e); }}function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments)).next());
    });
};
function wait(n) {returnnew Promise(done => setTimeout(() => done(n), n));
}function main() {return __awaiter(this, void 0, void 0, function* () {
        console.log("start");
        for (var i = 0; i < 10; i++) {
            yield wait(1000);
            console.log("next");
        }});
}
main();
//# sourceMappingURL=index.js.map

意外とシンプルなコードが生成されてますね。

__awaiterってヘルパーが作られ、TypeScriptのコードでawaitな関数呼び出しをした部分で使用されてます。 ターゲットがES6なら、genaratorがあるからこのように変換できるみたい。

今後、ES3/ES5向けにも対応するみたいだけど、genaratorのない環境で、どんなコード生成するんだろ。。
まぁそれはそれとして、TypeScript2.1での、async/awaitのES3/ES5対応が待ち遠しいです。

Windows10 Anniversary Updateに更新

$
0
0

さっそくアップデートしてみました。

自分のメインPCはずいぶん古いので、WindowsUpdateではまだ降ってきません。

ということで、Windows10 更新アシスタントを使ってアップデートを行います。

設定から「更新とセキュリティ」を開き、Windows Updateタブの中の「詳細情報」というリンクを押します。
f:id:minami_SC:20160803234538p:plain

このリンクを開いた先のサイトで、「Anniversary Updateを入手する」というボタンを押すと、更新アシスタントのプログラムがダウンロードできます。
f:id:minami_SC:20160803234741p:plain

で、コイツを実行するとこんな画面が出てくるので、画面の案内に従ってアップデートを行います。
f:id:minami_SC:20160803234801p:plain:w300f:id:minami_SC:20160803234807p:plain:w300

こんな風に、ダウンロードと更新処理が進んでいきます。
自分のとこでは、だいたい2~3時間くらいかかりました。

まだあまり新機能などは試せてませんが、 全般的にストアアプリの挙動がキビキビ動作するようになった気がします。

NTVS 1.2 をインストールしてみた

$
0
0

Visual StudioでNode.jsアプリ開発を行うための拡張機能のNode.js Tools for Visual Studio(NTVS)ですが、コイツの新バージョンNTVS 1.2がリリースされてます。

インテリセンスのためのTypeScript/JavaScriptコード解析エンジンが更新されたようで、劇的にパフォーマンスが改善されています。

↓を見ると、新しいエンジンはSalsaが使われているようですね。
https://github.com/Microsoft/nodejstools/wiki/IntelliSense-and-Editing#intellisense-in-ntvs-12

今までのバージョンだと、ちょっと大きめのプロジェクトなどを開いたときに、VSの動作がとてつもなく遅くなったりしてました。
自分の環境でも、VSのプロセスがメモリ2GB近く消費することもちょくちょくあり、最近ではNode.js系の開発は、極力VSを使わずにVSCodeで行ってました。

ですが、NTVS1.2の新エンジンでは、この辺のパフォーマンスが大幅に改善されています。
NTVS1.2に更新して、インテリセンスのエンジンを新しいものに変更すると、サクサク動作するようになります。 f:id:minami_SC:20160806094850p:plain

ちなみに、TypeScriptの新規プロジェクト・ウィザードの項目はこんな感じ。
そろそろ、Express4のテンプレートにして欲しい気もします。
f:id:minami_SC:20160806094859p:plain

でもまぁ、古いバージョンのTypeScriptコンパイラ使ってると、新しい型定義ファイルが使えなかったり、、、いろいろと組み合わせの問題があるし。。。

結局はこういうテンプレート使うより、自分でプロジェクト作る方が何かと便利かもしれません。

Visual Studio Code 1.4の新機能・変更点

$
0
0

VSCode 1.4がリリースされました。
今回も、個人的に気になる新機能・変更点をメモしときます。

先月の1.3では新機能盛りだくさんだったこともあり、今回の更新は変更点控えめです。

エディタ関連

コードスニペット関連

コードスニペットに関して、色々と便利な機能が追加されてます。

スニペットのサジェスト

インテリセンスの候補表示時に、コードスニペットの項目をどのように表示するかをカスタマイズできるようになりました。

settings.jsoneditor.snippetSuggestionsという項目を編集することで、コードスニペット候補表示をカスタマイズできます。

↓topを選ぶと、こんな感じ。
f:id:minami_SC:20160807104643p:plain

コマンドパレットからのコードスニペット入力

Insert Snippetというコマンドが追加されました。
コマンドパレットを開き、Insert Snippetとコマンドを打つと、コードスニペットの一覧が表示されます。

f:id:minami_SC:20160807104649p:plain

タブの横のアイコン

Markdownなどのプレビュー表示や、Git連携時のコード変更点表示などを行うためのボタンが復活しました。
以前のバー所ナップで、これらのアイコンは一度削除されましたが、ユーザーからのフィードバックを反映して、これらのボタンを元に戻したようです。
f:id:minami_SC:20160807104713p:plain

デバッガ関連

Restart Frame

デバッガでの実行時に、今までのコールスタックの関数開始位置まで、プログラムの実行状態を戻す機能ができました。
で、コールスタックの各関数開始位置まで戻って、そこからデバッガの実行を再開できます。
すげぇ!!
地味に便利!!
f:id:minami_SC:20160807104738p:plain

注意点
この機能は、今のところNode.jsのデバッガのみの対応とのこと。
他の言語は、その言語のデバッガが対応したら使えるようになるようです。
また、Node.jsで使うときは、Node.js 5.11以降のバージョンが必要みたい。それ以前のバージョンだと、うまく動作しない場合があるようです。

その他

他にも以下のような細かい点が改善されてます。

  • ドラッグ&ドロップの動作改善
    • VSCodeのウィンドウをまたいで、別のVSCodeのウィンドウへと、タブをドラッグ&ドロップできるようになりました。
  • Ctrl+Pクイックオープンのパフォーマンス改善
    • 巨大なワークスペースを開いた場合のCtrl+Pのパフォーマンスが改善されました。
  • VSCode組み込みのターミナルの動作改善
    • IMEがサポートされ、日本語入力できるようになった
      • ただし、Win環境だと変換候補ウィンドウの位置がちょこちょこズレたり、微妙な動作したりします。。。
    • Ctrl+Shift+C``Ctrl+Shift+Vでコピペができるようになった。
    • 右クリックで、メニュー表示がでるようになった。(新しいターミナルを開いたり、コピペしたりができます)

W700DをWin10 Anniversary Updateに更新してみた

$
0
0

手持ちのサブ機のW700DもWindows10 Anniversary Updateに更新してみました。

以前Win10に更新したときは、↓のようにプリインストールアプリとの相性問題などもありましたが、

このとき問題になってたアプリは無効化しているので、今回は特に問題なく使えています。

アップデートには20GB以上の空き領域が必要なのですが、 タブレットでこれだけ空き領域を作るのは、なかなか大変でした・・・・ VSとかいろいろインストールしてると、なんだかんだで結構容量食ってしまうし・・・

Edge

ようやくEdgeがまともなブラウザになってきた感じです。
左右スワイプでの戻る/進む、という動作ができるようになりました。

ページの描画速度など、レンダリングエンジン自体はいい感じなのに、UIまわりが残念すぎたり、いまいち動作が安定しなかったり、って感じで、ずっと使うの避けてました。。
ですが、タブレット用途ではそろそろEdgeをメインブラウザに戻してみようかと思ってます。

Windows Ink

今回のアップデートでは、 ink系の機能がやたらプッシュされてますね。
ペン付きの機種では、こんなボタンがあったりするそうです。 しかし、タッチパネルだけのW700Dでは、デフォルトではこの機能が有効になっていません。

ってことで、さっそくWindows Inkの機能を有効にしましょう。

Windows Inkの有効化

設定から、「個人用設定」を開き、タスクバータブの「システムアイコンのオン/オフの切り替え」という項目をクリックします。
f:id:minami_SC:20160807231132p:plain

すると、こんな風に各機能の有効無効を切り替える画面になるので、「Windows Ink ワークスペース」というのをオンにします。
f:id:minami_SC:20160807231152p:plain

使ってみる

Windows Inkを有効にすると、タスクトレイに↓のようなボタンが追加されます。
f:id:minami_SC:20160807231201p:plain:w200

コイツを押すと、画面右側にこんな風にWindows Ink ワークスペースの各種項目が表示されます。
f:id:minami_SC:20160807231209p:plain:w250

スケッチパッドを起動すると↓みたいに、定規なども使ってお絵かき的なメモが取れます。
f:id:minami_SC:20160807231220p:plain

他にも画面キャプチャに対しても、同じように手書きメモを取ることができます。

この辺は、説明用のキャプチャ画像を作るときなどに結構便利な気がします。
てか、そろそろちゃんとペンが付いたタブレット欲しくなってきました。


OpenCvSharp3を使ってみた

$
0
0

以前、C#からOpenCVを扱うためのラッパーライブラリのOpenCvSharpというライブラリを使ってみました↓
http://sourcechord.hatenablog.com/entry/2014/09/22/010344

OpenCV3.0に対応した、このライブラリの新バージョンOpenCvSharp3を使ってみたのでφ(..)メモメモ

変更点については、作者さんの↓の記事を参照

よく使うクラスなどに関わる、大きな変更点は以下のような点でしょうか。

  • IplImage型がなくなった
  • Cvクラス、CvWindowクラスなどがなくなった⇒Cv2クラス、Windowクラスを使う

今回のサンプル類一式は、以下の場所に置いてます。
https://github.com/sourcechord/OpenCvSharp3Sample

コンソールアプリ

とりあえず、GitHubのReadMeを見ながら、最低限のサンプルコードを動かしてみます。

class Program
    {
        staticvoid Main(string[] args)
        {
            var src = new Mat(@"Images/1.jpg");
            var dst = new Mat();

            Cv2.CvtColor(src, dst, ColorConversionCodes.BGRA2GRAY);

            using (new Window("dst image", dst))
            {
                Cv2.WaitKey();
            }
        }
    }

画像データは、IplImage型を使わずにMat型で扱うということを意識すれば、だいたい同じ感覚で書けそうですね。

f:id:minami_SC:20160811121338p:plain:w400

WPFとの連携

以前のサンプルと同じように、OpenCVSharpで加工した画像を、WPFのImageコントロールで表示してみます。

MatからWriteableBitmapへの変換

Mat型にもToWriteableBitmapという拡張メソッドが用意されていて、IplImageと同じようにWriteableBitmapに変換できます。

サンプルコード

ボタンを押すと、このように画像をグレースケールで表示します。
f:id:minami_SC:20160811121355p:plain:w400

MainWindow.xaml

<Window x:Class="WpfSample.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:local="clr-namespace:WpfSample"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"Title="MainWindow"Width="525"Height="350"mc:Ignorable="d"><Grid><Grid.RowDefinitions><RowDefinition /><RowDefinition Height="Auto" /></Grid.RowDefinitions><Image x:Name="imgResult"Margin="10" /><Button Grid.Row="1"Width="75"Margin="10"HorizontalAlignment="Right"VerticalAlignment="Top"Click="Button_Click"Content="表示" /></Grid></Window>

MainWindow.xaml.cs

/// <summary>/// MainWindow.xaml の相互作用ロジック/// </summary>publicpartialclass MainWindow : System.Windows.Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        privatevoid Button_Click(object sender, RoutedEventArgs e)
        {
            var src = new Mat(@"Images/1.jpg");
            var dst = new Mat();
            Cv2.CvtColor(src, dst, ColorConversionCodes.BGRA2GRAY);
            imgResult.Source = dst.ToWriteableBitmap();
        }
    }

注意点
System.WindowsOpenCvSharp名前空間に、それぞれWindowという同名のクラスが定義されています。
そのため、usingでどちらの名前空間も読み込んでいる場合には、MainWindowの親クラス指定で、明示的にクラス名を指定する必要があります。

OpenCvSharp3入門

$
0
0

前回に続き、再度OpenCvSharpネタです。
色々使ってみたので、使い方などを一通りメモしときます。

参考情報

OpenCvSharpのC++API対応についての説明
http://schima.hatenablog.com/entry/2014/03/29/140106

OpenCvSharpのWiki。ここのC++APIの部分など。
https://github.com/shimat/opencvsharp/wiki

http://opencv.jp/reference_manual

OpenCvSharp3ではC APIは廃止して、C++APIを使うようになっています。
まずは、この辺のページを見て、OpenCVC++APIをざっと把握するとよいと思います。

画像の入出力

以下の関数で、画像ファイルからMatクラスのデータを作ったり、、Matクラスのインスタンスの内容をファイルに書き出したりできます。

  • Cv2.Imread・・・画像ファイルの読み込み
  • Cv2.Imwrite・・・画像ファイルへの書き出し
            var src = Cv2.ImRead(@"Images/1.jpg");
            Cv2.ImWrite(@"output.jpg", src);

画像データの形式(Matクラス)

Imreadで読み込んだデータは、Matという型のインスタンスとして返されます。
これは、画像データをはじめ、各種行列形式のデータを汎用的に扱うための型とのこと。

詳しいことは、以下のリンクなどを参照してください。
http://opencv.jp/cookbook/opencv_mat.html
http://opencv.jp/opencv-2svn/cpp/core_basic_structures.html#mat

Matクラス作成時の画像読み込み

Imreadメソッドを使わなくても、以下のようにMatクラスのコンストラクタで、画像ファイルのパスを指定することで画像の読み込みができます。

インスタンス作成時に、画像読み込みまでしたい場合は、こちらの方が便利。
この呼び出し方はOpenCV本家のものではなく、OpenCvSharpnの独自拡張かな?たぶん。
細かい部分ですが、使いやすくなるよう配慮されてていいライブラリですね。

            var img = new Mat(@"Images/1.jpg");
            Cv2.ImShow("test", img);
            Cv2.WaitKey();

f:id:minami_SC:20160815234922p:plain

他にも、OpenCV本家と同様な、多数のコンストラクタのオーバーロードがあります。
こんな風に、塗りつぶし色を指定して、Matのインスタンスを作ることもできます。

            var img = new Mat(240, 320, MatType.CV_8UC3, new Scalar(0, 0, 255));
            Cv2.ImShow("test", img);
            Cv2.WaitKey();

f:id:minami_SC:20160815234954p:plain

ウィンドウ表示

今までもサラッとImShowなどの関数を使ってきましたが、
ここらで改めて、ウィンドウ表示関連の機能をまとめておきます。

以下のような関数があります。

  • Cv2.ImShow・・・・・引数で指定した内容をウィンドウ表示する
  • Cv2.WaitKey・・・・・キー入力が行われるまで、処理を止めて待機
  • Cv2.DestroyWindow・・引数で指定したウィンドウを破棄
  • Cv2.DestroyAllWindows・・OpenCVで作成したすべてのウィンドウを破棄
            var img = new Mat(@"Images/1.jpg");
            // 「test」という名前のウィンドウを作りimgの内容を表示
            Cv2.ImShow("test", img);

            // キー入力があるまで待機
            Cv2.WaitKey();

            // 明示的に全画像の破棄を指示
            Cv2.DestroyAllWindows();

Windowクラスを使ったウィンドウ表示

OpenCvSharpでは、Windowというクラスが定義されており、以下のようにWinowを作成して表示することができます。

            var img = new Mat(@"Images/1.jpg");
            using(var win = new Window("Sample Window", img))
            {
                Cv2.WaitKey();
            }

前回の記事でも書きましたが、WPF環境などで使う場合は、Windowというクラス名がSystem.WindowsOpenCvSharpそれぞれの名前空間に存在するので、両方の名前空間をusingしている場合には注意が必要です。

Matクラスへのアクセス

各種画像の情報取得

画像の幅・高さや、チャンネル数・ビット深度情報、などなどの情報を表示してみます。

// Matクラスの各種情報を確認
            var img = new Mat(@"Images/1.jpg");
            Console.WriteLine($"Width: {img.Width}, Height: {img.Height}");
            Console.WriteLine($"Cols: {img.Cols}, Rows: {img.Rows}");
            Console.WriteLine($"Channels: {img.Channels()}, Depth: {img.Depth()}");

f:id:minami_SC:20160815235019p:plain

このDepthメソッドで取得できる値は、Matの各要素のビット深度を表します。ただし、この値はビット深度をビット数やバイト数で表した数値ではなく、OpenCV内で定義されたビット深度の種別を示す定数値となっているので注意が必要です。
http://opencv.jp/opencv-2svn/cpp/core_basic_structures.html#cv-mat-depth
このサンプルでは「0」という値になっていますが、これはOpenCvで定義されている定数のCV_8Uにあたるもので、8ビット符号なしデータとなります。

画像の加工/コピーなど

            var src = new Mat(@"Images/1.jpg");
            var dst = new Mat();

            // リサイズ後の画像サイズを指定してリサイズする場合
            Cv2.Resize(src, dst, new Size(320, 240), 0, 0, InterpolationFlags.Cubic);

            // 倍率指定でリサイズする場合
            Cv2.Resize(src, dst, Size.Zero, 1, 0.5, InterpolationFlags.Cubic);

            // X軸方向に画像反転
            Cv2.Flip(src, dst, FlipMode.X);

            // Y軸方向に画像反転
            Cv2.Flip(src, dst, FlipMode.Y);


            // 画像データの複製
            var clone = src.Clone();

            // 画像の一部分を切り出して複製
            var partialClone = src.Clone(new Rect(100, 100, 200, 150));

ピクセルデータの取得、設定

続いて、Matクラスとして扱っている画像データの、各ピクセルデータにアクセスしてみます。

ここでは何通りかの方法を用いてピクセルデータを直接操作し、ネガポジ反転を行ってみます。

// Get/Setメソッドを使ってアクセス
            var src = new Mat(@"Images/1.jpg");
            for (var y = 0; y < src.Height; y++)
            {
                for (var x = 0; x < src.Width; x++)
                {
                    var px = src.Get<Vec3b>(y, x);
                    px[0] = (byte)(255 - px[0]);
                    px[1] = (byte)(255 - px[1]);
                    px[2] = (byte)(255 - px[2]);
                    src.Set(y, x, px);
                }
            }
            Cv2.ImShow("image", src);
            Cv2.WaitKey();
// インデクサを使ったアクセス
            var src = new Mat(@"Images/1.jpg");
            var indexer = src.GetGenericIndexer<Vec3b>();
            for (var y = 0; y < src.Height; y++)
            {
                for (var x = 0; x < src.Width; x++)
                {
                    var px = indexer[y, x];
                    px[0] = (byte)(255 - px[0]);
                    px[1] = (byte)(255 - px[1]);
                    px[2] = (byte)(255 - px[2]);
                    indexer[y, x] = px;
                }
            }
            Cv2.ImShow("image", src);
            Cv2.WaitKey();
// 特定のデータ型に特化したMat派生クラスを使ったアクセス
            var src = new Mat(@"Images/1.jpg");
            var mat3 = new MatOfByte3(src);
            var indexer = mat3.GetIndexer();
            for (var y = 0; y < src.Height; y++)
            {
                for (var x = 0; x < src.Width; x++)
                {
                    var px = indexer[y, x];
                    px[0] = (byte)(255 - px[0]);
                    px[1] = (byte)(255 - px[1]);
                    px[2] = (byte)(255 - px[2]);
                    indexer[y, x] = px;
                }
            }
            Cv2.ImShow("image", src);
            Cv2.WaitKey();

f:id:minami_SC:20160815235032p:plain

↓のページを見てみると、MatOfByte3など、特定のデータ型に特化したMat派生クラスを通してアクセスするのが最も高速なようです。
https://github.com/shimat/opencvsharp/wiki/%5BCpp%5D-Accessing-Pixel

とりあえず、最低限このようなピクセルデータへのアクセスだけできれば、自分で画像処理のロジックをガリガリ書いて色々遊べますね。

OpenCVの機能を使ってネガポジ反転

上で書いたサンプルでは、ピクセルデータを直接操作してネガポジ反転を行いましたが、単純にネガポジ反転するだけであれば、以下のようにOpenCVの機能でシンプルに書くこともできます。

// ネガポジ反転するだけなら、以下のようにNot演算で可能
            var src = new Mat(@"Images/1.jpg");
            var result1 = new Mat();
            Cv2.BitwiseNot(src, result1);
            // ↓こんな書き方もあり
            var result2 = ~src;

各種アルゴリズム

Matクラスのデータに対して、様々な処理を行う関数が多数用意されてます。
ここでは初めの一歩として、ぼかし効果を与えるblurメソッドを呼び出してみたいと思います。

            var src = new Mat(@"Images/1.jpg");
            var dst = new Mat();
            Cv2.Blur(src, dst, new Size(5, 5));
            Cv2.ImShow("blur", dst);
            Cv2.WaitKey();

他にも多数のアルゴリズムが実装されています。
それぞれの使い方は、必要に応じてリファレンスを参照すればよいかと思います。

図形の描画

OpenCVでは、Mat型の画像に対して、線分やテキストなどの図形データを描画する方法が用意されてます。
こんな風に呼び出して、図形などを描画することができます。

            var img = new Mat(240, 320, MatType.CV_8UC3, new Scalar(0, 0, 0));

            // 直線を描画
            Cv2.Line(img, new Point(10, 10), new Point(300, 10), new Scalar(0, 0, 255));
            Cv2.Line(img, new Point(10, 30), new Point(300, 30), new Scalar(0,255, 0), 2);

            // 矩形を描画
            Cv2.Rectangle(img, new Rect(50, 50, 100, 100), new Scalar(255, 0, 0), 2);

            // 文字を描画
            Cv2.PutText(img, "Hello OpenCvSharp!!", new Point(10, 180), HersheyFonts.HersheyComplexSmall, 1, new Scalar(255, 0, 255), 1, LineTypes.AntiAlias);

            Cv2.ImShow("image", img);
            Cv2.WaitKey();

f:id:minami_SC:20160815235102p:plain

Matクラスのお作法

今までは、特に何も注意せずにMatクラスのインスタンスを作って使ってきましたが、ここではMat型のデータのメモリ管理を少し意識してみたいと思います。

OpenCvSharpでは、MatクラスをIDisposableなクラスとして定義しています。
なので、using構文などを用いて、リソース破棄のタイミングを厳密に管理することができます。

逆に言うと、using使ったり、Dispose()メソッドの呼び出しをしたりしないと、
Matクラスを作って確保されたメモリ領域がいつ破棄されるかは、.NetのGCがかかるタイミング次第、、、という事になってしまいます。

Matで扱うデータは、主に画像などのメモリを大量に消費するものになります。
基本的にはちゃんとusing使って、破棄のタイミングを適切に管理するのが望ましいかと思います。

using (var src = new Mat(@"Images/1.jpg"))
            using (var dst = new Mat())
            {
                // ぼかしをかける
                Cv2.Blur(src, dst, new Size(5, 5));
                // 結果表示用のウィンドウ作成using (var win = new Window("result", dst))
                {
                    Cv2.WaitKey();
                }
            }

動画データを扱う

最後に動画データの扱いについてサラッと試してみます。
動画ファイルや、カメラからのキャプチャなど、動画データのソースとなるものを読み込むには、VideoCaptureクラスを用いることで簡単に利用できるようになります。

動画ファイルの読み込み

まずは、動画ファイルを読み込みしてみます。

このようにVideoCaptureクラスのコンストラクタで、動画ファイルのパスを渡すと、動画の各フレームデータを取得できるようになります。

以下のようなコードで動画ファイルの再生ができるはず、、、なのですが、
自分の環境では再生できませんでした。 OpenCvSharp2.4では、同様のコードで再生できたんだけど・・・
この辺は、原因調査中です。。。

            var capture = new VideoCapture(@"Path/To/MovieFile.xxx");
            using (var win = new Window("capture"))
            using (var mat = new Mat())
            {
                while (true)
                {
                    capture.Read(mat);
                    // 読み込めるフレームがなくなったら終了if (mat.Empty()) { break; }

                    win.ShowImage(mat);
                    Cv2.WaitKey(33);
                }
            }

Webカメラからのキャプチャ

Webカメラからのキャプチャも、画像ファイルを扱うのと同じような感じでコーディングできます。

以下のように、VideoCaptureクラスのコンストラクタに、デバイスIDの数値を渡すことで、指定したデバイスでキャプチャを開始することができます。
このとき、「0」を指定するとデフォルトのデバイスをオープンします。

// デフォルトのカメラをオープン
            var capture = new VideoCapture(0);
            using (var win = new Window("capture"))
            using (var mat = new Mat())
            {
                while (true)
                {
                    capture.Read(mat);
                    win.ShowImage(mat);
                    if (Cv2.WaitKey(30) >= 0) { break; }
                }
            }

こちらは、OpenCvSharp3系のバージョンでもうまく動きました。

動画データの保存

以下のように、VideoWriterクラスを使って、動画データの保存ができます。
ただし、こちらも動画読み込みと同じように、自分の環境では正しく動画データの出力できず・・・

実行すると、エンコーダの選択画面が出るのですが、選んだものによってはファイルが出力されない、、とか、ファイル出力されても、再生できなかったり、、、などなど。

この辺も、もう少し調べてみようと思います。

// デフォルトのカメラをオープンusing (var capture = new VideoCapture(0))
            using (var writer = new VideoWriter("test.avi", FourCC.Default, capture.Fps, new Size(capture.FrameWidth, capture.FrameHeight)))
            using (var win = new Window("capture"))
            using (var mat = new Mat())
            using (var dst = new Mat())
            {
                while (true)
                {
                    capture.Read(mat);
                    Cv2.CvtColor(mat, dst, ColorConversionCodes.BGR2GRAY);
                    win.ShowImage(dst);
                    writer.Write(dst);
                    if (Cv2.WaitKey(30) >= 0) { break; }
                }
            }

OneNote2010で、OneDrive上のノートブックが同期できない問題【解決済み?】

$
0
0

数日前に、自分のメインPCで利用しているOneNote2010を開いたら、全てのセクションが消えてしまう、という現象が起きました。 f:id:minami_SC:20160821110302p:plain:w300

一瞬、全部のセクションやページが消えたのか、、、と思い焦りましたが、ブラウザからOneNote Onlineのページを見てみると、ノートの内容は残っている模様。。。

ということで、OneNote2010側の問題かと思い、色々検索してたら、↓のようにドンピシャな情報が見つかりました。
http://answers.microsoft.com/ja-jp/office/forum/office_2010-onenote/onenote2010%E3%81%AE%E4%B8%8D%E5%85%B7%E5%90%88/4684976e-34d4-4347-a29c-400434caf6e7

ちょっと面倒だけど、自分もこの対処しなきゃなぁ、、、と思いながら、しばらく放置してました。
ですが、今日(8/21)再びOneNoteを起動してみたら、ちゃんと同期できるようになってました。

OneDrive側で何か対処があったのかな???
とりあえず、今後のトラブルに備えメモしときます。

そろそろ2016にバージョンアップした方がいいかな、、とか悩み中。。。

OpenCvSharpで作成したウィンドウにスライダーを付けてみる

$
0
0

OpenCvSharpで作成したウィンドウに、スライダーを付けてみます。

作成したウィンドウに対してCreateTrackbar2を呼び出すことで、ウィンドウにスライダーを付加できます。

ちなみに、CreateTrackbar/CreateTrackbar2と似たような名前の関数が用意されてますが、それぞれの用途の違いなどはまだ把握できてないです。。。
関数のシグネチャが若干違いますが、どちらの関数でもスライダーを作成できました。

スライダーの作成

まずは、スライダーを作成して、スライダーの位置が変化したらその座標をコンソールに表示してみます。

class Program
    {
        staticvoid Main(string[] args)
        {
            using (var src = new Mat(@"Images/1.jpg"))
            {
                using (var win = new Window("dst image", src))
                {
                    win.CreateTrackbar2("test", 10, 255, OnPosChanged, null);

                    Cv2.WaitKey();
                }
            }

        }

        privatestaticvoid OnPosChanged(int pos, object userdata)
        {
            Console.WriteLine($"pos: {pos}");
        }
    }

f:id:minami_SC:20160821201953p:plain

スライダーの設定値を利用して画像処理

続いて、スライダーを使って画像処理のパラメータを変化させてみます。
このサンプルでは、スライダーで指定した値を用いて、画像の二値化の閾値を変化させます。

ここでは、コールバック関数は関数として別途定義するのではなく、ラムダ式で書いてます。
こうしておくと、ラムダ式の外側の変数をキャプチャして、ラムダ式内で利用できるので、何かと便利です。

class Program
    {
        staticvoid Main(string[] args)
        {
            using (var src = new Mat(@"Images/1.jpg"))
            using (var gray = new Mat())
            using (var dst = new Mat())
            {
                Cv2.CvtColor(src, gray, ColorConversionCodes.BGRA2GRAY);
                using (var win = new Window("dst image", gray))
                {
                    win.CreateTrackbar2("Threshold", 10, 255, (pos, userdata) =>
                    {
                        Cv2.Threshold(gray, dst, pos, 255, ThresholdTypes.Binary);
                        win.ShowImage(dst);
                        // win.Image = dst; // ShowImageのかわりにこう書いてもOK
                    }, null);

                    Cv2.WaitKey();
                }
            }
        }
    }
実行結果

スライダーを操作すると、二値化処理の閾値を変更できます。
f:id:minami_SC:20160821202000p:plain

画像をHSV色空間に変換して表示

$
0
0

引き続き、OpenCvSharpネタです。

CvtColor関数で、通常のRGB色空間の画像データから、HSV色空間のデータに変換できます。

このサンプルでは、読み込んだ画像をHSV色空間に変換した後、H, S, Vの各チャンネルを分割し、それぞれの成分ごとのモノクロ画像を生成して表示しています。

staticvoid Main(string[] args)
        {
            using (var src = new Mat(@"Images/1.jpg"))
            using (var hsv = new Mat())
            {
                //Cv2.CvtColor(src, hsv, ColorConversionCodes.BGR2HSV);     // こうすると、H(彩度)は0~180の範囲の値になる
                Cv2.CvtColor(src, hsv, ColorConversionCodes.BGR2HSV_FULL);  // こちらは、H(彩度)は0~255の範囲の値になる// HSV色空間の画像を、各チャンネルごとに分割
                var channels = Cv2.Split(hsv);

                // それぞれの画像をウィンドウ表示using (var srcWin = new Window("original image", src))
                using (var hsvWin = new Window("hsv image", hsv))
                using (var hueWin = new Window("hue image", channels[0]))
                using (var satWin = new Window("saturation image", channels[1]))
                using (var valWin = new Window("value image", channels[2]))
                {
                    Cv2.WaitKey();
                }
            }
        }

f:id:minami_SC:20160823001102p:plain

OpenCVで色々な画像生成

$
0
0

今回もOpenCvSharpネタ。

今度はちょっと脱線気味。
OpenCVピクセル操作や図形描画機能を使って、いろんな画像を生成してみます。

ノイズ画像の生成

ピクセルのRGB値を乱数で設定すると、このようなノイズ画像が作成できます。

staticvoid Main(string[] args)
        {
            var r = new Random();
            var img = new Mat(240, 320, MatType.CV_8UC3, new Scalar(0, 0, 0));

            var mat3 = new MatOfByte3(img);
            var indexer = mat3.GetIndexer();
            for (var y = 0; y < img.Height; y++)
            {
                for (var x = 0; x < img.Width; x++)
                {
                    var px = indexer[y, x];
                    // RGB値すべて同じ値で、乱数値を設定
                    var val = (byte)(r.Next() * 255);
                    px[0] = val;
                    px[1] = val;
                    px[2] = val;
                    indexer[y, x] = px;
                }
            }

            Cv2.ImShow("image", img);
            Cv2.WaitKey();
        }

ピクセルのRGB値を同じ値にすると、こんな風にモノクロなノイズになり、
f:id:minami_SC:20160825074421p:plain RGB各々を別々なランダム値にすると、色のついたノイズ画像になります。

                    var px = indexer[y, x];
                    // RGB値それぞれ、別々の乱数値を設定
                    px[0] = (byte)(r.Next() * 255);
                    px[1] = (byte)(r.Next() * 255);
                    px[2] = (byte)(r.Next() * 255);
                    indexer[y, x] = px;

f:id:minami_SC:20160825074517p:plain

グラデーション画像の生成

今度は、各ピクセル値をループ変数で徐々に変化させ、グラデーション画像を描画してみます。

staticvoid Main(string[] args)
        {
            var img = new Mat(240, 320, MatType.CV_8UC3, new Scalar(0, 0, 0));

            var mat3 = new MatOfByte3(img);
            var indexer = mat3.GetIndexer();
            for (var y = 0; y < img.Height; y++)
            {
                for (var x = 0; x < img.Width; x++)
                {
                    var px = indexer[y, x];
                    var r = (float)x / img.Width;
                    var b = (float)y / img.Height;
                    px[0] = (byte)(r * 255);
                    px[1] = (byte)0;
                    px[2] = (byte)(y * 255);
                    indexer[y, x] = px;
                }
            }

            Cv2.ImShow("image", img);
            Cv2.WaitKey();
        }

f:id:minami_SC:20160825074532p:plain

ラインアート

もう、ここまでくると、完全にOpenCVでやるべき内容じゃないですね・・・w

staticvoid Main(string[] args)
        {
            var img = new Mat(240, 320, MatType.CV_8UC3, new Scalar(0, 0, 0));

            var mat3 = new MatOfByte3(img);
            var indexer = mat3.GetIndexer();

            var lineNum = 20; // 描画する線の数for (var i = 0; i < lineNum; i++)
            {
                var val = (float)i / lineNum;
                var x = val * img.Width;
                var y = val * img.Height;

                Cv2.Line(img, new Point(0, y), new Point(x, img.Height), new Scalar(0, val*255, 255-(val*255)));
            }

            Cv2.ImShow("image", img);
            Cv2.WaitKey();
        }

f:id:minami_SC:20160825074547p:plain

こんな風に、OpenCVの図形描画関数を使って、ラインアートを書いたりすることもできます。

ただし、OpenCVの図形描画関数は、α値を用いた透過処理をサポートしていません。
Scalarを引数で受けていて、Scalar型はα値も含んだ値を定義することができますが、α値は無視されて単純にRGBの色で上書きされます。

なので、αブレンドを用いて、キレイなグラフィック描画をする、などには向かないのです。
こういう用途は、OpenGLDirectXなど、ちゃんとしたグラフィック描画のためのライブラリ/フレームワークを使う方がよいですね。

まぁ、こんな風に使うこともできる、、、ってことで。

OpenCVでパラメータ操作用ウィンドウを作ってみる

$
0
0

以前、OpenCVSharpで作成したウィンドウに、スライダーを付けてみました。
http://sourcechord.hatenablog.com/entry/2016/08/21/202200

このスライダーを活用し、スライダーだけが並んだウィンドウを作ることができます。
画像を表示しているウィンドウ上にスライダーで余計なスペースを取ることなく、 画像を編集するためのスライダーが並んだ、操作パネルのようなものが作成できます。

class Program
    {
        staticint _threashold = 0;
        staticint _max = 0;

        static Window _win;
        static Mat _gray;
        static Mat _dst;

        staticvoid Main(string[] args)
        {
            _gray = new Mat();
            _dst = new Mat();
            using (var src = new Mat(@"Images/1.jpg"))
            {
                Cv2.CvtColor(src, _gray, ColorConversionCodes.BGRA2GRAY);

                _win = new Window("dst image", _gray);
                using (var ctrl = new Window("control panel", null))
                {
                    ctrl.Resize(640, 80);
                    ctrl.CreateTrackbar2("Threshold", 10, 255, OnThreasholdChanged, null);
                    ctrl.CreateTrackbar2("Max", 10, 255, OnMaxChanged, null);


                    Cv2.WaitKey();
                }
            }
        }

        privatestaticvoid OnThreasholdChanged(int pos, object userdata)
        {
            _threashold = pos;
            Console.WriteLine($"Threashold: {_threashold}");

            UpdateWindow(_win, _gray, _dst, _threashold, _max);
        }

        privatestaticvoid OnMaxChanged(int pos, object userdata)
        {
            _max = pos;
            Console.WriteLine($"Max: {_max}");

            UpdateWindow(_win, _gray, _dst, _threashold, _max);
        }

        privatestaticvoid UpdateWindow(Window win, Mat src, Mat dst, int threashold, int max)
        {
            Cv2.Threshold(src, dst, threashold, max, ThresholdTypes.Binary);
            win.ShowImage(dst);
        }
    }

f:id:minami_SC:20160826073211p:plain

スライダーの実装では、コールバック関数を使って設定値を扱うんで、微妙に値のやり取りがめんどくさいですね・・・

ここでは手軽に書くために、コールバック関数側でも色々な変数にアクセスできるように、static変数で定義したりしてます。
でも、こうするとusingを使ったリソース破棄ができないのが少々残念な感じ。

問題点

ただし、この方法も少し問題があります。

なぜか、スライダーのみのウィンドウは、思った通りにウィンドウサイズを調整できません。。。
Resize関数で、ウィンドウのリサイズもできるのですが、この関数でうまくリサイズできない場合もあったり、、、

あくまでも、OpenCVでのウィンドウ表示やスライダーなどのGUI機能は、 テスト用・プロトタイプ作成用と割り切って使うのがよいかもしれません。


OpenCvSharpでマウス・キーボード入力を扱う

$
0
0

OpenCVで作成したウィンドウで、マウスやキーボードの入力を扱ってみます

キーボード入力

まずはキーボード入力から。

このように、今まで普通に使ってきたCv2.WaitKey関数ですが、この関数は戻り値に入力されたキーの情報が入ってきます。

以下のように書くと、ESCキーまたはエンターキーを入力したときだけ終了、とすることができます。

staticvoid Main(string[] args)
        {
            using (var src = new Mat(@"Images/1.jpg"))
            using (var win = new Window("image", src))
            {
                while (true)
                {
                    // キー入力を受け付け
                    var key = Cv2.WaitKey();
                    Console.WriteLine($"key: {key}");
                    if (key == (int)ConsoleKey.Escape ||
                        key == (int)ConsoleKey.Enter)
                    {
                        // esc or enterキーで終了break;
                    }
                }
            }
        }

f:id:minami_SC:20160828120406p:plain

マウス入力

続いて、マウス入力を利用してみます。
作成したウィンドウに対し、OnMouseCallbackのイベントを行動すると、マウスのボタン押すタイミング/離すタイミングや、マウス移動などのイベント時にコールバック関数が呼ばれるようになります。

コールバック関数では、マウスイベントが発生した際のマウス座標とともに、@eventflagsという変数が渡ってきます。
@eventは発生したマウスイベントの種類。flagsの方は、イベント発生時に押されていたボタンの種類に関する情報です。

さっそく、コールバック関数でどのようなイベントが取得できるか、確認してみます。

staticvoid Main(string[] args)
        {
            using (var src = new Mat(@"Images/1.jpg"))
            using (var win = new Window("image", src))
            {
                win.OnMouseCallback += Win_OnMouseCallback;
                // ↓のような関数でもマウスのコールバック設定可能//Cv2.SetMouseCallback("image", Win_OnMouseCallback);
                Cv2.WaitKey();
            }
        }

        privatestaticvoid Win_OnMouseCallback(MouseEvent @event, int x, int y, MouseEvent flags)
        {
            Console.WriteLine($"event: {@event}, (x, y)= ({x}, {y}), flags: {flags}");
        }

f:id:minami_SC:20160828120413p:plain

ちなみに、@eventの値をコンソールに表示してみると、 マウス左クリックダウン/アップ時に、FlagLButton/FlagMButtonというのが表示されました。

気になってコードを見てみたところ、以下のように「LButtonDownとFlagLButton」、「LButtonUpとFlagMButton」が同じ値として列挙体で定義されているため、FlagLButtonなどの方が表示されていたようです。

https://github.com/shimat/opencvsharp/blob/master/src/OpenCvSharp/modules/highgui/Enum/MouseEvent.cs

OpenCVで浮動小数点形式の画像バッファを使ってみる

$
0
0

今までのサンプルコードでは、CV_8UC3のよう形で各要素ごとunsigned charなデータで画像バッファを扱っていました。

OpenCVでは、Mat型のインスタンスを作成するときの引数指定で、 16bit整数型や浮動小数点型などの形式のバッファも作れるようになっています。

利用できる型

Mat型の変数を作る際に、MatTypeで画像バッファのデータ型の種類が指定ができます。

var mat = new Mat(240, 320, MatType.CV_32FC3);

インテリセンスでのコード補間で候補が表示されるので、なんとなく使えると思います。
f:id:minami_SC:20160828231359p:plain

これらのMatType型の、各要素は以下のような意味になってます。
f:id:minami_SC:20160828231410p:plain

サンプル

これだけでは、あまり意味はないですが、CV_32FC3でMatを作成して、グラデーションを書いてみました。

ウィンドウ表示の前に、特に型変換などせずともそのまま表示できるようです。

staticvoid Main(string[] args)
        {
            using (var mat = new Mat(240, 320, MatType.CV_32FC3))
            using (var win = new Window("image"))
            {
                var indexer = mat.GetGenericIndexer<Vec3f>();

                for (var y = 0; y < mat.Height; y++)
                {
                    for(var x = 0; x < mat.Width; x++)
                    {
                        var px = new Vec3f();
                        px[0] = (float)x / mat.Width;
                        px[1] = (float)y / mat.Height;
                        px[2] = 0;
                        indexer[y, x] = px;
                    }
                }

                win.ShowImage(mat);
                Cv2.WaitKey();
            }
        }

f:id:minami_SC:20160828231417p:plain

ResponsiveGrid 0.3.1をリリースしました

$
0
0

以前、WPF/UWP向けにResponsiveGridというライブラリを作りました。

このライブラリですが、GitHubのIssuesで不具合報告もらったので修正してリリースしました。
今回のアップデートはバグフィックスのみです。

変更内容

ResponsiveGridをScrollViewr内に配置した場合に、スクロールできなくなる不具合を修正しました。

MeasureOverrideメソッドで戻り値として返す値にミスがあり、ResponsiveGridのDesiredSizeが常に(0, 0)になってしまってたことが原因でした。

バージョン番号のナンバリングについて

このライブラリのバージョン番号の付け方ですが、セマンティックバージョニングに基づいて行おうと思っています。
http://semver.org/lang/ja/
今回はバグフィックスだけなので、末尾のバージョンを上げています。

Visual Studio Code 1.5の新機能・変更点

$
0
0

VSCode 1.5がリリースされました。1.5では不具合があったようで、リリース後に速攻でバグフィックス版の1.5.1もリリースされてます。
今回も新機能・変更点で、個人的に気になった点などをメモしときます。

https://code.visualstudio.com/updates/v1_5

エディタ関連

フォルダ/ファイル種ごとのアイコン表示

VSCodeのエクスプローラで、フォルダやファイル種ごとにアイコンを表示できるようになりました。

メニューの以下の項目、またはコマンドパレットでFile Icon Themeというコマンドを実行すると、アイコン表示のテーマを選ぶことができます。

f:id:minami_SC:20160911035545p:plain
f:id:minami_SC:20160911035554p:plain

こんな風に、ファイル種に応じたアイコン表示ができるようになります。
f:id:minami_SC:20160911035602p:plain

dirtyファイルの自動保存機能

settings.jsonより、以下の設定を有効にすることで、VSCodeのウィンドウがフォーカスを失ったら、ファイルを自動で保存するようになります。

// ダーティ ファイルの自動保存を制御します。有効な値: "off"、"afterDelay"、"onFocusChange" (エディターがフォーカスを失います)、"onWindowChange" (ウィンドウがフォーカスを失います)。"afterDelay" に設定すると、"files.autoSaveDelay" で遅延を構成できます。"files.autoSave": "onWindowChange"

QuickOpenの閉じる条件

以下の設定をfalseにすると、QuickOpenやコマンドパレットなどを表示したあと、QuickOpenの領域がフォーカスを失っても閉じられないようになります。

// フォーカスを失ったときにクイック オープンを自動的に閉じるかどうかを制御します。"workbench.quickOpen.closeOnFocusLost": false

この設定をした状態も、escキーを押すとQuickOpenを閉じることができます。

閉じたタブの復元機能

Ctrl+Shift+Tで、閉じたタブを再度開きなおすことができるようになりました。
一般的なブラウザなどと同じショートカットなので、違和感なく便利に使えそうな機能です。

TypeScript関係

プロジェクト読み込み時にフォルダ内を確認し、npmからインストールしたTypeScriptがあると、こんな風にVSCodeが内部で持っているTypeScriptとバージョンが異なる旨の情報が表示されるようになりました。
f:id:minami_SC:20160911035621p:plain

VSCodeのエディタでコード補間や構文解析などをする際、TypeScriptの解析を行いますが、この解析のためのtscがVSCode自身が持っているものと、プロジェクト内で利用されているもので食い違っているためこのような確認が表示されます。

また、この表示から、VSCode内部のTypeScriptを使うか、プロジェクト内に自身でインストールしたTypeScriptを使うか選べるようになっています。

プロジェクト読み込み時に毎回確認が出るのがイヤという場合は、以下を参考に、settings.jsontypescript.tsdkの設定を加えるとよいかと思います。 https://code.visualstudio.com/docs/languages/typescript#_using-newer-typescript-versions

拡張機能

細かい点ですが、地味に便利になってます。

  • 拡張機能の更新方法
    • インストール済みのすべての拡張機能を更新
      • 拡張機能の「...」ボタンから、「Update All Extensions」という項目を選ぶと、インストール済みのすべての拡張機能を更新できるようになりました。
    • 自動更新
      • settings.jsonextensions.autoUpdateという項目を設定することで、拡張機能の自動更新を行えるようになりました。
  • 拡張機能のソート表示
    • インストール数/Ratingなどの数値でソートできるようになりました

デバッガ

デバッグコンソールでのコード補間

デバッグコンソールでも、こんな風にコード補間ができるようになりました。
f:id:minami_SC:20160911035630p:plain

デバッグコンソールでの複数行入力

デバッグコンソールで、複数行の入力を受け付けるようになりました。
Shift+Enterで改行できます。
f:id:minami_SC:20160911035645p:plain

Node.jsデバッグ時のVSCode統合のターミナル利用

launch.jsonでのデバッガ起動時の設定で、"console": "integratedTerminal"という設定を加えると、デバッガ動作時の出力を、VSCodeに内蔵された統合ターミナルにすることができます。

expressとかでWebサーバーを作ってる場合は特に使わないと思いますが、コンソールの標準入力から何か受け付けるようなスクリプトとかを作ってるときには、便利にデバッグできるかと思います。

その他

monaco-editorのアップデート

monaco-editorも月例でアップデートするようになるとのことです。

現時点では、0.6.1というバージョンがリリースされています。
https://github.com/Microsoft/monaco-editor/blob/master/CHANGELOG.md

ResponsiveGrid 0.3.2をリリースしました

$
0
0

先日リリースしたResponsiveGrid 0.3.1で、以下のような不具合がありました。

  • パネル内の要素数が0個の時、例外を吐いて終了する

ということで、修正して0.3.2としてリリースしました。

この間バグ対応して0.3.1を作った時に、MeasureOverrideの中の処理を作り壊してしまってました。
修正確認が不十分でしたね・・・

ってことで、ついでに簡単な動作確認を兼ねたサンプルコード類を少し拡充させたりしてました。
コード修正したら、この辺をもう少しちゃんと確認するようにしようかと。。(汗

Viewing all 153 articles
Browse latest View live