关于opencv中的坐标问题

关于opencv中的坐标问题

记性太差,理解不到位,总是弄错,特此记录一下。

对应关系:
row == heigh == Point.y
col == width == Point.x
cv::Mat::at(Point(x, y)) == cv::Mat::at(y,x)

一开始在用opencv做项目实验的时候,总是出现一些莫名其妙的错误,得出来的结果跟期望有点像,但并不是自己想要的。后来发现,cv::Vec3b &cv::Mat::at<cv::Vec3b>(int x, int y) cv::Point2i::Point_(int  x, int y) 两者之间的区别,其实蛮大的。

        在图像中,坐标系的零点坐标为图片的左上角,即左上角为原点,X轴为图像矩形的上面那条水平线Y轴为图像矩形左边的那条垂直线。该坐标系在诸如结构体Mat,Rect,Point中都是适用的。

        在使用image.at<datatype>(x1, x2)来访问图像中点的值的时候,x1并不是图片中对应点的x轴坐标,而是图片中对应点的y坐标,即对应的是行。因此其访问的结果其实是访问image图像中的Point(x2, x1)点,即与image.at(Point(x2, x1))效果相同。

         如果图像是多通道的,比如说image图像的通道数为n,则使用Mat::at(x, y)时,其x的范围依旧是0到image的高height,而y的取值范围则是0到image的宽width乘以n,因为这个时候是有n个通道,所以每个像素需要占有n列。但是如果在同样的情况下,使用cv::Mat::at<datatype>(point)来访问的话,则这时候可以不用考虑通道的个数,因为你要赋值给获取cv::Mat::at<datatype>(point)的值时,都不是一个数字,而是一个对应的n维向量。

通过以下实验,便可验证说明。

原型:cv::Point2i::Point_(int _x, int _y),其中:Y表示的是行位置,X是表示的列位置。

1、cv::circle(src, cv::Point(300, 100), 6, cv::Scalar(0, 255, 0), -1);//在图像中坐标为(300,100)的地方画一个实心圆

原型:C++  cv::Vec3b &cv::Mat::at<cv::Vec3b>(int row, int col),其中:row表示行,col表示列。

void testXY_col_row()
{
	//00.bmp:621*321
	cv::Mat src;
	src = cv::imread("..\\00.bmp", 1);

	assert(src.data != NULL);

	cv::namedWindow("0", 0);
	cv::imshow("0", src);
	cv::waitKey(0);

	if (3==src.channels())
	{
		int i = 0, j = 0;
		int flag = 0;
		//for ( i = 0; i < src.rows; i++)
		//{
		//	for ( j = 0; j < src.cols; j++)
		//	{
		//		if (i<300 && j<100)
		//		{
		//			src.at<cv::Vec3b>(i, j)[0] = 0;
		//			src.at<cv::Vec3b>(i, j)[1] = 1;
		//			src.at<cv::Vec3b>(i, j)[2] = 255;

		//			cv::namedWindow("01", 0);
		//			cv::imshow("01", src);
		//			cv::waitKey(10);
		//		}
		//		else if (i > 300 && j > 100)
		//		{
		//			flag = 1;
		//			break;
		//		}
		//	}
		//	if (1==flag)
		//	{
		//		break;
		//	}
		//}

		cv::circle(src, cv::Point(300, 100), 6, cv::Scalar(0, 255, 0), -1);
	}

	//cv::imwrite("..\\cv-Point(300-100).bmp", src);
	cv::imwrite("..\\00Point(300-100).bmp", src);
	cv::namedWindow("1", 0);
	cv::imshow("1", src);
	cv::waitKey(0);
}

2、C++  cv::Vec3b &cv::Mat::at<cv::Vec3b>(int x, int y)

将图像中坐标满足:(x<300&&y<100)的像素点全部描成红色。

	if (3==src.channels())
	{
		int i = 0, j = 0;
		int flag = 0;
		for ( i = 0; i < src.rows; i++)
		{
			for ( j = 0; j < src.cols; j++)
			{
				if (i<300 && j<100)
				{
					src.at<cv::Vec3b>(i, j)[0] = 0;
					src.at<cv::Vec3b>(i, j)[1] = 1;
					src.at<cv::Vec3b>(i, j)[2] = 255;

					cv::namedWindow("01", 0);
					cv::imshow("01", src);
					cv::waitKey(10);
				}
				else if (i > 300 && j > 100)
				{
					flag = 1;
					break;
				}
			}
			if (1==flag)
			{
				break;
			}
		}
    }

如果(1)处不是画圆,也是填充的话,那这个矩形就是一个横着的绿色矩形,而(2)处是一个竖着的红色矩形,大小一样。

  • 【坚持才是最难能可贵的】

猜你喜欢

转载自blog.csdn.net/yishuihanq/article/details/108638921