2012-12-15 133 views
3
template<typename T> 
cv::Mat_<T> const bilinear_interpolation(cv::Mat_<T> const &src, cv::Size dsize, 
            float dx, float dy) 
{ 
    cv::Mat_<T> dst = dsize.area() == 0 ? cv::Mat_<T>(src.rows * dy, src.cols * dx) : 
             cv::Mat_<T>(dsize); 

    float const x_ratio = static_cast<float>((src.cols - 1))/dst.cols; 
    float const y_ratio = static_cast<float>((src.rows - 1))/dst.rows; 
    for(int row = 0; row != dst.rows; ++row) 
    { 
    int y = static_cast<int>(row * y_ratio); 
    float const y_diff = (row * y_ratio) - y; //distance of the nearest pixel(y axis) 
    float const y_diff_2 = 1 - y_diff; 
    auto *dst_ptr = &dst(row, 0)[0]; 
    for(int col = 0; col != dst.cols; ++col) 
    { 
     int x = static_cast<int>(col * x_ratio); 
     float const x_diff = (col * x_ratio) - x; //distance of the nearet pixel(x axis) 
     float const x_diff_2 = 1 - x_diff; 
     float const y2_cross_x2 = y_diff_2 * x_diff_2; 
     float const y2_cross_x = y_diff_2 * x_diff; 
     float const y_cross_x2 = y_diff * x_diff_2; 
     float const y_cross_x = y_diff * x_diff; 
     for(int channel = 0; channel != cv::DataType<T>::channels; ++channel) 
     { 
      *dst_ptr++ = y2_cross_x2 * src(y, x)[channel] + 
         y2_cross_x * src(y, x + 1)[channel] + 
         y_cross_x2 * src(y + 1, x)[channel] + 
         y_cross_x * src(y + 1, x + 1)[channel]; 

     } 
    } 
} 

return dst; 

}慢無比雙線性插值(比較OpenCV的)

這是雙線性插值的實現,我用它來放大一個512 * 512像素的圖像( 「lena.png」) 2048 * 2048 ,完成這項工作需要0.195秒,但opencv的cv :: resize(不是gpu版本)只花費0.026secs。我不知道是什麼讓我的雙線變得如此緩慢(opencv比我快750%),我想看看opencv調整大小的源代碼,但我找不到它的實現。

你知道爲什麼openCV的調整大小可能如此之快,或者我的雙線速度太慢嗎?

{ 
     timeEstimate<> time; 
     cv::Mat_<cv::Vec3b> const src = input; 
     bilinear_interpolation(src, cv::Size(), dx, dy); 
     std::cout << "bilinear" << std::endl; 
    } 

    { 
     timeEstimate<> time; 
     cv::Mat output = input.clone(); 
     cv::resize(input, output, cv::Size(), dx, dy, cv::INTER_LINEAR); 
     std::cout << "bilinear cv" << std::endl; 
    } 

編譯:mingw4.6.2 操作系統:WIN7 64位CPU :英特爾I3-2330M(2.2G)

+1

例如,'cv :: resize'有可能利用處理器指令集擴展,如SSE,允許它並行運行多個乘法。要做到這一點,你需要智能編譯器優化或手動編寫x86程序集。 **編輯:** [根據消息來源,GCC使用'-O3'標誌實現了矢量化。](http://stackoverflow.com/questions/7919304/gcc-sse-code-optimization)。 (但是,'-O3'可能會導致令人難以置信的奇怪錯誤,所以一般不會使用它。) – 2012-12-15 00:47:52

+0

謝謝,我最近會看看opencl,希望gpgpu開發的代碼更加便攜。 – StereoMatching

+0

通過考慮具體情況的具體實現,您可以開始加速它,比方說每個通道具有8位深度的典型RGB整數圖像。然後可以用更少的乘法和更多的按位操作來執行內插。雖然我沒有一個符合評論的實現,但你可以在http://cboard.cprogramming.com/game-programming/19926-super-fast-bilinear-interpolation.html找到一個,我沒有檢查正確性。 – mmgp

回答

3

有做的OpenCV的版本快兩兩件事:

  1. OpenCV將調整大小作爲「可分離操作」。即它分兩步完成:圖像水平拉伸,然後垂直拉伸。該技術允許使用較少的算術運算來調整大小。

  2. 手動編碼的SSE優化。

+0

我檢查了第一個解決方案,但無法弄清楚如何分兩步操作。它可以用於某些矩陣乘法和dct,但我不知道如何將其應用於雙線性。 – StereoMatching

0

也許有點遲,還要檢查一下,看看你是否在調試模式下運行你的應用程序。 OpenCV是一個庫,可能通過編譯器優化進行編譯發佈。