OpenCV 与 Matplotlib 的结合使用:轮毂检测与目标跟踪

news2024/12/22 1:54:14

目录

绘制轮廓图像

实现思路

1. 读取图像并转换为灰度图像

2. 二值化处理

3. 查找轮廓

4. 绘制轮廓

5. 显示结果

代码实现

效果展示

动态逐步显示轮廓结果

实现思路

1. 读取图像并缩放

2. 转换为灰度图像

3. 二值化处理

4. 查找轮廓

5. 动态显示轮廓

6. 显示最终结果并关闭窗口

7. 使用 Matplotlib 显示最终图像

代码实现

效果展示

物体跟踪

实现思路

整体代码

效果展示


绘制轮廓图像

实现思路

使用 OpenCV 检测图像中的轮廓并在图像上绘制轮廓,最后通过 Matplotlib 来显示处理结果。以下是代码的具体实现思路:

1. 读取图像并转换为灰度图像

 
image = cv2.imread('./imgs/006.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

  • 首先,通过 cv2.imread() 读取指定路径下的图片文件,并将其存储在 image 变量中。image 是一个彩色图像,使用 BGR 颜色格式。
  • 为了简化后续的轮廓检测处理,将彩色图像转换为灰度图像,使用 cv2.cvtColor() 函数进行 BGR 到灰度的颜色空间转换。gray 变量存储灰度图像数据,灰度图像的每个像素点只有亮度信息,去除了颜色信息。

2. 二值化处理

 
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

  • 使用 cv2.threshold() 对灰度图像进行二值化处理。二值化的原理是将图像中的像素值按照阈值进行划分,大于 127 的像素值被设置为 255(白色),小于或等于 127 的像素值被设置为 0(黑色),生成一个只有黑白两色的图像 thresh
  • 这种处理方式非常适合用于轮廓检测,因为轮廓可以在二值化的图像中更加清晰地表现出来。

3. 查找轮廓

 
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

  • 在二值化图像 thresh 上查找轮廓,使用 cv2.findContours() 函数。该函数返回两个值:
    • contours:一个包含所有轮廓信息的列表。每个轮廓由一组点的坐标构成。
    • hierarchy:轮廓之间的层次结构信息。
  • cv2.RETR_EXTERNAL 参数指定只提取外部轮廓(不处理嵌套轮廓),而 cv2.CHAIN_APPROX_SIMPLE 参数则简化了轮廓的表示,去除了冗余点。

4. 绘制轮廓

 
cv2.drawContours(image, contours, -1, (0, 255, 0), 3)

  • 使用 cv2.drawContours() 在原始图像 image 上绘制所有检测到的轮廓。函数的参数解释如下:
    • image:要在其上绘制轮廓的图像。
    • contours:包含轮廓数据的列表。
    • -1:表示绘制所有轮廓。如果指定特定的索引,则只绘制该特定轮廓。
    • (0, 255, 0):指定轮廓的颜色为绿色(BGR 格式中的绿色)。
    • 3:指定轮廓线的粗细为 3 像素。

5. 显示结果

 
plt.figure(figsize=(10, 5))
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.title('Detected Contours')
plt.axis('off')
plt.show()

  • 使用 Matplotlib 来显示处理后的图像。由于 OpenCV 使用 BGR 颜色格式,而 Matplotlib 使用 RGB 格式,因此需要用 cv2.cvtColor() 函数将图像颜色从 BGR 转换为 RGB。
  • plt.imshow() 用于显示转换后的图像,并通过 plt.axis('off') 隐藏坐标轴。
  • 最后通过 plt.show() 函数展示出图像,图像上会标注出绿色的轮廓。

代码实现

import cv2
import matplotlib.pyplot as plt

# 读取图像并转换为灰度
image = cv2.imread('./imgs/006.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 二值化
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

# 查找轮廓
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 绘制轮廓
cv2.drawContours(image, contours, -1, (0, 255, 0), 3)

# 显示结果
plt.figure(figsize=(10, 5))
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.title('Detected Contours')
plt.axis('off')
plt.show()

效果展示

还可以但也是略显拉胯

动态逐步显示轮廓结果

实现思路

        通过 OpenCV 读取并处理图像,查找其中的轮廓,然后逐步绘制每个轮廓并动态显示处理结果,最后使用 Matplotlib 显示最终效果。代码的具体步骤如下:

1. 读取图像并缩放

 
image = cv2.imread('./imgs/006.jpg')

        首先,使用 cv2.imread() 读取指定路径下的图片文件,并存储在变量 image 中。

 
scale_percent = 50  # 调整比例,例如50%表示图片缩小一半
width = int(image.shape[1] * scale_percent / 100)
height = int(image.shape[0] * scale_percent / 100)
dim = (width, height)
resized_image = cv2.resize(image, dim, interpolation=cv2.INTER_AREA)

        接着,将读取的图片进行缩放,使其适合显示。scale_percent 设置为 50%,表示缩小至原图像的一半。cv2.resize() 根据新的宽度和高度调整图像大小,缩放后的图像存储在 resized_image 变量中。

2. 转换为灰度图像

 
gray = cv2.cvtColor(resized_image, cv2.COLOR_BGR2GRAY)

        将缩放后的彩色图像转换为灰度图像,因为在接下来的步骤中,轮廓检测通常是在灰度图上进行的。使用 cv2.cvtColor() 完成从 BGR(彩色)到灰度的转换。

3. 二值化处理

 
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

        使用 cv2.threshold() 对灰度图像进行二值化处理。该函数将图像中像素值大于 127 的部分设置为 255,其他部分设置为 0,生成一个只有黑白两种颜色的图像 thresh。这有助于后续的轮廓检测,使得轮廓更为清晰。

4. 查找轮廓

 
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

        在二值化图像上查找轮廓,使用 cv2.findContours() 函数。cv2.RETR_EXTERNAL 表示只提取最外层的轮廓,cv2.CHAIN_APPROX_SIMPLE 则减少冗余点以优化轮廓的表示。函数返回检测到的轮廓列表 contours,以及层次信息 hierarchy

5. 动态显示轮廓

 
for cnt in contours:
    # 绘制每个轮廓
    cv2.drawContours(resized_image, [cnt], -1, (0, 255, 0), 3)

    # 动态显示当前的结果
    cv2.imshow('Contour Detection', resized_image)

    # 设置等待时间,每隔500ms显示一个轮廓
    cv2.waitKey(500)

        在这部分,遍历所有检测到的轮廓 contours,并使用 cv2.drawContours() 将每个轮廓绘制在缩放后的图像 resized_image 上。每次绘制完一个轮廓后,使用 cv2.imshow() 动态显示当前处理的图像结果。

        cv2.waitKey(500) 控制显示的时间间隔为 500 毫秒,这使得用户可以看到轮廓逐步被绘制的过程,营造动态展示的效果。

6. 显示最终结果并关闭窗口

 
cv2.waitKey(0)
cv2.destroyAllWindows()

在所有轮廓绘制完成后,程序会停留在最后的显示结果上,直到用户按下任意键关闭窗口。cv2.destroyAllWindows() 用于关闭所有由 OpenCV 打开的窗口。

7. 使用 Matplotlib 显示最终图像

 
plt.figure(figsize=(10, 5))
plt.imshow(cv2.cvtColor(resized_image, cv2.COLOR_BGR2RGB))
plt.title('Detected Contours')
plt.axis('off')
plt.show()

        在完成 OpenCV 的处理后,使用 Matplotlib 来显示最终的检测结果。由于 OpenCV 使用的是 BGR 颜色空间,而 Matplotlib 使用 RGB,因此需要用 cv2.cvtColor() 将图像颜色从 BGR 转换为 RGB 格式。plt.imshow() 显示处理后的图像,并通过 plt.axis('off') 去掉坐标轴。

代码实现

import cv2
import matplotlib.pyplot as plt

# 读取图像并转换为灰度
image = cv2.imread('./imgs/006.jpg')

# 缩放图片,使窗口大小合适
scale_percent = 50  # 调整比例,例如50%表示图片缩小一半
width = int(image.shape[1] * scale_percent / 100)
height = int(image.shape[0] * scale_percent / 100)
dim = (width, height)
resized_image = cv2.resize(image, dim, interpolation=cv2.INTER_AREA)

# 转换为灰度
gray = cv2.cvtColor(resized_image, cv2.COLOR_BGR2GRAY)

# 二值化
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

# 查找轮廓
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 动态显示每个轮廓
for cnt in contours:
    # 绘制每个轮廓
    cv2.drawContours(resized_image, [cnt], -1, (0, 255, 0), 3)

    # 动态显示当前的结果
    cv2.imshow('Contour Detection', resized_image)

    # 设置等待时间,每隔500ms显示一个轮廓
    cv2.waitKey(500)

# 显示最终结果并关闭窗口
cv2.waitKey(0)
cv2.destroyAllWindows()

# 使用matplotlib显示最终图像
plt.figure(figsize=(10, 5))
plt.imshow(cv2.cvtColor(resized_image, cv2.COLOR_BGR2RGB))
plt.title('Detected Contours')
plt.axis('off')
plt.show()

效果展示

        这里的效果其实就是绘制轮廓图像然后让他一点点的绘制出来,就是这么个效果,动图不好截图,我就不再展示了。


物体跟踪

实现思路

  • 摄像头捕获cv2.VideoCapture(0) 打开系统默认摄像头并开始捕获视频流。
  • 背景减法:通过 cv2.createBackgroundSubtractorMOG2() 来生成前景掩码,用于检测运动物体。
  • 轮廓检测:使用 cv2.findContours() 检测运动物体的轮廓。
  • 物体跟踪:通过 cv2.boundingRect() 为每个符合条件的轮廓绘制边界框,实现物体的实时跟踪。
  • 退出条件:按下 'q' 键可退出循环并停止摄像头。

整体代码

import cv2

# 初始化视频捕获,打开摄像头
cap = cv2.VideoCapture(0)

# 创建背景减法器
fgbg = cv2.createBackgroundSubtractorMOG2()

while True:
    # 读取摄像头帧
    ret, frame = cap.read()
    if not ret:
        break

    # 对帧进行背景减除,获取前景掩码
    fgmask = fgbg.apply(frame)

    # 查找前景中的轮廓
    contours, _ = cv2.findContours(fgmask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    # 遍历每个轮廓,进行物体跟踪
    for cnt in contours:
        # 忽略较小的轮廓,避免噪声
        if cv2.contourArea(cnt) > 500:
            # 获取轮廓的边界框
            x, y, w, h = cv2.boundingRect(cnt)

            # 绘制边界框
            cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)

            # 在物体上显示跟踪的文字
            cv2.putText(frame, 'Tracking Object', (x, y - 10),
                        cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 0, 0), 2)

    # 显示视频流
    cv2.imshow('Object Tracking', frame)

    # 按下 'q' 键退出循环
    if cv2.waitKey(30) & 0xFF == ord('q'):
        break

# 释放资源并关闭窗口
cap.release()
cv2.destroyAllWindows()

效果展示

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于图神经网络的最大独立集问题的目标分支

文章目录 Abstract1 Introduction2 Related Work分支顶点选择图神经网络Abstract 分支归约方法结合了分支约束原则和归约规则,在处理以前无法管理的现实世界实例方面特别成功。分支策略决定下一个要在哪个顶点上进行分支。最近,最广泛使用的策略是选择最高度的顶点。 在这项…

C++为什么要引入智能指针?

智能指针的必要性 C 引入智能指针主要是为了解决手动管理动态分配内存时可能出现的几个问题,特别是内存泄漏、野指针和异常安全等问题。智能指针通过封装原始指针的操作,提供自动化的内存管理机制,以减少这些问题的发生。 具体来说&#xff…

c++基础补充

c基础补充 函数补充函数声明函数的分文件编写 指针补充占用大小空指针坏指针野指针 C内存分区模型 函数补充 函数声明 #include <iostream> using namespace std;int max(int a,int b);int main() {int result max(1,3);cout << result << endl;return 0;…

皮肤表皮层

表皮层的细胞大都是由基底层细胞分裂分化而来, 1:角质层 2:透明层 3:颗粒层 4:棘状层 5:基底层角质层 组成:由10-20 死细胞组成 细胞膜很厚 细胞核及胞器消失 细胞间隙被脂质连接 透明层 只出现在手掌和脚掌中 颗粒层 2-4层细胞角质细胞 活细胞 棘状层 有免疫…

chapter13-常用类——(Date、Calendar、LocalDate)—day17

目录 488-Date介绍 489-Date应用实例 490-Calendar介绍 491-Calendar应用实例 492-第三代日期使用 493-第三代日期方法 494-String翻转 495-注册处理题 496-字符串统计 497-String内存布局测试题 488-Date介绍 IDEA里面的properties是set/get方法 489-Date应用实例 49…

网络编程(UDP)

UDP编程 UDP&#xff1a;全双工通信、面向无连接、不可靠 UDP&#xff08;User Datagram Protocol&#xff09;用户数据报协议&#xff0c;是不可靠的无连接的协议。在数据发送前&#xff0c;因为不需要进行连接&#xff0c;所以可以进行高效率的数据传输。 适用场景 发送小尺寸…

transforemr网络理解

1.transformer网络中数据的流动过程&#xff1a; 2.transformer中残差的理解&#xff1a; 残差连接&#xff08;Residual Connection&#xff09; 的核心思想就是通过将输入与经过变化的输出相加&#xff0c;来最大限度地保留原始信息。 transforemr中注意力层网络和前馈神经…

国行 iPhone 15 Pro 开启苹果 Apple Intelligence 教程

一、前言苹果在 iOS 18.1 测试版上正式开启了 Apple Intelligence 的内测&#xff0c;但国行设备因政策原因不支持&#xff0c;且国行设备在硬件上被锁定。不过&#xff0c;我们可以通过一些方法来破解国行 iPhone 15 Pro&#xff0c;使其能够开启 Apple Intelligence。 以下是…

六、深入理解JVM 执行引擎

文章目录 前端编译与后端编译字节码指令是如何执行的解释执行与编译执行热点代码识别客户端编译器与服务端编译器 后端编译优化技术方法内联 Inline逃逸分析 Escape Analysis锁消除 lock elision 从计算机程序出现的第一天起&#xff0c;对执行效率的追求就是程序员天生的坚定信…

线程的状态(java)

“苦&#xff1f; 何止是苦~~~~~” 本期内容来分享一下线程状态相关的知识哦&#xff01;&#xff01;&#xff01; 对于进程来说&#xff0c;进程是有两种状态的。 一种是就绪状态&#xff1a;正在CPU上执行&#xff0c;或者随时可以去CPU上执行的。 另一种是阻塞状态&…

cesium地图高程数据DEM使用及转换

一.DEM高程图的下载&#xff0c;我是在地理空间数据云 (gscloud.cn)这个地方下载的&#xff0c;是免费的&#xff0c;可以下载30M和90M的高程数据。具体方式是进入“高级检索”&#xff0c;选择图源类型&#xff0c;需要下载的区域名称等&#xff0c;最后点击“检索”即可出现图…

mysql_redo_log_buffer

Redo Log MySQL 的 InnoDB 存储引擎使用 Redo Log 记录系统中每个事务的修改&#xff0c;从而在系统崩溃重启时能够把系统恢复到崩溃时的状态。因此&#xff0c;Redo Log 用于保证事务的持久性&#xff0c;即一旦某个事务成功提交&#xff0c;即使系统发生了崩溃&#xff0c;那…

C#开发移动应用系列(4.调用系统应用,以及第三方应用(调用与被调用))

写完这篇..本系列基本也就结束了. 看完这些,基本做个Webapp应该是毫无问题的了..其实略微有点伤感,Xamarin确实是好东西.. 奈何,生不逢时..等完善了. 开源了..社区化了..APP应用(指的是安装包类客户端)已经逐渐没落了.. 算了,话不多说.开始正文 确定一下本篇的学习目标: 1.…

【MySQL】—— MySQL命令行客户端介绍

目录 &#xff08;一&#xff09;mysql客户端简介 &#xff08;二&#xff09;mysql客户端选项 2.1 指定选项的方式 2.2 mysql 客户端命令常用选项 2.3 在命令行中使用选项 &#xff08;三&#xff09;选项(配置)文件 3.1 使用方法 3.2 选项文件位置及加载顺序 3.2.1…

mysql——关于表的增删改查(CRUD)

目录 比较运算符和逻辑运算符图 一、增加&#xff08;Create&#xff09; 1、全列插入 2、指定列插入 二、查询&#xff08;Retrieve&#xff09; 1、全列查询 2、指定列查询 3、别名&#xff08;as&#xff09; 4、表达式查询 5、去重&#xff08;distinct&#xff09; 6、…

全网最适合入门的面向对象编程教程:46 Python函数方法与接口-函数与事件驱动框架

全网最适合入门的面向对象编程教程&#xff1a;46 Python 函数方法与接口-函数与事件驱动框架 摘要&#xff1a; 函数是 Python 中的一等公民,是一种可重用的代码块,用于封装特定的逻辑&#xff1b;事件驱动框架是一种编程模式&#xff0c;它将程序的控制流转移给外部事件,如用…

Simulink库模块作用及简单应用(一)

01--Data Store Memory模块 数据存储模块一般是和数据写入还有数据访问一同搭配使用的 可以从帮助文档看到该模型如下的关键使用信息&#xff1a; Data Store Memory 模块定义并初始化一个命名的共享数据存储&#xff0c;即一个内存区域&#xff0c;供指定相同数据存储名称的…

客户端负载均衡Ribbon 小实例

文章目录 一&#xff0c;概述二&#xff0c;实现过程三&#xff0c;项目源码1. 源码放送&#xff1a;2. 部署方式 四&#xff0c;功能演示五&#xff0c;其他 一&#xff0c;概述 一般来说&#xff0c;提到负载均衡&#xff0c;大家一般很容易想到浏览器 -> NGINX -> 反…

Java 每日一刊(第一期):Java 的历史

文章目录 Java 的起源与诞生Java 的早期发展&#xff08;1995-2000&#xff09;Java 的转型与扩展&#xff08;2000-2010&#xff09;Oracle 时代的 Java&#xff08;2010-至今&#xff09;本期小知识 Java 的起源与诞生 Java 的历史可以追溯到 20 世纪 90 年代&#xff0c;由 …

【数据结构(初阶)】——二叉树

【数据结构】——二叉树 文章目录 【数据结构】——二叉树前言1. 树的概念及结构1.1 树的概念1.2 树的结构 2. 二叉树的概念及结构2.1 二叉树的概念2.2 二叉树的结构2.3 二叉树的性质 3. 二叉树顺序结构及概念3.1 二叉树的顺序结构3.2 堆的概念及结构3.3 堆的实现3.3.1 堆的基本…