Оптимизация функции C++
У меня есть функция следующим образом, она вызывается много раз, что заставляет мою программу работать медленно. Есть ли способ оптимизировать его? Например, используя SIMD инструкции или другие методы. Функция getray() предназначена для извлечения заданного вектора-3 запроса vector-2 из предварительно вычисленной справочной таблицы. Он скомпилирован в Visual-studio-2013, и его целевой конфигурацией является машина x64.
Кстати, цикл for, который вызывает эту функцию много раз, уже оптимизирован с помощью OpenMP.
Большое спасибо.
bool warpPlanarHomography(
const Eigen::Matrix3d& H_camera2_camera1
, const cv::Mat& image1
, const cv::Mat& image2
, FisheyeCameraUnified& cam1
, FisheyeCameraUnified& cam2
, const Eigen::Vector2i& patchCenter
, const int patchSize
, Eigen::Matrix<unsigned char, 7, 7>& patch1)
{
const int patchSize_2 = 3;
for (int v = 0; v < patchSize; ++v) // row
{
for (int u = 0; u < patchSize; ++u)
{
Eigen::Vector2i p1 = Eigen::Vector2i(u - patchSize_2, v - patchSize_2).cast<int>() + patchCenter;
if (p1(0, 0) < 0 || p1(1, 0) < 0 || p1(0, 0) >= image1.cols || p1(1, 0) >= image1.rows) return false;
Eigen::Vector3d ray1;
cam1.getRay(p1(1, 0), p1(0, 0), ray1);
Eigen::Vector2d p2;
if (!cam2.project(H_camera2_camera1 * ray1, p2))
{
return false;
}
if (p2.x() < 0.0 || p2.x() >= image2.cols - 1 ||
p2.y() < 0.0 || p2.y() >= image2.rows - 1)
{
return false;
}
getInterpolatedPixel(image2, p2, &patch1(v, u));
}
}
return true;
}
где функция проекта выглядит следующим образом
bool FisheyeCameraUnified::project(const Eigen::Vector3d& ray, Eigen::Vector2d& pt)
{
double fx, fy, cx, cy, xi;
fx = m_K(0, 0);
fy = m_K(1, 1);
cx = m_K(0, 2);
cy = m_K(1, 2);
xi = m_xi;
double d = ray.norm();
double rz = 1.0 / (ray(2) + xi * d);
// Project the scene point to the normalized plane.
Eigen::Vector2d m_d(ray(0) * rz, ray(1) * rz);
// Apply the projection matrix.
pt(0) = fx * m_d(0) + cx;
pt(1) = fy * m_d(1) + cy;
return true;
}
и getInterpolatedPixel() работают следующим образом
void getInterpolatedPixel(const cv::Mat& image, const Eigen::Vector2d& coords, unsigned char* pixel)
{
int ix = static_cast<int>(coords.x());
int iy = static_cast<int>(coords.y());
double dx = coords.x() - ix;
double dy = coords.y() - iy;
double dxdy = dx * dy;
const double w00 = 1.0 - dx - dy + dxdy;
const double w01 = dx - dxdy;
const double w10 = dy - dxdy;
const double w11 = dxdy;
const unsigned char* p00 = image.data + iy * image.step.p[0] + ix * image.channels();
const unsigned char* p01 = p00 + image.channels();
const unsigned char* p10 = p00 + image.step.p[0];
const unsigned char* p11 = p10 + image.channels();
for (int i = 0; i < image.channels(); ++i)
{
double value = w11 * p11[i] + w10 * p10[i] + w01 * p01[i] + w00 * p00[i];
pixel[i] = cv::saturate_cast<unsigned char>(value);
}
}
2 ответа
- измерить узкое место и попытаться сначала оптимизировать это место
- Вы можете использовать
float
вместоdouble
? - что
m_K(0, 0)
,m_K(1, 1)
... вы можете заменить его константами - развертываться
for (int i = 0; i < image.channels(); ++i)
цикл, если изображение может иметь только определенное количество каналов (1, 3, 4 - типичные числа) - вызов
image.channels()
только один раз и использовать сохраненное значение позже - попробуйте добавить
inline
модификатор для небольших функций
Это следует учитывать в дополнение к другим, более сфокусированным ответам.
поскольку getInterpolatedPixel
используется в узком цикле, я сосредоточился на сокращении вызовов функций:
void getInterpolatedPixel(const cv::Mat& image, const Eigen::Vector2d& coords, unsigned char* pixel)
{
//save two function calls here
double dx = coords.x();
double dy = coords.y();
int ix = static_cast<int>(dx);
int iy = static_cast<int>(dy);
dx -= ix;
dy -= iy;
//make this const
const double dxdy = dx * dy;
const double w00 = 1.0 - dx - dy + dxdy;
const double w01 = dx - dxdy;
const double w10 = dy - dxdy;
const double w11 = dxdy;
//cache image.channels()
const int channels = image.channels();
const unsigned char* p00 = image.data + iy * image.step.p[0] + ix * channels;
const unsigned char* p01 = p00 + channels;
const unsigned char* p10 = p00 + image.step.p[0];
const unsigned char* p11 = p10 + channels;
for (int i = 0; i < channels; ++i)
{
double value = w11 * p11[i] + w10 * p10[i] + w01 * p01[i] + w00 * p00[i];
pixel[i] = cv::saturate_cast<unsigned char>(value);
}
}