【python】OpenCV—Image Moments

文章目录
- 1、功能描述
- 2、图像矩
- 3、代码实现
- 4、效果展示
- 5、完整代码
- 6、涉及到的库函数
- cv2.moments
- 7、参考
1、功能描述
计算图像的矩,以质心为例
2、图像矩
什么叫图像的矩,在数字图像处理中有什么作用? - 谢博琛的回答 - 知乎
https://www.zhihu.com/question/26803016/answer/888699124

0 阶矩 m 00 m_{00} m00:目标区域的面积(Area)
1 阶矩 m 01 , m 10 m_{01}, m_{10} m01,m10:目标区域的质心(Centroid)
2 阶矩 m 02 , m 20 , m 11 m_{02}, m_{20}, m_{11} m02,m20,m11:即惯性矩,可计算目标图像的方向
3 阶矩 m 03 , m 30 , m 12 , m 21 m_{03}, m_{30}, m_{12}, m_{21} m03,m30,m12,m21:目标区域的方位和斜度,反应目标的扭曲
Hu 矩:目标区域往往伴随着空间变换(平移,尺度,旋转),所以需要在普通矩的基础上构造出具备不变性的矩组
中心矩:构造平移不变性
一文弄懂图像的矩和相关应用
矩是统计学的一个概念(pencv中的图像矩(空间矩,中心矩,归一化中心矩,Hu矩))
图像矩(Image moments)是指图像的某些特定像素灰度的加权平均值(矩),或者是图像具有类似功能或意义的属性。
图像矩通常用来描述分割后的图像对象。可以通过图像的矩来获得图像的部分性质,包括面积(或总体亮度),以及有关几何中心和方向的信息 。

例如工业缺陷检测中(实操教程|使用计算机视觉算法检测钢板中的焊接缺陷),使用图像矩测量缺陷严重性
3、代码实现
导入必要的库函数,固定随机种子,以保证绘制出来的图片色彩固定随机
from __future__ import print_function
from __future__ import division
import cv2 as cv
import numpy as np
import argparse
import random as rngrng.seed(12345)
读取图片,为空打印 could not open or find xxx
parser = argparse.ArgumentParser(description='Code for Image Moments tutorial.')parser.add_argument('--input', help='Path to input image.', default='1.jpg')args = parser.parse_args()src = cv.imread(cv.samples.findFile(args.input))if src is None:print('Could not open or find the image:', args.input)exit(0)
图片转化为灰度图,做模糊处理,并在窗口中显示
# Convert image to gray and blur itsrc_gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)src_gray = cv.blur(src_gray, (3, 3))source_window = 'Source'cv.namedWindow(source_window)cv.imshow(source_window, src)
调用 canny 算子边缘检测找出图片中需要计算矩的轮廓
把 canny 算子的 threshold 设置为滑动条的形式进行回调,默认为 100
max_thresh = 255thresh = 100 # initial thresholdcv.createTrackbar('Canny Thresh:', source_window, thresh, max_thresh, thresh_callback)thresh_callback(thresh)cv.waitKey()
看看核心函数 thresh_callback
计算 canny 边缘检测,调用找轮廓函数,获取所有边缘轮廓
def thresh_callback(val):threshold = valcanny_output = cv.Canny(src_gray, threshold, threshold * 2)contours, _ = cv.findContours(canny_output, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
计算每个轮廓的矩
# Get the momentsmu = [None] * len(contours)for i in range(len(contours)):mu[i] = cv.moments(contours[i])
计算每个轮廓的质心,图片中所有像素点的横坐标除以图片的像素点个数(面积),结果为质心的横坐标
同理可以计算出质心的纵坐标
# Get the mass centersmc = [None] * len(contours)for i in range(len(contours)):# add 1e-5 to avoid division by zero# print(mu[i]['m00'], mu[i]['m10'], mu[i]['m01'])mc[i] = (mu[i]['m10'] / (mu[i]['m00'] + 1e-5), mu[i]['m01'] / (mu[i]['m00'] + 1e-5))
看看计算出来的矩的所有信息
mu[0]
output
{'m00': 1.0, 'm10': 668.0, 'm01': 876.3333333333333, 'm20': 446224.1666666666, 'm11': 585390.6666666666, 'm02': 767960.1666666666, 'm30': 298077966.0, 'm21': 391041111.3666667, 'm12': 512997391.3333333, 'm03': 672989190.1, 'mu20': 0.16666666662786156, 'mu11': 0.0, 'mu02': 0.055555555620230734, 'mu30': 5.960464477539063e-08, 'mu21': -0.022222160400502844, 'mu12': 9.778887033462524e-09, 'mu03': 0.007407426834106445, 'nu20': 0.16666666662786156, 'nu11': 0.0, 'nu02': 0.055555555620230734, 'nu30': 5.960464477539063e-08, 'nu21': -0.022222160400502844, 'nu12': 9.778887033462524e-09, 'nu03': 0.007407426834106445}
绘制轮廓,绘制每个轮廓的质心,保存结果
# Draw contoursdrawing = np.zeros((canny_output.shape[0], canny_output.shape[1], 3), dtype=np.uint8)for i in range(len(contours)):color = (rng.randint(0, 256), rng.randint(0, 256), rng.randint(0, 256))cv.drawContours(drawing, contours, i, color, 2)cv.circle(drawing, (int(mc[i][0]), int(mc[i][1])), 4, color, -1)cv.imshow('Contours', drawing)cv.imwrite("result.jpg", drawing)
对比下我们通过图片矩计算出来的面积和直接调用 opencv 接口的轮廓面积
# Calculate the area with the moments 00 and compare with the result of the OpenCV functionfor i in range(len(contours)):print(' * Contour[%d] - Area (M_00) = %.2f - Area OpenCV: %.2f - Length: %.2f' % (i, mu[i]['m00'], cv.contourArea(contours[i]), cv.arcLength(contours[i], True)))
output
* Contour[0] - Area (M_00) = 1.00 - Area OpenCV: 1.00 - Length: 17.66* Contour[1] - Area (M_00) = 0.00 - Area OpenCV: 0.00 - Length: 426.14* Contour[2] - Area (M_00) = 1.50 - Area OpenCV: 1.50 - Length: 67.90......* Contour[539] - Area (M_00) = 92.00 - Area OpenCV: 92.00 - Length: 541.41* Contour[540] - Area (M_00) = 21.50 - Area OpenCV: 21.50 - Length: 84.47* Contour[541] - Area (M_00) = 81.50 - Area OpenCV: 81.50 - Length: 289.49* Contour[542] - Area (M_00) = 61.00 - Area OpenCV: 61.00 - Length: 452.42
可以看到结果是一致的
4、效果展示
输入图片

threshold = 10

threshold = 60

threshold = 112

threshold = 163

threshold = 214

只绘制矩,不绘制轮廓
eg,threshold = 125

输入图片

threshold = 64

输入图片

threshold = 64

输入图片

threshold = 64

输入图片

threshold = 64

输入图片

threshold = 64

输入图片

threshold = 64

5、完整代码
from __future__ import print_function
from __future__ import division
import cv2 as cv
import numpy as np
import argparse
import random as rngrng.seed(12345)def thresh_callback(val):threshold = valcanny_output = cv.Canny(src_gray, threshold, threshold * 2)contours, _ = cv.findContours(canny_output, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)# Get the momentsmu = [None] * len(contours)for i in range(len(contours)):mu[i] = cv.moments(contours[i])# Get the mass centersmc = [None] * len(contours)for i in range(len(contours)):# add 1e-5 to avoid division by zero# print(mu[i]['m00'], mu[i]['m10'], mu[i]['m01'])mc[i] = (mu[i]['m10'] / (mu[i]['m00'] + 1e-5), mu[i]['m01'] / (mu[i]['m00'] + 1e-5))# Draw contoursdrawing = np.zeros((canny_output.shape[0], canny_output.shape[1], 3), dtype=np.uint8)for i in range(len(contours)):color = (rng.randint(0, 256), rng.randint(0, 256), rng.randint(0, 256))cv.drawContours(drawing, contours, i, color, 2)cv.circle(drawing, (int(mc[i][0]), int(mc[i][1])), 4, color, -1)cv.imshow('Contours', drawing)cv.imwrite("result.jpg", drawing)# Calculate the area with the moments 00 and compare with the result of the OpenCV functionfor i in range(len(contours)):print(' * Contour[%d] - Area (M_00) = %.2f - Area OpenCV: %.2f - Length: %.2f' % (i, mu[i]['m00'], cv.contourArea(contours[i]), cv.arcLength(contours[i], True)))if __name__ == "__main__":parser = argparse.ArgumentParser(description='Code for Image Moments tutorial.')parser.add_argument('--input', help='Path to input image.', default='1.jpg')args = parser.parse_args()src = cv.imread(cv.samples.findFile(args.input))if src is None:print('Could not open or find the image:', args.input)exit(0)# Convert image to gray and blur itsrc_gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)src_gray = cv.blur(src_gray, (3, 3))source_window = 'Source'cv.namedWindow(source_window)cv.imshow(source_window, src)max_thresh = 255thresh = 100 # initial thresholdcv.createTrackbar('Canny Thresh:', source_window, thresh, max_thresh, thresh_callback)thresh_callback(thresh)cv.waitKey()
6、涉及到的库函数
cv2.moments
cv2.moments 是 OpenCV 库中的一个函数,用于计算图像轮廓的矩。
一、函数原型
retval = cv2.moments(array[, binaryImage])
二、参数说明
-
array:表示轮廓的数组,可以是点集、灰度图像或二值图像。当 array 是点集时,函数会将这些点集当成轮廓中的顶点,把整个点集作为一条轮廓来处理,而不是将它们当成独立的点来看待。
-
binaryImage:可选参数,布尔值。当该参数为 True 时,array 内所有的非零值都被处理为 1。
三、返回值
- retval:一个字典对象,包含了轮廓的各种矩信息。这些矩可以用于进一步分析,如计算轮廓的重心、长宽比、旋转角度等。
四、矩的类型和含义
- 零阶矩(m00):表示轮廓的面积。这是一个比较直观的含义,可以通过 M[“m00”] 来访问。
- 一阶矩(m10, m01):与轮廓的质心位置有关。其中,m10 表示关于 x 轴的亮度加权平均值(即质心的 x 坐标),m01 表示关于 y 轴的亮度加权平均值(即质心的 y 坐标)。
- 二阶矩及更高阶矩:提供了关于图像形状相对于其中心的分布信息,以及更复杂的形状特征。
五、使用示例
import cv2
import numpy as np# 读取图像
img = cv2.imread("image.jpg")# 转换为灰度图像并二值化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)# 查找轮廓
contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)# 计算每个轮廓的矩
for contour in contours:M = cv2.moments(contour)print("轮廓的矩:", M)print("轮廓的面积:", M["m00"])
六、注意事项
- 在使用 cv2.moments 函数之前,需要确保已经正确读取了图像并找到了轮廓。
- 返回值是一个字典对象,可以通过键来访问不同类型的矩值。
- 矩值可以用于后续的形状分析和特征提取任务中。
综上所述,cv2.moments 函数是 OpenCV 库中用于计算图像轮廓矩的重要工具,它提供了关于图像形状的重要信息,并广泛应用于形状分析、特征提取和形状识别等任务中。
7、参考
- https://docs.opencv.org/5.x/d0/d49/tutorial_moments.html
相关文章:
【python】OpenCV—Image Moments
文章目录 1、功能描述2、图像矩3、代码实现4、效果展示5、完整代码6、涉及到的库函数cv2.moments 7、参考 1、功能描述 计算图像的矩,以质心为例 2、图像矩 什么叫图像的矩,在数字图像处理中有什么作用? - 谢博琛的回答 - 知乎 https://ww…...
环境变量的知识
目录 1. 环境变量的概念 2. 命令行参数 2.1 2.2 创建 code.c 文件 2.3 对比 ./code 执行和直接 code 执行 2.4 怎么可以不带 ./ 2.4.1 把我们的二进制文件拷贝到 usr/bin 路径下,也不用带 ./ 了 2.4.2 把我们自己的路径添加到环境变量里 3. 认识PATH 3.…...
ATECLOUD测试平台有哪些功能?
测试方案搭建 可视化拖拽编程:采用零代码的图文拖拽形式,用户通过鼠标拖拽节点和连线,即可可视化地构建测试模型,无需懂得代码开发,15 分钟左右就能快速搭建项目,大大降低了上手门槛。 子项目多层嵌套&am…...
使用pyinstaller打包pyqt的程序,运行后提示ModuleNotFoundError: No module named ‘Ui_main‘
环境:windowpython3.9pyqt6 使用pyqt UI编辑器生成了main.ui ,main.ui编译成了Ui_main.py main.py 使用当前目录下的Ui_main.py。 打包过程没报错,运行报错。 错误如下: 解决方法:pyinstaller -Fw main.py --paths. 使…...
搭建分布式Spark集群
title: 搭建分布式Spark集群 date: 2024-11-29 12:00:00 categories: - 服务器 tags: - Spark - 大数据搭建分布式Spark集群 本次实验环境:Centos 7-2009、Hadoop-3.1.4、JDK 8、Zookeeper-3.6.3、scala-2.11.5、Spark-3.2.1 功能规划 MasterSlave1Slave2主节点…...
Django基础 - 01入门简介
一、 基本概念 1.1 Django说明 Django发布于2005年, 网络框架, 用Python编写的开源的Web应用框架。采用了MVC框架模式,也称为MTV模式。官网: https://www.djangoproject.com1.2 MVC框架 Model: 封装和数据库相关…...
简单的bytebuddy学习笔记
简单的bytebuddy学习笔记 此笔记对应b站bytebuddy学习视频进行整理,此为视频地址,此处为具体的练习代码地址 一、简介 ByteBuddy是基于ASM (ow2.io)实现的字节码操作类库。比起ASM,ByteBuddy的API更加简单易用。开发者无需了解class file …...
【服务端】Redis 内存超限问题的深入探讨
在 Java 后端开发中,Redis 内存超限是一个常见的问题,可能由多种原因引起。理解这些原因以及如何处理已经超出限制的数据对于保持系统的稳定性和性能至关重要。 一、Redis 内存超限的原因分析 Redis 是一个高性能的内存键值对存储系统,它在…...
Springboot logback 日志打印配置文件,每个日志文件100M,之后滚动到下一个日志文件,日志保留30天(包含traceid)
全部配置 logback.xml <?xml version"1.0" encoding"UTF-8"?> <configuration debug"false"><property name"LOG_HOME" value"log"/><property name"LOG_NAME" value"admin"/&g…...
《计算机组成及汇编语言原理》阅读笔记:p1-p8
《计算机组成及汇编语言原理》学习第 1 天,p1-p8 总结,总计 8 页。 一、技术总结 1.Intel 8088 microprocessor(微处理器), 1979-1988。 2.MS-DOS Microsoft Disk Operating System的缩写,是一个操作系统(operating system)。…...
【游戏中orika完成一个Entity的复制及其Entity异步落地的实现】 1.ctrl+shift+a是飞书下的截图 2.落地实现
一、orika工具使用 1)工具类 package com.xinyue.game.utils;import ma.glasnost.orika.MapperFactory; import ma.glasnost.orika.impl.DefaultMapperFactory;/*** author 王广帅* since 2022/2/8 22:37*/ public class XyBeanCopyUtil {private static MapperFactory mappe…...
在 Ubuntu 上安装 MySQL 的详细指南
在Ubuntu环境中安装 mysql-server 以及 MySQL 开发包(包括头文件和动态库文件),并处理最新版本MySQL初始自动生成的用户名和密码,可以通过官方的APT包管理器轻松完成。以下是详细的步骤指南,包括从官方仓库和MySQL官方…...
Java 优化springboot jar 内存 年轻代和老年代的比例 减少垃圾清理耗时 如调整 -XX:NewRatio
-XX:NewRatio 是 Java Virtual Machine (JVM) 的一个选项,用于调整 年轻代(Young Generation)和 老年代(Old Generation)之间的内存比例。 1. 含义 XX:NewRatioN 用于指定 老年代 与 年轻代 的内存比例。 N 的含义&…...
嵌入式驱动RK3566 HDMI eDP MIPI 背光 屏幕选型与调试提升篇-eDP屏
eDP是嵌入式显示端口,具有高数据传输速率,高带宽,高分辨率、高刷新率、低电压、简化接口数量等特点。现大多数笔记本电脑都是用的这种接口。整个eDP是很复杂的,这里我们不讲底层原理,我们先掌握如何用泰山派来驱动各种…...
在Java虚拟机(JVM)中,方法可以分为虚方法和非虚方法。
在Java虚拟机(JVM)中,方法可以分为虚方法和非虚方法。以下是关于这两种方法的详细解释: 一、虚方法(Virtual Method) 定义:虚方法是指在运行时由实例的实际类型决定的方法。在Java中,所有的非私有、非静态、非final方法都是虚方法。当调用一个虚方法时,JVM会根据实…...
【windows】sonarqube起不来的问题解决
1. 现象与本质 因JDK的问题(比如版本太低或者太高,推荐JDK17)或者其他环境因素,导致sonarqube启动后自动关闭了。 从日志来看,根本看不出来什么,只有警告,没有ERROR,警告也不是本质问题&#…...
golang异常
panic如果不处理会导致应用进程挂掉 defer recover可以处理这种情况 一个recover只处理自己协程 产生panic的情况 空指针 数组越界 空map中添加键值对 错误,error接口,不严重 error.wrapof解决嵌套问题或者error.unwrap erroe.is方法,判断是…...
搭建MongoDB
title: 搭建MongoDB date: 2024-11-30 23:30:00 categories: - 服务器 tags: - MongoDB - 大数据搭建MongoDB 环境:Centos 7-2009 1. 创建MongoDB的国内yum源 # 下载Centos7对应最新版7.0.15的安装包 cat >> /etc/yum.repos.d/mongodb.repo << &quo…...
Android中坐标体系知识超详细讲解
说来说去都不如画图示意简单易懂啊!!!真是的! 来吧先上张图! (一)首先明确一下android 中的坐标系统: 屏幕的左上角是坐标系统原点(0,0) 原点向右延伸是X轴正…...
不需要服务器,使用netlify快速部署自己的网站
Netlify简介 1.1 Netlify的功能与特点 Netlify 是一个功能强大的静态网站托管平台,它不仅提供了简单的网站部署功能,还集成了许多现代化的开发工具和服务,帮助开发者更高效地构建、部署和管理网站。Netlify 的核心功能包括: 自动…...
Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...
【VLNs篇】07:NavRL—在动态环境中学习安全飞行
项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战,克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...
【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
