【python】OpenCV—findContours(4.4)

在这里插入图片描述

文章目录

  • 1、功能描述
  • 2、代码实现
  • 3、完整代码
  • 4、结果展示
  • 5、涉及到的库函数
  • 6、参考

1、功能描述

找出物体轮廓,根据 PCA 计算特征值和特征向量,绘制特征值和特征向量,来初步展示物体的方向

2、代码实现

导入库函数,读入图片,判定图片是否存在,显示图片

import cv2 as cv
from math import atan2, cos, sin, sqrt, pi
import numpy as np# Load the image
img = cv.imread("1.jpeg")# Was the image there?
if img is None:print("Error: File not found")exit(0)cv.imshow('Input Image', img)

灰度化图片,二值化图片,为后续找轮廓做准备

# Convert image to grayscale
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
cv.imwrite("gray.jpg", gray)# Convert image to binary
_, bw = cv.threshold(gray, 50, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
cv.imwrite("bw.jpg", bw)

找轮廓

# Find all the contours in the thresholded image
contours, _ = cv.findContours(bw, cv.RETR_LIST, cv.CHAIN_APPROX_NONE)

遍历轮廓,剔除面积过小或者过大的轮廓,绘制轮廓,调用 getOrientation 获取物体方向并绘制,并显示绘制结果

for i, c in enumerate(contours):# Calculate the area of each contourarea = cv.contourArea(c)# Ignore contours that are too small or too largeif area < 1000 or 100000 < area:continue# Draw each contour only for visualisation purposes with red colorcv.drawContours(img, contours, i, (0, 0, 255), 2)# Find the orientation of each shapegetOrientation(c, img)cv.imshow('Output Image', img)
cv.waitKey(0)
cv.destroyAllWindows()# Save the output image to the current directory
cv.imwrite("output_img.jpg", img)

下面看看 getOrientation(c, img) 的实现

def getOrientation(pts, img):## [pca]# Construct a buffer used by the pca analysissz = len(pts)  # 轮廓的关键点数, pts (446, 1, 2)data_pts = np.empty((sz, 2), dtype=np.float64)  # (446, 2)for i in range(data_pts.shape[0]):data_pts[i, 0] = pts[i, 0, 0]data_pts[i, 1] = pts[i, 0, 1]# Perform PCA analysismean = np.empty((0))mean, eigenvectors, eigenvalues = cv.PCACompute2(data_pts, mean)# Store the center of the objectcntr = (int(mean[0, 0]), int(mean[0, 1]))  # (177, 349)## [pca]## [visualization]# Draw the principal componentscv.circle(img, cntr, 3, (255, 0, 255), 2)p1 = (cntr[0] + 0.025 * eigenvectors[0, 0] * eigenvalues[0, 0],cntr[1] + 0.025 * eigenvectors[0, 1] * eigenvalues[0, 0])p2 = (cntr[0] - 0.025 * eigenvectors[1, 0] * eigenvalues[1, 0],cntr[1] - 0.025 * eigenvectors[1, 1] * eigenvalues[1, 0])#  乘以0.25是为了放大这个距离,使其在图像上更加明显。drawAxis(img, cntr, p1, (255, 255, 0), 1)drawAxis(img, cntr, p2, (0, 0, 255), 5)angle = atan2(eigenvectors[0, 1], eigenvectors[0, 0])  # orientation in radians## [visualization]# Label with the rotation angle# label = "  Rotation Angle: " + str(-int(np.rad2deg(angle)) - 90) + " degrees"label = str(-int(np.rad2deg(angle)) - 90) + " degrees"textbox = cv.rectangle(img, (cntr[0]+15, cntr[1] - 50), (cntr[0] + 130, cntr[1] - 15), (255, 255, 255), -1)cv.putText(img, label, (cntr[0]+15, cntr[1]-25), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1, cv.LINE_AA)return angle

其中 cv2.PCACompute2 获取特征值和特征向量

p1p2 是计算特征向量乘以特征值,方便后续可视化物体方向,0.025 是系数,影响的是绘制时候的长度

drawAxis 绘制箭头,展示物体方向

def drawAxis(img, p_, q_, color, scale):p = list(p_)q = list(q_)## [visualization1]angle = atan2(p[1] - q[1], p[0] - q[0])  # angle in radianshypotenuse = sqrt((p[1] - q[1]) **2 + (p[0] - q[0])**2)# Here we lengthen the arrow by a factor of scaleq[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)# create the arrow hooks 绘制箭头的钩子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)## [visualization1]

可以看到有三个 cv2.line,第一个是绘制方向的直线,第二个和第三个分别绘制箭头,偏离直线 ±45°

scale 控制箭头直线的长度

3、完整代码

import cv2 as cv
from math import atan2, cos, sin, sqrt, pi
import numpy as npdef drawAxis(img, p_, q_, color, scale):p = list(p_)q = list(q_)## [visualization1]angle = atan2(p[1] - q[1], p[0] - q[0])  # angle in radianshypotenuse = sqrt((p[1] - q[1]) **2 + (p[0] - q[0])**2)# Here we lengthen the arrow by a factor of scaleq[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)# create the arrow hooks 绘制箭头的钩子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)## [visualization1]def getOrientation(pts, img):## [pca]# Construct a buffer used by the pca analysissz = len(pts)  # 轮廓的关键点数, pts (446, 1, 2)data_pts = np.empty((sz, 2), dtype=np.float64)  # (446, 2)for i in range(data_pts.shape[0]):data_pts[i, 0] = pts[i, 0, 0]data_pts[i, 1] = pts[i, 0, 1]# Perform PCA analysismean = np.empty((0))mean, eigenvectors, eigenvalues = cv.PCACompute2(data_pts, mean)# Store the center of the objectcntr = (int(mean[0, 0]), int(mean[0, 1]))  # (177, 349)## [pca]## [visualization]# Draw the principal componentscv.circle(img, cntr, 3, (255, 0, 255), 2)p1 = (cntr[0] + 0.025 * eigenvectors[0, 0] * eigenvalues[0, 0],cntr[1] + 0.025 * eigenvectors[0, 1] * eigenvalues[0, 0])p2 = (cntr[0] - 0.025 * eigenvectors[1, 0] * eigenvalues[1, 0],cntr[1] - 0.025 * eigenvectors[1, 1] * eigenvalues[1, 0])#  乘以0.25是为了放大这个距离,使其在图像上更加明显。drawAxis(img, cntr, p1, (255, 255, 0), 1)drawAxis(img, cntr, p2, (0, 0, 255), 5)angle = atan2(eigenvectors[0, 1], eigenvectors[0, 0])  # orientation in radians## [visualization]# Label with the rotation angle# label = "  Rotation Angle: " + str(-int(np.rad2deg(angle)) - 90) + " degrees"label = str(-int(np.rad2deg(angle)) - 90) + " degrees"textbox = cv.rectangle(img, (cntr[0]+15, cntr[1] - 50), (cntr[0] + 130, cntr[1] - 15), (255, 255, 255), -1)cv.putText(img, label, (cntr[0]+15, cntr[1]-25), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1, cv.LINE_AA)return angle# Load the image
img = cv.imread("1.jpeg")# Was the image there?
if img is None:print("Error: File not found")exit(0)cv.imshow('Input Image', img)# Convert image to grayscale
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
cv.imwrite("gray.jpg", gray)# Convert image to binary
_, bw = cv.threshold(gray, 50, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
cv.imwrite("bw.jpg", bw)# Find all the contours in the thresholded image
contours, _ = cv.findContours(bw, cv.RETR_LIST, cv.CHAIN_APPROX_NONE)for i, c in enumerate(contours):# Calculate the area of each contourarea = cv.contourArea(c)# Ignore contours that are too small or too largeif area < 1000 or 100000 < area:continue# Draw each contour only for visualisation purposes with red colorcv.drawContours(img, contours, i, (0, 0, 255), 2)# Find the orientation of each shapegetOrientation(c, img)cv.imshow('Output Image', img)
cv.waitKey(0)
cv.destroyAllWindows()# Save the output image to the current directory
cv.imwrite("output_img.jpg", img)

4、结果展示

输入图片

在这里插入图片描述

灰度图

在这里插入图片描述

二值化后的结果

在这里插入图片描述

绘制的方向,drawAxis(img, cntr, p2, (0, 0, 255), 1)

在这里插入图片描述

drawAxis(img, cntr, p2, (0, 0, 255), 5)

在这里插入图片描述

角度怎么分析呢?

在这里插入图片描述

上图展示的是正方向

逆时针旋转能还原成上图情况就是负角度

在这里插入图片描述

仔细核对发现这个不符合上述的规则,个人理解,因为这个和正方向是反的(还原不到上述的正方向)

逆时针旋转,还原到 x 朝左,正好是 93°

5、涉及到的库函数

一、函数简介

cv2.PCACompute2 是 OpenCV 库中用于执行主成分分析(PCA)的函数。 PCA是一种统计方法,用于减少数据集的维度,同时保留数据中的主要变化特征。通过PCA,可以找到数据中的“主成分”,这些主成分定义了数据的主要变化方向。

二、函数参数

cv2.PCACompute2 函数接受多个参数,以下是其主要参数的解释:

  • data_pts:一个二维NumPy数组,包含所有数据点的坐标。每个数据点由一个包含两个元素的元组(x, y)表示。
  • mean:可选参数,用于指定数据点的平均值。如果未提供,OpenCV会自动计算数据点的平均值。
  • eigenvectors:可选参数,用于指定特征向量。如果未提供,OpenCV会自动计算特征向量。
  • eigenvalues:可选参数,用于指定特征值。如果未提供,OpenCV会自动计算特征值。
  • noise_cov:可选参数,用于指定噪声的协方差矩阵。如果未提供,OpenCV会使用单位协方差矩阵。
  • flags:可选参数,用于指定计算方式。默认值为0,表示使用OpenCV内置的计算方式。
  • iterations:可选参数,用于指定迭代次数。默认值为0,表示使用OpenCV内置的迭代次数。
  • eigenvalue_threshold:可选参数,用于指定特征值阈值。如果特征值小于这个阈值,它们将被忽略。默认值为0.0,表示不使用阈值。
  • eigenvector_threshold:可选参数,用于指定特征向量阈值。如果特征向量的模小于这个阈值,它们将被忽略。默认值为0.0,表示不使用阈值。

三、函数返回值

cv2.PCACompute2 函数返回以下三个值:

  • mean:数据点的平均值。
  • eigenvectors:特征向量。这些特征向量指向PCA认为信息最丰富的方向。
  • eigenvalues:特征值。特征值表示了对应特征向量方向上的方差大小。

四、使用示例

以下是一个使用 cv2.PCACompute2 函数的简单示例:

import numpy as np  
import cv2  # 生成一组多元正态分布的数据  
mean = [20, 20]  
cov = [[5, 5], [5, 25]]  
X = np.random.multivariate_normal(mean, cov, 500)  # 执行PCA计算  
mean, eigenvectors, eigenvalues = cv2.PCACompute2(X.T)  # 输出结果  
print("Mean:", mean)  
print("Eigenvectors:\n", eigenvectors)  
print("Eigenvalues:\n", eigenvalues)

在这个示例中,我们首先生成了一组多元正态分布的数据,然后使用 cv2.PCACompute2 函数执行PCA计算,并输出平均值、特征向量和特征值。

五、注意事项

在使用 cv2.PCACompute2 函数之前,需要确保已经安装了OpenCV库。

  • 输入的 data_pts 参数应该是一个二维 NumPy 数组,且每个数据点应该由一个包含两个元素的元组(x, y)表示。
  • 根据实际需求,可以选择性地提供 mean、eigenvectors、eigenvalues、noise_cov 等参数。如果未提供这些参数,OpenCV会自动计算它们。
  • 返回值中的 eigenvectors 和 eigenvalues 分别表示了数据的主成分方向和对应的特征值大小。这些结果可以用于进一步的数据分析和处理。

通过合理使用该函数,可以有效地减少数据的维度并提取出数据中的主要变化特征。

6、参考

  • 使用OpenCV如何确定一个对象的方向
  • https://automaticaddison.com/how-to-determine-the-orientation-of-an-object-using-opencv/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/460653.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Jmeter实际应用

环境准备 JDK1.8Jmeter 5.6.3 下载地址Jmeter 插件 下载地址 放到lib/ext下 常用命令 # 启动 sh jmeter# 集群模式下启动节点&#xff0c;不启动用不了集群 sh jmeter-server#生成ssl需要的证书, 这里会要求输入个密码&#xff0c;是要在jmeter中用的 keytool -import -ali…

Javaweb 实验4 xml

我发现了有些人喜欢静静看博客不聊天呐&#xff0c; 但是ta会点赞。 这样的人呢帅气低调有内涵&#xff0c; 美丽大方很优雅。 说的就是你&#xff0c; 不用再怀疑哦 实验四 XML 目的&#xff1a; 安装和使用XML的开发环境认识XML的不同类型掌握XML文档的基本语法了解D…

C#界面设计--9--fatal error C1083: 无法打开包括文件:“jruparse.h”: No such file or directory

1、VS2008-编译时报错“fatal error C1083: 无法打开包括文件:“jruparse.h”: No such file or directory” 2、问题出现的原因及解决方法 1、如果要引入的这些,h文件跟.cpp在同一个目录下&#xff0c;就不会出现这种问题&#xff0c;检査在工程的include目录下是不是真的存…

【机器学习】 15. SVM 支撑向量机 support vector machine,拉格朗日,软边界,核函数

SVM 支撑向量机 support vector machine&#xff0c;拉格朗日&#xff0c;软边界&#xff0c;核函数 1. 超平面边界 margin of hyperplane2. 边界越大的超平面越好原因 3. 线性模型通过决策边界分类4. SVM的问题5. 拉格朗日乘子与SVM结合求最大边界6. SVM软边界和硬边界7. 非线…

SpringBoot获取resources目录下的文件

在 Spring Boot 项目中&#xff0c;获取 resources 目录中的文件路径通常涉及到访问类路径资源&#xff08;classpath resources&#xff09;。Spring Boot 提供了一些工具类和方法&#xff0c;可以方便地访问这些资源。以下是一些常见的方法&#xff1a; 首先&#xff0c;我们…

GitLab代码仓管理安装配置使用

Gitlab介绍 GitLab是一个基于Git的开源项目管理工具&#xff0c;它集成了版本控制、代码审查、持续集成&#xff08;CI&#xff09;/持续部署&#xff08;CD&#xff09;、自动化测试等多种功能&#xff0c;是一个完整的DevOps平台。以下是对GitLab的详细介绍&#xff1a; 一…

C#/WinForm 基于ffmpeg视频流转GIF

源码&#xff1a;https://gitee.com/feng-cai/screenshot-recording

Pinctrl子系统pinctrl_desc结构体进一步介绍

往期内容 本专栏往期内容&#xff1a; Pinctrl子系统和其主要结构体引入 input子系统专栏&#xff1a; 专栏地址&#xff1a;input子系统input角度&#xff1a;I2C触摸屏驱动分析和编写一个简单的I2C驱动程序 – 末片&#xff0c;有往期内容观看顺序 I2C子系统专栏&#xff1a;…

基于OSS搭建在线教育视频课程分享网站

OSS对象存储服务是海量、安全、低成本、高持久的存储服务。适合于存储大规模非结构化数据&#xff0c;如图片、视频、备份文件和容器/虚拟机镜像等。 安装nginx wget https://nginx.org/download/nginx-1.20.2.tar.gz yum -y install zlib zlib-devel gcc-c pcre-devel open…

研究轮腿运动学方案的看法

本文学习自电科中山柳同学的方案分享 遇到的问题&#xff1a; 1、轮毂输出力矩不足以配合腿部收敛机体姿态&#xff08;即腿部关节输出和轮毂输出都被LQR拉大了&#xff0c;但是轮毂最大力矩不够用了&#xff09; 可以引入MPC对LQR输出的反馈增益矩阵K 进行反向增益&#xf…

Linux学习_11

第十章管理Linux的联网 主要包括配置网络&#xff0c;通过域名访问主机&#xff0c;从网站瞎子啊文件&#xff0c;VMware三种网络模式 配置网络 概念 网络接口是指网络中的计算机或网络设备与其他设备实现通讯的进出口&#xff0c;一般是指计算机的网络接口即网卡设备 从RHEL7开…

VBto Converter是一款功能强大的工具,可让您快速轻松地将Microsoft Visual Basic 6.0项目转换

VBto Converter是一款功能强大的工具&#xff0c;可让您快速轻松地将Microsoft Visual Basic 6.0项目转换 1、简介2、官方网站3、本站下载&#xff08;已汉化&#xff09; 1、简介 VBto Converter V2.90 版本&#xff0c;是一款功能强大的工具&#xff0c;可让您快速轻松地将M…

巨好看的登录注册界面源码

展示效果 源码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta http-equiv"X-UA-Compatible" content"IEedge" /><meta name"viewport" content"widthdevic…

突破挑战,创新前行 | 生信科技SOLIDWORKS 2025新品发布会·合肥站精彩回顾

2024年10月18日&#xff0c;由生信科技举办的首场SOLIDWORKS 2025新产品发布会在安徽合肥圆满落幕。现场邀请到制造业的专家学者们一同感受SOLIDWORKS 2025最新功能&#xff0c;探索制造业数字化转型之路。 合肥站活动日&#xff0c;由生信科技副总经理徐建开场。他以智造无界&…

【解决方案】微信小程序如何使用 ProtoBuf 进行 WebSocket 通信

前言 故事背景 简单说下背景&#xff0c;项目中需要用 ProtoBuf 协议转换请求参数&#xff0c;并通过 WebSocket 进行双向通信。重点&#xff01;一个是 web端&#xff08;Vue3 TS&#xff09;&#xff0c;一个是微信小程序端&#xff08;原生 JS&#xff09;。 剧情发展 …

Copilot一又成编程助手Top1,GitHub官宣接入Claude+Gemini!OpenAI的Canvas沦为备胎

Copilot一又成编程助手Top1&#xff0c;GitHub官宣接入ClaudeGemini&#xff01;OpenAI的Canvas沦为备胎 &#x1f31f; &#x1f44b; 大家好&#xff0c;我是猫头虎&#xff01;今天带大家来深度解读GitHub Copilot 的最新动态&#xff01;在第十届 GitHub 开发者大会上&…

三周精通FastAPI:24 OAuth2 实现简单的 Password 和 Bearer 验证

官网文档&#xff1a;https://fastapi.tiangolo.com/zh/tutorial/security/simple-oauth2/ OAuth2 实现简单的 Password 和 Bearer 验证 本章添加上一章示例中欠缺的部分&#xff0c;实现完整的安全流。 获取 username 和 password 首先&#xff0c;使用 FastAPI 安全工具获…

Hugging Face | 个人使用笔记

一、网站介绍 模型和数据集都是开源的 搜索模型是默认按照趋势排序的 二、模型具体页面 三、调用API小练习 模型网站&#xff1a;flux-RealismLora 1.点击View Code 获取参考代码 2.创建一个python文件复制进一个代码编辑器 注意&#xff1a;需要补充最后一行保存代码 …

用unity XR interaction Toolkit 制作垃圾分类虚拟仿真项目

项目效果演示&#xff1a; 垃圾分类虚拟仿真项目演示 1.环境配置 选择universal 3D(通用渲染管道)项目&#xff08;不然导入素材包会丢失材质&#xff09;。 选择Window->Package Manager,安装其中的XR interaction Toolkit。 选择其中的Samples,导入Starter Assets。 选择…

基于web的便捷饭店点餐小程序的设计与实现(lw+演示+源码+运行)

摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。针对高校教师成果信息管理混乱&#xff0c;出错率高&#xff0c;信息安全…