OpenCV快速席元素和邻居访问

时间:2014-04-24 16:40:57

标签: c++ opencv image-processing matrix

我使用OpenCV(C ++)Mat作为我的矩阵,并希望尽可能快地访问单个Mat元素。从OpenCV教程中,我找到了有效访问的代码:

for( i = 0; i < nRows; ++i)
    {
        p = I.ptr<uchar>(i);
        for ( j = 0; j < nCols; ++j)
        {
            p[j] = table[p[j]];
        }
    }

对于我的问题,我需要访问Mat元素及其邻居(i-1,j-1)进行计算。如何调整给定代码以访问单个mat元素及其周围元素?由于速度很重要,我想避免Mat.at<>()。 访问Mat值及其邻居值的最有效方法是什么?

3 个答案:

答案 0 :(得分:1)

像素及其相邻像素可以形成cv::Rect,然后您只需使用:

cv::Mat mat = ...;
cv::Rect roi= ...; // define it properly based on the neighbors defination
cv::Mat sub_mat = mat(roi);

如果您的邻居定义不规则,即它们不能形成矩形区域,请改用掩码。查看here以获取示例。

答案 1 :(得分:0)

您可以直接引用Mat :: data:

template<class T, int N>
T GetPixel(const cv::Mat &img, int x, int y) {
    int k = (y * img.cols + x) * N;
    T pixel;
    for(int i=0;i<N;i++)
        pixel[i] = *(img.data + k + i);
    return pixel;
}

template<class T,int N>
void SetPixel(const cv::Mat &img, int x, int y, T t) {
    int k = (y * img.cols + x) * N;
    for(int i=0;i<N;i++)
        *(img.data + k + i) = t[i];
}

template<>
unsigned char GetPixel<unsigned char, 1>(const cv::Mat &img, int x, int y) {
    return *(img.data + y * img.cols + x);
}

template<>
void SetPixel<unsigned char, 1>(const cv::Mat &img, int x, int y, unsigned char p) {
    *(img.data + y * img.cols + x) = p;
}




int main() {
    unsigned char r,g,b;
    int channels = 3;
    Mat img = Mat::zeros(256,256, CV_8UC3);
    for(int x=0;x<img.cols;x+=2)
        for(int y=0;y<img.rows;y+=2) 
             SetPixel<cv::Vec3b, 3>(img, x, y, cv::Vec3b(255,255,255));


    Mat imgGray = Mat::zeros(256,256, CV_8UC1);
    for(int x=0;x<imgGray.cols;x+=4)
        for(int y=0;y<imgGray.rows;y+=4) 
             SetPixel<unsigned char, 1>(imgGray, x, y, (unsigned char)255);



    imwrite("out.jpg", img);
    imwrite("outGray.jpg", imgGray);

    return 0;
}

我觉得这很快。

out.jpg:

out

outGray.jpg:

outGray

答案 2 :(得分:0)

对于任何未来的读者:请阅读此博客文章https://www.learnopencv.com/parallel-pixel-access-in-opencv-using-foreach/,而不是阅读此处的答案,以获得对此功能的基于对基准的分析,因为有些答案有点不合时宜。

从那篇文章中你可以看到访问像素的最快方法是使用forEach C ++ Mat函数。如果你想要邻里,它取决于大小;如果你正在寻找平常的3x3平方,请使用这样的指针:

Mat img = Mat(100,100,CV_8U, Scalar(124)); // sample mat
uchar *up, *row, *down; // Pointers to rows
uchar n[9]; // neighborhood

for (int y = 1 ; y < (img.rows - 1) ; y++) {
    up = img.ptr(y - 1);
    row = img.ptr(y);
    down = img.ptr(y + 1);
    for (int x = 1 ; x < (img.cols - 1) ; x++) {
        // Examples of how to access any pixel in the 8-connected neighborhood
        n[0] = up[x - 1];
        n[1] = up[x];
        n[2] = up[x + 1];
        n[3] = row[x - 1];
        n[4] = row[x];
        n[5] = row[x + 1];
        n[6] = down[x - 1];
        n[7] = down[x];
        n[8] = down[x + 1];
    }
}

这段代码仍然可以优化,但使用行指针的想法正是我试图传达的;这比使用.at()函数快一点,你可能需要做基准测试以注意差异(在OpenCV 3+的版本中)。在决定优化像素访问之前,您可能希望使用.at()。