【从零学习OpenCV 4】图像矩的计算与应用

重磅干货,第一时间送达
经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍《从零学习OpenCV 4》。为了更让小伙伴更早的了解最新版的OpenCV 4,小白与出版社沟通,提前在公众号上连载部分内容,请持续关注小白。

矩是描述图像特征的算子,被广泛用于图像检索和识别、图像匹配、图像重建、图像压缩以及运动图像序列分析等领域。本节中将介绍几何矩与Hu矩的计算方法以及应用Hu矩实现图像轮廓的匹配。

几何矩与中心矩

图像几何矩的计算方式如式(7.8)所示:

其中是像素处的像素值。当x和y同时取值0时称为零阶矩,零阶矩可以用于计算某个形状的质心,当x和y分别取值0和1时被称为一阶矩,以此类推。图像质心的计算公式如(7.9)所示:

图像中心距计算方式如式(7.10)所示:

图像归一化几何矩计算方式如式所示:

OpenCV 4提供了计算图像矩的moments()函数,该函数的函数原型在代码清单7-28中给出。

代码清单7-28 moments()函数原型Moments cv::moments(InputArray array, bool binaryImage = false )
  • array:计算矩的区域2D像素坐标集合或者单通道的CV_8U图像
  • binaryImage:是否将所有非0像素值视为1的标志。

该函数用于计算图像连通域的几何矩和中心距以及归一化的几何矩。函数第一个参数是待计算矩的输入图像或者2D坐标集合。函数第二个参数为是否将所有非0像素值视为1的标志,该标志只在第一个参数输入为图像类型的数据时才会有作用。函数会返回一个Moments类的变量,Moments类中含有几何矩、中心距以及归一化的几何矩的数值属性,例如Moments.m00是零阶矩,Moments.m01和Moments.m10是一阶矩。Moments类中所有的属性在表7-5给出。

表7-5 Moments类的属性

种类 属性
spatial moments m00、m10、m01、m20、m11、m02、m30、m21、m12、m03
central moments mu20、mu11、mu02、mu30、mu21、mu12、mu03
central normalized moments nu20、nu11、nu02、nu30、nu21、nu12、nu03

为了了解函数的使用方法,在代码清单7-29中给出了计算图像矩和读取每一种矩数值方法的示例程序,程序的部分运行结果如图7-24所示。

代码清单7-29 myMoments.cpp计算图像的矩#include <opencv2/opencv.hpp>#include <iostream>#include <vector>
using namespace cv;using namespace std;
int main(){Mat img = imread("approx.png");
// 二值化Mat gray, binary;cvtColor(img, gray, COLOR_BGR2GRAY);threshold(gray, binary, 105, 255, THRESH_BINARY);
//开运算消除细小区域Mat k = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));morphologyEx(binary, binary, MORPH_OPEN, k);
// 轮廓发现vector<vector<Point>> contours;vector<Vec4i> hierarchy;findContours(binary, contours, hierarchy, 0, 2, Point());for (int n = 0; n < contours.size(); n++) {Moments M;M = moments(contours[n], true);cout << "spatial moments:" << endl<< "m00:" << M.m00 << " m01:" << M.m01 << " m10:" << M.m10 << endl<< "m11:" << M.m11 << " m02:" << M.m02 << " m20:" << M.m20 << endl<< "m12:" << M.m12 << " m21:" << M.m21 << " m03:" << M.m03 << " m30:"<< M.m30 << endl;
cout << "central moments:" << endl<< "mu20:" << M.mu20 << " mu02:" << M.mu02 << " mu11:" << M.mu11 << endl<< "mu30:" << M.mu30 << " mu21:" << M.mu21 << " mu12:" << M.mu12 << " mu03:" << M.mu03 << endl;
cout << "central normalized moments:" << endl<< "nu20:" << M.nu20 << " nu02:" << M.nu02 << " nu11:" << M.nu11 << endl<< "nu30:" << M.nu30 << " nu21:" << M.nu21 << " nu12:" << M.nu12 << " nu03:" << M.nu03 << endl;}return 0;}

图7-24 myMoments.cpp程序部分运行结果

Hu矩

Hu矩具有旋转、平移和缩放不变性,因此在图像具有旋转和放缩的情况下Hu矩具有更广泛的应用领域。Hu矩是由二阶和三阶中心距计算得到七个不变矩,具体计算公式如式(7.12)所示:

OpenCV 4提供了用于计算Hu矩的HuMoments()函数,根据参数类型的不同该函数具有两种原型。在代码清单7-30中给出这两种函数原型。

代码清单7-30 HuMoments()函数原型void cv::HuMoments(const Moments & moments, double hu[7] )void cv::HuMoments(const Moments & m, OutputArray hu )
  • moments:输入的图像矩
  • hu[7]:输出Hu矩的七个值
  • m:输入的图像矩
  • hu:输出Hu矩的矩阵

该函数可以根据图像的中心距计算图像的Hu矩。两个函数原型只有第二个参数的数据类型不同,第一个参数是输入图的Moments类的图像矩,第二个参数是输出的Hu矩,第一种函数原型输出值存放在长度为7的double类型数组中,第二种函数原型输出值为Mat类型。

为了了解函数的使用方法,在代码清单7-31中给出了计算图像Hu的示例程序,程序的部分运行结果如图7-25所示。

代码清单7-31 myHuMoments.cpp计算图像的Hu矩#include <opencv2/opencv.hpp>#include <iostream>#include <vector>
using namespace cv;using namespace std;
int main(){system("color F0"); //更改输出界面颜色Mat img = imread("approx.png");if (img.empty()){cout << "请确认图像文件名称是否正确" << endl;return -1;}// 二值化Mat gray, binary;cvtColor(img, gray, COLOR_BGR2GRAY);threshold(gray, binary, 105, 255, THRESH_BINARY);
//开运算消除细小区域Mat k = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));morphologyEx(binary, binary, MORPH_OPEN, k);
// 轮廓发现vector<vector<Point>> contours;vector<Vec4i> hierarchy;findContours(binary, contours, hierarchy, 0, 2, Point());for (int n = 0; n < contours.size(); n++){Moments M;M = moments(contours[n], true);Mat hu;HuMoments(M, hu); //计算Hu矩cout << hu << endl;}return 0;}

图7-25 myHuMoments.cpp程序部分运行结果

基于Hu矩的轮廓匹配

Hu矩具有旋转、平移和比例不变性,因此可以通过Hu实现图像轮廓的匹配。OpenCV 4提供了利用Hu矩进行轮廓匹配的matchShapes()函数,该函数的函数原型在代码清单7-32中给出。

代码清单7-32 matchShapes()函数原型double cv::matchShapes(InputArray contour1, InputArray contour2, int method, double parameter )
  • contour1:原灰度图像或者轮廓
  • contour2:模板图像或者轮廓
  • method:匹配方法的标志,可以选择的参数及含义在表7-6给出。
  • parameter:特定于方法的参数(现在不支持)

该函数用于实现在图像或者轮廓中寻找与模板图像或者轮廓像素匹配的区域。函数的第一个参数是原灰度图像或者轮廓,第二个参数是模板图像或者轮廓。函数第三个参数是两个轮廓Hu矩匹配的计算方法标志,可以选择的参数和每种方法相似性计算公式在表7-6给出。函数最后一个参数在目前的OpenCV 4版本中没有意义,可以将参数设置为0。

表7-6 matchShapes()函数中匹配方法的标志

标志参数 简记 原理
CONTOURS_MATCH_I1 1
CONTOURS_MATCH_I2 2
CONTOURS_MATCH_I3 3

为了了解函数的用法,在代码清单7-33中给出了利用Hu矩实现模板与原图像或者轮廓之间匹配的示例程序。程序中原图像有三个字母,模板图像有一个字母,并且模板图像中字母的尺寸小于原图像中字母的尺寸。通过对两张图像提取轮廓并计算每个轮廓的Hu矩,之后寻找原图像和模板图像中Hu矩最相似的两个轮廓,并在原图像中绘制出相似轮廓,程序运行结果在图7-26给出。

代码清单7-33 myMatchShapes.cpp基于Hu矩的轮廓匹配#include <opencv2/opencv.hpp>#include <iostream>#include <vector>
using namespace cv;using namespace std;
void findcontours(Mat &image, vector<vector<Point>> &contours){Mat gray, binary;vector<Vec4i> hierarchy;//图像灰度化cvtColor(image, gray, COLOR_BGR2GRAY);//图像二值化threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);//寻找轮廓findContours(binary, contours, hierarchy, 0, 2);}
int main(){Mat img = imread("ABC.png");Mat img_B = imread("B.png");if (img.empty() || img_B.empty()){cout << "请确认图像文件名称是否正确" << endl;return -1;}
resize(img_B, img_B, Size(), 0.5, 0.5);imwrite("B.png", img_B);imshow("B", img_B);
// 轮廓提取vector<vector<Point>> contours1;vector<vector<Point>> contours2;findcontours(img, contours1);findcontours(img_B, contours2);// hu矩计算Moments mm2 = moments(contours2[0]);Mat hu2;HuMoments(mm2, hu2);// 轮廓匹配for (int n = 0; n < contours1.size(); n++){Moments mm = moments(contours1[n]);Mat hum;HuMoments(mm, hum);//Hu矩匹配double dist;dist = matchShapes(hum, hu2, CONTOURS_MATCH_I1, 0);if (dist < 1){drawContours(img, contours1, n, Scalar(0, 0, 255), 3, 8);}}imshow("match result", img);waitKey(0);return 0;}

图7-26 myMatchShapes.cpp程序运行结果

(0)

相关推荐

  • OpenCV学习28

    查找轮廓 什么是轮廓:一个轮廓是由图像中的一系列点组成的,也就是图像中的一条曲线.在OpenCV中一般用序列来存储轮廓信息.序列中的每个元素是曲线中每个点的位置. 关于序列:序列是内存存储器中可以存储 ...

  • 【OpenCV读取标记点坐标】管道测速

    文章目录 一.项目简介 二.思考步骤 1. 图像二值化 2. 滤波去噪 3. Canny算法检测边缘 4. 查找轮廓并计算 5. 绘制轮廓并表示质心 三.测试结果 四.工程代码 一.项目简介 昨天一个 ...

  • OpenCV探索之路(十一):轮廓查找和多边形包围轮廓

    Canny一类的边缘检测算法可以根据像素之间的差异,检测出轮廓边界的像素,但它没有将轮廓作为一个整体.所以要将轮廓提起出来,就必须将这些边缘像素组装成轮廓. OpenCV中有一个很强大的函数,它可以从 ...

  • opencv笔记(二十九)——提取轮廓相关函数使用方法

    opencv中常用的跟轮廓相关的操作有:findContours()查找轮廓:drawContours()画轮廓:轮廓填充:计算轮廓的面积和周长:提取轮廓凸包,矩形,最小外接矩形,外接圆等.它们都有相 ...

  • findContours()函数

    函数原型 findContours(InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int m ...

  • OPENCV之寻找并绘制轮廓以及提取轮廓重心坐标

    OPENCV之寻找并绘制轮廓以及提取轮廓重心坐标 1.寻找轮廓 声明:在寻找图像轮廓之前需要对图像进行阈值分割或者Canny.拉普拉斯等边缘检测算子处理. 寻找轮廓的算子: findContours( ...

  • 【从零学习OpenCV】图像的保存&视频的保存

    重磅干货,第一时间送达 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍<从零学习OpenCV 4>.为了更让小伙伴更早的了解最新版的OpenCV 4,小白与出版社沟通 ...

  • 【从零学习OpenCV 4】图像修复

    重磅干货,第一时间送达 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍<OpenCV 4开发详解>.为了更让小伙伴更早的了解最新版的OpenCV 4,小白与出版社沟通 ...

  • 【从零学习OpenCV 4】分割图像——Mean-Shift分割算法

    重磅干货,第一时间送达 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍<从零学习OpenCV 4>.为了更让小伙伴更早的了解最新版的OpenCV 4,小白与出版社沟通 ...

  • 【从零学习OpenCV 4】分割图像——Grabcut图像分割

    重磅干货,第一时间送达 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍<OpenCV 4开发详解>.为了更让小伙伴更早的了解最新版的OpenCV 4,小白与出版社沟通 ...

  • 【从零学习OpenCV 4】分割图像——分水岭法

    重磅干货,第一时间送达 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍<OpenCV 4开发详解>.为了更让小伙伴更早的了解最新版的OpenCV 4,小白与出版社沟通 ...

  • 【从零学习OpenCV 4】图像膨胀

    重磅干货,第一时间送达 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍<OpenCV 4开发详解>.为了更让小伙伴更早的了解最新版的OpenCV 4,小白与出版社沟通 ...

  • 【从零学习OpenCV 4】图像距离变换

    重磅干货,第一时间送达 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍<OpenCV 4开发详解>.为了更让小伙伴更早的了解最新版的OpenCV 4,小白与出版社沟通 ...

  • 【从零学习OpenCV 4】图像中添加高斯噪声

    重磅干货,第一时间送达 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍<从零学习OpenCV 4>.为了更让小伙伴更早的了解最新版的OpenCV 4,小白与出版社沟通 ...

  • 【从零学习OpenCV 4】图像中添加椒盐噪声

    重磅干货,第一时间送达 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍<从零学习OpenCV 4>.为了更让小伙伴更早的了解最新版的OpenCV 4,小白与出版社沟通 ...