计算方盒

时间:2018-06-22 15:03:34

标签: javascript opencv math triangulation

我想在下面的图像中检测一个正方形:

image 1

我想通过在正方形的角上画一个 3维框来突出显示正方形,如下图所示:

image 2

如何精确计算所有线坐标,以便稍后在“ 3维”框中绘制? (给出的是黑色正方形的4个角点)

image 4

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

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

2 个答案:

答案 0 :(得分:2)

首先找到轮廓,然后选择极限点。然后,您指定新的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)

结果:

enter image description here

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

enter image description here

编辑:

要使盒子旋转,请尝试使用从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

enter image description here

enter image description here

答案 1 :(得分:0)

如果您的照片是等轴测图,这将减少以下问题:

您想要找到与立方体的三个正交边相对应的三个向量的度量。

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

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

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

最后,由于您要处理一个多维数据集,所以您知道每个向量的大小都相同。

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