2014-06-17 105 views
1

我有一個cv::Mat,我想做一些元素操作。例如,我有一個浮點矩陣,如cv::Mat m(100,100, CV_64F);。我有另一個功能如下:每元素操作的Opencv矩陣

double fun(double elem); 

如何應用此功能的矩陣,它可以做每元素操作。

回答

1

簡單循環呢?

cv::Mat m(100, 100, CV_64F); 
for(int x=0;x<m.cols;x++) 
    for(int y=0;y<m.rows;y++) 
     m.at<double>(y,x) = fun(m.at<double>(y,x)); 

如果您使用opencv庫的發佈版本,這是非常快的。如果你可以改變有趣功能的來源,它改變了說法本身並沒有返回它形成功能:

void fun(double &elem); 

然後,您可以省略一個在()調用:

cv::Mat m(100, 100, CV_64F); 
for(int x=0;x<m.cols;x++) 
    for(int y=0;y<m.rows;y++) 
     fun(m.at<double>(y,x)); 
5

你可以不喜歡它這樣的:

double func(double x) 
{ 
    return(sin(x)); 
} 

int main(void) 
{ 
    Mat M=Mat::eye(3,3,CV_64FC1); 
    std::transform(M.begin<double>(),M.end<double>(),M.begin<double>(),func); 
    cout << M; 
    getchar(); 
    return 0; 
} 
+0

非常優雅的使用標準庫的解決方案。但是,我想知道它是否真的有效,因爲從舊的實驗來看,MatIterator比直接訪問行數據要慢得多 – remi

+0

@remi但是也許MatIterator的性能取決於你正在使用的庫的類型(調試/發佈) ,就像Mat :: at()方法的情況一樣?我的意思是,在釋放版本中性能相當高。 – marol

+0

@marol我說的是比較性能,使用相同的環境(發佈版本的opencv),btw原始數據和MatIterator。原始數據> Mat.at> MatIterator如果我記得不錯,但不知道什麼是最好的btw mat.at和迭代器。這看起來很正常,因爲mat.at總是計算從矩陣開始的位移,並且注意到mat.isContinuous()不是必需的,MatIterator也是如此。如果你知道你的矩陣是連續的,並且想要最好的處理時間,只需使用原始數據指針 – remi

2

1)檢查您的墊子是連續

if(mat.isContinuous()) 

2)訪問的行數據指針,並投它加倍

double* buffer = (double*)mat.data; 
// or 
double* buffer = mat.ptr<double>(0); 
double *bufferEnd = (double*)mat.end; 

3)打電話給你的功能上的緩衝液,例如每個ELEM

for (; buffer != bufferEnd; ++buffer) 
     *buffer = fun(*buffer) 
0

設計一個通用的for循環矩陣

/** 
*@brief apply stl like for_each algorithm on every channels 
* 
* @param T : the type of the channel(ex, uchar, float, double and so on) 
* @param func : Unary function that accepts an element in the range as argument 
* 
*@return : 
* return func 
*/ 
template<typename T, typename UnaryFunc, typename Mat> 
UnaryFunc for_each_channels(Mat &&input, UnaryFunc func) 
{ 
    int rows = input.rows; 
    int cols = input.cols; 

    if(input.isContinuous()){ 
     cols = input.total() * input.channels(); 
     rows = 1; 
    } 

    for(int row = 0; row != rows; ++row){ 
     auto begin = input.template ptr<T>(row); 
     auto end = begin + cols; 
     while(begin != end){ 
      func(*begin); 
      ++begin; 
     } 
    } 

    return func; 
} 

使用它作爲以下

cv::Mat m(100, 100, CV_64F); 
//......initialize m 
for_each_channels<double>(m, [](double &a) 
{ 
    a = std::sin(a) * 2.14168;; 
}); 

你可以擴展API以支持向量型太

for_each<cv::vec3d>(m, [](cv::vec3d& a) 
{ 
    a = ..... //do something 
}); 

我阿里亞dy設計了一些通用api來使用,我把它們放在了github