【OpenCV-Python】教程:3-9 轮廓(2)轮廓特征

news2024/11/17 0:03:51

OpenCV Python 轮廓特征

【目标】

  • 轮廓矩
  • 轮廓周长、轮廓面积
  • 轮廓拟合、轮廓凸包、轮廓凹凸性检查
  • 外接矩形、最小包围圈
  • 椭圆拟合、直线拟合

【代码】

  • 周长、面积、矩

在这里插入图片描述

第一幅图像为原始轮廓图像,第二幅图像为轮廓点拟合图像(精度为周长的1/10),第三幅图像为轮廓点拟合图像(精度为周长的 5/1000)

import numpy as np
import cv2

# 读入图像并二值化
img = cv2.imread('star1.png', 0)
img_color = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
ret,thresh = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)

# 寻找轮廓,图像中第一个轮廓就是需要的轮廓,
# 如果在其他程序中,需要根据一定条件进行筛选
# 图像矩可以计算一些特征,例如:物体的质心,物体的面积
# Cx = M10 / M00, Cy = M01 / M00
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
cnt = contours[0]
M = cv2.moments(cnt)
print("星号的矩为:", M )
img_color0 = img_color.copy()
cv2.drawContours(img_color0, [cnt], 0, (0, 128, 255), 3, maxLevel=0)
cv2.imshow("contours-src", img_color0)


# contour的面积可以直接使用 contourArea
# 也可以用 M['m00'] 来获得
area = cv2.contourArea(cnt)
print("星号的面积为:", area)

# 输出周长
# 第二个参数如果为True,则为闭合的轮廓,否则为弧
perimeter = cv2.arcLength(cnt, True)
print("星号的周长为:", perimeter)

# 轮廓近似
# 用另一个更少点的形状去拟合原来的轮廓(使用算法为 道格拉斯-普克算法 , 
# 将曲线近似表示为一系列点,并减少点的数量的一种 算法)
img_color1 = img_color.copy()
epsilon = 0.1 * perimeter
approx = cv2.approxPolyDP(cnt, epsilon, True)
cv2.drawContours(img_color1, [approx], 0, (0, 255, 0), 3, maxLevel=0)
cv2.imshow("0.1-approxPolyDP", img_color1)

# 拟合精度更高,需要的点回更多一些
img_color2 = img_color.copy()
epsilon2 = 0.005 * perimeter
approx2 = cv2.approxPolyDP(cnt, epsilon2, True)
cv2.drawContours(img_color2, [approx2], 0, (0, 255, 255), 3, maxLevel=0)
cv2.imshow("0.005-approxPolyDP", img_color2)

cv2.waitKey(0)
cv2.destroyAllWindows()

以上代码打印如下:

星号的矩为: {'m00': 130522.0, 'm10': 33632144.0, 'm01': 24005228.166666664, 'm20': 10974770282.666666, 'm11': 6224358011.416666, 'm02': 5406270574.5, 'm30': 4011914771313.0, 'm21': 2046283287276.75, 'm12': 1408108180508.5833, 'm03': 1363179635382.75, 'mu20': 2308636527.15621, 'mu11': 38831506.65739727, 'mu02': 991298544.2389975, 'mu30': -5751574310.887695, 'mu21': 7823576580.904053, 'mu12': 768507355.5574036, 'mu03': 4240497589.183838, 'nu20': 0.13551523513082395, 'nu11': 0.0022793803586064827, 'nu02': 0.058188482130994895, 'nu30': -0.0009344959758346628, 'nu21': 0.001271147765169143, 'nu12': 0.00012486442708533664, 'nu03': 0.000688981436808956}
星号的面积为: 130522.0
星号的周长为: 2386.9503506422043
  • 凸包

在这里插入图片描述

# 什么是凸包?
# 凸: 凸对象内部任意两点连接所有点都在图像内部,则为凸对象,否则为非凸或凹对象。
# 包: 能够完全包住对象的最小形状

import numpy as np
import cv2

# 读入灰度图像,并阈值化
image = cv2.imread("worldmap.png", 0)
ret, thresh = cv2.threshold(image, 200, 255, cv2.THRESH_BINARY_INV)

# 寻找阈值图像的轮廓
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# # 画出所有轮廓
map_color = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)
cv2.drawContours(map_color, contours, -1, (0, 255, 0), 1)

# 计算各个轮廓的凸包
hull = []
for i in range(len(contours)):
    hull.append(cv2.convexHull(contours[i], False))

# 创建一个黑色的画布
drawing = np.zeros((thresh.shape[0], thresh.shape[1], 3), np.uint8)
# 画轮廓和凸包点
for i in range(len(contours)):
    color_contours = (0, 255, 0)  # green - color for contours
    hullcolor = (0, 0, 255)  # blue - color for convex hull
    
    # 画轮廓
    cv2.drawContours(drawing, contours, i, color_contours, 1, 8, hierarchy)
    
    # 画凸包
    cv2.drawContours(drawing, hull, i, hullcolor, 1, 8)

cv2.imshow("drawing", drawing)
cv2.imshow("map_color", map_color)
cv2.imshow("thresh", thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()

  • 拟合

在这里插入图片描述

import numpy as np
import cv2

# 读入灰度图像,并阈值化
image = cv2.imread("testfit.png", 0)
ret, thresh = cv2.threshold(image, 127, 255, cv2.THRESH_BINARY)
colorim = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)

# 寻找阈值图像的轮廓
contours, hierarchy = cv2.findContours(
    thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

cnt = contours[0]

# 找到最小的外接矩形
boundingRectImg = colorim.copy()
x,y,w,h = cv2.boundingRect(cnt)
cv2.rectangle(boundingRectImg, (x,y), (x+w, y+h), (0, 255, 0), 2)

# 找到最小倾斜矩形
minAreaRectImg = colorim.copy()
rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)
box = np.int0(box)
cv2.drawContours(minAreaRectImg, [box], 0, (0, 0, 255), 2)

# 最小圆拟合
minEnclosingCircleImg = colorim.copy()
(x,y),radius = cv2.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
cv2.circle(minEnclosingCircleImg, center, radius, (0,255,0), 2)

# 最小椭圆拟合
fitEllipseImg = colorim.copy()
ellipse = cv2.fitEllipse(cnt)
cv2.ellipse(fitEllipseImg, ellipse, (0,255,0), 2)

# 直线拟合
fitLineImg = colorim.copy()
rows, cols = img.shape[:2]
[vx, vy, x, y] = cv2.fitLine(cnt, cv2.DIST_L2, 0, 0.01, 0.01)
lefty = int((-x*vy/vx) + y)
righty = int(((cols-x)*vy/vx)+y)
cv2.line(fitLineImg, (cols-1, righty), (0, lefty), (0, 255, 0), 2)


cv2.imshow("thresh", thresh)
cv2.imshow("boundingRect", boundingRectImg)
cv2.imshow("minAreaRect", minAreaRectImg)
cv2.imshow("minEnclosingCircleImg", minEnclosingCircleImg)
cv2.imshow("fitEllipseImg", fitEllipseImg)
cv2.imshow("fitLineImg", fitLineImg)

cv2.waitKey(0)
cv2.destroyAllWindows()

【接口】

  • moments
Moments cv::moments	(	InputArray 	array,
bool 	binaryImage = false 
);
cv.moments(	array[, binaryImage]	) ->	retval

计算图像最高到三阶的所有矩;

  • array: 数字化图像, 单通道, 8位或2D浮点矩阵或者 1xN 或者 Nx1 的二维点集
  • binaryImage: 如果为真,则所有非零为1,该参数只适合图像。
  • contourArea
double cv::contourArea	(	InputArray 	contour,
bool 	oriented = false 
);
cv.contourArea(	contour[, oriented]	) ->	retval

计算一个轮廓的面积

  • contour: 输入的2维点集的vector, 存储为 std::vector或者Mat
  • oriented: 定向区域标志,如果为真,则返回有符号的面积值,可以通过值的正负来确定方向,一般情况下默认为false.
  • arcLength
double cv::arcLength	(	InputArray 	curve,
bool 	closed 
);
cv.arcLength(	curve, closed	) ->	retval

计算一个轮廓的周长或者一个曲线的弧长

  • curve: 输入的2维点集的vector, 存储为 std::vector或者Mat
  • closed: 表明曲线是否为闭合
  • approxPolyDP
void cv::approxPolyDP	(	InputArray 	curve,
OutputArray 	approxCurve,
double 	epsilon,
bool 	closed 
);
cv.approxPolyDP(	curve, epsilon, closed[, approxCurve]	) ->	approxCurve

近似拟合以一定精度拟合很多个点的曲线,道格拉斯-普克算法

  • curve: 输入的2维点集的vector, 存储为 std::vector或者Mat
  • approxCurve: 近似拟合的曲线结果
  • epsilon: 精度
  • closed: 如果为真,则为闭合的曲线,首尾相连
  • convexHull
void cv::convexHull	(	InputArray 	points,
OutputArray 	hull,
bool 	clockwise = false,
bool 	returnPoints = true 
);
cv.convexHull(	points[, hull[, clockwise[, returnPoints]]]	) ->	hull

找到点集的一个凸包

  • points: 输入的2维点集的vector, 存储为 std::vector或者Mat
  • hull: 输出的凸包点集
  • clockwise: 方向标志,如果为真,则为顺时针
  • returnPoints: 操作标记,在矩阵(二维图像)下,如果flag为真,则返回的是凸包点集,否则返回的是索引。当输出是 std::vector 时,该标记被忽略。std::vector implies returnPoints=false, std::vector implies returnPoints=true.
  • boundingRect
Rect cv::boundingRect	(	InputArray 	array	)	
cv.boundingRect(	array	) ->	retval

计算一个灰阶图像中点集或非零像素的外接矩形

  • array: 点集
  • minAreaRect
RotatedRect cv::minAreaRect	(	InputArray 	points	);
cv.minAreaRect(	points	) ->	retval

找二维点集的最小面积外接矩形(可能旋转的)

  • points: 输入的2维点集的vector, 存储为 std::vector或者Mat
  • boxPoints
void cv::boxPoints	(	RotatedRect 	box,
OutputArray 	points 
);
cv.boxPoints(	box[, points]	) ->	points

找一个旋转矩形的四个顶点,用于画旋转矩形

  • box: 旋转矩形
  • points: 输出的4个顶点
  • fitEllipse
RotatedRect cv::fitEllipse	(	InputArray 	points	)	
cv.fitEllipse(	points	) ->	retval

拟合二维点集的椭圆

  • points: 输入的二维点集.
  • minEnclosingCircle
void cv::minEnclosingCircle	(	InputArray 	points,
Point2f & 	center,
float & 	radius 
);
cv.minEnclosingCircle(	points	) ->	center, radius

计算一个二维点集最小的包围圆

  • points: 输入的二维点集
  • center: 输入的圆心
  • radius: 输出的半径
  • fitLine
void cv::fitLine	(	InputArray 	points,
OutputArray 	line,
int 	distType,
double 	param,
double 	reps,
double 	aeps 
);
cv.fitLine(	points, distType, param, reps, aeps[, line]	) ->	line

直线拟合二维或者三维点集

  • points: 输入的二维或者三维点集,存储为 std::vector<> or Mat.
  • line: 输出的直线参数,如果是二维点集,则 (like Vec4f) - (vx, vy, x0, y0), where (vx, vy) is a normalized vector collinear to the line and (x0, y0) is a point on the line. In case of 3D fitting, it should be a vector of 6 elements (like Vec6f) - (vx, vy, vz, x0, y0, z0), where (vx, vy, vz) is a normalized vector collinear to the line and (x0, y0, z0) is a point on the line.
  • distType: 距离计算的类型;
  • param: Numerical parameter ( C ) for some types of distances. If it is 0, an optimal value is chosen.
  • reps: 半径的精度(坐标轴中心到直线的距离)
  • aeps: 角度的精度,0.01是一个比较好的默认值。

在这里插入图片描述

【参考】

  1. OpenCV 官方文档
  2. 【从零学习OpenCV 4】图像矩的计算与应用
  3. Convex Hull using OpenCV in Python and C++

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

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

相关文章

Docker——Windows版本Docker安装

目录 一、简介 1.1 Docker如何解决大型项目依赖关系复杂&#xff0c;不同组件依赖的兼容性问题&#xff1f; 1.2 Docker如何解决开发、测试、生产环境有差异的问题 1.3 Docker 和 虚拟机的区别 1.4 Docker架构 1.5 总结 二、Docker安装&#xff08;Windows版&#xff09; 2.1…

电容笔可以用什么代替?好用电容笔品牌推荐

在互联网办公、互联网教学等领域&#xff0c;电容笔再次成为全球流行的电子产品。用平替电容笔来代替苹果的电容笔吗&#xff1f;实际上&#xff0c;我们可以考虑买一支平替电容笔&#xff0c;而不用再买昂贵的苹果 Pencil。一支平替电容笔&#xff0c;一两百块钱&#xff0c;比…

spring web 简单项目数据库查询 纯注解版替代web.xml

关键词句&#xff1a;第一个spring 简单项目 纯注解 包括替代web.xml 文件 第一个spring mvc web 简单项目 纯注解 用纯注解写spring web 简单项目 纯注解写web 项目 spring 写数据库 查询 注解方式 spring 数据接链接池 用的阿里的 spring jdbc jdbcTemplate类使用…

python--星际大战(基础版)

实现功能&#xff1a; 运用python的pygame模块实现上方出现一群体的敌机&#xff0c;每个敌机会随机不定时发射子弹&#xff0c;下方是玩家飞机&#xff0c;通过控制方向和发射子弹来摧毁所以敌机&#xff0c;在游戏开始前会有一个计时器&#xff08;3秒&#xff09;计时结束&…

3、Pinpoint-Agent端注册服务到Server端

0、此节简介 此章节大部分操作是在另一台服务器上&#xff0c;vm7。 Agent端配置 项目发布 注册到Pinpoint服务端 接口调用&#xff0c;服务端查看详情 1、Agent端配置 Agent推荐使用和Pinpoint服务端同样的版本。 1.1、下载Pinpoint-Java-Agent包 Github下载链接&#xff1a;h…

第七章 规范化:Eslint + Prettier + Husky

第七章 规范化&#xff1a;Eslint Prettier Husky 为了项目能够长期健康的发展。代码的规范性建设非常重要。只有纪律严明的队伍才能不断打胜仗。 规范制定容易&#xff0c;执行的难度很大。 项目规范可以分为&#xff1a; 编码规范&#xff1b;项目结构规范&#xff1b;…

hyper-v虚拟机ubuntu ssh配置

环境描述&#xff1a; 本地机&#xff1a;win10系统 linux机&#xff1a;hyper-v 虚拟机中的ubuntu 1、ssh 安装和启用 //安装ssh sudo apt-get install ssh//启用ssh service ssh start//查看ssh状态 service ssh status 2、网络工具安装和ip查看 //安装网络工具 sudo ap…

[附源码]SSM计算机毕业设计基于篮球云网站JAVA

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

$.ajax异步请求总结

$.ajax()简单介绍 AJAX 是一种与服务器交换数据的技术&#xff0c;可以在不重新载入整个页面的情况下更新网页的一部分 $.ajax()是万能的&#xff0c;是最基础&#xff0c;最全面的那个&#xff1b;剩余的方法都是针对某种特定场景下的$.ajax()的简化形式 $.ajax()、$.post()…

Java环境变量学习

0. 找到你的安装路径 C:\Program Files\Java 这种语言的开发工具&#xff0c;重要的东西建议就安装在C盘 0.1 里面有什么&#xff1f; 其实就是很多java命令而已 用来编译的&#xff0c;运行的 JDK开发用的JRE运行用的 就像python中给你开发工具的同时&#xff0c;再给你一个…

[附源码]java毕业设计学习资源共享与在线学习系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Jetpack Compose中的state核心思想

Compose 中的状态 应用的“状态”是指可以随时间变化的任何值。这是一个非常宽泛的定义&#xff0c;从 Room 数据库到类的变量&#xff0c;全部涵盖在内。 所有 Android 应用都会向用户显示状态。下面是 Android 应用中的一些状态示例&#xff1a; 聊天应用中最新收到的消息…

Unity3D : 本地坐标系,世界坐标系,和TransformPoint,TransformVector,TransformDirection的区别

目录 一、世界坐标系与本地坐标系 二、srcGameObject.transform.TransformPoint(Vector3 vec) 三、srcGameObject.transform.TransformVector(Vector3 vec) 四、srcGameObject.transform.TransformDirection(Vector3 vec) 五:示例 一、世界坐标系与本地坐标系 世界坐标很…

[LabVIEW]圖像內的物件計算_Count objects

NI雖然是以賣硬件為主的公司&#xff0c;但其在軟件(LabVIEW)的著墨也相當深厚&#xff0c;尤其是各類應用模組的更新速度和對應功能。 每每不經意地碰觸到新版本的LabVIEW&#xff0c;都會不由自主地翻閱和嘗試新增模組。 本文藉由兩個模組串接簡易製作一支圖像計數程式&…

七、模型评估指标

当训练好模型之后&#xff0c;检测模型训练效果如何&#xff0c;评价指标有哪些&#xff1f;通过查阅相关资料&#xff0c;我将以这五个指标来对所训练的模型进行评估&#xff0c;下图是评价指标运行结果图。 一、混淆矩阵&#xff08;Confusion Matrix&#xff09; 解释&…

【网安神器篇】——Whatweb指纹识别工具

作者名&#xff1a;Demo不是emo 主页面链接&#xff1a;主页传送门创作初心&#xff1a;舞台再大&#xff0c;你不上台&#xff0c;永远是观众&#xff0c;没人会关心你努不努力&#xff0c;摔的痛不痛&#xff0c;他们只会看你最后站在什么位置&#xff0c;然后羡慕或鄙夷座右…

CV—cs231n二刷

文章目录cv应用优化训练牛顿法HOGYOLO风格迁移GAN语义分割实例分割LSTMDL框架GPU相关cs231n.stanford.edu cv应用 图像分类、目标检测、人脸识别、语义分割、风格迁移、GAN生成、VQA多模态、点云分割、姿态估计、游戏学习等 优化训练 避免后期训练还在大幅震荡&…

[carla] GNSS传感器与Carla坐标系 转换方法

文章目录方法1:通过python API直接获取转换后坐标1.1 GNSS传感器消息-内容介绍1.2 在线获取方法1.3 完整代码方法2-通过离线读取转换关系的方式转换2.1 转换类代码和使用方法2.2 转换矩阵保存和读取2.3 运行结果2.5 注意事项附件 所有地图的转换矩阵参考链接:方法1:通过python …

工作中学到的一些小点

1.结构体对齐 记得之前面试的时候被问过这个问题【汗】 这个结构体占多大 struct sExample {char c;int n; };占8字节&#xff0c;问有没有办法让它占5个字节&#xff1f; 有 #pragma pack(push) //保存对齐状态 #pragma pack(1) //设定为1字节对齐struct sExample {char c;…

qt串口配置(端口号列表选择/自动保存/初始化模板)复制粘贴直接用

一、前言 废话不多说&#xff0c;写这个作为串口模板&#xff0c;后续会继续补充其他模板&#xff0c;有相识功能直接复制模板里东西到程序中&#xff0c;直接使用&#xff0c;无需大的调整&#xff0c;为自己模板记录&#xff0c;也提供给需要的朋友们。 二、环境 qt5.7 win…