OpenCV/C++程序比numpy程序慢,我该怎么办
OpenCV/C++ program slower than its numpy counterpart, what should I do?
我不久前在Python中实现了Procrustes Analysis算法,最近被告知要将其移植到OpenCV/C++。完成后,我运行了一些测试,对于相同的输入/实例,C++代码所花费的时间是Python代码的两倍(分别约为8秒和4秒。我重复了一千次测试,只是为了确保我不会在太短的时间内测量它们(。我对这些结果感到困惑。
我使用gprof试图了解发生了什么,但除了cv::Mat::~Mat((占用了34.67%的执行时间,并且被调用的频率比任何其他函数都高出100多次之外,我看不出有什么错误。我也不知道该怎么办,除非我应该用cv::Mats代替std::vectors或原始数组,这两种方法对我来说都是一种糟糕的做法
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);
}
这是用于对齐两组点的代码。它调用了一些没有显示的函数,但它们很简单,如果需要,我可以解释它们,尽管我希望这些名称足以理解它们的作用
我是一个随意的C++程序员,伙计们,对我宽容一点。
看来伊格纳西奥·巴斯克斯·艾布拉姆斯的想法是正确的。一个更简洁/直接的例子:
#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;
}
在我的机器里大约需要14秒以上。现在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()
这需要4秒钟以上的时间,尽管C++的例子只做了10次,而Python(Fortran(的例子做了1000次。
好吧,更新时间。
我查看了我使用的Python代码,意识到它只加载了一个子集(大约5%(。。。这意味着我的C++测试实际上运行的实例是Python代码的20倍,所以C++代码实际上快了大约10倍,因为代码的速度只有Python代码的两倍。不过,numpy在某些操作中似乎仍然击败了OpenCV。
for(int i = 0; i < 10; i++) {
cv::Mat m3 = m1 * m2;
}
这在c++中是完全没有意义的,m3在循环的每次迭代中都会被破坏——这就是为什么你会得到所有的析构函数调用。
编辑:
cv::Mat m3 = m1 * m2;
和
m3 = np.dot(m1, m2)
不是一回事。你有没有试过比较numpy中的叉积或opencv中的点积?
- 我的 cout 上有一个奇怪的输出,它把答案放在第一位,然后在我调用它的地方放一个奇怪的输出.我该怎么办?
- 当两个相等的双精度的相对比较不起作用时,我该怎么办?
- 我需要通过窗口句柄(HWND)获取文件,我该怎么办?
- 我正在"void value not ignored as it ought to be"我该怎么办?
- 未定义的引用错误,我该怎么办?
- 我在此代码中要求一个数字,如果用户给出一个字母,我该怎么办?
- 当一个功能完成另一个功能打开时,我该怎么办?
- 如果我尝试将 graphics.h 用于 c/c++ 时显示错误,我该怎么办?
- 这对我来说真的很难,我该怎么办
- IPP如何改进OpenCV应用程序?我该如何整合它
- 在C 中,我该怎么办才能格式化输出
- 当MPI中未知的发送消息数量时,我该怎么办
- 如果违反了利斯科夫替代原则,我该怎么办?
- 当(CUDA 7.5的)nvcc / cudafe++崩溃并出现段错误时,我该怎么办?
- 当来自外部库的线程不可预测地崩溃我的应用程序时,我该怎么办
- C++ 中的整数范围 - 当标准尚不存在时我该怎么办
- Visual Studio C++:获取未解析的令牌和未解析的链接.我该怎么办
- qextserialport在Windows上丢弃数据——我该怎么办
- 函数内存不足-我该怎么办
- OpenCV/C++程序比numpy程序慢,我该怎么办