关于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)处是一个竖着的红色矩形,大小一样。
- 【坚持才是最难能可贵的】