OpenCV图像像素访问

  • 在我们使用OpenCV进行图像处理时,最常用到的就是对图像像素的访问,OpenCV支持5种访问方式,他们的访问速度和效率各不相同。这里以三通道图像为例简单说明一下。

访问速度:3>4>2>5>1

OpenCV Mat对象成员简介

  • data: uchar型的指针,指向矩阵数据
  • dims: 矩阵的维度
  • rows:矩阵行数
  • cols:矩阵列数
  • channels:矩阵元素所拥有的通道数
  • type:矩阵的元素类型和矩阵的通道数,其命名规则为CV_(位数)+(数据类型)+(通道数)如CV_16UC2,表示的是元素类型是一个16位的无符号整数,通道为2,这里U(unsigned integer)表示的是无符号整数,S(signed integer)是有符号整数,F(float)是浮点数
  • depth:一个通道的数据类型,命名为type去掉通道数;type一般是在创建Mat对象时设定,如果要取得Mat的元素类型,则使用depth
  • elemSize:一个元素所占的字节数,如CV_16SC3,elemSize = 3 * 16 / 8 = 6
  • elemSize1:一个元素每个通道占的字节数,如CV_16SC3,elemSize1 = 16 / 8 = 2
  • step:step[0]是矩阵中一行元素的字节数,step[1]和elemSize含义一样
  • step1:step / elemSize1

1. 使用at<>访问

  • 此方法类似二维数组的行列访问
for (int row = 0; row < img.rows; row++)
		{
			for (int col = 0; col < img.cols; col++)
			{
				img.at<Vec3b>(row, col)[0] = 255 - img.at<Vec3b>(row, col)[0];
				img.at<Vec3b>(row, col)[1] = 255 - img.at<Vec3b>(row, col)[1];
				img.at<Vec3b>(row, col)[2] = 255 - img.at<Vec3b>(row, col)[2];
			}
		}

2. 使用ptr<>(row, col)访问


for (int row = 0; row < img.rows; row++){			
    for (int col = 0; col < img.cols; col++){
        Vec3b* pData = img.ptr<Vec3b>(row, col);
        (*pData)[0] = 255 - (*pData)[0];
        (*pData)[1] = 255 - (*pData)[1];
        (*pData)[2] = 255 - (*pData)[2];

        //另一个方式
        // uchar* pData = img.ptr<uchar>(row, col);
        // *(pData + 0) = 255 - *(pData + 0);
        // *(pData + 1) = 255 - *(pData + 1);
        // *(pData + 2) = 255 - *(pData + 2);
    }
}

3. 使用ptr<>(row)访问

  • 类似二维数组指针访问
for (int row = 0; row < img.rows; row++){
    Vec3b* pData = img.ptr<Vec3b>(row);
    for (int col = 0; col < img.cols; col++){
        (*(pData + col))[0] = 255 - (*(pData + col))[0];
        (*(pData + col))[1] = 255 - (*(pData + col))[1];
        (*(pData + col))[2] = 255 - (*(pData + col))[2];
    }
}
// 另一个方式
for (int row = 0; row < img.rows; row++){
    uchar* pData = img.ptr<uchar>(row);
    for (int col = 0; col < img.cols; col++){
        *(pData + col*img.channels() + 0) = 255 - *(pData + col*img.channels() + 0);
        *(pData + col*img.channels() + 1) = 255 - *(pData + col*img.channels() + 1);
        *(pData + col*img.channels() + 2) = 255 - *(pData + col*img.channels() + 2);
    }

}

4. data结合step访问

  • step存的是图像一行所占的字节数
uchar* pData = img.data;
MatStep mst = img.step;

for (int row = 0; row < img.rows; row++){			
    for (int col = 0; col < img.cols; col++){
        //*mst.p表示的是图像一行的长度(例如图像为500宽度的3通道图像,则该值为1500=500*3)
        //cout << *mst.p << endl;

        *(pData + row * *mst.p + col * img.channels() + 0) = 255 - *(pData + row * *mst.p + col * img.channels() + 0);
        *(pData + row * *mst.p + col * img.channels() + 1) = 255 - *(pData + row * *mst.p + col * img.channels() + 1);
        *(pData + row * *mst.p + col * img.channels() + 2) = 255 - *(pData + row * *mst.p + col * img.channels() + 2);
        
        // 另一种
        //*(pData + row * mst[0] + col * mst[1] + 0) = 255 - *(pData + row * mst[0] + col * mst[1] + 0);
        //*(pData + row * mst[0] + col * mst[1] + 1) = 255 - *(pData + row * mst[0] + col * mst[1] + 1);
        //*(pData + row * mst[0] + col * mst[1] + 2) = 255 - *(pData + row * mst[0] + col * mst[1] + 2);
    }
}

5. 迭代器访问

for (int i = 0; i < testCount; i++){
    
    MatIterator_<Vec3b> it = img.begin<Vec3b>();
    MatIterator_<Vec3b> itEnd = img.end<Vec3b>();

    //只读的迭代器,迭代器指向的值不可修改
    MatConstIterator_<Vec3b> it = img.begin<Vec3b>();
    MatConstIterator_<Vec3b> itEnd = img.end<Vec3b>();

    //这样也可以
    Mat_<Vec3b>::iterator it = img.begin<Vec3b>();
    Mat_<Vec3b>::iterator itEnd = img.end<Vec3b>();

    while (it!=itEnd){
        (*it)[0] = 255 - (*it)[0];
        (*it)[1] = 255 - (*it)[1];
        (*it)[2] = 255 - (*it)[2];

        it++;
    }
}

Guess you like

Origin blog.csdn.net/qq_34935373/article/details/119742348