本文共 4885 字,大约阅读时间需要 16 分钟。
本文来源公众号“OpenCV与AI深度学习”,仅用于学术分享,侵权删,干货满满。
原文链接:
本文将介绍如何使用OpenCV确定对象的方向(即旋转角度,以度为单位)。
安装Python3.7或者更高版本。可以参考下文链接:
https://automaticaddison.com/how-to-set-up-anaconda-for-windows-10/
或者自行下载安装:
https://www.python.org/getit/
在我们开始之前,让我们确保我们已经安装了所有的软件包。检查您的机器上是否安装了OpenCV。如果你使用 Anaconda,你可以输入:
conda install -c conda-forge opencv
或者使用pip安装,指令:
pip install opencv-python
安装科学计算库 Numpy:
pip install numpy
找一张图片。我的输入图像宽度为 1200 像素,高度为 900 像素。我的输入图像的文件名是input_img.jpg。
这是代码。它接受一个名为input_img.jpg的图像并输出一个名为output_img.jpg的带注释的图像。部分代码来自官方 OpenCV 实现:
https://docs.opencv.org/4.x/d1/dee/tutorial_introduction_to_pca.html
代码示例:
import cv2 as cvfrom math import atan2, cos, sin, sqrt, piimport numpy as np def drawAxis(img, p_, q_, color, scale):p = list(p_)q = list(q_)angle = atan2(p[1] - q[1], p[0] - q[0]) # angle in radianshypotenuse = sqrt((p[1] - q[1])**2 + (p[0] - q[0])**2)q[0] = p[0] - scale * hypotenuse * cos(angle)q[1] = p[1] - scale * hypotenuse * sin(angle)cv.line(img, (int(p[0]), int(p[1])), (int(q[0]), int(q[1])), color, 3, cv.LINE_AA)p[0] = q[0] + 9 * cos(angle + pi / 4)p[1] = q[1] + 9 * sin(angle + pi / 4)cv.line(img, (int(p[0]), int(p[1])), (int(q[0]), int(q[1])), color, 3, cv.LINE_AA)p[0] = q[0] + 9 * cos(angle - pi / 4)p[1] = q[1] + 9 * sin(angle - pi / 4)cv.line(img, (int(p[0]), int(p[1])), (int(q[0]), int(q[1])), color, 3, cv.LINE_AA) def getOrientation(pts, img):sz = len(pts)data_pts = np.empty((sz, 2), dtype=np.float64)for i in range(data_pts.shape[0]):data_pts[i,0] = pts[i,0,0]data_pts[i,1] = pts[i,0,1]mean, eigenvectors, eigenvalues = cv.PCACompute2(data_pts, mean)cntr = (int(mean[0,0]), int(mean[0,1]))p1 = (cntr[0] + 0.02 * eigenvectors[0,0] * eigenvalues[0,0], cntr[1] + 0.02 * eigenvectors[0,1] * eigenvalues[0,0])p2 = (cntr[0] - 0.02 * eigenvectors[1,0] * eigenvalues[1,0], cntr[1] - 0.02 * eigenvectors[1,1] * eigenvalues[1,0])drawAxis(img, cntr, p1, (255, 255, 0), 1)drawAxis(img, cntr, p2, (0, 0, 255), 5)angle = atan2(eigenvectors[0,1], eigenvectors[0,0])label = " Rotation Angle: " + str(-int(np.rad2deg(angle)) - 90) + " degrees"textbox = cv.rectangle(img, (cntr[0], cntr[1]-25), (cntr[0] + 250, cntr[1] + 10), (255,255,255), -1)cv.putText(img, label, (cntr[0], cntr[1]), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0,0,0), 1, cv.LINE_AA)return angle img = cv.imread("input_img.jpg")if img is None:print("Error: File not found")exit(0)cv.imshow('Input Image', img)gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)bw = cv.threshold(gray, 50, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)contours, _ = cv.findContours(bw, cv.RETR_LIST, cv.CHAIN_APPROX_NONE)for i, c in enumerate(contours):area = cv.contourArea(c)if area < 3700 or 100000 < area:continuerect = cv.minAreaRect(c)box = cv.boxPoints(rect)box = np.int0(box)center = (int(rect[0][0]), int(rect[0][1]))width = int(rect[1][0])height = int(rect[1][1])angle = int(rect[2])if width < height:angle = 90 - angleelse:angle = -anglelabel = " Rotation Angle: " + str(angle) + " degrees"textbox = cv.rectangle(img, (center[0]-35, center[1]-25), (center[0] + 295, center[1] + 10), (255,255,255), -1)cv.putText(img, label, (center[0]-50, center[1]), cv.FONT_HERSHEY_SIMPLEX, 0.7, (0,0,0), 1, cv.LINE_AA)cv.drawContours(img,[box],0,(0,0,255),2)cv.imshow('Output Image', img)cv.waitKey(0)cv.destroyAllWindows()cv.imwrite("output_img.jpg", img) 使用PCA(主成分分析)方法获取物体的主方向,效果如下:
每个对象的正 x 轴是红线。每个对象的正 y 轴是蓝线。
全局正x 轴从左到右水平穿过图像。全局正z 轴指向此页外。全局正y 轴从图像底部垂直指向图像顶部。
使用右手定则测量旋转,将四根手指伸直(食指到小指)沿全局正 x 轴方向伸出。
如果我们要计算对象的方向并确保结果始终在 0 到 180 度之间,我们可以使用以下代码:
import cv2 as cvfrom math import atan2, cos, sin, sqrt, piimport numpy as npimg = cv.imread("input_img.jpg")if img is None: print("Error: File not found") exit(0)cv.imshow('Input Image', img)gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)bw = cv.threshold(gray, 50, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)contours, _ = cv.findContours(bw, cv.RETR_LIST, cv.CHAIN_APPROX_NONE)for i, c in enumerate(contours): area = cv.contourArea(c) if area < 3700 or 100000 < area: continue rect = cv.minAreaRect(c) box = cv.boxPoints(rect) box = np.int0(box) center = (int(rect[0][0]), int(rect[0][1])) width = int(rect[1][0]) height = int(rect[1][1]) angle = int(rect[2]) if width < height: angle = 90 - angle else: angle = -angle label = " Rotation Angle: " + str(angle) + " degrees" textbox = cv.rectangle(img, (center[0]-35, center[1]-25), (center[0] + 295, center[1] + 10), (255,255,255), -1) cv.putText(img, label, (center[0]-50, center[1]), cv.FONT_HERSHEY_SIMPLEX, 0.7, (0,0,0), 1, cv.LINE_AA) cv.drawContours(img,[box],0,(0,0,255),2)cv.imshow('Output Image', img)cv.waitKey(0)cv.destroyAllWindows()cv.imwrite("min_area_rec_output.jpg", img) 最终输出结果:
https://automaticaddison.com/how-to-determine-the-orientation-of-an-object-using-opencv/
THE END!
转载地址:http://oesfk.baihongyu.com/