【问题标题】:OpenCV Point(x,y) represent (column,row) or (row,column)OpenCV Point(x,y) 表示 (column,row) 或 (row,column)
【发布时间】:2021-12-21 01:41:54
【问题描述】:

我在矩阵src 中有一张 300x200 的图像。我正在对图片做如下操作。

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&lt;uchar&gt;(i,j) 使用(i,j) 作为(行,列),但Point(x,y) 使用(x,y) 作为(列,行)

【问题讨论】:

  • 没错。文档说了很多 - Point(x,y) 和 at(row,col) 是它的实现方式。
  • 是的。点和大小 go (x,y); (width,height) ,- Mat 有 (row,col)。
  • 感谢您提出这个问题。这种该死的不一致花费了我数小时的调试时间......

标签: c++ opencv


【解决方案1】:

因此,这意味着 src.at(i,j) 使用 (i,j) 作为(行、列)但 Point(x,y) 使用 (x,y) 作为(列、行)

没错!因为这似乎让很多人感到困惑,所以我会写下我的解释:

在 OpenCV 中,cv::Mat 用于图像和矩阵,因为离散图像与矩阵基本相同。

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

  1. 矩阵,有许多行和许多列。
  2. (函数的)图形,具有多个轴并以图像的形式以图形方式表示图形。
  3. 点,按坐标系的轴排序,通常是笛卡尔坐标。

1.对于矩阵,数学符号是按行主要顺序排列的,即

按照传统的矩阵表示法,行由二维数组的第一个索引编号,列由第二个索引编号,即 a1,2 是第一行的第二个元素,向下和向右计数。 (注意这与笛卡尔约定相反。)

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

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

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

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

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

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

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

所以在一个完美的世界中,我们会选择点/图像的坐标系为:

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

但由于我们希望该原点位于左上角并且正值位于底部,因此改为:

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

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

因此,在 OpenCV 中,您可以使用:mat.at&lt;type&gt;(row,column)mat.at&lt;type&gt;(cv::Point(x,y)) 访问同一点,如果 x=columny=row 完全可以理解 =)

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

【讨论】:

  • 有趣的事实:在学校我一开始不太容易记住矩阵索引的顺序,所以我有根据的猜测是“列索引可能是第一个,因为它与 x 轴的方向相同,这是第一个点”......不幸的是错了:-(
  • 你所说的“图(函数)”是什么意思?抱歉,我没听懂。您能否详细说明一下或分享任何有用的资源?谢谢!
  • (函数的)图形是数学中的可视化,类似于图像,其中 x 和 y 坐标方向按惯例给出。
  • 哦,现在,我明白了。我把它与“图形——一种数据结构”和“函数——在编程中”混淆了:-D 感谢您的澄清:)
【解决方案2】:

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

通过这种方式,我能够使用我现有的算法和所有标准的笛卡尔系统方程与 opencv,而无需通过在坐标系之间进行昂贵的转换而给系统带来太多开销。

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

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

【讨论】:

  • 我正在尝试将 opencv 坐标转换为笛卡尔坐标。你能解释一下你是怎么做到的吗?我正在使用python。并获得 x, y 与 x,y,w,h = cv2.boundingRect(c) 函数协同。谢谢
  • 只是想说我之前给出的答案是错误的。这是正确的,引号中的标记更改
  • 因此,在坐标的“纵坐标”上添加一个 -ve 符号,即将“y”更改为“-y”,它应该可以完成这项工作。 w, h 可以保持原样,因为它们不是坐标
  • 为什么这样有效?在 OpenCV 世界中,当沿水平轴从左到右移动时,我们看到坐标增加,当沿着垂直轴从上到下移动时,坐标增加。在笛卡尔系统的第四象限中观察到这种行为。
【解决方案3】:

这是一个直观的示例,用于区分 python 的 [row, columns] 和 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')

这将输出:

【讨论】:

    【解决方案4】:

    通常,指向 OpenCV 后跟 (x, y)。 x 在计算机屏幕上是按列排列的,而 y 是按行排列的。这是使用内置circle 函数的示例。

    win_name = "Test"
        
    image_width, image_height = 300, 200
    center_x, center_y = 300, 0
       
    circle_radius = 9 
        
    # Create a black image
    img = np.zeros((image_height, image_width, 3), np.uint8)
    # BGR
    cv2.circle(img, center=tuple([center_x, center_y]), 
        radius=circle_radius, color=(255,0,0), 
        thickness=-1)
            
    # Open openCV window
    cv2.namedWindow(win_name, cv2.WINDOW_NORMAL)
    cv2.resizeWindow(win_name, image_width, image_height)
    cv2.moveWindow(win_name, 120, 850)
    cv2.setWindowTitle(win_name, win_name)
    cv2.imshow(win_name, img) 
    k = cv2.waitKey(0)
    

    顺便说一句,他们在制作图像时遵循高度和宽度顺序,并且 BGR 颜色格式不是 RGB。这与传统相反。

    【讨论】:

      猜你喜欢
      • 2018-01-31
      • 2014-07-26
      • 1970-01-01
      • 1970-01-01
      • 2020-06-12
      • 2013-03-28
      相关资源
      最近更新 更多