【python】OpenCV—Image Moments

ops/2024/12/22 13:01:09/

在这里插入图片描述

文章目录

  • 1、功能描述
  • 2、图像矩
  • 3、代码实现
  • 4、效果展示
  • 5、完整代码
  • 6、涉及到的库函数
  • 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、代码实现

导入必要的库函数,固定随机种子,以保证绘制出来的图片色彩固定随机

python">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

python">    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)

图片转化为灰度图,做模糊处理,并在窗口中显示

python">    # 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

python">    max_thresh = 255thresh = 100  # initial thresholdcv.createTrackbar('Canny Thresh:', source_window, thresh, max_thresh, thresh_callback)thresh_callback(thresh)cv.waitKey()

看看核心函数 thresh_callback

计算 canny 边缘检测,调用找轮廓函数,获取所有边缘轮廓

python">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)

计算每个轮廓的矩

python">    # Get the momentsmu = [None] * len(contours)for i in range(len(contours)):mu[i] = cv.moments(contours[i])

计算每个轮廓的质心,图片中所有像素点的横坐标除以图片的像素点个数(面积),结果为质心的横坐标

同理可以计算出质心的纵坐标

python">    # 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))

看看计算出来的矩的所有信息

python">mu[0]

output

python">{'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}

绘制轮廓,绘制每个轮廓的质心,保存结果

python">    # 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 接口的轮廓面积

python">    # 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

python"> * 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、完整代码

python">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、涉及到的库函数

moments_340">cv2.moments

cv2.moments 是 OpenCV 库中的一个函数,用于计算图像轮廓的矩。

一、函数原型

python">retval = cv2.moments(array[, binaryImage])

二、参数说明

  • array:表示轮廓的数组,可以是点集、灰度图像或二值图像。当 array 是点集时,函数会将这些点集当成轮廓中的顶点,把整个点集作为一条轮廓来处理,而不是将它们当成独立的点来看待。

  • binaryImage:可选参数,布尔值。当该参数为 True 时,array 内所有的非零值都被处理为 1。

三、返回值

  • retval:一个字典对象,包含了轮廓的各种矩信息。这些矩可以用于进一步分析,如计算轮廓的重心、长宽比、旋转角度等。

四、矩的类型和含义

  • 零阶矩(m00):表示轮廓的面积。这是一个比较直观的含义,可以通过 M[“m00”] 来访问。
  • 一阶矩(m10, m01):与轮廓的质心位置有关。其中,m10 表示关于 x 轴的亮度加权平均值(即质心的 x 坐标),m01 表示关于 y 轴的亮度加权平均值(即质心的 y 坐标)。
  • 二阶矩及更高阶矩:提供了关于图像形状相对于其中心的分布信息,以及更复杂的形状特征。

五、使用示例

python">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、参考


http://www.ppmy.cn/ops/144022.html

相关文章

大模型技术优化负载均衡:AI驱动的智能化运维

在现代信息技术环境中,负载均衡是确保系统稳定、高效运行的关键技术。随着大模型技术(Large Model Technology, LMT)的发展,AI驱动的智能化负载均衡成为了优化系统性能、提升用户体验的重要手段。本文将详细介绍如何使用Python实现…

linux springboot项目启动端口被占用 Port 8901 was already in use.

....eb server failed to start. Port 8901 was already in use.Action:Identify and stop the process thats listening on port 8901 or configure this application to listen on another port.问题分析 这个错误表明端口 8901 已被其他进程占用。为了启动你的应用&#xf…

基于Spring Boot的新能源汽车个性化推荐系统

一、系统背景与意义 随着新能源汽车市场的快速发展,消费者对新能源汽车的需求日益多样化。为了满足消费者的个性化需求,提高购车体验,开发一个基于Spring Boot的新能源汽车个性化推荐系统显得尤为重要。该系统能够根据用户的偏好、历史行为等…

【单片机原理】第1章 微机基础知识,运算器,控制器,寄存器,微机工作过程,数制转换

关注作者了解更多 我的其他CSDN专栏 过程控制系统 工程测试技术 虚拟仪器技术 可编程控制器 工业现场总线 数字图像处理 智能控制 传感器技术 嵌入式系统 复变函数与积分变换 单片机原理 线性代数 大学物理 热工与工程流体力学 数字信号处理 光电融合集成电路…

Java模拟多个Mqtt客户端连接Mqtt Broker

上一次我们介绍了Java模拟单个Mqtt客户端的场景&#xff0c;但是在实际的业务场景中&#xff0c;可能需要我们模拟多个Mqtt客户端&#xff0c;比如&#xff1a;我们要对云平台的连接和设备上下行做压测。 Java模拟多个Mqtt客户端基本流程 引入Paho MQTT客户端库 <depende…

git管理

Git 项目管理&#xff1a;从本地开发到远程仓库提交 在这篇博客中&#xff0c;我将向你展示如何将本地的一个 Python 项目与远程 Git 仓库进行关联&#xff0c;并完成代码的提交和管理&#xff0c;同时处理一些常见的 Git 操作问题。以下是详细的步骤&#xff1a; 一、初始化…

srping2.0+升级到spring3.0+遇到的问题,es部分记录一下

最近公司项目,在做版本升级,首先srping2.0升级到spring3.0,目前无漏洞版本是springBoot3.2.12springClould2023.0.3,升级完spring,紧接着升级es,原来我们使用的es客户端版本是7.9.3,升级到无漏洞版本是7.17.23 <elasticsearch.version>7.17.23</elasticsearch.version…

题海拾贝:力扣 86.分隔链表

Hello大家好&#xff01;很高兴我们又见面啦&#xff01;给生活添点passion&#xff0c;开始今天的编程之路&#xff01; 我的博客&#xff1a;<但凡. 我的专栏&#xff1a;《编程之路》、《数据结构与算法之美》、《题海拾贝》 欢迎点赞&#xff0c;关注&#xff01; 1、题…