【问题标题】:How can I decide the points which I should give in cv2.getPerspectiveTransform()?我如何决定我应该在 cv2.getPerspectiveTransform() 中给出的分数?
【发布时间】:2020-09-04 18:56:59
【问题描述】:

我正在尝试扭曲下面的图像,以便获得更大的墙的正面平行视图,即图像左侧的墙。但是,我无法决定应该在函数 cv2.getPerspectiveTransform() 中给出哪些点,以便获得矩阵,如果应用该矩阵会产生所需的结果。

我使用的代码是:

import cv2
import numpy as np

circles = np.zeros((4,2),np.int)
counter = 0

def mousePoints(event,x,y,flags,params):
    global counter
    if event == cv2.EVENT_LBUTTONDOWN:

        circles[counter] = x,y
        counter = counter + 1
        print(circles)

img = cv2.imread("DSC_0273.JPG")

img = cv2.resize(img,(1500,1000))
q = 0
while True:

    if counter == 4:
        q = q+1

        height1,width1 = 1080,1920
        pts1 = np.float32([circles[0],circles[1],circles[2],circles[3]])
        width = np.sqrt((circles[1][0] - circles[0][0])**2 + (circles[1][1] - circles[0][1])**2)
        height =  np.sqrt((circles[2][1] - circles[0][1])**2 + (circles[2][0] - circles[0][0])**2)
        width = int(np.round(width))
        height = int(np.round(height))
        x1,y1 = circles[0]
    
        pts2 = np.float32([[x1,y1],[(x1+width),y1],[(x1+width),(y1+height)],[x1,(y1+height)]])
        matrix = cv2.getPerspectiveTransform(pts1,pts2)

        if q == 1:
            print(matrix.shape)
            print(matrix)
        imgOutput = cv2.warpPerspective(img,matrix,(width1,height1))
        cv2.imshow("Output Image ", imgOutput)


for x in range (0,4):
    cv2.circle(img,(circles[x][0],circles[x][1]),3,(0,255,0),cv2.FILLED)

cv2.imshow("Original Image ", img)
cv2.setMouseCallback("Original Image ", mousePoints)
cv2.waitKey(1)

所以基本上,我点击 4 个点,我的代码将找到扭曲矩阵,以便将这 4 个点内的区域映射到一个矩形,这样我给出的第一个点就会映射到相同的像素位置,并且调整其他4个点,使包围变成一个矩形。为了推断这一点,我在整个图像上应用了相同的矩阵。 我试过的一组点(通过鼠标点击给出的4个点)是: [[349, 445], [396, 415],[388, 596], [338, 610]] 我得到的结果是:

【问题讨论】:

  • 请将您的代码编辑到您的问题中,并显示您尝试过的要点,以及您得到的结果。
  • 给出了典型的描述和匹配的关键点,如 sift 或 surf 或 orb,因为它们被设计为在不同的图像中匹配。
  • @barny 根据你的要求,我已经添加了我的代码、我使用的一组点以及我得到的输出。
  • @Micka 恐怕我不清楚你的意思。你能详细说明一下吗?
  • 请修正你的代码缩进 - 它现在不会执行。想象一下,我想亲自尝试您的代码,我需要能够将其粘贴到文件中并运行它 - 所以我需要一个 minimal reproducible example

标签: python opencv image-processing perspective


【解决方案1】:

我无法让您的代码正常工作,坦率地说,当有问题的代码不是最小的可重现示例时,这真的很痛苦,我只是坚持,因为我对这个问题感兴趣 - 我不明白您的代码是怎样的应该收集四次鼠标点击然后处理透视图但是你的缩进是垃圾。

每次运行都必须点击点的一个问题是很难获得可比较的运行 - 所以我收集了一次点击并使用这些点击来检查。

我遇到的一个问题是点击的顺序。 AFAICT 获得工作转换的正确顺序是左上、右上、左下、右下。令人困惑的是,您在问题中列出的点顺序并非如此。我不得不交换 pts2 中的最后两个值以对应正确的序列。也许两个交换相互补偿,我没有精力去猜测你的非工作代码。

您的点相对接近 - 我认为您会通过更广泛的点获得更好的结果。请注意“更好”而不是“完美” - 我认为您正在尝试做的事情没有“完美”,因为透视失真是如此之大,WarpPerspective 无法神奇地重新投影图像中的不同深度。

将输出与输入进行比较也很困难,因为点击的位置在输入或输出上不可见。

我不确定的另一件事是调整我下载的寺庙源图像的大小(如果 1500 宽 x 1000 高)。忽略这个。

说了这么多,我认为你得到的几乎就是你应该得到的。是的,它非常失真,但扭曲透视是一种简单的 2D 操作,它并没有声称可以进行重投影,从而导致镜头失真。

这是您的代码的简化版本,它使用四个固定点 - 我在转换之前将它们覆盖在源图像上,以便它们在输出图像中可见 - 您还可以在输入图像上覆盖网格线并查看这些看起来像在输出图像中。是的,输出确实包含四个绿点,由于转换,右边的两个非常小。例如,您可以检查拱门的尖端是否对齐 - 显然其中的 3-d 内容看起来很奇怪,但正如我所说,没有魔杖。

import cv2
import numpy as np

circles = np.zeros((4,2),np.int)

circles = [(349, 473), (903, 158),(336, 713), (918, 758) ]

img = cv2.imread("temple.JPG")

for x in range (0,4):
    cv2.circle(img,(circles[x][0],circles[x][1]),3,(0,255,0),cv2.FILLED)

cv2.imshow("Original Image ", img)

cv2.waitKey(-1)
    
height1,width1 = 1080,1920

pts1 = np.float32([circles[0],circles[1],circles[2],circles[3]])
width = np.sqrt((circles[1][0] - circles[0][0])**2 + (circles[1][1] - circles[0][1])**2)
height =  np.sqrt((circles[2][1] - circles[0][1])**2 + (circles[2][0] - circles[0][0])**2)
width = int(np.round(width))
height = int(np.round(height))
x1,y1 = circles[0]

print( f"{x1=} {y1=} {width=} {height=}")

# NOTE the third and fourth values are swapped from the original code
pts2 = np.float32([[x1,y1],[(x1+width),y1],[x1,(y1+height)],[(x1+width),(y1+height)]])
matrix = cv2.getPerspectiveTransform(pts1,pts2)

print(matrix.shape)
print(matrix)

imgOutput = cv2.warpPerspective(img,matrix,(width1,height1))
cv2.imshow("Output Image ", imgOutput)

cv2.waitKey(-1)

输入点叠加的输入图像:

裁剪部分输出图像:

【讨论】:

  • 我真的很抱歉我的代码中的缩进搞砸了。它没有引起我的注意。
  • 我使用的顺序是左上、右上、右下然后左下。我认为这是造成混乱的原因。该代码对我来说确实可以正常工作,但我很困惑,无法清楚地给出 4 分来给出预期的结果。
  • 另外,您建议提供更多分散点而不是 4 个关闭点。为什么是这样?墙是直的刚体。所以如果我得到一个小墙内的变换矩阵,并将其应用于整面墙,我应该在技术上正确地扭曲整面墙,对吧?
  • 点越分散,精度越高。这个概念是识别建筑物中水平和垂直直线上的点。因此,请使用建筑物上的线条,并尝试想象它们如何在垂直于您要矫正的面部观看时形成一个矩形。请记住,透视变换会保留所有直线。通常地平面会形成一条直线。因此,建筑物和地面相交的地方将是一个好地方。但是,您的图像会因广角镜头而产生一些桶形失真。所以地面有点弯曲。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多