如何使用相机计算方形物体相对于二维平面图像的角度?
How to calculate Angle of a square object with respect to image in 2D plane using camera?
我使用网络摄像头拍摄了一张图像,将其倒置在 table 水平上方。在 table 上,我有一个方形物体或一张卡片。我已经成功检测到物体并找到它的中心坐标(质心)。现在我想找到物体相对于图像的旋转角度。考虑 2D 图像平面中的所有内容。我如何计算角度?
这张图片代表了我想要实现的目标:
我得到了解决方案。正如我在上面的问题中所说,我编写代码来执行所需的操作。我正在使用 OpenCV 4 + Python 3.8.3 + Spyder IDE
这是我的工作代码:
# This code is used to Find the Origin and Rotation Angle of a Rectangle
#First of all place a blue colored rectangle card on the table below the camera
# Then execute the code. The code will detect the Rectangle in Blue color then find the origin and rotation values.
#[Resources]
#
# https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_contours/py_contours_begin/py_contours_begin.html#how-to-draw-the-contours
# https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_contours/py_contour_features/py_contour_features.html#b-rotated-rectangle
#
import numpy as np
import cv2
import sys
import yaml
import os
import warnings
warnings.filterwarnings("ignore")
#Global Variables
cx = 0.0 #x locaton of Rectangle
cy = 0.0 #y location of Rectangle
angle = 0.0 #Angle of rotation of Rectangle
if __name__ == "__main__":
while(1):
try:
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
while(1):
_,frame = cap.read()
k = cv2.waitKey(5)
if k == 27: #exit by pressing Esc key
cv2.destroyAllWindows()
sys.exit()
if k == 13: #Save the centroid and angle values of the rectangle in a file
result_file = r'rectangle_position.yaml'
try:
os.remove(result_file) #Delete old file first
except:
pass
print("Saving Rectangle Position Matrix in: ",result_file)
data={"rect_position": [cx,cy,angle]}
with open(result_file, "w") as f:
yaml.dump(data, f, default_flow_style=False)
#Detecting Blue Color
red = np.matrix(frame[:,:,2]) #extracting red layer (layer No 2) from RGB
green = np.matrix(frame[:,:,1]) #extracting green layer (layer No 1) from RGB
blue = np.matrix(frame[:,:,0]) #extracting blue layer (layer No 0) from RGB
#it will display only the Blue colored objects bright with black background
blue_only = np.int16(blue)-np.int16(red)-np.int16(green)
blue_only[blue_only<0] =0
blue_only[blue_only>255] =255
blue_only = np.uint8(blue_only)
# cv2.namedWindow('blue_only', cv2.WINDOW_AUTOSIZE)
# cv2.imshow("blue_only",blue_only)
# cv2.waitKey(1)
#https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_thresholding/py_thresholding.html#otsus-binarization
#Gaussian filtering
blur = cv2.GaussianBlur(blue_only,(5,5),cv2.BORDER_DEFAULT)
#Otsu's thresholding
ret3,thresh = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
cv2.namedWindow('Threshold', cv2.WINDOW_AUTOSIZE)
cv2.imshow("Threshold",thresh)
cv2.waitKey(1)
#Finding Conture of detected Rectangle
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
for contour in contours:
area = cv2.contourArea(contour)
if area>100000:
contours.remove(contour)
cnt = contours[0] #Conture of our rectangle
#
#fit bounding rectangle around contour
rotatedRect = cv2.minAreaRect(cnt)
#getting centroid, width, height and angle of the rectangle conture
(cx, cy), (width, height), angle = rotatedRect
#centetoid of the rectangle conture
cx=int(cx)
cy=int(cy)
print (cx,cy) #centroid of conture of rectangle
# we want to choose the Shorter edge of the rotated rect to compute the angle between Vertical
#
if(width > height):
angle = angle+180
else:
angle = angle+90
print("Angle b/w shorter side with Image Vertical: \n", angle)
#Draw rectangle around the detected object
#https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_contours/py_contours_begin/py_contours_begin.html#how-to-draw-the-contours
im = cv2.drawContours(frame,[cnt],0,(0,0,255),2)
cv2.circle(im, (cx,cy), 2,(200, 255, 0),2) #draw center
cv2.putText(im, str("Angle: "+str(int(angle))), (int(cx)-40, int(cy)+60), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,0,255), 1, cv2.LINE_AA)
cv2.putText(im, str("Center: "+str(cx)+","+str(cy)), (int(cx)-40, int(cy)-50), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,0,255), 1, cv2.LINE_AA)
cv2.namedWindow('Detected Rect', cv2.WINDOW_AUTOSIZE)
cv2.imshow('Detected Rect',im)
cv2.waitKey(1)
except Exception as e:
print("Error in Main Loop\n",e)
cv2.destroyAllWindows()
sys.exit()
cv2.destroyAllWindows()
代码运行良好,可以计算矩形的原点及其相对于图像垂直的旋转角度。
结果:
我从这些链接获得了帮助:
- https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_contours/py_contours_begin/py_contours_begin.html#how-to-draw-the-contours
- https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_contours/py_contour_features/py_contour_features.html#b-rotated-rectangle
我使用网络摄像头拍摄了一张图像,将其倒置在 table 水平上方。在 table 上,我有一个方形物体或一张卡片。我已经成功检测到物体并找到它的中心坐标(质心)。现在我想找到物体相对于图像的旋转角度。考虑 2D 图像平面中的所有内容。我如何计算角度? 这张图片代表了我想要实现的目标:
我得到了解决方案。正如我在上面的问题中所说,我编写代码来执行所需的操作。我正在使用 OpenCV 4 + Python 3.8.3 + Spyder IDE
这是我的工作代码:
# This code is used to Find the Origin and Rotation Angle of a Rectangle
#First of all place a blue colored rectangle card on the table below the camera
# Then execute the code. The code will detect the Rectangle in Blue color then find the origin and rotation values.
#[Resources]
#
# https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_contours/py_contours_begin/py_contours_begin.html#how-to-draw-the-contours
# https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_contours/py_contour_features/py_contour_features.html#b-rotated-rectangle
#
import numpy as np
import cv2
import sys
import yaml
import os
import warnings
warnings.filterwarnings("ignore")
#Global Variables
cx = 0.0 #x locaton of Rectangle
cy = 0.0 #y location of Rectangle
angle = 0.0 #Angle of rotation of Rectangle
if __name__ == "__main__":
while(1):
try:
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
while(1):
_,frame = cap.read()
k = cv2.waitKey(5)
if k == 27: #exit by pressing Esc key
cv2.destroyAllWindows()
sys.exit()
if k == 13: #Save the centroid and angle values of the rectangle in a file
result_file = r'rectangle_position.yaml'
try:
os.remove(result_file) #Delete old file first
except:
pass
print("Saving Rectangle Position Matrix in: ",result_file)
data={"rect_position": [cx,cy,angle]}
with open(result_file, "w") as f:
yaml.dump(data, f, default_flow_style=False)
#Detecting Blue Color
red = np.matrix(frame[:,:,2]) #extracting red layer (layer No 2) from RGB
green = np.matrix(frame[:,:,1]) #extracting green layer (layer No 1) from RGB
blue = np.matrix(frame[:,:,0]) #extracting blue layer (layer No 0) from RGB
#it will display only the Blue colored objects bright with black background
blue_only = np.int16(blue)-np.int16(red)-np.int16(green)
blue_only[blue_only<0] =0
blue_only[blue_only>255] =255
blue_only = np.uint8(blue_only)
# cv2.namedWindow('blue_only', cv2.WINDOW_AUTOSIZE)
# cv2.imshow("blue_only",blue_only)
# cv2.waitKey(1)
#https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_thresholding/py_thresholding.html#otsus-binarization
#Gaussian filtering
blur = cv2.GaussianBlur(blue_only,(5,5),cv2.BORDER_DEFAULT)
#Otsu's thresholding
ret3,thresh = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
cv2.namedWindow('Threshold', cv2.WINDOW_AUTOSIZE)
cv2.imshow("Threshold",thresh)
cv2.waitKey(1)
#Finding Conture of detected Rectangle
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
for contour in contours:
area = cv2.contourArea(contour)
if area>100000:
contours.remove(contour)
cnt = contours[0] #Conture of our rectangle
#
#fit bounding rectangle around contour
rotatedRect = cv2.minAreaRect(cnt)
#getting centroid, width, height and angle of the rectangle conture
(cx, cy), (width, height), angle = rotatedRect
#centetoid of the rectangle conture
cx=int(cx)
cy=int(cy)
print (cx,cy) #centroid of conture of rectangle
# we want to choose the Shorter edge of the rotated rect to compute the angle between Vertical
#
if(width > height):
angle = angle+180
else:
angle = angle+90
print("Angle b/w shorter side with Image Vertical: \n", angle)
#Draw rectangle around the detected object
#https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_contours/py_contours_begin/py_contours_begin.html#how-to-draw-the-contours
im = cv2.drawContours(frame,[cnt],0,(0,0,255),2)
cv2.circle(im, (cx,cy), 2,(200, 255, 0),2) #draw center
cv2.putText(im, str("Angle: "+str(int(angle))), (int(cx)-40, int(cy)+60), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,0,255), 1, cv2.LINE_AA)
cv2.putText(im, str("Center: "+str(cx)+","+str(cy)), (int(cx)-40, int(cy)-50), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,0,255), 1, cv2.LINE_AA)
cv2.namedWindow('Detected Rect', cv2.WINDOW_AUTOSIZE)
cv2.imshow('Detected Rect',im)
cv2.waitKey(1)
except Exception as e:
print("Error in Main Loop\n",e)
cv2.destroyAllWindows()
sys.exit()
cv2.destroyAllWindows()
代码运行良好,可以计算矩形的原点及其相对于图像垂直的旋转角度。
结果:
我从这些链接获得了帮助:
- https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_contours/py_contours_begin/py_contours_begin.html#how-to-draw-the-contours
- https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_contours/py_contour_features/py_contour_features.html#b-rotated-rectangle