Opencv轮廓矩【判断形态方向、匹配度】
轮廓矩
原理部分:
矩
一、概率论上的定义
看到矩这个字,很容易联想到概率论,在概率论中,定义如下:
或者说:
设 X 和 Y 是随机变量,c 为常数,k 为正整数,
如果E(|X−c|^k)E(|X−c|^k)存在,则称E(|X−c|^k)E(|X−c|^k)为 X 关于点 c 的 k 阶矩。
- c = 0 时, 称为 k 阶原点矩;
- c = E(x) 时,称为 k 阶中心矩。
如果E(|X−c1|^p⋅|Y−c2|^q)存在,则称其为 X,Y 关于 c 点 p+q 阶矩。
其余基本概率论知识可参考:https://www.cnblogs.com/wyuzl/p/7845948.html
二、在图像学上的定义
一幅M×N的数字图像f(i,j),其p+q阶几何矩和中心矩为:
其中:
- f(i,j)为图像在坐标点(i,j)处的灰度值。
- 重心:,也是图像的一阶矩
三、几何矩的基本意义
(1)零阶矩
可以发现,当图像为二值图时,就是这个图像上白色区域的总和,因此,可以用来求二值图像(轮廓,连通域)的面积。
(2)一阶矩
当图像为二值图时,就是白色像素关于x坐标的累加和,而则是y坐标的累加和
由此,可获得图像的重心:,也就是前文提到的。
(3)二阶矩
二阶矩可以用来求物体形状的方向。
后续会有介绍,具体可参考:https://blog.csdn.net/qq826309057/article/details/70039397
四、由几何矩可表示出中心距如下:
摘自:https://blog.csdn.net/keith_bb/article/details/70197104
为了消除图像比例变化带来的影响,定义规格化中心矩如下:
利用二阶和三阶规格中心矩可以导出下面7个不变矩组(Φ1 Φ7),它们在图像平移、旋转和比例变化时保持不变
Opencv应用部分
核心函数:
(1)求矩
Moments moments(inputArray array, bool binaryImage=false)
- 输入参数,可以是光栅图像(单通道,8位或浮点的二维数组)或二维数组(1N或N1)
- 默认值false,若此参数取true,则所有非零像素为1.此参数仅对图像使用
(2)计算轮廓面积
double contourArea(inputArray contour, bool oriented=false)
- 输入的向量,二维点(轮廓顶点)
- 面向区域标识符,若为true,该函数返回一个带符号的面积值,其正负取决于轮廓的方向(顺时针还是逆时针)。根据这个特性我们可以根据面积的符号来确定轮廓的位置。需要注意的是,这个参数有默认值false,表示以绝对值返回,不带符号。
(3) 计算轮廓长度
double arcLength(inputArray curve,bool closed)
- 输入的二维点集
- 一个用于指示曲线是否封闭的标识符,默认值closed,表示曲线封闭
一、求图像的重心和方向
前面提到二阶矩可以用来求物体形状的方向。
其中:
,
,
fastAtan2()为opencv的函数,输入向量,返回一个0-360的角度。
个人认为:关于fastAtan2()的推算如下:
当然这只是个人推导,有兴趣的同学可以验证一下。
另外,fastAtan2()返回的角度指自然坐标系下x轴正半轴按顺时针到图像轴的角,如下图的α角:
【注意:实际处理时,需把目标部分变成白色,背景为黑色。这里只是为了方便看才把目标变成黑色而已】
测试代码:
- #include<opencv2/imgproc/imgproc.hpp>
- #include<opencv2/highgui/highgui.hpp>
- #include<opencv2/features2d/features2d.hpp>
- #include<stdlib.h>
- #include<stdio.h>
- #include<iostream>
- using namespace std;
- using namespace cv;
- void main()
- {
- Mat srcImg;
- srcImg = imread("F:\\opencv_re_learn\\flash.jpg");
- if (!srcImg.data){
- cout<< "failed to read" << endl;
- system("pause");
- return;
- }
- Mat srcGray;
- cvtColor(srcImg, srcGray, CV_BGR2GRAY);
- Mat thresh;
- threshold(srcGray, thresh, 100, 255, CV_THRESH_BINARY_INV |
- CV_THRESH_OTSU);//二值化时主要要让目标部分是白色像素
- Moments m = moments(thresh, true);//moments()函数计算出三阶及一下的矩
- Point2d center(m.m10 / m.m00, m.m01 / m.m00);//此为重心
- //计算方向
- double a = m.m20 / m.m00 - center.x*center.x;
- double b = m.m11 / m.m00 - center.x*center.y;
- double c = m.m02 / m.m00 - center.y*center.y;
- double theta = fastAtan2(2 * b, (a - c)) / 2;//此为形状的方向
- cout << 2 * b << endl;
- cout << a - c << endl;
- cout <<"角度是:"<< theta << endl;
- //绘制重心
- circle(srcImg, center, 2, Scalar(0, 0, 255),2);
- imshow("src", srcImg);
- imshow("Gray", srcGray);
- imshow("Thresh", thresh);
- waitKey(0);
- }
二、轮廓匹配
轮廓匹配并没有直接用到Moments ,但是是基于轮廓矩的7个不变形矩进行比较的。
相关函数:
- double MatchShapes(const void* object1, const void* object2,
- int method, double parameter = 0);
- 第一个参数是待匹配的物体1
- 第二个是待匹配的物体2
- 第三个参数method有三种输入:【即三种不同的判定物体相似的方法】
- CV_CONTOURS_MATCH_I1
- CV_CONTOURS_MATCH_I2
- CV_CONTOURS_MATCH_I3
测试代码:
- #include<opencv2/highgui/highgui.hpp>
- #include<opencv2/imgproc/imgproc.hpp>
- #include<opencv2/core/core.hpp>
- #include<iostream>
- using namespace std;
- using namespace cv;
- RNG rng(12345);
- Mat init_src(string filename)
- {
- Mat srcImg = imread(filename);
- if (!srcImg.data){
- cout << "filed to read" << endl;
- system("pause");
- return Mat::zeros(100, 100, CV_8UC1);
- }
- return srcImg;
- }
- vector<vector<Point>> find_contour(Mat thresh,string window_name)
- {
- Mat canny_output;
- vector<vector<Point>>contours;
- vector<Vec4i> hierarchy;
- medianBlur(thresh, thresh, 5);
- //canny边缘检测
- //如果图片的轮廓分明,建议可以不进行canny边缘检测,可直接对二值化图像进行findcontours
- //Canny(thresh, thresh, 10, 10 * 2, 3);
- //寻找轮廓
- findContours(thresh, contours, hierarchy,
- CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
- Mat drawing = Mat::zeros(thresh.size(), CV_8UC3);
- for (int i = 0; i < contours.size(); i++){
- //定义随机颜色
- Scalar color = Scalar(rng.uniform(0, 255),
- rng.uniform(0, 255), rng.uniform(0, 255));
- //绘制
- drawContours(drawing, contours, i, color,
- 2, 8, hierarchy, 0, Point());
- }
- //显示
- namedWindow(window_name, CV_WINDOW_AUTOSIZE);
- imshow(window_name, drawing);
- return contours;
- }
- void main()
- {
- //图片读取、预处理
- Mat srcImg1 = init_src("F:\\opencv_re_learn\\angle_test2.jpg");
- Mat srcImg2 = init_src("F:\\opencv_re_learn\\angle_test.jpg");
- Mat srcGray1, srcGray2;
- cvtColor(srcImg1, srcGray1, CV_BGR2GRAY);
- cvtColor(srcImg2, srcGray2, CV_BGR2GRAY);
- Mat thresh1, thresh2;
- threshold(srcGray1, thresh1, 100, 255, CV_THRESH_BINARY_INV |
- CV_THRESH_OTSU);
- threshold(srcGray2, thresh2, 100, 255, CV_THRESH_BINARY_INV |
- CV_THRESH_OTSU);
- //imshow("thresh1", thresh1);
- //imshow("thresh2", thresh2);
- //获取轮廓
- vector<vector<Point>> contours1 = find_contour(thresh1,"contour1");
- vector<vector<Point>> contours2 = find_contour(thresh2,"contour2");
- //轮廓比较
- cout << "first method to match, result:" <<
- matchShapes(contours1[0], contours2[0], CV_CONTOURS_MATCH_I1, 0) << endl;;
- cout << "second method to match, result:" <<
- matchShapes(contours1[0], contours2[0], CV_CONTOURS_MATCH_I2, 0) << endl;
- cout << "third method to match, result:" <<
- matchShapes(contours1[0], contours2[0], CV_CONTOURS_MATCH_I2, 0)<<endl;
- imshow("src1", srcImg1);
- imshow("src2", srcImg2);
- waitKey(0);
- }
应该只需修改图片的路径即可进行调试
1)读入两张相同的图片,三种方法匹配的结果都是0,表示完全匹配
2)还是读入上面的两张图片,但是其中一张经过旋转
结果:三种方法匹配的结果都很接近0,表示这两个轮廓还是基本匹配的
3)读入两张不同的图片
结果明显偏离0,但是可以说还是有一点相似性吧。。。
参考文章:
https://blog.csdn.net/qq_31531635/article/details/73692611
https://blog.csdn.net/qq826309057/article/details/70039397
https://blog.csdn.net/keith_bb/article/details/70197104
https://blog.csdn.net/mingzhentanwo/article/details/45155307
Opencv轮廓矩【判断形态方向、匹配度】相关推荐
- opencv轮廓及点在轮廓内判断
查找轮廓 轮廓到底是什么?一个轮廓一般对应一系列的点,也就是图像中的一条曲线.表示的方法可能根据不同情况而有所不同.有多重方法可以表示曲线.在openCV中一般用序列来存储轮廓信息.序列中的每一个元素 ...
- 使用OpenCV计算图像的轮廓矩的代码
图像处理开发需求.图像处理接私活挣零花钱,请加微信/QQ 2487872782 图像处理开发资料.图像处理技术交流请加QQ群,群号 271891601 轮廓矩用来干嘛?说实话,我是没有找到相关文章专门 ...
- OpenCV之imgproc 模块. 图像处理(5)在图像中寻找轮廓 计算物体的凸包 创建包围轮廓的矩形和圆形边界框 为轮廓创建可倾斜的边界框和椭圆 轮廓矩 多边形测试
在图像中寻找轮廓 目标 在这个教程中你将学到如何: 使用OpenCV函数 findContours 使用OpenCV函数 drawContours 原理 例程 教程的代码在下面给出. 你也可以从 这里 ...
- OpenCV-Python实战(11)——OpenCV轮廓检测相关应用
OpenCV-Python实战(11)--OpenCV轮廓检测相关应用 0. 前言 1. 轮廓绘制 2. 轮廓筛选 3. 轮廓识别 4. 轮廓匹配 小结 系列链接 0. 前言 在计算机视觉领域,轮廓通 ...
- Python,OpenCV轮廓属性、轮廓检测及绘制
Python,OpenCV轮廓属性.轮廓检测及绘制 1. 效果图 2. 源码 2.1 轮廓属性 2.2 轮廓特征 参考 这篇博客将介绍OpenCV中的轮廓,轮廓的特征及属性(质心,面积,轮廓,近似轮廓 ...
- OpenCV-Python实战(10)——详解 OpenCV 轮廓检测
OpenCV-Python实战(10)--详解 OpenCV 轮廓检测 0. 前言 1. 轮廓介绍 2. 轮廓检测 3. 轮廓压缩 4. 图像矩 4. 1 一些基于矩的对象特征 4.2 Hu 不变矩 ...
- 12月19日 OpenCV 实战基础学习笔记——特征匹配
文章目录 前言 一.特征匹配 1.Brute-force 蛮力匹配 2.1 对 1 匹配 3.k 对最佳匹配 二.答题卡识别 前言 本文为12月19日 OpenCV 实战基础学习笔记--特征匹配,分为 ...
- OpenCV学习之六: 使用方向梯度直方图估计图像旋转角度
OpenCV学习之六: 使用方向梯度直方图估计图像旋转角度 原文:http://blog.csdn.net/zhjm07054115/article/details/26964275 下面的代码通过计 ...
- 德国计算机课程匹配度,匹配度对于德国留学有多重要
对于留学的申请来说,匹配都是一个比较重要的因素.那么为什么德国的留学这么看重匹配度?到出国留学网这里了解他的原因吧. 一.课程匹配度这么重要 大家在申请的时候可能第一个考虑的.就是语言或者是APS审核 ...
- 德国计算机课程匹配度,为什么德国大学就这么看重本科的课程匹配?
hi~大家12月好. 不知不觉2019年已经进入最后一个月了,回忆一下这一年,大家过得怎么样? 在12月的第一个工作日,我要给大家掰一掰,这个让大家恨得深沉,累得头秃的大问题. 德国大学硕士申请为何如 ...
最新文章
- Python3学习笔记-数据类型和变量
- if语句的一种使用失误
- oracle常用函数归纳
- vba 提取 json某个值_Excel中提取不重复值的方法汇总(5种基础+VBA+1个自定义函数)...
- postgresql主从备份_基于windows平台的postgresql主从数据库流备份配置
- js php c语言for循环,小蚂蚁学习C语言(8)——C语言for循环
- java 祖父类_JAVA的XX.put中的put方法,是在哪个父类或祖父类中,详述父类链。
- 也谈zabbix性能优化
- EasyRecovery数据恢复软件100%恢复的成功率
- csgo服务器怎么显示cmd,CSGO服务器搭建教程——KZ模式
- 有各组方差怎么算组间平方和_方差分析:组间离差平方和组内离差平方的定义是什么?...
- android高仿ios键盘,iOS仿工商银行app自定义键盘
- SCI论文写作是用主动语态好还是被动语态好?
- arcgis pro发布矢量切片服务及利用arcgis api for javascript进行调用
- 千万别小瞧九宫格 一道题就能让候选人原形毕露!
- 【JMeter】Jmeter分布式压测教程
- 浅谈递归函数—C语言
- 月球公转与自转(一)
- 您的Android手机可以充当盖革计数器的双重职责
- Android禁用截屏