2013-01-09 160 views
5

numpyのndarray関数を同等のものに変換する際に問題が発生しました n次元のcv :: Matを適切なスライスに再形成/分割するためのOpenCV C++呼び出し。 特にOpenCV python2サンプル "texture_flow.py" (> = OpenCV 2.4.3)をC++に変換しようとしています。問題の行を以下のスニペットでマークしました。numpyの配列の形状をOpenCVに変換する

# [......] 
img = cv2.imread(fn) 
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 
# simple width and height tuple 
h, w = img.shape[:2] 

eigen = cv2.cornerEigenValsAndVecs(gray, 15, 3) 
print eigen.shape # prints: (height, widht, 6), i.e. 6 channels 

# Problem 1: 
# OpenCV's reshape function is not sufficient to do this. 
# probably must be split into several steps... 
eigen = eigen.reshape(h, w, 3, 2) # [[e1, e2], v1, v2] 
print eigen.shape # prints: (height, width, 3, 2) 

# Problem 2: 
# I assume this is meant to get the the v1 and v2 matrices 
# from the previous reshape 
flow = eigen[:,:,2] 
print flow.shape # prints: (height, width, 2), i.e. 2 channels 

vis = img.copy() 
# C++: vis.data[i] = (uchar)((192 + (int)vis.data[i])/2); 
vis[:] = (192 + np.uint32(vis))/2 

d = 12 

# Problem 3: 
# Can probably be split into 2 nested for-loops 
points = np.dstack(np.mgrid[d/2:w:d, d/2:h:d]).reshape(-1, 2) 

# [......] 

問題の行をC++に翻訳する手助けができますか?

答えて

2

徹底的に考えてみると、予想以上に簡単でした。それは私を混乱させるだけの面白いnumpy配列の構文です。 numpyの配列の整形は、結果として得られるcv :: Mat "eigen"の単一チャンネルにアクセスするためのPythonの方法です。 次のコードは、OpenCVの "texture_flow.py"のC++バージョンです(OpenCV 2.4.3から取りました)。結果のフローイメージは、pythonバージョンと100%同一ではありませんが、十分に近いです。

#include <opencv2/opencv.hpp> 
#include <iostream> 

int main (int argc, char** argv) 
{ 
    cv::TickMeter tm; 
    tm.start(); 
    cv::Mat img = cv::imread(argv[1]); 
    cv::Mat gray = cv::Mat(); 
    cv::cvtColor(img, gray, CV_BGR2GRAY); 
    // to preserve the original image 
    cv::Mat flow = gray.clone(); 
    int width = img.cols; 
    int height = img.rows; 
    int graySize = width * height; 
    // "brighten" the flow image 
    // C++ version of: 
    // vis[:] = (192 + np.uint32(vis))/2 
    for (unsigned int i=0; i<graySize; ++i) 
    { 
     flow.data[i] = (uchar)((192 + (int)flow.data[i])/2); 
    } 
    cv::Mat eigen = cv::Mat(height, width, CV_32FC(6)); 
    cv::cornerEigenValsAndVecs(gray, eigen, 15, 3); 
    // this is the equivalent to all the numpy's reshaping etc. to 
    // generate the flow arrays 
    // simply use channel 4 and 5 as the actual flow array in C++ 
    std::vector<cv::Mat> channels; 
    cv::split(eigen, channels); 

    int d = 12; 
    cv::Scalar col(0, 0, 0); 
    // C++ version of: 
    // points = np.dstack(np.mgrid[d/2:w:d, d/2:h:d]).reshape(-1, 2) 
    // including the actual line drawing part 
    for (unsigned int y=(d/2); y<flow.rows; y+=d) 
    { 
     for (unsigned int x=(d/2); x<flow.cols; x+=d) 
     { 
      if (x < flow.cols && y < flow.rows) 
      { 
       cv::Point p(x, y); 
       float dx = channels[4].at<float>(p) * (d/2); 
       float dy = channels[5].at<float>(p) * (d/2); 
       cv::Point p0(p.x - dx, p.y - dy); 
       cv::Point p1(p.x + dx, p.y + dy); 
       cv::line(flow, p0, p1, col, 1); 
       } 
     } 
    } 
    tm.stop(); 
    std::cout<<"Flow image generated in "<<tm.getTimeMilli()<<" ms."<<std::endl; 
    cv::imshow("FLOW", flow); 
    cv::waitKey(); 
    return 0; 
} 
関連する問題