旅行好きなソフトエンジニアの備忘録

プログラミングや技術関連のメモを始めました

【OpenCV】 穴を塗りつぶす

learnopencv.comのブログ(Filling holes in an image using OpenCV ( Python / C++ ) | Learn OpenCV)のメモになります。タイトルにあるように、OpenCVを使って穴を塗りつぶす方法についてブログに書かれており、MATLABにはimfillという関数があるけど、OpenCVには無いからどうする?という問いかけがされています。

f:id:ni4muraano:20170329234450j:plain:w150 ⇒ f:id:ni4muraano:20170329234507j:plain:w150

// Step1:画像の読み込み
Mat image = imread("nickel.jpg", IMREAD_GRAYSCALE);

// Step2:二値化処理を行う(二値化処理が上手くいかなかったため、ソース元と少し閾値を変更した)
Mat binary_image;
threshold(image, binary_image, 200, 255, THRESH_BINARY_INV);

// Step3:コインの外側の色を反転させる
Mat floodfilled_image = binary_image.clone();
floodFill(floodfilled_image, cv::Point(0, 0), Scalar(255));

// Step4:全体を反転させる
Mat inverted_floodfilled_image;
bitwise_not(floodfilled_image, inverted_floodfilled_image);

// Step5:コインの中を塗りつぶす
Mat foreground = (binary_image | inverted_floodfilled_image);

floodFillというメソッドがOpenCVにはあることも勉強になったので、覚えておきたいと思います。最後にソースコード中のステップ1からステップ5までの画像を並べます。

f:id:ni4muraano:20170329234450j:plain:w100 ⇒ f:id:ni4muraano:20170329235330j:plain:w100 ⇒ f:id:ni4muraano:20170329235340j:plain:w100 ⇒ f:id:ni4muraano:20170329235351j:plain:w100 ⇒ f:id:ni4muraano:20170329234507j:plain:w100

【Python】 KerasでResNet等のショートカット構造を実装する

Kerasでは学習済みのResNetが利用できるため、ResNetを自分で作ることは無いと思います。ただ、ResNet以外にも下の写真のようなショートカット構造を持つネットワークがあり、これらを実装したい時にどのように作成するかをメモします。
f:id:ni4muraano:20170325221400p:plain

単純なネットワークの場合、KerasではSequentialを生成して、レイヤーをaddしていくのが通常ですが(Sequentialモデルのガイド - Keras Documentation)、少し複雑なネットワークを作成する場合はFunctional APIを利用します(Functional APIのガイド - Keras Documentation)。
Functional APIはSequentialを利用するプログラミングと比較した場合は多少直観性に劣りますが、別段難しいものではありません。例えば下図のようにInput⇒Convolutionというシーケンスは以下のように書くことができます。

from keras.layers import Input, Convolution2D

# 入力の形状を指定する(CIFAR-10のような32×32×3の画像を想定)
in_ = Input((32, 32, 3))
# Input⇒Convolution2D
in_conv = Convolution2D(10, 3, 3, border_mode='same')(in_)

f:id:ni4muraano:20170325223257p:plain

Input⇒Convolutionに更にConvolutionを接続するのも一行追加するだけです。

from keras.layers import Input, Convolution2D

# 入力の形状を指定する(CIFAR-10のような32×32×3の画像を想定)
in_ = Input((32, 32, 3))
# Input⇒Convolution2D
in_conv = Convolution2D(10, 3, 3, border_mode='same')(in_)
# Input⇒Convolution2D⇒Convolution2D
in_conv_conv = Convolution2D(10, 3, 3, border_mode='same')(in_conv)

f:id:ni4muraano:20170325224113p:plain

Input⇒Convolution2Dをショートカットさせます。これはInput⇒Convolution2DとInput⇒Convolution2D⇒Convolution2Dをマージさせることで実現できます。keras.layersにはMergeとmergeがあるのですが、mergeを利用します。間違えてMergeをimportしないよう注意して下さい。

from keras.layers import Input, Convolution2D, merge

# 入力の形状を知らせる(ここではCIFAR-10のような32×32×3としている)
in_ = Input((32, 32, 3))
# Input⇒Convolution2D
in_conv = Convolution2D(10, 3, 3, border_mode='same')(in_)
# Input⇒Convolution2D⇒Convolution2D
in_conv_conv = Convolution2D(10, 3, 3, border_mode='same')(in_conv)
# Input⇒Convolution2DとInput⇒Convolution2D⇒Convolution2Dをマージする
merged = merge([in_conv_conv, in_conv], mode='sum')

f:id:ni4muraano:20170325224731p:plain

以上でショートカット構造を実現できました。最後に、最初に示した図の構造を実現するためのコードを下記にまとめます。

from keras.layers import Input, Convolution2D, merge
from keras.models import Model
from keras.utils.visualize_util import plot

# 入力の形状を知らせる(ここではCIFAR-10のような32×32×3としている)
in_ = Input((32, 32, 3))
# Input⇒Convolution2D
in_conv = Convolution2D(10, 3, 3, border_mode='same')(in_)
# Input⇒Convolution2D⇒Convolution2D
in_conv_conv = Convolution2D(10, 3, 3, border_mode='same')(in_conv)
# Input⇒Convolution2DとInput⇒Convolution2D⇒Convolution2Dをマージする
merged = merge([in_conv_conv, in_conv], mode='sum')
# 更にConvolution2Dを接続する
merged_conv = Convolution2D(10, 3, 3, border_mode='same')(merged)
# input, outputを指定してモデルを作成する
model = Model(input=in_, output=merged_conv)
# モデルを図示する
plot(model, 'shortcut_structure_example.png')

【WPF】 画像の差分を計算してWPFのImageに表示したい

タイトルの通り画像の差分を計算してWPFのImageに表示する必要があったためメモします。画像の差分を取るためにはOpenCvC#用ラッパーであるOpenCvSharpを利用すればすぐに済むため、結局OpenCvSharpのMatクラスをWPFのImage.Sourceにどう入れるか、という話になります。

手順
  1. NuGetを利用してOpenCvSharpを導入する
  2. “参照の追加"からSystem.Drawingを追加する
  3. usingに"using OpenCvSharp;“ "using OpenCvSharp.Extensions;"を追加する
  4. 下記コードを記述する
// 画像1を読み込む
using (Mat image1 = Cv2.ImRead("lenna1.jpg"))
// 画像2を読み込む
using (Mat image2 = Cv2.ImRead("lenna2.jpg"))
// 差分画像を保存する領域を確保する
using (Mat diff = new Mat(new OpenCvSharp.Size(image1.Cols, image1.Rows), MatType.CV_8UC3))
{
    // 画像1と画像2の差分をとる
    Cv2.Absdiff(image1, image2, diff);
    // BitmapSourceConverterを利用するとMatをBitmapSourceに変換できる
    BitmapSource bitmap = BitmapSourceConverter.ToBitmapSource(diff);
    // Sourceに画像を割り当てる
    ImageToShowDiffImage.Source = bitmap;
}

【Python】 二次元データを一次元データに変換する

import numpy as np

# one_dimの変更はtwo_dimに影響を与えない
two_dim = np.array([[1, 2], [3, 4]])
one_dim = two_dim.flatten()


import numpy as np

# one_dimの変更はtwo_dimに影響を与える
two_dim = np.array([[1, 2], [3, 4]])
one_dim = two_dim.ravel()

【Docker】 コンテナ管理用サブコマンド

コンテナにホストのディレクトリをマウントする

$ docker run -it -v ホストのディレクトリ:コンテナのディレクトリ イメージ名
  • -vがマウントするためのオプション
  • 使用例:$ docker run -it -v /root/data:/tmp/data ubuntu:14.04

コンテナとクライアント環境の間でファイルをコピーする

$ docker cp コンテナ:パス クライアント環境のパス
  • コンテナ:パス⇒クライアント環境のパスへファイルをコピーする
  • 使用例:$ docker cp happy_austin:/etc /tmp

Docker入門

Docker入門

【Docker】 ローカル環境でのイメージ管理サブコマンド

書籍「Docker入門」のChapter3-03とChapter3-04で紹介されているサブコマンドのメモです。

既存イメージを別名でコピーする

$ docker tag 既存イメージ名 変更後イメージ名


イメージやコンテナの詳細情報を表示する

$ docker inspect コンテナ名またはイメージ名


イメージの作成履歴を表示する

$ docker history イメージ名


イメージをtar.gz形式で保存する

$ docker save イメージ名 | gzip > ファイル名.tar.gz


tar.gz形式で保存したイメージを復元する

$ docker load -i ファイル名.tar.gz


Docker入門

Docker入門