博客
关于我
OpenCV与AI深度学习 | 实战 | 使用OpenCV确定对象的方向(附源码)
阅读量:791 次
发布时间:2023-02-23

本文共 4885 字,大约阅读时间需要 16 分钟。

使用OpenCV确定对象方向

本文来源公众号“OpenCV与AI深度学习”,仅用于学术分享,侵权删,干货满满。

原文链接:

导读

本文将介绍如何使用OpenCV确定对象的方向(即旋转角度,以度为单位)。

1. 先决条件

安装Python3.7或者更高版本。可以参考下文链接:

https://automaticaddison.com/how-to-set-up-anaconda-for-windows-10/

或者自行下载安装:

https://www.python.org/getit/

2. 相关包安装与设置

在我们开始之前,让我们确保我们已经安装了所有的软件包。检查您的机器上是否安装了OpenCV。如果你使用 Anaconda,你可以输入:

conda install -c conda-forge opencv

或者使用pip安装,指令:

pip install opencv-python

安装科学计算库 Numpy:

pip install numpy

3. 准备测试图像

找一张图片。我的输入图像宽度为 1200 像素,高度为 900 像素。我的输入图像的文件名是input_img.jpg。

4. 编写代码

这是代码。它接受一个名为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)

5. 运行结果

使用PCA(主成分分析)方法获取物体的主方向,效果如下:

了解旋转轴

每个对象的正 x 轴是红线。每个对象的正 y 轴是蓝线。

全局正x 轴从左到右水平穿过图像。全局正z 轴指向此页外。全局正y 轴从图像底部垂直指向图像顶部。

使用右手定则测量旋转,将四根手指伸直(食指到小指)沿全局正 x 轴方向伸出。

计算0~180°之间的方向

如果我们要计算对象的方向并确保结果始终在 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/

你可能感兴趣的文章
Objective-C实现无锁链表(附完整源码)
查看>>
Objective-C实现时间戳转为年月日时分秒(附完整源码)
查看>>
Objective-C实现是否为 Pythagoreantriplet 毕氏三元数组算法(附完整源码)
查看>>
Objective-C实现显示响应算法(附完整源码)
查看>>
Objective-C实现普通矩阵A和B的乘积(附完整源码)
查看>>
Objective-C实现更新数字指定偏移量上的值updateBit算法(附完整源码)
查看>>
Objective-C实现最大类间方差法OTSU算法(附完整源码)
查看>>
Objective-C实现最大非相邻和算法(附完整源码)
查看>>
Objective-C实现最小二乘多项式曲线拟合(附完整源码)
查看>>
Objective-C实现最小路径和算法(附完整源码)
查看>>
Objective-C实现最快的归并排序算法(附完整源码)
查看>>
Objective-C实现最长公共子序列算法(附完整源码)
查看>>
Objective-C实现最长回文子串算法(附完整源码)
查看>>
Objective-C实现最长回文子序列算法(附完整源码)
查看>>
Objective-C实现最长子数组算法(附完整源码)
查看>>
Objective-C实现最长字符串链(附完整源码)
查看>>
Objective-C实现最长递增子序列算法(附完整源码)
查看>>
Objective-C实现有限状态机(附完整源码)
查看>>
Objective-C实现有限状态自动机FSM(附完整源码)
查看>>
Objective-C实现有限集上给定关系的自反关系矩阵和对称闭包关系矩阵(附完整源码)
查看>>