我使用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值及其邻居值的最有效方法是什么?
答案 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:
outGray.jpg:
答案 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()。