Edited at

OpenCvを少し動かしてみる。mac or linux


opencvって

画像処理の定番ライブラリです。

画像処理って面白い。AR VRやりたい。

AR機能とかは確か拡張機能なんでインストール方法が別です。

一からビルドしないといけないです。しかも拡張機能ごとになんか設定違ったりめんどい。

よって今回省きます。

スクリーンショット 2017-03-24 9.18.48.png

こちらのunityのサンプルは有料アセット。opencvのhog+カスケードで目などの部位を推定しているので精度が悪い。

スクリーンショット 2017-03-24 9.18.54.png

スクリーンショット 2017-03-24 9.19.03.png

スクリーンショット 2017-03-24 9.19.11.png

opencv動画たち

http://miyamotok0105.hatenablog.com/entry/2017/03/12/182056


opencvの動作環境

mac

linux

win(今回省きます。)


opencvの言語環境

もっといろんな言語で動いてると思いますが下記に絞ります。

c言語でも書けますが、自分の場合g++コンパイラでないと通りませんでした。

ただc言語で書いてるソースを使うこと自体は可能です。

C

http://opencv.jp/opencv-2svn/c/

http://opencv.jp/opencv-2svn_org/c/

C++

http://opencv.jp/opencv-2svn/cpp/

http://opencv.jp/opencv-2svn_org/cpp/

python

http://opencv.jp/opencv-2svn/py/

http://opencv.jp/opencv-2svn_org/py/


opencv2とopencv3で

http://tatsyblog.sakura.ne.jp/wordpress/programming/cpp/662/

この辺が変わってるようです。

cv::imread

cv::cvtColor

cv::TermCriteria

cv::VideoCapture::get

cv::PCA


Pythonの開発環境


Pythonインストール(mac,linux)

すごいハマルことが多かったので最短をメモ。pythonしてる人の場合はcondaで入れるのが最短です。

condaについてはここには書いていません。一からビルドする場合はちょっと時間のある時にやった方がいいです。


condaの場合

conda install -c menpo opencv=2.4.11

or
conda install -c menpo opencv3=3.1.0


ビルドの場合

結構時間がかかります。

git clone https://github.com/Itseez/opencv.git

cd opencv
mkdir build
cd build
cmake ..
make -j4 or make -j8
sudo make install

azureでエラッた時にオプション弄りまくった。

cmake -D WITH_OPENMP=ON -D CMAKE_BUILD_TYPE=RELEASE -D BUILD_opencv_python2=Off  -D BUILD_opencv_python3=On -D PYTHON2_EXECUTABLE="" -D PYTHON2_INCLUDE_DIR="" -D PYTHON2_LIBRARY="" -D PYTHON2_PACKAGES_PATH="" -D OPENCV_FORCE_PYTHON_LIBS=On -D PYTHON3_PACKAGES_PATH=$PYTHON3_PACKAGES_PATH -D CMAKE_INSTALL_PREFIX=$LOCAL_PREFIX -D WITH_CUDA=Off -D BUILD_opencv_photo=OFF -D BUILD_opencv_shape=OFF -D BUILD_opencv_video=OFF -D ENABLE_NEON=OFF -D WITH_DC1394=ON -D WITH_FFMPEG=OFF ..


Pythonアンインストール

うまくいかなかった時は何度か入れて消してをすることがあります。何個かバージョンが重なってる場合とか一回全部消した方がいい場合がありました。バージョンが古くなってしまってる場合もあるので気をつけてください。


condaの場合

何個も入っちゃってた場合は全部消す

conda uninstall -c menpo opencv=2.4.11
conda uninstall opencv
conda uninstall opencv3
全部消えたかを確認
conda list | grep opencv


ビルドの場合

sudo make uninstall


Pythonで動かしてみる


試してる動作環境

pyenv

anaconda
python2.7
mac


カメラキャプション

カメラ付きのパソコンの場合はいきなり自分の顔が登場します。

numpyがない場合は入れてください。

pip install numpy


sample.py

# -*- coding: utf-8 -*-

import numpy as np
import cv2

cap = cv2.VideoCapture(0)

while(True):
# Capture frame-by-frame
ret, frame = cap.read()

# Our operations on the frame come here
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

# Display the resulting frame
cv2.imshow('frame',gray)
if cv2.waitKey(1) & 0xFF == ord('q'):
break

# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()



Haar-Like特徴

画像の一部を切り出し、局所的な明暗差を算出。

特徴を元にカテゴリを分類する。

541197b2-2c06-102f-a275-704a8c12136c.png

アルゴリズムイメージの動画。見ればなんとなくわかる。

https://vimeo.com/12774628

xmlをgitから取得して指定してください。

https://github.com/opencv/opencv/blob/master/data/haarcascades

ファイル名
内容

haarcascade_eye.xml

haarcascade_eye_tree_eyeglasses.xml
眼鏡

haarcascade_frontalcatface.xml
猫の顔(正面)

haarcascade_frontalcatface_extended.xml
猫の顔(正面)

haarcascade_frontalface_alt.xml
顔(正面)

haarcascade_frontalface_alt2.xml
顔(正面)

haarcascade_frontalface_alt_tree.xml
顔(正面)

haarcascade_frontalface_default.xml
顔(正面)

haarcascade_fullbody.xml
全身

haarcascade_lefteye_2splits.xml
左目

haarcascade_licence_plate_rus_16stages.xml
ロシアのナンバープレート(全体)

haarcascade_lowerbody.xml
下半身

haarcascade_profileface.xml
顔(証明写真)

haarcascade_righteye_2splits.xml
右目

haarcascade_russian_plate_number.xml
ロシアのナンバープレート(数字)

haarcascade_smile.xml
笑顔

haarcascade_upperbody.xml
上半身


sample.py

#python2

import cv2
import sys

cascPath = sys.argv[1]
faceCascade = cv2.CascadeClassifier(cascPath)

video_capture = cv2.VideoCapture(0)

while True:
# Capture frame-by-frame
ret, frame = video_capture.read()

gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.1,
minNeighbors=5,
minSize=(30, 30),
flags=cv2.CASCADE_SCALE_IMAGE
)

# Draw a rectangle around the faces
for (x, y, w, h) in faces:
cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)

# Display the resulting frame
cv2.imshow('Video', frame)

if cv2.waitKey(1) & 0xFF == ord('q'):
break

# When everything is done, release the capture
video_capture.release()
cv2.destroyAllWindows()



テンプレートマッチング

2つの画像を比べて、似た画像がないか調べる。

ほぼ完全一致が求められるが、ある程度の精度は出る。

動かない場合は↓を参照。

http://answers.opencv.org/question/187096/why-opencv-matchtemplate-api-not-detect-all-occurrence-of-image/

このほかには特徴量抽出して場所を特定する方法がある。

また深層学習と組み合わせたマッチングも研究分野としては興味深い。

https://arxiv.org/pdf/1705.08593.pdf

https://ricardodeazambuja.com/deep_learning/2017/03/05/easy-peasy_conv_deep_learning_two/ https://github.com/sunsided/convolution-template-matching https://www.jstage.jst.go.jp/article/transinf/E100.D/1/E100.D_2016EDP7233/_pdf

http://cs231n.stanford.edu/reports/2017/pdfs/817.pdf


LBP特徴

ヒストグラムにより特徴を算出。

https://pebbie.wordpress.com/2011/11/10/local-binary-pattern-in-opencv-python/

jalan2.jpg

jalan2_lbp.jpg


sample.py

import cv

def calc_lbp(im):
"""
calculate LBP (Local Binary Pattern) image N8 neighborhood
"""

sz = cv.GetSize(im)
gr = cv.CreateImage(sz, 8, 1)
lbp = cv.CreateImage(sz, 8, 1)

#convert to grayscale
cv.CvtColor(im, gr, cv.CV_BGR2GRAY)

LBPMASK = [(0,-1),(1,-1),(1,0),(1,1),(0,1),(-1,-1),(-1,0),(-1,1)]

for y in xrange(1, sz[1]-2):
for x in xrange(1, sz[0]-2):
n = 0
gv = gr[y,x]
for i in xrange(len(LBPMASK)):
m = LBPMASK[i]
if gr[y+m[1], x+m[0]]>gv:
n += 1 << i
lbp[y,x] = n

return lbp

if __name__ == '__main__':
im = cv.LoadImage('jalan2.jpg')

lbpim = calc_lbp(im)
cv.ShowImage('lbp', lbpim)

key = cv.WaitKey(0)



HOG特徴

輝度の勾配方向の分布により特徴算出。

14284822109749698.png

14284829323973886.png


sample.py

 import cv2

converter = cv2.HOGDescriptor()
img = cv2.imread('test.png')
hog = hog.compute(img)


カスケード分類器を作る


opencv_createsamples

正解画像を1つのベクトルファイルにする。正解画像は7000枚以上、不正解画像は3000枚以上あると良いと書かれてるが場合によると思われる。

http://kivantium.hateblo.jp/entry/2015/05/13/153122

https://www.pro-s.co.jp/engineerblog/opencv/post_6397.html

opencv_createsamples -info train.dat -vec train.vec -num 1000


opencv_traincascade

Haar-Like特徴・LBP特徴・HOG特徴のいずれかで機械学習。

xmlファイルの吐き出し。あとはxmlを読み込んで使えばOK。

opencv_traincascade -data cascade/ -vec train.vec -bg bg.dat -numPos 900 -numNeg 1000 -featureType LBP -mode ALL


動画を再生する

動画は好きな動画を探してきて、ffmpegで形式をmp4に変換してフレームを下げた。

http://qiita.com/miyamotok0105/items/6de05e5a13e7ffd456fc


sample.py

# -*- coding: utf-8 -*-

import numpy as np
import cv2

cap = cv2.VideoCapture('sample.mp4')
fps = 15
size = (640,480)
cap.set(3, size[0]) # Width
cap.set(4, size[1]) # Heigh
cap.set(5, fps) # FPS

while(cap.isOpened()):
ret, frame = cap.read()

# gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break

cap.release()
cv2.destroyAllWindows()



VideoWriterを使った例

「ストリームに最新の画像フレームが一枚ずつ新たに読み込まれる」というのがOpenCVの動画読み込みの仕様。

# -*- coding: utf-8 -*-

#!/usr/bin/python
import cv2
import time

class Camera():
# Constructor...
def __init__(self):

self.cap = cv2.VideoCapture(0) # Prepare the camera...

print("Camera warming up ...")
time.sleep(1)
# if self.cap.isOpened():
# print(self.cap.get(3))
# print(self.cap.get(4))

w = int(self.cap.get(3)) # Frame width...
h = int(self.cap.get(4)) # Frame hight...
fps = 20.0 # Frames per second...
resolution = (w, h) # Frame size/resolution...

# Prepare Capture
self.ret, self.frame = self.cap.read()

# Prepare output window...
self.winName = "Motion Indicator"
cv2.namedWindow(self.winName, cv2.WINDOW_AUTOSIZE)

# Read three images first...
self.prev_frame = cv2.cvtColor(self.cap.read()[1],cv2.COLOR_RGB2GRAY)
self.current_frame = cv2.cvtColor(self.cap.read()[1],cv2.COLOR_RGB2GRAY)
self.next_frame = cv2.cvtColor(self.cap.read()[1],cv2.COLOR_RGB2GRAY)

# Define the codec and create VideoWriter object
self.fourcc = cv2.VideoWriter_fourcc(*'H264') # You also can use (*'XVID')
self.out = cv2.VideoWriter('output.avi',self.fourcc, fps, (w, h), True)

# Frame generation for Browser streaming wiht Flask...
def get_frame(self):
self.frames = open("stream.jpg", 'w+')
s, img = self.cap.read()
if s: # frame captures without errors...
cv2.imwrite("stream.jpg", img) # Save image...
return self.frames.read()

def diffImg(self, tprev, tc, tnex):
# Generate the 'difference' from the 3 captured images...
Im1 = cv2.absdiff(tnex, tc)
Im2 = cv2.absdiff(tc, tprev)
return cv2.bitwise_and(Im1, Im2)

def captureVideo(self):
# Read in a new frame...
self.ret, self.frame = self.cap.read()
# Image manipulations come here...
# This line displays the image resulting from calculating the difference between
# consecutive images...
diffe = self.diffImg(self.prev_frame, self.current_frame, self.next_frame)
cv2.imshow(self.winName,diffe)

# Put images in the right order...
self.prev_frame = self.current_frame
self.current_frame = self.next_frame
self.next_frame = cv2.cvtColor(self.frame, cv2.COLOR_RGB2GRAY)
return()

def saveVideo(self):
# Write the frame...
self.out.write(self.frame)
return()

def __del__(self):
self.cap.release()
cv2.destroyAllWindows()
self.out.release()
print("Camera disabled and all output windows closed...")
return()

def main():
# Create a camera instance...
cam1 = Camera()

while(True):
# Display the resulting frames...
cam1.captureVideo() # Live stream of video on screen...
cam1.saveVideo() # Save video to file 'output.avi'...
if cv2.waitKey(1) & 0xFF == ord('q'):
break
return()

if __name__=='__main__':
main()


ブラウザで確認する

主にラズパイなど端末内でopencvプラスhttpサーバーを実行する場合などに下記を使用して状況を確認するサーバーを作れる。screenコマンドやtmuxコマンドを使ってバックグラウンドで動かすのが最短だが、nginxやapache上に配置してもよし。個人的にはapacheのが初心者向け。


BaseHTTPServerとSocketServerを使った例

#!/usr/bin/python

'''
Author:
A Simple mjpg stream http server
use python2

python simple_mjeg_streamer_...py

then see down
http://127.0.0.1:8080/cam.mjpg
'''
import cv2
from PIL import Image
import threading
from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer
from SocketServer import ThreadingMixIn
import StringIO

import time
capture=None

class CamHandler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path.endswith('.mjpg'):
self.send_response(200)
self.send_header('Content-type','multipart/x-mixed-replace; boundary=--jpgboundary')
self.end_headers()
while True:
try:
rc,img = capture.read()
if not rc:
continue
imgRGB=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
jpg = Image.fromarray(imgRGB)
tmpFile = StringIO.StringIO()
jpg.save(tmpFile,'JPEG')
self.wfile.write("--jpgboundary")
self.send_header('Content-type','image/jpeg')
self.send_header('Content-length',str(tmpFile.len))
self.end_headers()
jpg.save(self.wfile,'JPEG')
time.sleep(0.05)
except KeyboardInterrupt:
break
return
if self.path.endswith('.html'):
self.send_response(200)
self.send_header('Content-type','text/html')
self.end_headers()
self.wfile.write('<html><head></head><body>')
self.wfile.write('<img src="http://127.0.0.1:8080/cam.mjpg"/>')
self.wfile.write('</body></html>')
return

class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
"""Handle requests in a separate thread."""

def main():
global capture
capture = cv2.VideoCapture(0)
# capture.set(cv2.cv.CV_CAP_PROP_FRAME_WIDTH, 320);
# capture.set(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT, 240);
# capture.set(cv2.cv.CV_CAP_PROP_SATURATION,0.2);
global img
try:
server = ThreadedHTTPServer(('localhost', 8080), CamHandler)
print("server started")
server.serve_forever()
except KeyboardInterrupt:
capture.release()
server.socket.close()

if __name__ == '__main__':
main()


flaskを使った例

templatesフォルダ以下にindex.htmlを格納。

よくあるflaskの構造にしてください。


index.html

<html>

<head>
<title>Video Streaming Demonstration</title>
</head>
<body>
<h1>Video Streaming Demonstration</h1>
<img src="{{ url_for('video_feed') }}">
</body>
</html>


# -*- coding: utf-8 -*-


#python2

from flask import Flask, render_template, Response
#from camera import VideoCamera
from time import time
from PIL import Image
import cv2
import numpy as np

class Camera(object):
def __init__(self, cap):
rc,img = cap.read()

def get_frame(self):
self.frames = open("stream.jpg", 'w+')
s, img = cap.read()
if s: # frame captures without errors...
cv2.imwrite("stream.jpg", img) # Save image...
return self.frames.read()

cap=cv2.VideoCapture(0)
imagen = cap.read()
app = Flask(__name__)

@app.route('/')
def index():
return render_template('index.html')

def gen(camera):
while True:
frame = camera.get_frame()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')

@app.route('/video_feed')
def video_feed():
return Response(gen(Camera(cap)),
mimetype='multipart/x-mixed-replace; boundary=frame')

if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080, debug=True, threaded=False)


ブラウザからブラウザに転送する

p2pを簡単に使えるライブラリ。サーバーいらずでクライアント同士で通信できる。

詳しくいうと繋げる場合と繋げない場合があるようですが、今回はあまり深入りしません。

サンプルがいっぱいあるので面白い。


WebRTC

https://webrtc.github.io/samples/

https://tech-sketch.jp/2014/07/webrtcpeerjs1.html


C++の環境設定


C++インストール(mac)

brew tap homebrew/science/

brew update
brew install opencv3 --with-contrib --with-python
brew install pkg-config

以下にインストールされてる

/usr/local/Celler/opencv3

cd /usr/local/Cellar/opencv3/3.1.0_4/lib/pkgconfig

sudo cp opencv.pc /usr/local/lib/pkgconfig/opencv.pc

opencv.pcをpkgconfig以下にコピーする。


画像を表示する

#include <stdio.h>

#include <opencv2/opencv.hpp>
//g++ `pkg-config --cflags opencv` `pkg-config --libs opencv` 001.cpp -o 001
using namespace cv;

int main(int argc, char** argv ) {
Mat image;
image = imread("../../img/hari.jpeg", 1 );
if ( !image.data ) {
printf("No image data \n");
return -1;
}
namedWindow("Display Image", WINDOW_AUTOSIZE );
imshow("Display Image", image);
waitKey(0);
return 0;
}

g++ `pkg-config --cflags opencv` `pkg-config --libs opencv` 001.cpp -o 001



OpenCV 2.2 チートシート (C++)

どんな機能があるのかとかサラッと流す用です。

7vyls.png


OpenCV の重要なクラス


  • Point 2 次元点クラステンプレート

  • Point3 3 次元点クラステンプレート

  • Size サイズ (幅,高さ) クラステンプレート

  • Vec ショートベクトルクラステンプレート

  • Matx 小型行列クラステンプレート

  • Scalar 4-要素ベクトル

  • Rect 矩形

  • Range 整数値で表現される範囲

  • Mat 2 次元 または 多次元の密な配(行列,画像,ヒストグラム,特徴ディスクリプタ,ボクセルボリュームなどを格納できます)

  • SparseMat 多次元の疎な配列

  • Ptr スマートポインタのクラステンプレート


行列の基礎


行列の作成

Mat image(240, 320, CV 8UC3);


宣言済み行列の(再)配置

image.create(480, 640, CV 8UC3);


行列を定数で初期化

Mat A33(3, 3, CV 32F, Scalar(5));

Mat B33(3, 3, CV 32F); B33 = Scalar(5);
Mat C33 = Mat::ones(3, 3, CV 32F)*5.;
Mat D33 = Mat::zeros(3, 3, CV 32F) + 5.;


行列を特定の値で初期化

double a = CV PI/3;

Mat A22 = (Mat <float>(2, 2) <<
cos(a), -sin(a), sin(a), cos(a));
float B22data[] = {cos(a), -sin(a), sin(a), cos(a)};
Mat B22 = Mat(2, 2, CV 32F, B22data).clone();


行列を乱数で初期化

randu(image, Scalar(0), Scalar(256)); // 一様分布

randn(image, Scalar(128), Scalar(10)); // 正規分布


行列と他の構造体を互いに変換

(データコピーなし)

Mat image alias = image;

float* Idata=new float[480*640*3];
Mat I(480, 640, CV 32FC3, Idata);
vector<Point> iptvec(10);
Mat iP(iptvec); // iP – 10x1 CV 32SC2 matrix
IplImage* oldC0 = cvCreateImage(cvSize(320,240),16,1);
Mat newC = cvarrToMat(oldC0);
IplImage oldC1 = newC; CvMat oldC2 = newC;


... (データコピーあり)

Mat newC2 = cvarrToMat(oldC0).clone();

vector<Point2f> ptvec = Mat <Point2f>(iP);


行列の要素にアクセス

A33.at<float>(i,j) = A33.at<float>(j,i)+1;

Mat dyImage(image.size(), image.type());
for(int y = 1; y < image.rows-1; y++) {
Vec3b* prevRow = image.ptr<Vec3b>(y-1);
Vec3b* nextRow = image.ptr<Vec3b>(y+1);
for(int x = 0; y < image.cols; x++)
for(int c = 0; c < 3; c++)
dyImage.at<Vec3b>(y,x)[c] = saturate cast<uchar>(nextRow[x][c] - prevRow[x][c]);
}
Mat <Vec3b>::iterator it = image.begin<Vec3b>(),
itEnd = image.end<Vec3b>();
for(; it != itEnd; ++it)
(*it)[1] ^= 255;


行列操作: コピー,シャッフル,部分行列


  • src.copyTo(dst) 別の行列へのコピー

  • src.convertTo(dst,type,scale,shift) スケーリングと別のデータ型への変換

  • m.clone() 行列の深いコピー

  • m.reshape(nch,nrows) データをコピーせずに,行列の次元,チャンネル数を変更

  • m.row(i), m.col(i) 行列の行と列

  • m.rowRange(Range(i1,i2))
    m.colRange(Range(j1,j2)) 行列の行と列(範囲指定)

  • m.diag(i) 行列の対角要素

  • m(Range(i1,i2),Range(j1,j2)),m(roi) 部分行列

  • m.repeat(ny,nx) 小さい行列から大きな行列を作成

  • flip(src,dst,dir) 行列の行(または列)の順序を反転

  • split(...) マルチチャンネル行列を各チャンネル毎に分離

  • merge(...) 各チャンネル毎の行列からマルチチャンネル行列を作成

  • mixChannels(...) split() と merge() の一般型

  • randShuffle(...) 行列の要素をランダムにシャッフル

例1. 画像 ROI を平滑化します

Mat imgroi = image(Rect(10, 20, 100, 100));

GaussianBlur(imgroi, imgroi, Size(5, 5), 1.2, 1.2);

例 2. 線形代数アルゴリズム

m.row(i) += m.row(j)*alpha;

例 3. 画像 ROI を別の画像に,変換しながらコピーします

Rect r(1, 1, 10, 20);

Mat dstroi = dst(Rect(0,10,r.width,r.height));
src(r).convertTo(dstroi, dstroi.type(), 1, 0);


シンプルな行列操作

OpenCV には多くの一般的な,行列の算術演算,論理演算,その他の処理

が実装されています.例えば,

• add(), subtract(), multiply(), divide(), absdiff(),

bitwise and(), bitwise or(), bitwise xor(), max(), min(),

compare()

– 和や差,要素毎の掛け算 ... 二つの行列の比較や行列とスカラの比較,などに相当する演算.

例. アルファ合成 関数:

void alphaCompose(const Mat& rgba1, const Mat& rgba2, Mat& rgba dest)

{
Mat a1(rgba1.size(), rgba1.type()), ra1;
Mat a2(rgba2.size(), rgba2.type());
int mixch[]={3, 0, 3, 1, 3, 2, 3, 3};
mixChannels(&rgba1, 1, &a1, 1, mixch, 4);
mixChannels(&rgba2, 1, &a2, 1, mixch, 4);
subtract(Scalar::all(255), a1, ra1);
bitwise or(a1, Scalar(0,0,0,255), a1);
bitwise or(a2, Scalar(0,0,0,255), a2);
multiply(a2, ra1, a2, 1./255);
multiply(a1, rgba1, a1, 1./255);
multiply(a2, rgba2, a2, 1./255);
add(a1, a2, rgba dest);
}

• sum(), mean(), meanStdDev(), norm(), countNonZero(),minMaxLoc(),

– 行列要素の様々な統計量.

• exp(), log(), pow(), sqrt(), cartToPolar(), polarToCart()

– 古典的な算術関数.

• scaleAdd(), transpose(), gemm(), invert(), solve(),determinant(), trace() eigen(), SVD,

– 代数関数 + SVD クラス.

• dft(), idft(), dct(), idct(),

– 離散フーリエ変換,離散コサイン変換

さらに便利な 代数表記 が利用できる処理もあります.例えば:

Mat delta = (J.t()*J + lambda*

Mat::eye(J.cols, J.cols, J.type()))

.inv(CV SVD)*(J.t()*err);

これは,LeLevenberg-Marquardt 最適化アルゴリズムの要です.


画像処理


フィルタリング


  • filter2D() 非分離型線形フィルタ

  • sepFilter2D() 分離型線形フィルタ

  • boxFilter(),GaussianBlur(),medianBlur(),bilateralFilter() 線形または非線形のフィルタを用いた画像の平滑化

  • Sobel(), Scharr() 微分画像の計算

  • Laplacian() ラプラシアンの計算


- erode(), dilate() 画像の収縮膨張

例. 3x3 のハイパスフィルタを適用します

(全体に 128 足して,負の値が失われないようにします):

filter2D(image, image, image.depth(), (Mat <float>(3,3)<<

-1, -1, -1, -1, 9, -1, -1, -1, -1), Point(1,1), 128);


幾何学変換


  • resize() 画像のリサイズ

  • getRectSubPix() 画像パッチの抽出

  • warpAffine() 画像のアフィン変換

  • warpPerspective() 画像の透視変換

  • remap() 汎用的な画像変換

  • convertMaps() remap() を高速に実行するためのマップ最適化

例.

ルート2 分の一に画像を縮小します:

Mat dst; resize(src, dst, Size(), 1./sqrt(2), 1./sqrt(2));


様々な画像変換


  • cvtColor() 画像を別の色空間に変換

  • threshold(),adaptivethreshold() 固定あるいは可変の閾値を用いて,グレースケール画像を 2 値画像に変換

  • floodFill() 領域拡張アルゴリズムを用いた,連結成分の検出

  • integral() インテグラルイメージの計算

  • distanceTransform() 2 値画像に対する,距離画像またはボロノイ図の構築

  • watershed(), grabCut() マーカベースの画像セグメンテーションアルゴリズム watershed.cpp や grabcut.cpp のサンプルを参照してください.


ヒストグラム


  • calcHist() 画像のヒストグラムの計算

  • calcBackProject() ヒストグラムの逆投影

  • equalizeHist() 画像の明るさとコントラストの正規化

  • compareHist() 2 つのヒストグラムの比較

例. 画像の色相-彩度ヒストグラムを計算します:

Mat hsv, H; MatND tempH;

cvtColor(image, hsv, CV BGR2HSV);
int planes[]={0, 1}, hsize[] = {32, 32};
calcHist(&hsv, 1, planes, Mat(), tempH, 2, hsize, 0);
H = tempH;


輪郭

輪郭の意味や使い方については contours.cpp や squares.cpp のサンプルを参照してください.

データの入出力

XML/YAML ストレージ は(入れ子可能な)コレクションで,スカラ値,構造体,様々なリストを含むことができます.


YAML(または XML)へのデータの書き込み

// ファイルの種類は拡張子によって決められます

FileStorage fs("test.yml", FileStorage::WRITE);

fs << "i" << 5 << "r" << 3.1 << "str" << "ABCDEFGH";
fs << "mtx" << Mat::eye(3,3,CV 32F);
fs << "mylist" << "[" << CV PI << "1+1" <<
"{:" << "month" << 12 << "day" << 31 << "year"
<< 1969 << "}" << "]";
fs << "mystruct" << "{" << "x" << 1 << "y" << 2 <<
"width" << 100 << "height" << 200 << "lbp" << "[:";
const uchar arr[] = {0, 1, 1, 0, 1, 1, 0, 1};
fs.writeRaw("u", arr, (int)(sizeof(arr)/sizeof(arr[0])));
fs << "]" << "}";

<< 演算子を用いて,スカラ値 (整数,浮動小数点数,文字列),行列,ス

カラ値やその他の型の STL vector をファイルストレージに書き込むこと

ができます

データの読み出し

// ファイルの種類は内容によって決められます

FileStorage fs("test.yml", FileStorage::READ);
int i1 = (int)fs["i"]; double r1 = (double)fs["r"];
string str1 = (string)fs["str"];
Mat M; fs["mtx"] >> M;
FileNode tl = fs["mylist"];
CV Assert(tl.type() == FileNode::SEQ && tl.size() == 3);
double tl0 = (double)tl[0]; string tl1 = (string)tl[1];
int m = (int)tl[2]["month"], d = (int)tl[2]["day"];
int year = (int)tl[2]["year"];
FileNode tm = fs["mystruct"];
Rect r; r.x = (int)tm["x"], r.y = (int)tm["y"];
r.width = (int)tm["width"], r.height = (int)tm["height"];
int lbp val = 0;
FileNodeIterator it = tm["lbp"].begin();
for(int k = 0; k < 8; k++, ++it)
lbp val |= ((int)*it) << k;

FileNode のキャスト演算子を用いて,スカラ値を読み込みます.行列やそ

の他の型は, >> 演算子を用いて読み込みます.リストを読み込む場合は,

FileNodeIterator を利用します.

ラスタ画像の書き込みと読み込み

imwrite("myimage.jpg", image);

Mat image color copy = imread("myimage.jpg", 1);
Mat image grayscale copy = imread("myimage.jpg", 0);

これらの関数が読み書き可能なフォーマット: BMP (.bmp), JPEG

(.jpg, .jpeg), TIFF (.tif, .tiff), PNG (.png), PBM/PGM/PPM

(.p?m), Sun Raster (.sr), JPEG 2000 (.jp2). 各フォーマットは,

8 ビット,1- または 3-チャンネルの画像をサポートします.1 チャンネル

が 16 ビットの画像をサポートするフォーマット (PNG, JPEG 2000) も

あります.

動画ファイルやカメラから画像を読み込みます

VideoCapture cap;

if(argc > 1) cap.open(string(argv[1])); else cap.open(0);
Mat frame; namedWindow("video", 1);
for(;;) {
cap >> frame; if(!frame.data) break;
imshow("video", frame); if(waitKey(30) >= 0) break;
}


シンプル GUI(highgui モジュール)


  • namedWindow(winname,flags)名前付き highgui ウィンドウを作成します

  • destroyWindow(winname) 指定したウィンドウを破棄します

  • imshow(winname, mtx) ウィンドウ内に画像を表示します

  • waitKey(delay) 指定時間だけ(あるいは永遠に)キーが押されるのを待ちます.待ち時間にイベントの処理を行います. この関数を,1 秒間に数回程度呼び出すの
    を忘れないように.

  • createTrackbar(...) 指定したウィンドウにトラックバー(スライダー)を追加します.

  • setMouseCallback(...) 指定したウィンドウ内でのマウスのクリックと移動に対して,コールバックを設定します.
    GUI 関数の使い方については, camshiftdemo.cpp や OpenCV
    samples を参照してください.


カメラキャリブレーション,姿勢推定,奥行き推定


  • calibrateCamera() キャリブレーションパターンを写した複数枚の画像を用いて,カメラをキャリブレーションします.

  • findChessboardCorners() チェッカーボードキャリブレーションパターン上の特徴点を検出します.

  • solvePnP() その特徴点を投影した結果から,元の物体の姿勢を求めます.

  • stereoCalibrate() ステレオカメラをキャリブレーションします.

  • stereoRectify() キャリブレーションされたステレオカメラ画像の平行化を行います.

  • initUndistortRectifyMap() ステレオカメラの各カメラに対する, ( remap() 用の )平行化マップを計算します.

  • StereoBM, StereoSGBM 平行化されたステレオペア上で実行される,ステレオ対応点探索エンジンです.

  • reprojectImageTo3D() 視差マップを 3 次元点群に変換します.

  • findHomography() 2 次元点集合間の最適な透視変換を求めます.

カメラをキャリブレーションするには,サンプル calibration.cpp やstereo calib.cpp を利用できます.視差マップや 3 次元点群を得るには,サンプル stereo match.cpp を利用してください.


物体検出


  • matchTemplate 入力テンプレートに対する一致度マップを求めます.

  • CascadeClassifier Viola が提唱した Haar や LBP 特徴量を利用するブースティング分類器のカスケードです.
    facedetect.cpp を参照してください.

  • HOGDescriptor N. Dalal が提唱した HOG 特徴量を利用する物
    体検出器です.peopledetect.cpp を参照してく
    ださい.


気になるページ

nodeで動画をサーバーに送信

https://github.com/na2hiro/webrtc-distribution

opencvのストーリミングのスピードをあげる

http://nobutobook.blogspot.jp/2016/10/python-opencv.html

face tracking

https://01.org/developerjourney/face-tracking

https://realpython.com/blog/python/face-detection-in-python-using-a-webcam/

http://manmade2.com/simple-home-surveillance-with-opencv-python-and-raspberry-pi/

Python live browser surveillance with motion detection

https://github.com/Arri/Py_WebSurveillance

streamming

https://svds.com/streaming-video-analysis-python/

motion track

https://github.com/svetlichnaya/Motion-Tracking

rgbからlow color hight colorに変換

https://henrydangprg.com/2016/06/26/color-detection-in-python-with-opencv/


参考

https://www.pro-s.co.jp/engineerblog/opencv/post_6231.html

http://qiita.com/hitomatagi/items/04b1b26c1bc2e8081427

http://derivecv.tumblr.com/post/73561473978

http://opencv.jp/opencv-2svn/opencv_cheatsheet.pdf

C++環境まわり

http://www2.meijo-u.ac.jp/~kohara/cms/technicalreport/opencv_intall4mac

http://purple-apple.hatenadiary.jp/entry/2017/02/05/195109