2011-07-13 39 views
7

Tôi đã thực hiện một thời gian trước thuật toán Phân tích Procrustes trong Python và được yêu cầu chuyển nó sang OpenCV/C++ gần đây. Sau khi hoàn thành nó, tôi chạy một số kiểm tra và cho cùng một input/instances, mã C++ lấy hai lần thời gian mã Python (khoảng 8 vs 4 giây, tương ứng. Tôi lặp lại các bài kiểm tra hàng nghìn lần để đảm bảo rằng tôi 'không đo lường chúng trong một khoảng thời gian quá nhỏ). Tôi bị bối rối bởi những kết quả này.Chương trình OpenCV/C++ chậm hơn so với chương trình của nó, tôi nên làm gì?

Tôi đã sử dụng gprof để cố gắng hiểu điều gì đang diễn ra, nhưng tôi không thể nói được nhiều sai lầm, ngoài thực tế là cv :: Mat :: ~ Mat() đang chiếm 34,67% số lần thực thi thời gian và được gọi là hơn 100 lần so với bất kỳ chức năng nào khác. Không chắc chắn tôi nên làm gì về điều đó, trừ khi tôi phải thay thế cv :: Mats cho std :: vectơ hoặc mảng thô, cả hai đều có vẻ như là một hành động xấu với tôi.

void align(const cv::Mat& points, const cv::Mat& pointsRef, cv::Mat& res, cv::Mat& ops) { 
    cv::Mat pts(points.rows, points.cols, CV_64FC1); 
    cv::Mat ptsRef(points.rows, points.cols, CV_64FC1); 
    points.copyTo(pts); 
    pointsRef.copyTo(ptsRef); 

    cv::Mat avgs = meanOfColumns(pts); 
    for(int i = 0; i < avgs.cols; i++) { 
     pts.col(i) -= avgs.col(i); 
    } 
    cv::Mat avgsR = meanOfColumns(ptsRef); 
    for(int i = 0; i < avgsR.cols; i++) { 
     ptsRef.col(i) -= avgsR.col(i); 
    } 

    cv::Mat x2(pts.rows, 1, CV_64FC1); 
    cv::Mat y2(pts.rows, 1, CV_64FC1); 
    cv::Mat x2R(pts.rows, 1, CV_64FC1); 
    cv::Mat y2R(pts.rows, 1, CV_64FC1); 
    cv::pow(pts.col(0), 2, x2); 
    cv::pow(pts.col(1), 2, y2); 
    cv::pow(ptsRef.col(0), 2, x2R); 
    cv::pow(ptsRef.col(1), 2, y2R); 
    cv::Mat sqrootP(pts.rows, 1, CV_64FC1); 
    cv::Mat sqrootPR(pts.rows, 1, CV_64FC1); 
    cv::sqrt(x2R + y2R, sqrootPR); 
    cv::sqrt(x2 + y2, sqrootP); 
    double offsetS = (cv::mean(sqrootPR)/cv::mean(sqrootP))[0]; 
    pts *= offsetS; 

    cv::Mat rot(pts.rows, 1, CV_64FC1); 
    cv::Mat rotR(pts.rows, 1, CV_64FC1); 
    rot = arctan2(pts.col(1), pts.col(0)); 
    rotR = arctan2(ptsRef.col(1), ptsRef.col(0)); 
    double offsetR = -cv::mean((rot - rotR))[0]; 
    cv::Mat angRot(pts.rows, 1, CV_64FC1); 
    angRot = rot + offsetR; 
    cv::Mat dist(pts.rows, 1, CV_64FC1); 
    cv::pow(pts.col(0), 2, x2); 
    cv::pow(pts.col(1), 2, y2); 
    cv::sqrt(x2 + y2, dist); 
    copyColumn(dist.mul(cosine(angRot)), res, 0, 0); 
    copyColumn(dist.mul(sine(angRot)), res, 0, 1); 

    ops.at<double>(0, 0) = -avgs.at<double>(0, 0); 
    ops.at<double>(0, 1) = -avgs.at<double>(0, 1); 
    ops.at<double>(0, 2) = offsetS * cv::cos(offsetR/RADIANS_TO_DEGREES); 
    ops.at<double>(0, 3) = offsetS * cv::sin(offsetR/RADIANS_TO_DEGREES); 
} 

Đây là mã để căn chỉnh 2 bộ điểm. Nó gọi một số chức năng không được hiển thị, nhưng chúng đơn giản và tôi có thể giải thích chúng nếu cần thiết, mặc dù tôi hy vọng rằng những cái tên đó là đủ để hiểu những gì chúng làm.

Tôi là một lập trình viên C++ bình thường, dễ dàng với các bạn.

Dường như Ignacio Vazquez-Abrams có ý tưởng đúng. Ví dụ ngắn gọn/trực tiếp hơn:

#include <boost/date_time/posix_time/posix_time.hpp> 
#include <cv.hpp> 
#include <iostream> 

using namespace boost::posix_time; 

int main() { 
    cv::Mat m1(1000, 1000, CV_64FC1); 
    cv::Mat m2(1000, 1000, CV_64FC1); 
    ptime firstValue(microsec_clock::local_time()); 
    for(int i = 0; i < 10; i++) { 
     cv::Mat m3 = m1 * m2; 
    } 
    ptime secondValue(microsec_clock::local_time()); 
    time_duration diff = secondValue - firstValue; 
    std::cout << diff.seconds() << "." << diff.fractional_seconds() << " microsec" << std::endl; 
} 

Mất khoảng 14 giây trong máy của tôi. Bây giờ Python:

import datetime 
import numpy as np 

if __name__ == '__main__': 
    print datetime.datetime.now() 
    m1 = np.zeros((1000, 1000), dtype=float) 
    m2 = np.zeros((1000, 1000), dtype=float) 
    for i in range(1000): 
     m3 = np.dot(m1, m2) 
    print datetime.datetime.now() 

Đó mất 4+ giây, mặc dù C++ ví dụ chỉ làm việc đó 10 lần, trong khi Python (Fortran) ai làm việc đó 1000.

Vâng okay, cập nhật thời gian.

Tôi đã xem lại mã Python tôi đang sử dụng và nhận ra rằng nó chỉ tải một tập con của các điểm (khoảng 5%) ... Điều đó có nghĩa là các kiểm tra C++ của tôi thực sự chạy nhiều hơn 20 lần so với mã Python. mã C++ thực sự nhanh hơn khoảng 10 lần, vì mã chỉ chậm gấp hai lần. Nó vẫn có vẻ như numpy có OpenCV đánh bại trong một số hoạt động mặc dù.

+3

Mã hoặc nó không xảy ra. –

+1

Vui lòng đăng một số mã đại diện. Không thể nói mà không có thêm chi tiết. –

+0

Bạn không so sánh C++ với Python, bạn đang so sánh C++ với Fortran. Nếu đó là số crunching, sau đó Fortran * sẽ * giành chiến thắng. –

Trả lời

1
for(int i = 0; i < 10; i++) { 
     cv::Mat m3 = m1 * m2; 
} 

Điều này hoàn toàn vô nghĩa trong C++, m3 bị hủy trên mỗi lần lặp của vòng lặp - đó là lý do bạn nhận được tất cả các cuộc gọi hủy đó.

chỉnh sửa:

cv::Mat m3 = m1 * m2; 

m3 = np.dot(m1, m2) 

không phải là những điều tương tự. Bạn đã thử so sánh một sản phẩm chéo trong sản phẩm numpy hoặc một dấu chấm trong opencv?

+1

Tôi thậm chí còn nghi ngờ rằng toàn bộ vòng lặp được tối ưu hóa với -O3. – pmr

+0

Tôi nhận ra rằng, tôi không sử dụng mã đó trong mã của mình. Tôi chỉ thêm nó sau này để kiểm tra giả thuyết của Ignacio. – friday

+0

Theo http://opencv.willowgarage.com/documentation/cpp/basic_structures.html (phần Biểu thức Ma trận), A * B là phép nhân ma trận trong OpenCV. Theo http://docs.scipy.org/doc/numpy/reference/generated/numpy.dot.html, numpy.dot là phép nhân ma trận cho các mảng 2D. Tôi có thể bị nhầm lẫn, nhưng theo như tôi có thể nói, hai phương pháp là tương đương trong các ví dụ đã cho. – friday

Các vấn đề liên quan