OpenCV Point(x,y)表示(列,行)或(行,列)


77

我在Matrix中有一个300x200的图片src。我正在对图像执行以下操作。

for(int i=0;i<src.rows;i++){
  for(int j=0;j<src.cols;j++){
    line( src, Point(i,j),Point(i,j), Scalar( 255, 0, 0 ),  1,8 );
  }
}
imshow("A",src);
waitKey(0);

我期望它能以白色覆盖整个图像,但是图像的下部仍然是空白。如果我这样做

  for(int i=0;i<src.rows;i++){
    for(int j=0;j<src.cols;j++){
      src.at<uchar>(i,j)=255;
    }
  }
  imshow("A",src);
  waitKey(0);

整个图像以白色覆盖。因此,这意味着src.at<uchar>(i,j)正在使用(i,j)as(row,column)但Point(x,y)正在使用(x,y)as(column,row)


2
没错 该文档说了很多-Point(x,y)和at(row,col)是实现它的方式。
罗杰·罗兰

1
是。点数和大小为(x,y); (宽度,高度),-垫有(行,col)。
berak

1
感谢您提出这个问题。这个该死的不一致花费了我数小时的调试...
yuqli

Answers:


119

因此,这意味着src.at(i,j)正在使用(i,j)as(row,column)但Point(x,y)正在使用(x,y)as(column,row)

没错!由于这似乎使许多人感到困惑,因此我将解释写在下面:

在OpenCV中,cv::Mat由于离散图像基本上与矩阵相同,因此可同时用于图像和矩阵。

在数学中,我们有一些不同的东西:

  1. 具有多个行和多个列的矩阵。
  2. 具有多个轴的(功能)图形,并以图像形式图形表示图形。
  3. 点,由坐标系统的轴排序,该坐标系通常是笛卡尔坐标。

1.对于矩阵,数学符号按行优先顺序排列,即

按照常规矩阵符号,行由二维数组的第一个索引编号,列由第二个索引编号,即a1,2是第一行的第二个元素,向下和向右计数。(请注意,这与笛卡尔惯例相反。)

取自http://en.wikipedia.org/wiki/Row-major_order#Explanation_and_example

与数学一样,第0行,第0列是矩阵的左上角元素。行/列就像表格中的...

0/0---column--->
 |
 |
row
 |
 |
 v

2.对于Points,选择一个满足以下两个条件的坐标系:1.它使用与矩阵符号相同的单位大小和相同的“原点”,因此左上角是Point(0,0)和轴长1表示1行或1列的长度。2.它使用“图像符号”进行轴排序,这意味着横坐标(水平轴)是指定x方向的第一个值,而纵坐标(垂直轴)是指定y方向的第二个值。

轴相交的点是两条数字线的共同原点,简称为原点。通常将其标记为O,如果这样,则将轴称为Ox和Oy。定义了x轴和y轴的平面通常称为笛卡尔平面或xy平面。x的值称为x坐标或横坐标,而y的值称为y坐标或纵坐标。

字母的选择来自原始约定,即使用字母的后半部分指示未知值。字母的第一部分用于指定已知值。

http://zh.wikipedia.org/wiki/Cartesian_coordinate_system#Two_dimensions

因此,在理想世界中,我们将点/图像的坐标系选择为:

 ^
 |
 |
 Y
 |
 |
0/0---X--->

但由于我们希望该原点位于左上角,而正值要移至最底端,因此它是:

0/0---X--->
 |
 |
 Y
 |
 |
 v

因此,对于图像处理人员来说,行优先表示法可能很奇怪,但是对于数学家来说,x轴优先表示法访问矩阵是很奇怪的。

因此,在OpenCV中,如果和完全可理解=),则可以使用:mat.at<type>(row,column)mat.at<type>(cv::Point(x,y))访问同一点。x=columny=row

希望这个正确。我对这些符号了解不多,但这就是我在数学和图像处理方面的经验告诉我的。


2
有趣的事实:在学校里,我不容易记住起初的矩阵索引顺序,因此我的有根据的猜测是“列索引可能首先出现,因为它与x轴的方向相同,而x轴是第一个点”。不幸的是,错了:-(
米卡

“功能图”是什么意思?抱歉,我没听懂。您能否对此进行详细说明或共享任何有用的资源?谢谢!
米兰

(函数的)图是数学中的可视化图像,类似于图像,其中x和y坐标方向按惯例给出。
米卡

1
哦,现在,我明白了。我曾将其与“图形-数据结构”和“函数-编程中”混淆:-D感谢您澄清:)
米兰

5

通过将坐标从opencv转换为第四象限的笛卡尔坐标,我发现了一个快速解决此问题的方法,只需将(-)ve符号放在y坐标前面即可。

这样,我能够通过opencv使用我现有的算法和所有标准的笛卡尔系统方程,而无需通过在坐标系之间进行昂贵的转换而在系统上增加很多开销。

0/0---X--->
 |
 |
 Y
 |
 |
 v
 (opencv)

0/0---X----> 
|
|
|
-Y
|
|
v
(4th quadrant)

我正在尝试将opencv坐标转换为笛卡尔坐标。你能解释一下你是怎么做到的。我正在使用python。并使用x,y,w,h = cv2.boundingRect(c)函数获得x,y代词。谢谢
SergioGeeK7 '17

只是想说我先前给出的答案是错误的。这是正确的引号中的明显变化
Dev Aggarwal

因此,在坐标的“坐标”上添加-ve符号,即将“ y”更改为“ -y”,这样就可以完成工作。w,h可能会保留,因为它们不是坐标
Dev Aggarwal

为什么这样有效?在OpenCV世界中,当沿水平轴“从左到右”移动时,我们看到坐标增加,而当沿垂直轴从上到下移动时,坐标增加。在笛卡尔系统的第四象限中观察到这种行为。
Dev Aggarwal

3

这是一个视觉示例,可将python的[行,列]与OpenCV的[x,y]区分开。

import numpy as np
import matplotlib.pyplot as plt
import cv2

img = np.zeros((5,5))  # initialize empty image as numpy array
img[0,2] = 1  # assign 1 to the pixel of row 0 and column 2

M = cv2.moments(img)  # calculate moments of binary image
cX = int(M["m10"] / M["m00"])  # calculate x coordinate of centroid
cY = int(M["m01"] / M["m00"])  # calculate y coordinate of centroid

img2 = np.zeros((5,5))  # initialize another empty image
img2[cX,cY] = 1  # assign 1 to the pixel with x = cX and y = cY

img3 = np.zeros((5,5))  # initialize another empty image
img3[cY,cX] = 1  # invert x and y

plt.figure()
plt.subplots_adjust(wspace=0.4)  # add space between subplots
plt.subplot(131), plt.imshow(img, cmap = "gray"), plt.title("With [rows,cols]")
plt.subplot(132), plt.imshow(img2, cmap = "gray"), plt.title("With [x,y]")
plt.subplot(133), plt.imshow(img3, cmap= "gray"), plt.title("With [y,x]"), plt.xlabel('x'), plt.ylabel('y')

这将输出:

在此处输入图片说明

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.