LoginSignup
35
61

More than 1 year has passed since last update.

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

Last updated at Posted at 2017-03-24

opencvって

画像処理の定番ライブラリです。
画像処理って面白い。AR VRやりたい。
AR機能とかは確か拡張機能なんでインストール方法が別です。
一からビルドしないといけないです。しかも拡張機能ごとになんか設定違ったりめんどい。
よって今回省きます。

この辺りは結構の情報はまとまってますよ。
https://learnopencv.com/
https://www.pyimagesearch.com/
公式も良い
https://vovkos.github.io/doxyrest-showcase/opencv/sphinx_rtd_theme/page_tutorial_root.html

スクリーンショット 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

Rectangle検出
スクリーンショット 2020-05-29 22.28.34.png

https://github.com/shibatch/rectdetect
https://www.youtube.com/watch?v=HpaY0HOomAI
https://www.youtube.com/watch?v=BLJEYui0XcY

動いてる状態で検出

スクリーンショット 2020-05-29 22.31.27.png

https://shibata.naist.jp/~n-sibata/software/baum/
https://www.youtube.com/watch?v=KtO5TxG4T0M

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で

この辺が変わってるようです。
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つの画像を比べて、似た画像がないか調べる。
ほぼ完全一致が求められるが、ある程度の精度は出る。
動かない場合は↓を参照。

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

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

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

35
61
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
35
61