homebrewで導入したpyenvにpythonを導入しようとした際に、
うまくいかなかったことがあったのでメモ

~ $ pyenv install 2.7.8
Downloading Python-2.7.8.tgz...
-> https://yyuu.github.io/pythons/74d70b914da4487aa1d97222b29e9554d042f825f26cb2b93abd20fdda56b557
Installing Python-2.7.8...
patching file ./Lib/site.py
ERROR: The Python zlib extension was not compiled. Missing the zlib?

Please consult to the Wiki page to fix the problem.
https://github.com/yyuu/pyenv/wiki/Common-build-problems


BUILD FAILED (OS X 10.11.1 using python-build 20150818)


こちらのページにも同様の現象が報告、解決策が提示されていました。
Can't compile on El Capitan #448

結論としては、下記のツールが入っていなかっただけでした。
~ $ xcode-select --install
xcode-select: note: install requested for command line developer tools


再度、installを実施してみたところ。
~ $ pyenv install 2.7.8
Downloading Python-2.7.8.tgz...
-> https://yyuu.github.io/pythons/74d70b914da4487aa1d97222b29e9554d042f825f26cb2b93abd20fdda56b557
Installing Python-2.7.8...
patching file ./Lib/site.py
Installing pip from https://bootstrap.pypa.io/get-pip.py...
Installed Python-2.7.8 to /Users/tki/.pyenv/versions/2.7.8
うまくいきました。
よく位相限定相関(POC)をキーワードでブログにいらっしゃる方がいるのと、
自分のためにまとめておきます。


理論
位相限定相関法についての求め方を書いてあります。

また、4ではOpenCVで実装されているものの紹介。
5では従来の手法では検出できない回転に対して検出するための前処理であるLog-Polar変換を書いております。

  1. 位相画像
  2. 位相限定相関法(POC)
  3. 位相限定相関(POC)でサブピクセル精度を求める方法
  4. 位相限定相関(POC)がOpenCVで実装されている
  5. Log-Polar変換を画像に適用



OpenCvSharp
OpenCvSharpで実装してみたものです。。。があまり自信はありません。
  1. 位相画像をC#とOpenCVSharpで実装
  2. 位相限定相関法(POC)をOpenCVSharpで



画像補間について
回転がされている場合でも検出できるようにLog-Polar変換の時に必要であったため記載したものです。
ですが、有名な補間手法なので画像の回転・拡大・縮小に使えます。

  1. 画像を回転させる際の画素を補間するコード
  2. 回転した画像をLanczos補間する
  3. 回転した画像をバイキュービック補間する
  4. 回転した画像をバイリニア補間する
  5. 画像を回転させる



何か進展があればまた追記していきます。


以前、書いた投稿でSURFで二枚の画像での対応付けを行いました。

PythonからOpenCVのSURFを使う | 詠み人知らずの備忘録



SURFで抽出した対応する座標を用いれば、画像同士を合成することができます。
以下に参考にしたサイトです。


2枚の画像のモザイキング | Miyabiarts.net
前に紹介した「OpenCVを用いた特徴点対応付け」を応用することで複数の画像をモザイキングすることができます。 今回は、OpenCVを用いて下に示す2枚の画像をモザイキングして、1枚の大きな画像を作ります。 今回の例では、2枚の画像が大体半分程度重なり合ってないと上手くいかないです。 あと、画像合成の関係上、1枚目の画像に対して2枚目の画像が左側になるように撮影しないと正しい結果が得られませんので気をつけてください。



Panorama – Image Stitching in OpenCV | ramsrigoutham
he code snippet shown below is for simple image stitching of two images in OpenCV . It can easily be modified to stitch multiple images together and create a Panorama. OpenCV also has a stitching module which helps in achieving this task and which is more robust than this. The code presented here will help in understanding the major steps involved in image stitching algorithm. I am using OpenCV 2.4.3 and Visual studio 2010. This code is based on the openCV tutorial available here.



SURFを実行しても、surf結果画像のように完璧に対応点を抽出できません。 いくつか、誤検出が発生してしまいます。


surf結果画像
surf.png


そのため、誤検出を取り除く処理が必要になります。
RANSACが有名な方法のようです。

画像を合成する際に移動および回転などをさせるために射影変換を行いますが、OpenCVのfindhomographyでは、CV_RANSACを第3引数にすることにより、対応点をRANSACでふるいにかけてくれるようです。

ソース

途中まではSURFを求めるまでは前回までと同じソースを使用しています。
その座標を用いてHomography行列を求め合成しています。

# -*- coding: shift_jis -*-
# matching features of two images
import cv2
import sys
import scipy as sp
import numpy

if len(sys.argv) < 3:
    print 'usage: %s img1 img2' % sys.argv[0]
    sys.exit(1)

img1_path = sys.argv[1]
img2_path = sys.argv[2]

img1 = cv2.imread(img1_path, cv2.CV_LOAD_IMAGE_GRAYSCALE)
img2 = cv2.imread(img2_path, cv2.CV_LOAD_IMAGE_GRAYSCALE)

detector = cv2.FeatureDetector_create("SURF")
descriptor = cv2.DescriptorExtractor_create("BRIEF")
matcher = cv2.DescriptorMatcher_create("BruteForce-Hamming")

# detect keypoints
kp1 = detector.detect(img1)
kp2 = detector.detect(img2)

print '#keypoints in image1: %d, image2: %d' % (len(kp1), len(kp2))

# descriptors
k1, d1 = descriptor.compute(img1, kp1)
k2, d2 = descriptor.compute(img2, kp2)

print '#keypoints in image1: %d, image2: %d' % (len(d1), len(d2))

# match the keypoints
matches = matcher.match(d1, d2)

# visualize the matches
print '#matches:', len(matches)
dist = [m.distance for m in matches]

print 'distance: min: %.3f' % min(dist)
print 'distance: mean: %.3f' % (sum(dist) / len(dist))
print 'distance: max: %.3f' % max(dist)

# threshold: half the mean
thres_dist = (sum(dist) / len(dist)) * 0.9

# keep only the reasonable matches
sel_matches = [m for m in matches if m.distance < thres_dist]

print '#selected matches:', len(sel_matches)

point1 = [[k1[m.queryIdx].pt[0], k1[m.queryIdx].pt[1]] for m in sel_matches]
point2 = [[k2[m.trainIdx].pt[0], k2[m.trainIdx].pt[1]] for m in sel_matches]

point1 = numpy.array(point1)
point2 = numpy.array(point2)

H, Hstatus = cv2.findHomography(point2,point1,cv2.RANSAC)

# 移動量を算出
x=0
y=0
cnt=0
for i,v in enumerate(Hstatus):
    if v==1:
        x += point1[i][0]-point2[i][0]
        y += point1[i][1]-point2[i][1]
        cnt += 1

# カラー画像として改めて読み込む
img1 = cv2.imread(img1_path)
img2 = cv2.imread(img2_path)

x = abs(int(round(x/cnt)))
y = abs(int(round(y/cnt)))

# sizeを取得
h1, w1 = img1.shape[:2]
h2, w2 = img2.shape[:2]

dst = cv2.warpPerspective(img2,H,(w2+x,h2+y))

for i in xrange(w1):
    for j in xrange(h1):
        dst[j,i] = img1[j,i]

cv2.imshow("result", dst)
cv2.waitKey()



結果

入力画像
wall1.jpg


wall2.jpg


2枚目画像のHomography行列と演算結果
homography1.png


結果画像
homography2.png


2枚目画像のHomography行列と演算結果を見て分かるかもしれませんが、気づいたことを何点か・・・

このプログラムでは、1枚目の画像に合わせるように2枚目の画像を射影変換して合わせているため、 画像の左右の対応関係が逆だったりすると合成がうまくいかなかったり。
1枚目の画像より上部にある2枚目の画像が反映されていなかったりとあります。
#それは、理論というよりもプログラム上の問題かもしれませんが

ただ、複数枚つなげていくと誤差が積み重なっていきそうではあります。



以前、IronPythonでimportができない例を書きました。

C#でIronPythonと連携する際にnumpyがimportできない | 詠み人知らずの備忘録



上記の対応を行うことで、DLLがロードできるため
numpyやwaveなどをimportできるようにはなったのですが、Scipyだけは下記のようにエラーが出てだめでした。

'module' object has no attribute '_getframe'

Scipy_error.png

どうやらコンソールからIronPythonを起動する際にScipyを使用するに、 -X:Frames と引数を渡していることに関係あるみたいです。

結果としては、Pythonのエンジンを起動する際に下記のようにオプションを設定して起動するように行えばいいようです。

var options = new Dictionary();
options["Frames"] = true;
options["FullFrames"] = true;
ScriptEngine engine = Python.CreateEngine(options);

※1行目と5行目がなぜかおかしくなっています。
 ただしくは、
 var options = new Dictionary<string, object>();
 です。



また、Python側でも以下のpathを追加していないとno moduleのエラーがでます。
特に、Scipyでは4行目の定義も必要のようです。
sys.path.append(r'C:\Program Files\IronPython 2.7')
sys.path.append(r'C:\Program Files\IronPython 2.7\DLLs')
sys.path.append(r'C:\Program Files\IronPython 2.7\Lib')
sys.path.append(r'C:\Program Files\IronPython 2.7\Lib\site-packages')



C#にはどうやら音声ファイルを簡単に読み込む手段がないようで、
じゃあPythonに任せればいいのでは?


。。。ということで今回は、C#とIronPythonで音声ファイルのデータを読み込みます。


Pythonの音声ファイルの取得はこちらを参考にしました。
漫ろ草 SozoroGusa: pythonでwaveファイル(2)



ソース

C#側
using System;
using System.Collections.Generic;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using IronPython.Hosting;           // for IronPython
using Microsoft.Scripting.Hosting;  // for IronPython

namespace LoadWave
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void 開くOToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //「ファイルの種類」を設定
            openFileDialog1.Filter = "音声ファイル(WAV)|*.wav;|すべてのファイル(*.*)|*.*";
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                // Scipyを起動するためのオプション設定
                var options = new Dictionary();
                options["Frames"] = true;
                options["FullFrames"] = true;

                ScriptEngine engine = Python.CreateEngine(options);

                ScriptSource script = engine.CreateScriptSourceFromFile("sample.py");
                ScriptScope scope = engine.CreateScope();
                
                // 選択したwavファイルをPythonに渡す値として設定
                scope.SetVariable("filename", openFileDialog1.FileName);

                // IronPythonを実行
                script.Execute(scope);

                // 処理した音声データを取得
                var audio = scope.GetVariable("audio");
            }
        }
    }
}



C#のopenFileDialogで、選択した音声ファイルをIronPythonに渡してfilenameという変数で使用しています。
// 選択したwavファイルをPythonに渡す値として設定
scope.SetVariable("filename", openFileDialog1.FileName);



IronPythonで取得した音声データ(audio)をC#側に返しています。
// 処理した音声データを取得
var audio = scope.GetVariable("audio");



IronPython側
#-*- coding: utf-8 -*-
import sys
sys.path.append(r'C:\Program Files\IronPython 2.7')
sys.path.append(r'C:\Program Files\IronPython 2.7\DLLs')
sys.path.append(r'C:\Program Files\IronPython 2.7\Lib')
sys.path.append(r'C:\Program Files\IronPython 2.7\Lib\site-packages')

import clr
clr.AddReference('mtrand.dll')

import wave
import struct

wf = wave.open(filename, "rb")

#オーディオチャンネル数(モノラルなら1、ステレオなら2)
nchannels=wf.getnchannels()
#サンプルサイズ(バイト)
sampwidth=wf.getsampwidth()
#サンプリングレート
framerate=wf.getframerate()
#オーディオフレーム数
nframes=wf.getnframes()
#オーディオフレーム(リストオブジェクト)
frames=wf.readframes(nframes)
wf.close()

audio = struct.unpack("%dh" %nframes*nchannels, frames)



C#で配列を受け取る際にどのようにすればいいのか、特に記載はなかったのですが。
上記のようで問題ないようです。



ちなみに、正弦波の音声データを読み込んで、取得したデータを表示したものが下記のグラフです。

sin.png


FC2カウンター
プロフィール

詠み人知らず

Author:詠み人知らず
プログラム好きな名もなき凡人がお送りしています。(得意とは言っていない
最近の興味はPython、C#、Matlab(Octave)、画像処理、AR(拡張現実)、統計などなど・・・

気分で思いついたことを書くため話題に一貫性がないかもしれません。

カレンダー
07 | 2017/08 | 09
- - 1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31 - -
最新記事
タグクラウドとサーチ

カテゴリ
最新コメント
最新トラックバック
月別アーカイブ