当前位置: 首页 > news >正文

【python】OpenCV—Connected Components

在这里插入图片描述

文章目录

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

1、任务描述

基于 python opencv 的连通分量标记和分析函数,分割车牌中的数字、号码、分隔符

  • cv2.connectedComponents
  • cv2.connectedComponentsWithStats
  • cv2.connectedComponentsWithAlgorithm
  • cv2.connectedComponentsWithStatsWithAlgorithm

2、代码实现

导入必要的包,加载输入图像,将其转换为灰度,并对其进行二值化处理

# 导入必要的包
import argparse
import cv2# 解析构建的参数解析器
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", default="1.jpeg", help="path to input image")
ap.add_argument("-c", "--connectivity", type=int, default=4, help="connectivity for connected analysis")
args = vars(ap.parse_args())  # 将参数转为字典格式# 加载输入图像,将其转换为灰度,并对其进行阈值处理
image = cv2.imread(args["image"])  # (366, 640, 3)
cv2.imshow("src", image)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv2.imwrite("gray.jpg", gray)thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv2.imshow("threshold", thresh)
cv2.imwrite("threshold.jpg", thresh)

对阈值化后的图像应用连通分量分析

# 对阈值化后的图像应用连通分量分析
output = cv2.connectedComponentsWithStats(thresh, args["connectivity"], cv2.CV_32S)
(numLabels, labels, stats, centroids) = output

cv2.connectedComponentsWithStats 可以结合后面章节的介绍查看

输入图片的尺寸假如是 (366, 640, 3),看看 cv2.connectedComponentsWithStats 的返回情况

"""
[labels] (366, 640)array([[1, 1, 1, ..., 1, 1, 1],[1, 1, 1, ..., 1, 1, 1],[1, 1, 1, ..., 1, 1, 1],...,[1, 1, 1, ..., 1, 1, 1],[1, 1, 1, ..., 1, 1, 1],[1, 1, 1, ..., 1, 1, 1]], dtype=int32)[state]
array([[    83,     83,    482,    163,  57925],[     0,      0,    640,    366, 155776],[    96,     96,    456,    138,   2817],[   113,    108,     75,    113,   5915],[   194,    119,     52,     90,   2746],[   270,    120,     62,     90,   2260],[   489,    124,     46,     85,   2370],[   344,    126,     29,     82,   1398],[   394,    126,     29,     82,   1397],[   445,    126,     29,     82,   1396],[   253,    149,     17,     18,    240]], dtype=int32)[centroids]
array([[333.22577471, 163.75948209],[317.48520953, 191.81337305],[323.41924033, 174.62051828],[148.71885038, 163.47658495],[219.46686089, 164.00837582],[299.82566372, 161.7420354 ],[512.84767932, 165.38818565],[362.91773963, 161.85479256],[412.91481747, 161.956335  ],[463.91833811, 161.96919771],[261.3125    , 157.22083333]])
"""

注意这里是质心,不是连通区域矩形框的中心

对于 x 方向的质心,图像在质心左右两边像素和相等,y 同理,上下两边像素和相等

遍历每个连通分量,忽略 label = 0 背景,提取当前标签的连通分量统计信息和质心,可视化边界框和当前连通分量的质心

# 遍历每个连通分量
for i in range(0, numLabels):# 0表示的是背景连通分量,忽略if i == 0:text = "examining component {}/{} (background)".format(i + 1, numLabels)# otherwise, we are examining an actual connected componentelse:text = "examining component {}/{}".format(i + 1, numLabels)# 打印当前的状态信息print("[INFO] {}".format(text))# 提取当前标签的连通分量统计信息和质心x = stats[i, cv2.CC_STAT_LEFT]  # 左上角横坐标y = stats[i, cv2.CC_STAT_TOP]  # 左上角纵坐标w = stats[i, cv2.CC_STAT_WIDTH]  # 边界框的宽h = stats[i, cv2.CC_STAT_HEIGHT]  # 边界框的高area = stats[i, cv2.CC_STAT_AREA]  # 边界框的面积(cX, cY) = centroids[i]  # 边界框的质心# 可视化边界框和当前连通分量的质心# clone原始图,在图上画当前连通分量的边界框以及质心output = image.copy()cv2.rectangle(output, (x, y), (x + w, y + h), (0, 255, 0), 3)  # 绿色边界框cv2.circle(output, (int(cX), int(cY)), 4, (0, 0, 255), -1)  # 红色质心# 创建掩码componentMask = (labels == i).astype("uint8") * 255  # 绘制 mask,对应label 置为 255,其余为 0# 显示输出图像和掩码cv2.imshow("Output", output)cv2.imwrite(f"output-{str(i).zfill(3)}.jpg", output)cv2.imshow("Connected Component", componentMask)cv2.imwrite(f"componentMask-{str(i).zfill(3)}.jpg", componentMask)cv2.waitKey(0)

创建掩码的时候比较巧妙 componentMask = (labels == i).astype("uint8") * 255

3、完整代码

# 导入必要的包
import argparse
import cv2# 解析构建的参数解析器
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", default="1.jpeg", help="path to input image")
ap.add_argument("-c", "--connectivity", type=int, default=4, help="connectivity for connected analysis")
args = vars(ap.parse_args())  # 将参数转为字典格式# 加载输入图像,将其转换为灰度,并对其进行阈值处理
image = cv2.imread(args["image"])  # (366, 640, 3)
cv2.imshow("src", image)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv2.imwrite("gray.jpg", gray)thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv2.imshow("threshold", thresh)
cv2.imwrite("threshold.jpg", thresh)# 对阈值化后的图像应用连通分量分析
output = cv2.connectedComponentsWithStats(thresh, args["connectivity"], cv2.CV_32S)
(numLabels, labels, stats, centroids) = output# 遍历每个连通分量
for i in range(0, numLabels):# 0表示的是背景连通分量,忽略if i == 0:text = "examining component {}/{} (background)".format(i + 1, numLabels)# otherwise, we are examining an actual connected componentelse:text = "examining component {}/{}".format(i + 1, numLabels)# 打印当前的状态信息print("[INFO] {}".format(text))# 提取当前标签的连通分量统计信息和质心x = stats[i, cv2.CC_STAT_LEFT]  # 左上角横坐标y = stats[i, cv2.CC_STAT_TOP]  # 左上角纵坐标w = stats[i, cv2.CC_STAT_WIDTH]  # 边界框的宽h = stats[i, cv2.CC_STAT_HEIGHT]  # 边界框的高area = stats[i, cv2.CC_STAT_AREA]  # 边界框的面积(cX, cY) = centroids[i]  # 边界框的质心# 可视化边界框和当前连通分量的质心# clone原始图,在图上画当前连通分量的边界框以及质心output = image.copy()cv2.rectangle(output, (x, y), (x + w, y + h), (0, 255, 0), 3)  # 绿色边界框cv2.circle(output, (int(cX), int(cY)), 4, (0, 0, 255), -1)  # 红色质心# 创建掩码componentMask = (labels == i).astype("uint8") * 255  # 绘制 mask,对应label 置为 255,其余为 0# 显示输出图像和掩码cv2.imshow("Output", output)cv2.imwrite(f"output-{str(i).zfill(3)}.jpg", output)cv2.imshow("Connected Component", componentMask)cv2.imwrite(f"componentMask-{str(i).zfill(3)}.jpg", componentMask)cv2.waitKey(0)

4、结果展示

输入图片

在这里插入图片描述
output

[INFO] examining component 1/11 (background)
[INFO] examining component 2/11
[INFO] examining component 3/11
[INFO] examining component 4/11
[INFO] examining component 5/11
[INFO] examining component 6/11
[INFO] examining component 7/11
[INFO] examining component 8/11
[INFO] examining component 9/11
[INFO] examining component 10/11
[INFO] examining component 11/11

灰度图

在这里插入图片描述

二值化后的结果

在这里插入图片描述

遍历每个连通分量

componentMask0
在这里插入图片描述

output0,车牌外矩形轮廓
在这里插入图片描述

componentMask1
在这里插入图片描述
output1,图像边界的大框

在这里插入图片描述

componentMask2
在这里插入图片描述
output2,车牌内矩形轮廓

在这里插入图片描述

componentMask3

在这里插入图片描述
output3,汉字豫

在这里插入图片描述

componentMask4

在这里插入图片描述

output4,字母 U

在这里插入图片描述

componentMask5

在这里插入图片描述

output5,字母 V

在这里插入图片描述

componentMask6

在这里插入图片描述
output6,数字 9

在这里插入图片描述

componentMask7

在这里插入图片描述

output7,数字 1

在这里插入图片描述

componentMask8

在这里插入图片描述

output8,数字 1

在这里插入图片描述

componentMask9

在这里插入图片描述

output9,数字 1

在这里插入图片描述

componentMask10

在这里插入图片描述

output10,分隔符

在这里插入图片描述

总结,配合车牌检测,和 OCR 就能形成一个简略的车牌识别系统 😊

5、涉及到的库函数

cv2.connectedComponentsWithStats 是 OpenCV 库中的一个函数,用于寻找图像中的连通区域,并计算每个连通区域的统计信息。这个函数在处理二值图像时非常有用,可以帮助我们了解图像中不同对象的数量和特征。

一、函数原型

retval, labels, stats, centroids = cv2.connectedComponentsWithStats(image, connectivity=8, ltype=CV_32S)

二、参数说明

  • image: 输入图像,应为二值图像(黑白图像),即图像中的每个像素点非黑即白。
  • connectivity: 像素的连通性。4 或 8,表示每个像素点与其上下左右(4连通)或上下左右加对角线方向(8连通)的像素点是否视为连通。默认值为 8。
  • ltype: 输出标签图像的类型,通常为 cv2.CV_32S。

三、返回值

  • retval: 连通区域的数量(包括背景,如果背景被视为一个连通区域的话)。
  • labels: 与输入图像同样大小的标签图像,其中每个连通区域被赋予一个唯一的标签值。
  • stats: 一个矩阵,包含了每个连通区域的统计信息。对于每个连通区域,矩阵中存储了以下信息:(x, y, width, height, area),其中 (x, y) 是连通区域的边界框的左上角坐标,width 和 height 是边界框的宽度和高度,area 是连通区域的面积。
  • centroids: 连通区域的质心坐标矩阵,每个连通区域有一个对应的 (cx, cy) 坐标。

四、示例

下面是一个简单的使用 cv2.connectedComponentsWithStats 的示例:

import cv2  
import numpy as np  # 读取图像并转换为灰度图像  
image = cv2.imread('example.png', 0)  # 二值化处理(例如,阈值分割)  
_, binary = cv2.threshold(image, 127, 255, cv2.THRESH_BINARY)  # 查找连通区域及统计信息  
num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(binary)  # 打印连通区域的数量  
print('Number of connected components:', num_labels)  # 遍历每个连通区域,并打印其统计信息  
for i in range(1, num_labels):  # 注意:背景区域的标签为0,从1开始遍历  x, y, w, h, area = stats[i, 0:5]  print(f'Component {i}: (x, y) = ({x}, {y}), Width = {w}, Height = {h}, Area = {area}')

五、注意事项

  • 在处理二值图像时,确保图像已经正确地进行了二值化处理。
  • 连通区域的数量(返回值 retval)包括了背景区域,如果背景被视为一个连通区域的话。
  • 输出的标签图像 labels 中的每个像素值代表了对应像素点所属的连通区域的标签。

通过 cv2.connectedComponentsWithStats,我们可以方便地获取图像中连通区域的数量和统计信息,这对于图像分析和处理中的许多任务都是非常有用的。

6、参考

  • OpenCV 连通分量标记和分析
  • https://pyimagesearch.com/2021/02/22/opencv-connected-component-labeling-and-analysis/
  • https://docs.opencv.org/4.x/de/d01/samples_2cpp_2connected_components_8cpp-example.html

相关文章:

【python】OpenCV—Connected Components

文章目录 1、任务描述2、代码实现3、完整代码4、结果展示5、涉及到的库函数6、参考 1、任务描述 基于 python opencv 的连通分量标记和分析函数,分割车牌中的数字、号码、分隔符 cv2.connectedComponentscv2.connectedComponentsWithStatscv2.connectedComponents…...

【优选算法篇】前缀之序,后缀之章:于数列深处邂逅算法的光与影

文章目录 C 前缀和详解:基础题解与思维分析前言第一章:前缀和基础应用1.1 一维前缀和模板题解法(前缀和)图解分析C代码实现易错点提示代码解读题目解析总结 1.2 二维前缀和模板题解法(二维前缀和)图解分析C…...

win10 更新npm 和 node

win10 更新npm 和 node win10 更新 npm winR 输入cmd,打开命令行,并输入如下 # 查看当前npm版本 npm -v # 清缓存 npm cache clean --force # 强制更新npm,试过npm update -g,没起作用,版本没变化 npm install -g …...

搜索引擎算法更新对网站优化的影响与应对策略

内容概要 随着互联网的不断发展,搜索引擎算法也在不断地进行更新和优化。了解这些算法更新的背景与意义,对于网站管理者和优化人员而言,具有重要的指导意义。不仅因为算法更新可能影响到网站的排名,还因为这些变化也可能为网站带…...

使用 Q3D 计算芯片引线的 AC 和 DC R 和 L

摘要: 模具经常用于电子行业。了解其导联的寄生特性对于设计人员来说很重要。Q3D 是计算 RLCG 的完美工具。它可用于高速板或低频电力电子设备。 在下面的视频中,我们展示了如何修改几何结构、设置模型和检查结果。 详细信息: 几何图形可以在 Q3D 中创建,也可以作为不同…...

前端_008_Vite

文章目录 Vite项目结构依赖构建插件 官网:https://vitejs.cn/vite3-cn/guide/ 一句话简介:前端的一个构建工具 Vite项目结构 index.html package.json vite.config.js public目录 src目录 #新建一个vite项目 npm create vitelatest原有项目引入vite需要…...

ssm007亚盛汽车配件销售业绩管理统(论文+源码)_kaic

本科毕业设计论文 题目:亚盛汽车配件销售业绩管理系统设计与实现 系 别: XX系(全称) 专 业: 软件工程 班 级: 软件工程15201 学生姓名: 学生学号: 指导教师&am…...

如何使用python完成时间序列的数据分析?

引言 时间序列分析是统计学和数据分析中的一个重要领域,广泛应用于经济学、金融、气象学、工程等多个领域。 时间序列数据是按时间顺序排列的一系列数据点,通常用于分析数据随时间的变化趋势。 本文将介绍时间序列分析的基本概念、常用方法以及如何使用Python进行时间序列…...

数字ic设计,Windows/Linux系统,其他相关领域,软件安装包(matlab、vivado、modelsim。。。)

目录 一、总述 二、软件列表 1、modelsim_10.6c 2、notepad 3、matlab 4、Visio-Pro-2016 5、Vivado2018 6、VMware15 7、EndNote X9.3.1 8、Quartus 9、pycharm 10、CentOS7-64bit 一、总述 过往发了很多数字ic设计领域相关的内容,反响也很好。 最近…...

SD-WAN分布式组网:构建高效、灵活的企业网络架构

随着企业数字化转型的深入,分布式组网逐渐成为企业网络架构中的核心需求。无论是跨区域的分支机构互联,还是企业与云服务的连接,如何在不同区域实现高效、低延迟的网络传输,已成为业务成功的关键。SD-WAN(软件定义广域…...

Task :prepareKotlinBuildScriptModel UP-TO-DATE,编译卡在这里不动或报错

这里写自定义目录标题 原因方案其他思路 原因 一般来说,当编译到这个task之后,后续是要进行一些资源的下载的,如果你卡在这边不动的话,很有可能就是你的IDE目前没有办法进行下载。 方案 开关一下IDE内部的代理,或者…...

unseping攻防世界

源码分析 <?php highlight_file(__FILE__);//代码高亮 class ease{//声明了两个私有属性&#xff1a;保存要调用的方法的名称和保存该方法的参数。$method&#xff0c;$argsprivate $method;private $args;//构造函数在实例化类的对象时初始化,即为对象成员变量赋初始值。…...

大厂面试真题-简单描述一下SpringBoot的启动过程

SpringBoot的启动流程是一个复杂但有序的过程&#xff0c;它涉及多个步骤和组件的协同工作。以下是SpringBoot启动流程的详细解析&#xff1a; 一、启动main方法 当SpringBoot项目启动时&#xff0c;它会在当前工作目录下寻找有SpringBootApplication注解标识的类&#xff0c…...

4. 硬件实现

博客补充&#xff1a; CUDA C 编程指南学习_c cuda编程-CSDN博客https://blog.csdn.net/qq_62704693/article/details/141225395?spm1001.2014.3001.5501NVIDIA GPU 架构是围绕可扩展的多线程流式多处理器 &#xff08;SM&#xff09; 阵列构建的。当主机 CPU 上的 CUDA 程序…...

《操作系统真象还原》第3章 完善MBR【3.1 — 3.2】

目录 引用与说明 3.1、地址、section、vstart 浅尝辄止 1、什么是地址 2、什么是 section【汇编】 3、什么是 vstart【汇编】 3.2、CPU 的实模式 1、CPU 工作原理【重要】 2、实模式下的寄存器 4、实模式下 CPU 内存寻址方式 5、栈到底是什么玩意儿 6 ~ 8 无条件转移…...

八大排序-冒泡排序

在里面找动图理解 【数据结构】八大排序(超详解附动图源码)_数据结构排序-CSDN博客 一 简介 冒泡排序应该是我们最熟悉的排序了&#xff0c;在C语言阶段我们就学习了冒泡排序。 他的思想也非常简单&#xff1a; 两两元素相比&#xff0c;前一个比后一个大就交换&#xff0…...

基于Spring Boot+Vue的助农销售平台(协同过滤算法、节流算法、支付宝沙盒支付、图形化分析)

&#x1f388;系统亮点&#xff1a;协同过滤算法、节流算法、支付宝沙盒支付、图形化分析&#xff1b; 一.系统开发工具与环境搭建 1.系统设计开发工具 后端使用Java编程语言的Spring boot框架 项目架构&#xff1a;B/S架构 运行环境&#xff1a;win10/win11、jdk17 前端&…...

uniapp写抖音小程序阻止右滑返回上一个页面

最近用uniapp写小程序遇到一个问题因为内部用到右滑的业务&#xff0c;但是只要右滑就会回到上一页面&#xff0c;用了event.preventDeafult()没有用&#xff0c;看了文档找到了解决办法 1.在最外层view加上touchstart事件 <view class"container" touchstart&q…...

华为配置手工负载分担模式链路聚合实验

目录 组网需求 配置思路 操作步骤 配置文件 组网图形 图1 配置手工负载分担模式链路聚合组网图 组网需求配置思路操作步骤配置文件 组网需求 如图1所示&#xff0c;AC1和AC2通过以太链路分别都连接VLAN10和VLAN20&#xff0c;且AC1和AC2之间有较大的数据流量。 用户希望A…...

【Spring】Cookie与Session

&#x1f490;个人主页&#xff1a;初晴~ &#x1f4da;相关专栏&#xff1a;计算机网络那些事 一、Cookie是什么&#xff1f; Cookie的存在主要是为了解决HTTP协议的无状态性问题&#xff0c;即协议本身无法记住用户之前的操作。 "⽆状态" 的含义指的是: 默认情况…...

Linux链表操作全解析

Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表&#xff1f;1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装

以下是基于 vant-ui&#xff08;适配 Vue2 版本 &#xff09;实现截图中照片上传预览、删除功能&#xff0c;并封装成可复用组件的完整代码&#xff0c;包含样式和逻辑实现&#xff0c;可直接在 Vue2 项目中使用&#xff1a; 1. 封装的图片上传组件 ImageUploader.vue <te…...

有限自动机到正规文法转换器v1.0

1 项目简介 这是一个功能强大的有限自动机&#xff08;Finite Automaton, FA&#xff09;到正规文法&#xff08;Regular Grammar&#xff09;转换器&#xff0c;它配备了一个直观且完整的图形用户界面&#xff0c;使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论

路径问题的革命性重构&#xff1a;基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中&#xff08;图1&#xff09;&#xff1a; mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...

三分算法与DeepSeek辅助证明是单峰函数

前置 单峰函数有唯一的最大值&#xff0c;最大值左侧的数值严格单调递增&#xff0c;最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值&#xff0c;最小值左侧的数值严格单调递减&#xff0c;最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...

Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)

引言 在人工智能飞速发展的今天&#xff0c;大语言模型&#xff08;Large Language Models, LLMs&#xff09;已成为技术领域的焦点。从智能写作到代码生成&#xff0c;LLM 的应用场景不断扩展&#xff0c;深刻改变了我们的工作和生活方式。然而&#xff0c;理解这些模型的内部…...

渗透实战PortSwigger靶场:lab13存储型DOM XSS详解

进来是需要留言的&#xff0c;先用做简单的 html 标签测试 发现面的</h1>不见了 数据包中找到了一个loadCommentsWithVulnerableEscapeHtml.js 他是把用户输入的<>进行 html 编码&#xff0c;输入的<>当成字符串处理回显到页面中&#xff0c;看来只是把用户输…...

comfyui 工作流中 图生视频 如何增加视频的长度到5秒

comfyUI 工作流怎么可以生成更长的视频。除了硬件显存要求之外还有别的方法吗&#xff1f; 在ComfyUI中实现图生视频并延长到5秒&#xff0c;需要结合多个扩展和技巧。以下是完整解决方案&#xff1a; 核心工作流配置&#xff08;24fps下5秒120帧&#xff09; #mermaid-svg-yP…...

李沐--动手学深度学习--GRU

1.GRU从零开始实现 #9.1.2GRU从零开始实现 import torch from torch import nn from d2l import torch as d2l#首先读取 8.5节中使用的时间机器数据集 batch_size,num_steps 32,35 train_iter,vocab d2l.load_data_time_machine(batch_size,num_steps) #初始化模型参数 def …...