Opencv矩阵的每元素操作

Opencv matrix per-element operation

本文关键字:元素 操作 Opencv      更新时间:2023-10-16

我有一个cv::Mat,我想对每个元素做一些操作。例如,我有一个像cv::Mat m(100,100, CV_64F);这样的浮点矩阵。我有另一个函数,如下所示:

double fun(double elem);

如何将此函数应用于矩阵,该矩阵可以执行逐元素操作

你可以这样做:

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

1)检查你的垫子是否连续

if(mat.isContinuous())
2)访问行数据指针并将其强制转换为double
double* buffer = (double*)mat.data; 
// or
double* buffer = mat.ptr<double>(0);
double *bufferEnd = (double*)mat.end;
3)在缓冲区的每个元素上调用你的函数,例如
 for (; buffer != bufferEnd; ++buffer)
        *buffer = fun(*buffer)

简单的循环呢?

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

如果你使用openv库的发布版本,这是相当快的。如果你可以改变源函数它会改变参数本身而不是以函数的形式返回

void fun(double &elem);

可以省略一个at()调用:

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

为矩阵设计一个通用的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
});

我已经设计了一些通用的api使用,我把它们放在github