【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

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

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

相关文章

日期选择简化版今日、本周、本月、本季度、本年

function 未来之窗_时间_现在() {let date new Date(),year date.getFullYear(), //获取完整的年份(4位)month date.getMonth() 1, //获取当前月份(0-11,0代表1月)strDate date.getDate() // 获取当前日(1-31),小时 date.getHours(),分钟 date.getMinutes();if (month &…

基于安卓Android的健康饮食系统APP(源码+文档+部署+讲解)

!!!!!!!!! 会持续一直更新下去 有问必答 一键收藏关注不迷路 源码获取:https://pan.baidu.com/s/1aRpOv3f2sdtVYOogQjb8jg?pwdjf1d 提取码: jf1d &#…

【Unity基础】初识UI Toolkit - 编辑器UI

(本文所需图片在文章上面的资源中,点击“立即下载”。) 本文介绍了如何通过UI工具包(UI Toolkit)来创建一个编辑器UI。 一、创建项目 1. 打开Unity创建一个空项目(任意模板),这里我…

【网络】传输层协议TCP

目录 四位首部长度 序号 捎带应答 标记位 超时重传机制 连接管理机制(RST标记位) 三次握手及四次挥手的原因 TCP的全称是传输控制协议(Transmission Control Protocol),也就是说,对于放到TCP发送缓冲…

docker基础篇(尚硅谷)

学习链接 docker1️⃣基础篇(零基小白) - 语雀文档 (即本篇) Docker与微服务实战(基础篇) Docker与微服务实战(高级篇)- 【上】 Docker与微服务实战(高级篇)- 【下】 文章目录 学习…

Spark RDD

概念 RDD是一种抽象,是Spark对于分布式数据集的抽象,它用于囊括所有内存中和磁盘中的分布式数据实体 RDD 与 数组对比 对比项数组RDD概念类型数据结构实体数据模型抽象数据跨度单机进程内跨进程、跨计算节点数据构成数组元素数据分片(Partitions)数据…

OmicsTools软件和R语言分析环境安装配置答疑汇总最新版

OmicsTools软件和R语言分析环境安装配置答疑汇总 前言提示 我开发了一款本地电脑无限使用的零代码生信数据分析作图神器电脑软件OmicsTools,欢迎大家使用进行生物医学科研数据分析和作图,不需要学编程写代码,分析次数没有限制,可…

java web调试时清理当前网址的缓存

java web调试时清理当前网址的缓存 背景 开发后端接口的时候,出现页面已经重新部署启动。但页面报错404的问题。询问前端同学后,发现是因为没有清理页面缓存导致的。特别在此记录。 清理页面缓存 操作方式 chrome浏览器 F12 > 应用 > 存储 &g…

分布式 ID 生成策略(二)

在上一篇文章,分布式 ID 生成策略(一),我们讨论了基于数据库的 ID 池策略,今天来看另一种实现,基于雪花算法的分布式 ID 生成策略。 如图所示,我们用 41 位时间戳 12 位机器 ID 10 位序列号&a…

解决edge浏览器无法同步问题

有时候电脑没带,但是浏览器没有同步很烦恼。chrome浏览器的同步很及时在多设备之间能很好使用。但是edge浏览器同步没反应。 在这里插入图片描述 解决方法: 一、进入edge浏览器点击图像会显示未同步。点击“管理个人资料”,进入后点击同步&…

【机器学习】14. 集成学习 ensemble: bagging, boosting, 随机森林 random forest

集成学习 ensemble: bagging, boosting, 随机森林 random forest 1. Ensemble 整体认知2. 使用Ensemble的原因3. 构建Ensemble 的方法4. Bagging(bootstrap aggregation)特点 5. BoostingAdaBoost整体算法思路 6. 比较7. 随机森林 1. Ensemble 整体认知 …

记录一次更新idea

一、官网下载安装包&#xff0c;拿所需版本 二、链接下载&#xff0c; 逐行仔细读readme.txt 三、执行script(unstall<->install)vbs、-javaagent:更改时记得

低代码平台如何通过AI赋能,实现更智能的业务自动化?

引言 随着数字化转型的加速推进&#xff0c;企业在日常运营中面临的业务复杂性与日俱增。如何快速响应市场需求&#xff0c;优化流程&#xff0c;并降低开发成本&#xff0c;成为各行业共同关注的核心问题。低代码平台作为一种能够快速构建应用程序的工具&#xff0c;因其可视化…

实现企业微信打卡月报与简道云的高效集成

实现企业微信打卡月报与简道云的高效集成 企业微信打卡月报同步到简道云 在企业管理中&#xff0c;员工的考勤数据是至关重要的一环。为了实现高效的数据管理和分析&#xff0c;我们需要将企业微信的打卡月报数据集成到简道云平台。本文将分享一个具体的技术案例&#xff0c;展…

【Redis】常见基本全局命令

一、Redis俩大核心命令 由于Redis是以键值对的形式进行数据存取&#xff0c;自然就离不开不断的存储和获取&#xff0c;而其所对应的命令则是set和get&#xff0c;如此说来二者为Redis的核心基础命令也不为过。 作用&#xff1a;用于存储Stirng类型的数据 返回&#xff1a;当…

GPT避坑指南:如何辨别逆向、AZ、OpenAI官转

市面上有些说自己是官转&#xff0c;一刀只需要1块甚至几毛钱&#xff0c;并声称官方倍率的&#xff0c;很大可能就是使用的是 逆向或Azure。 如何鉴别逆向 逆向的种类很多&#xff0c;主要分为3类 逆向不知名A| 镜像站或偷的 key。成本约等于0&#xff0c;调用聊天数据可能在…

【PnP】详细公式推导,使用DLT直接线性变换法求解相机外参

文章目录 &#x1f680;PnP1️⃣ 求解不考虑尺度的解2️⃣ 恢复解的尺度3️⃣ 另一种解法 &#x1f680;PnP PnP(Perspective-n-Point)是求解3D到2D点相机外参的算法。PnP算法有DLT直接线性变换、P3P三对点估计位姿、EPnP(Efficient PnP)、BA(Bundle Adjustment)光速法平差。这…

数据库基础介绍

前言&#xff1a; 在当今信息化、数字化的时代&#xff0c;数据库是支撑一切信息系统的核心基础设施。无论是金融机构的账户管理、电商平台的商品库存&#xff0c;还是社交媒体的用户信息&#xff0c;数据库都在背后扮演着关键角色数据库不仅用于存储和管理数据&#xff0c;更…

[Ansible实践笔记]自动化运维工具Ansible(一):初探ansibleansible的点对点模式

文章目录 Ansible介绍核心组件任务执行方式 实验前的准备更新拓展安装包仓库在ansible主机上配置ip与主机名的对应关系生成密钥对将公钥发送到被管理端&#xff0c;实现免密登录测试一下是否实现免密登录 常用工具ansibleansible—docansible—playbook 主要配置文件 Ansible 模…

Hash表算法

哈希表 理论知识&#xff08;本文来自于代码随想录摘抄&#xff09;什么是哈希常见的三种哈希结数组&#xff1a;set:map:其他常用方法或者技巧&#xff08;自己总结的&#xff09; 练习题和讲解有效的字母移位词349. 两个数组的交集1. 两数之和454. 四数相加 II15. 三数之和 总…