2016-08-19 24 views
6

Mam funkcję w następujący sposób, nazywa się ją wiele razy, co powoduje, że mój program działa powoli. Czy istnieje sposób na jej optymalizację? Na przykład za pomocą instrukcji SIMD lub innych technik. Funkcja getray() służy do pobrania zapytania vector-2 wektor-2 z wstępnie obliczonej tabeli przeglądowej. Został skompilowany w Visual-studio-2013, a docelową konfiguracją jest maszyna x64.Optymalizacja funkcji C++

Nawiasem mówiąc, pętla for, która wywołuje tę funkcję wiele razy, jest już zoptymalizowana za pomocą OpenMP.

Dziękuję bardzo.

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; 
} 

, gdzie funkcja projekt wygląda tak

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; 
} 

i getInterpolatedPixel() funkcji w następujący sposób

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); 
    } 
} 
+1

Jak powiedział pętlę w 'getInterpolatedPixel' to wąskie gardło, nie spróbujesz użyć OpenMP do tego? Czy OpenMP jest dla Ciebie opcją? Aby uzyskać proste użycie instrukcji SIMD, spróbuj [VC] (https://github.com/VcDevel/Vc). –

+0

Nie próbowałem używać OpenMP do funkcji getInterpolatedPixel, ale próbowałem dla WarpPlanarHomography. Nie daje mi to żadnych korzyści. Sądzę, że powodem jest to, że pętla for jest mała, gdzie usprawnienia wydajności nie mogą zrekompensować kosztów ogólnych spowodowanych przez OpenMP. Myślę więc, że dobrym pomysłem byłoby zoptymalizowanie tej małej funkcji za pomocą SIMD i optymalizacja zewnętrznej dużej pętli for z OpenMP. Tak, dziękuję za informacje z biblioteki. Spróbuję. – Peidong

+0

Myślę, że funkcja 'projektu' została pomieszana przez skopiowanie i wklejenie –

Odpowiedz

3
  1. środka gdzie jest wąskim gardłem i staramy się optymalizować pierwszy
  2. to miejsce
  3. możesz zamiast tego użyć float z double?
  4. jakie są m_K(0, 0), m_K(1, 1) ... można wymienić go na stałe
  5. UNROLL for (int i = 0; i < image.channels(); ++i) pętli czy obraz może mieć tylko określoną liczbę kanałów (1, 3, 4 są typowe numery)
  6. połączenia image.channels() tylko raz zastosowanie zapisana wartość później
  7. spróbuj dodać inline modifyer małych funkcji
+0

Na większości współczesnych architekturach liczba dublerów jest większa niż liczba elementów pływających. –

+0

dziękuję za odpowiedź. Zmierzyłem wąskie gardło, że jest to funkcja preojct() i funkcja getinterpolatedpixel. Reszta jest możliwa. Spróbuję. – Peidong

+0

co mam na myśli to, że można sparować pętlę for, ponieważ dla łatki 7x7 jest ona nazywana 49 razy z tymi samymi instrukcjami dla różnych danych? – Peidong

3

należy to uwzględnić, oprócz innych, szerzej koncentruje odpowiedzi.

Od getInterpolatedPixel jest stosowany w ciasnej pętli, skupiłem się tam na zmniejszenie wywołań funkcji:

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); 
    } 
}