【问题标题】:calculate box around square计算正方形周围的框
【发布时间】:2018-12-02 02:24:02
【问题描述】:

我想检测如下图像中的正方形:

我想通过在正方形角周围绘制一种 3 维 框来突出显示正方形,如下图所示:

如何准确计算所有线坐标以便稍后绘制“3 维”框? (给出的是黑色方块的四个角点)

注意:你可以在这里https://www.youtube.com/watch?v=oSq9V2b5AZ8找到我想要实现的视频。

如果您愿意帮助我,如果您分享一些代码行如何计算 4 个缺失点以及如何知道哪些点匹配在一起以绘制从 startPoint(x,y) 到 endPoint 的线,我将非常高兴(x,y)。例如 js 中的一些行会有很大帮助 :)

【问题讨论】:

  • 我没有尝试发布答案,如果您要尝试帮助人们尝试提供帮助,那么我不会打扰。至于你的问题,它对 SO 来说太宽泛了,因此离题了
  • @Pete 我真的不认为它很广泛。此外,还发布了一个可行的解决方案!!
  • 请注意,“方形”标签是针对Square POS software 的API,而不是几何图形,因此您应该删除它。 ;-)

标签: javascript opencv math triangulation


【解决方案1】:

首先找到你的轮廓,然后选择极值点。然后指定新的 3D 角并使用 cv2.line() 绘制它们。

例子:

import cv2
import numpy as np
import imutils

image = cv2.imread('3d2.png')

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (5, 5), 0)
thresh = cv2.threshold(gray, 190, 255, cv2.THRESH_BINARY)[1]
cv2.bitwise_not(thresh, thresh)

cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
        cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if imutils.is_cv2() else cnts[1]
c = max(cnts, key=cv2.contourArea)

extLeft = tuple(c[c[:, :, 0].argmin()][0])
extRight = tuple(c[c[:, :, 0].argmax()][0])
extTop = tuple(c[c[:, :, 1].argmin()][0])
extBot = tuple(c[c[:, :, 1].argmax()][0])

leftx = int(extLeft[0])
lefty = int(extLeft[1]) - 90

rightx = int(extRight[0])
righty = int(extRight[1]) -90

topx = int(extTop[0])
topy = int(extTop[1]) -90

bottomx = int(extBot[0])
bottomy = int(extBot[1]) -90

leftc = (leftx, lefty)
rightc = (rightx, righty)
topc = (topx, topy)
bottomc = (bottomx, bottomy)

line = cv2.line(image, extLeft, leftc, (0,255,0), 2)
line = cv2.line(image, extRight, rightc, (0,255,0), 2)
line = cv2.line(image, extTop, topc, (0,255,0), 2)
line = cv2.line(image, extBot, bottomc, (0,255,0), 2)
line = cv2.line(image, bottomc, leftc, (0,255,0), 2)
line = cv2.line(image, rightc, topc, (0,255,0), 2)
line = cv2.line(image, leftc, topc, (0,255,0), 2)
line = cv2.line(image, rightc, topc, (0,255,0), 2)
line = cv2.line(image, bottomc, rightc, (0,255,0), 2)
cv2.drawContours(image, [c], -1, (0,255,0), 2)

cv2.imshow("Image", image)
cv2.imwrite('3Dbox1.png', image)
cv2.waitKey(0)

结果:

您可以按照自己的意愿提出新的观点(例如,如果您希望与图片中的相同,则给出 x+50 和 y-150):

编辑:

要使盒子旋转,请尝试使用您可以从 cv2.minAreaRect() 函数获得的角度,如下所示:

import cv2
import numpy as np
import imutils

cap = cv2.VideoCapture(0)

while True:

    try:
        ret, image = cap.read()

        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        gray = cv2.GaussianBlur(gray, (5, 5), 0)
        thresh = cv2.threshold(gray, 190, 255, cv2.THRESH_BINARY)[1]
        #cv2.bitwise_not(thresh, thresh)

        cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
                cv2.CHAIN_APPROX_SIMPLE)
        cnts = cnts[0] if imutils.is_cv2() else cnts[1]
        c = max(cnts, key=cv2.contourArea)

        rect = cv2.minAreaRect(c)
        angle = rect[2]


        extLeft = tuple(c[c[:, :, 0].argmin()][0])
        extRight = tuple(c[c[:, :, 0].argmax()][0])
        extTop = tuple(c[c[:, :, 1].argmin()][0])
        extBot = tuple(c[c[:, :, 1].argmax()][0])

        if angle < 0:

            leftx = int(extLeft[0]) - int(angle)
            lefty = int(extLeft[1]) - 50 + int(angle)

            rightx = int(extRight[0]) - int(angle)
            righty = int(extRight[1]) -50 + int(angle)

            topx = int(extTop[0]) - int(angle)
            topy = int(extTop[1]) -50 + int(angle) 

            bottomx = int(extBot[0]) - int(angle)
            bottomy = int(extBot[1]) -50 + int(angle)

            leftc = (leftx, lefty)
            rightc = (rightx, righty)
            topc = (topx, topy)
            bottomc = (bottomx, bottomy)

            line = cv2.line(image, extLeft, leftc, (0,255,0), 2)
            line = cv2.line(image, extRight, rightc, (0,255,0), 2)
            line = cv2.line(image, extTop, topc, (0,255,0), 2)
            line = cv2.line(image, extBot, bottomc, (0,255,0), 2)
            line = cv2.line(image, bottomc, leftc, (0,255,0), 2)
            line = cv2.line(image, rightc, topc, (0,255,0), 2)
            line = cv2.line(image, leftc, topc, (0,255,0), 2)
            line = cv2.line(image, rightc, topc, (0,255,0), 2)
            line = cv2.line(image, bottomc, rightc, (0,255,0), 2)
            cv2.drawContours(image, [c], -1, (0,255,0), 2)

        elif angle > 0:

            leftx = int(extLeft[0]) + int(angle)
            lefty = int(extLeft[1]) + 50 + int(angle)

            rightx = int(extRight[0]) + int(angle)
            righty = int(extRight[1]) +50 + int(angle)

            topx = int(extTop[0]) + int(angle)
            topy = int(extTop[1]) +50 + int(angle) 

            bottomx = int(extBot[0]) + int(angle)
            bottomy = int(extBot[1]) +50 + int(angle)

            leftc = (leftx, lefty)
            rightc = (rightx, righty)
            topc = (topx, topy)
            bottomc = (bottomx, bottomy)

            line = cv2.line(image, extLeft, leftc, (0,255,0), 2)
            line = cv2.line(image, extRight, rightc, (0,255,0), 2)
            line = cv2.line(image, extTop, topc, (0,255,0), 2)
            line = cv2.line(image, extBot, bottomc, (0,255,0), 2)
            line = cv2.line(image, bottomc, leftc, (0,255,0), 2)
            line = cv2.line(image, rightc, topc, (0,255,0), 2)
            line = cv2.line(image, leftc, topc, (0,255,0), 2)
            line = cv2.line(image, rightc, topc, (0,255,0), 2)
            line = cv2.line(image, bottomc, rightc, (0,255,0), 2)
            cv2.drawContours(image, [c], -1, (0,255,0), 2)

    except:
        pass

    cv2.imshow("Image", image)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

【讨论】:

  • 这是一个不错的微小解决方案,但它并不是我真正想要实现的目标:/您的解决方案并不是真正的透视 3 维立方体,它是一个“假”的 2 维立方体,因为它的价值x / y 转换应该是计算而不是硬编码。因此,使用给定值(如您的情况:-90)旋转正方形或对图像应用某种倾斜会破坏正确的视角。这与您在我链接的视频中可以找到的情况并不完全相同。不管怎么说,多谢拉。 +1
  • 我添加了几行...不知道它是否会起作用,因为我没有相同的视频,但我认为它可能会起作用。
  • 当角度为负数或正数时,可能必须添加 if 语句来改变加法到减法,反之亦然......
  • 更新:如果不从 Y 坐标减小角度会更好
  • Tbh 这不是一个 100% 有效的解决方案,而且确实不是我所期望的(参见顶部的评论),但在某些情况下它工作得很好。你会得到正确的分数,因为看起来你投入了很多时间,如果其他人甚至没有人得到分数,那将是不公平的。非常感谢。问候 - 乔纳斯
【解决方案2】:

如果您的照片是等距视图,则这会简化为以下问题:

您想要找到对应于立方体三个正交边的三个向量的测量值。

Edge1:(X1,Y1,Z1)
边 2:(X2,Y2,Z2)
Edge3:(X3,Y3,Z3)

从您的图像中,您可以测量其中两个向量的 X 和 Y 值,留下 5 个未知值。

由于所有三个边都是正交的,因此您也知道它们的点积为零。

最后,由于您正在处理一个立方体,您知道每个向量具有相同的大小。

这为您提供了五个方程来求解五个未知变量,它们可以唯一地标识一个解。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-30
    • 2011-12-04
    • 1970-01-01
    • 2018-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多