opencv Mat和iplimage 访问图像元素方法总结

Mat

Mat一般是二维向量,如果是灰度图,一般存放 <uchar>类型;如果是RGB彩色图,存放 <Vec3b>类型。
单通道灰度图数据格式:

多通道的图像中,每列并列存放通道数量的子列,如RGB三通道彩色图:

注意通道的顺序反转了:BGR。通常情况内存足够大的话图像的每一行是连续存放的,也就是在内存上图像的所有数据存放成一行,这中情况在访问时可以提供很大方便。可以用  isContinuous()函数来判断图像数组是否为连续的。
1.用指针访问元素
	Mat imgs = imread("1.jpg", 1);
	if (imgs.empty())
	{
		cout << "fail to read image" << endl;
		return -1;
	}
	Mat img1 = imgs.clone();
	int div = 64;

	/* 方法1:用指针访问 */
	//多通道访问法1
	int rows = img1.rows;
	int cols = img1.cols;
	for (int i = 0; i < rows; i++)
	{
		//uchar* p = img1.ptr<uchar>(i);  //获取第i行的首地址
		for (int j = 0; j < cols; j++)
		{
			//在这里操作具体元素
			uchar *p = img1.ptr<uchar>(i, j);
			p[0] = p[0] / div*div + div / 2;
			p[1] = p[1] / div*div + div / 2;
			p[2] = p[2] / div*div + div / 2;
		}
	}

	imshow("lean", img1);

	//多通道访问法2
	Mat img3 = imgs.clone();
	int channels = img3.channels(); //获取通道数
	int rows3 = img3.rows;
	int cols3 = img3.cols* channels; //注意,是列数*通道数
	for (int i = 0; i < rows3; i++)
	{
		uchar* p = img3.ptr<uchar>(i);  //获取第i行的首地址
		for (int j = 0; j < cols3; j++)
		{
			//在这里操作具体元素
			p[j] = p[j] / div*div + div / 2;
			p[j + 1] = p[j + 1] / div*div + div / 2;
			p[j + 2] = p[j + 2] / div*div + div / 2;
		}
	}

	imshow("lean3", img3);

	//单通道图像
	Mat img2 = imgs.clone();
	cvtColor(img2, img2, COLOR_BGR2GRAY);
	for (int i = 0; i < img2.rows; i++)
	{
		uchar* p = img2.ptr<uchar>(i);  //获取第i行的首地址
		for (int j = 0; j < img2.cols; j++)
		{
			//在这里操作具体元素
			//p[j] = p[j] / div*div + div / 2;
			p[j] = p[j];
		}
	}

	imshow("lean2", img2);

	waitKey(0);

2.用迭代器访问元素

    Mat img = imread("lena.jpg",1); //载入灰度图
    Mat img1 = img.clone();
    int div = 64;
    /* 方法2:用迭代器访问 */

    /******************多通道的可以这么写***************/
    Mat_<Vec3b>::iterator it = img1.begin<Vec3b>();  //获取起始迭代器
    Mat_<Vec3b>::iterator it_end = img1.end<Vec3b>();  //获取结束迭代器
    for (; it != it_end; it++)
    {
        //在这里分别访问每个通道的元素
        (*it)[0] = (*it)[0] / div*div + div / 2;
        (*it)[1] = (*it)[1] / div*div + div / 2;
        (*it)[1] = (*it)[1] / div*div + div / 2;
    }

    imshow("lean", img1);


    /******************单通道的可以这么写***************/
    Mat img2;
    cvtColor(img, img2, COLOR_RGB2GRAY); //转化为单通道灰度图

    Mat_<uchar>::iterator it2 = img2.begin<uchar>();  //获取起始迭代器
    Mat_<uchar>::iterator it_end2 = img2.end<uchar>();  //获取结束迭代器
    for (; it2 != it_end2; it2++)
    {
            //在这里分别访问每个通道的元素
            *it2 = *it2 / div*div + div / 2;
    }
    imshow("lena2", img2);

    waitKey(0);

若要从图像的第二行开始,程序该怎么修改? 我们可以用

image.begin<cv::Vec3b>()+image.cols

初始化cv::Mat迭代器。 获得集合结束位置的方法也类似, 只是改用end方法。 但是, 用end方法得到的迭代器已经超出了集合范围, 因此必须在结束位置停止迭代过程。 结束的迭代器也能使用数学计算, 例如, 如果你想在最后一行前就结束迭代, 可使用

image.end<cv::Vec3b>()-image.cols

3.动态地址+at()访问元素

  Mat img = imread("lena.jpg",1); 
    Mat img1 = img.clone();
    int div = 64;
    /* 方法3:用at访问 */

    /****************访问多通道元素*********************/
    int rows = img1.rows;
    int cols = img1.cols;
    for (int i = 0; i < rows; i++)
    {
        for (int j = 0; j < cols; j++)
        {
            //在这里访问每个通道的元素,注意,成员函数at(int y,int x)的参数
            img1.at<Vec3b>(i,j)[0] = img1.at<Vec3b>(i, j)[0] / div*div + div / 2;
            img1.at<Vec3b>(i, j)[1] = img1.at<Vec3b>(i, j)[1] / div*div + div / 2;
            img1.at<Vec3b>(i, j)[2] = img1.at<Vec3b>(i, j)[2] / div*div + div / 2;

        }
    }

    imshow("lena", img1);

    /****************访问单通道元素*********************/
    Mat img2;
    cvtColor(img, img2, COLOR_RGB2GRAY);

    for (int i = 0; i < rows; i++)
    {
        for (int j = 0; j < cols; j++)
        {
            //在这里访问每个通道的元素,注意,成员函数at(int y,int x)的参数
            img2.at<uchar>(i, j) = img2.at<uchar>(i, j) / div*div + div / 2;
        }
    }

    imshow("lena2", img2);

    waitKey(0);



Iplimage


 /*访问多通道元素*/
    IplImage* img = cvCreateImage(cvSize(640, 480), IPL_DEPTH_8U, 3);
    uchar* data = (uchar *)img->imageData;
    int step = img->widthStep / sizeof(uchar);
    int channels = img->nChannels;
    uchar b, g, r;
    for (int i = 0; i < img->height; i++)
    {
        for (int j = 0; j < img->width; j++)
        {
            //获得元素的值
            b = data[i*step + j*channels + 0];
            g = data[i*step + j*channels + 1];
            r = data[i*step + j*channels + 2];


            //修改元素的值
            data[i*step + j*channels + 0] = 255;
        }
    }


    cvShowImage("img", img);




    /*访问单通道元素*/
    IplImage* img2 = cvCreateImage(cvSize(640, 480), IPL_DEPTH_8U, 1);
    uchar* data2 = (uchar *)img2->imageData;
    int step2 = img2->widthStep / sizeof(uchar);
    uchar v;
    for (int i = 0; i < img2->height; i++)
    {
        for (int j = 0; j < img2->width; j++)
        {
            //获得元素的值
            v = data2[i*step2 + j];


            //修改元素的值
            data2[i*step2 + j] = 255;
        }
    }


    cvShowImage("img2", img2);






    waitKey(0);


参考:

1.https://blog.csdn.net/xiaowei_cqu/article/details/7557063

2.http://www.cnblogs.com/skyfsm/p/7082914.html

3.https://blog.csdn.net/xiaowei_cqu/article/details/7557063

猜你喜欢

转载自blog.csdn.net/qq_42189368/article/details/80848071