一、图像的轮廓(Contours of Image)

轮廓可以说是一个很好的图像目标的外部特征,这种特征对于我们进行图像分析,目标识别和理解等更深层次的处理都有很重要的意义。那么,怎么取提取轮廓呢?

轮廓提取的基本原理:

        (针对二值化的轮廓提取是这样的)对于一幅背景为白色、目标为黑色的二值图像,如果在图中找到一个黑色点,且它的8邻域(或4邻域)也均为黑色,则说明该点是目标的内部点,将其置为白色,视觉上就像内部被掏空一样;否则保持黑色不变,该点是目标的边界点。

这里顺带提下边缘检测,和轮廓提取的区别:

边缘检测主要是通过一些手段检测数字图像中明暗变化剧烈(即梯度变化比较大)像素点,偏向于图像中像素点的变化。如canny边缘检测,结果通常保存在和源图片一样尺寸和类型的边缘图中。 
轮廓检测指检测图像中的对象边界,更偏向于关注上层语义对象。如OpenCV中的findContours()函数, 它会得到每一个轮廓并以点向量方式存储,除此也得到一个图像的拓扑信息,即一个轮廓的后一个轮廓、前一个轮廓、父轮廓和内嵌轮廓的索引编号。

1.1 发现与绘制轮廓

在OpenCV里面利用findContours()函数和drawContours()函数实现这一功能。

API介绍:

C++:void findContours(InputOutputArray  image,OutputArrayOfArrays  contours,OutputArray  hierarchy,int  mode,int  method,Point  offset = Point() )   

参数详解:

参数一: image,单通道图像矩阵,可以是灰度图,但更常用的是二值图像,一般是经过Canny、拉普拉斯等边缘检测算子处理过的二值图像;

参数二: contours是一个向量,并且是一个双重向量,向量内每个元素保存了一组由连续的Point点构成的点的集合的向量,每一组Point点集就是一个轮廓。有多少轮廓,向量contours就有多少元素。

参数三: hierarchy也是一个向量,向量内每个元素保存了一个包含4个int整型的数组。向量hiararchy内的元素和轮廓向量contours内的元素是一一对应的,向量的容量相同。hierarchy向量内每一个元素的4个int型变量——hierarchy[i][0] ~hierarchy[i][3],分别表示第i个轮廓的后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号。如果当前轮廓没有对应的后一个轮廓、前一个轮廓、父轮廓或内嵌轮廓的话,则hierarchy[i][0] ~hierarchy[i][3]的相应位被设置为 默认值-1。

参数四: int型的mode,定义轮廓的检索模式:

模式一:CV_RETR_EXTERNAL只检测最外围轮廓,包含在外围轮廓内的内围轮廓被忽略

模式二:CV_RETR_LIST 检测所有的轮廓,包括内围、外围轮廓,但是检测到的轮廓不建立等级关系,彼此之间独立,没有等级关系,这就意味着这个检索模式下不存在父轮廓或内嵌轮廓,所以hierarchy向量内所有元素的第3、第4个分量都会被置为-1,

模式三:CV_RETR_CCOMP 检测所有的轮廓,但所有轮廓只建立两个等级关系,外围为顶层,若外围内的内围轮廓还包含了其他的轮廓信息,则内围内的所有轮廓均归属于顶层

模式四:CV_RETR_TREE, 检测所有轮廓,所有轮廓建立一个等级树结构。外层轮廓包含内层轮廓,内层轮廓还可以继续包含内嵌轮廓。

参数五: int型的method,定义轮廓的近似方法:

方式一:CV_CHAIN_APPROX_NONE 保存物体边界上所有连续的轮廓点到contours向量内

方式二:CV_CHAIN_APPROX_SIMPLE 仅保存轮廓的拐点信息,把所有轮廓拐点处的点保存入contours 向量内,拐点与拐点之间直线段上的信息点不予保留

方式三和四:CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法

参数六: Point偏移量,所有的轮廓信息相对于原始图像对应点的偏移量,相当于在每一个检测出的轮廓 点上加上该偏移量,并且Point还可以是负值

drawContours(//InputOutputArray  binImg, // 输出图像//OutputArrayOfArrays  contours,//  全部发现的轮廓对象//Int contourIdx// 轮廓索引号//const Scalar & color,// 绘制时候颜色//int  thickness,// 绘制线宽//int  lineType,// 线的类型LINE_8//InputArray hierarchy,// 拓扑结构图//int maxlevel,// 最大层数, 0只绘制当前的,1表示绘制绘制当前及其内嵌的轮廓//Point offset = Point()// 轮廓位移,可选

示例程序

//轮廓发现(find contour)
//轮廓发现是基于图像边缘提取的基础寻找对象轮廓的方法。所以边缘提取的阈值选定会影响最终轮廓发现结果
//步骤:输入图像转为灰度图像cvtColor//使用Canny进行边缘提取,得到二值图像//使用findContours寻找轮廓//使用drawContours绘制轮廓#include"stdafx.h"
#include<opencv2/opencv.hpp>
#include<iostream>
#include<math.h>using namespace std;
using namespace cv;Mat src, dst;
char input[] = "gray image";
int threshold_value = 100;
int threshold_max = 255;
void find_contour_demo(int, void*);
int main(int argc, char*argv)
{src = imread("C:\\Users\\59235\\Desktop\\imag\\mixed_03.png");if (!src.data){printf("could not load image...\n");return -1;}namedWindow(input, CV_WINDOW_AUTOSIZE);namedWindow("result", CV_WINDOW_AUTOSIZE);//输入图像转为灰度图像cvtColor(src, src, CV_BGR2GRAY);imshow(input, src);const char*thresh = "threshold value";createTrackbar(thresh, input, &threshold_value, threshold_max, find_contour_demo);find_contour_demo(0, 0);waitKey(0);return 0;
}void find_contour_demo(int, void*)
{//使用Canny进行边缘提取,得到二值图像Canny(src, dst, threshold_value, threshold_value * 2, 3, false);imshow("canny detection", dst);//使用findContours寻找轮廓vector<vector<Point>> contours;vector<Vec4i> hierachy;findContours(dst, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));//findContours(//InputOutputArray  binImg, // 输入图像,非0的像素被看成1,0的像素值保持不变,8-bit//OutputArrayOfArrays  contours,//  全部发现的轮廓对象//OutputArray, hierachy// 图该的拓扑结构,可选,该轮廓发现算法正是基于图像拓扑结构实现。//int mode, //  轮廓返回的模式//int method,// 发现方法//Point offset = Point()//  轮廓像素的位移,默认(0, 0)没有位移)//使用drawContours绘制轮廓Mat drawImage = Mat::zeros(src.size(), CV_8UC3);RNG rng(12345);for (int i = 0; i < contours.size(); i++){Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));drawContours(drawImage, contours, i, color, 2, LINE_AA, hierachy, 0, Point(0, 0));//drawContours(//InputOutputArray  binImg, // 输出图像//OutputArrayOfArrays  contours,//  全部发现的轮廓对象//Int contourIdx// 轮廓索引号//const Scalar & color,// 绘制时候颜色//int  thickness,// 绘制线宽//int  lineType,// 线的类型LINE_8//InputArray hierarchy,// 拓扑结构图//int maxlevel,// 最大层数, 0只绘制当前的,1表示绘制绘制当前及其内嵌的轮廓//Point offset = Point()// 轮廓位移,可选}imshow("result", drawImage);return;
}

效果图:                        (灰度图)                                                                                                               (canny边缘检测图)

(绘制轮廓图)

总结:

OpenCV提取轮廓之后,还可以进行许多操作:

  • ArcLength() 计算轮廓长度
  • ContourArea() 计算轮廓区域的面积
  • BoundingRect() 轮廓的外包矩形
  • ConvexHull() 提取轮廓的凸包
  • IsContourConvex() 测试轮廓的凸性
  • MinAreaRect() 轮廓的最小外包矩形
  • MinEnclosingCircle() 轮廓的最小外包圆
  • fitEllipse()用椭圆拟合二维点集
  • approxPolyDP()逼近多边形曲线

 二、图像的矩(Image Moments)

矩的概念介绍

       矩函数在图像分析中有着广泛的应用,如模式识别、目标分类、目标识别与方位估计、图像的编码与重构等。从一幅图像计算出来的矩集,不仅可以描述图像形状的全局特征,而且可以提供大量关于该图像不同的几何特征信息,如大小,位置、方向和形状等。图像矩这种描述能力广泛应用于各种图像处理、计算机视觉和机器人技术领域的目标识别与方位估计中。

一阶矩:与形状有关;

二阶矩:显示曲线围绕直线平均值的扩展程度;

三阶矩:关于平均值的对称性测量;由二阶矩和三阶矩可以导出7个不变矩。而不变矩是图像的统计特性,满足平移、伸缩、旋转均不变的不变性、在图像识别领域得到广泛的应用。

1 、空间矩/几何矩

空间矩的实质为面积或者质量。可以通过一阶矩计算质心/重心。

重心(中心centers):

2、中心矩

中心矩体现的是图像强度的最大和最小方向(中心矩可以构建图像的协方差矩阵),其只具有平移不变性,所以用中心矩做匹配效果不会很好。

3、归一化的中心矩

归一化后具有尺度不变性。

4、Hu矩

Hu矩由于具有尺度、旋转、平移不变性,可以用来做匹配。

cv::moments 计算生成数据:

//图像矩:(Image Moments)
//步骤:提取图像边缘
//发现轮廓
//计算每个轮廓对象的矩
//计算每个对象的中心、弧长、面积#include"stdafx.h"
#include<opencv2/opencv.hpp>
#include<iostream>
#include<math.h>using namespace cv;
using namespace std;Mat src, dst, drawImage;
const char*result = "moments_demo";
int threshold_value = 120;
int threshold_max = 255;
RNG rng(12345);
void Moments_demo(int, void*);
int main(int argc, char*argv)
{src = imread("C:\\Users\\59235\\Desktop\\imag\\mixed_01.png");if (!src.data){printf("could not load image...\n");return -1;}char input[] = "gray image";namedWindow(input, CV_WINDOW_AUTOSIZE);namedWindow(result, CV_WINDOW_AUTOSIZE);//输入图像转为灰度图像cvtColor(src, dst, CV_BGR2GRAY);GaussianBlur(dst, dst, Size(3, 3), 0, 0);imshow(input, dst);const char*thresh = "threshold value";createTrackbar(thresh, result, &threshold_value, threshold_max, Moments_demo);Moments_demo(0, 0);waitKey(0);return 0;
}void Moments_demo(int, void*)
{//提取图像边缘Mat canny_out;Canny(dst, canny_out, threshold_value, threshold_value * 2, 3, false);//imshow("canny image", canny_out);//发现轮廓,找到图像轮廓vector<vector<Point>> contours;vector<Vec4i> hierachy;findContours(canny_out, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));//计算每个轮廓对象的矩vector<   Moments> contours_moments(contours.size());vector<Point2f> centers(contours.size());for (size_t i = 0; i < contours.size(); i++){//计算矩contours_moments[i] = moments(contours[i]);//moments(InputArray  array,//输入数据//bool   binaryImage = false // 是否为二值图像centers[i] = Point(static_cast<float>(contours_moments[i].m10 / contours_moments[i].m00), static_cast<float>(contours_moments[i].m01 / contours_moments[i].m00));//图像中心Center(x0, y0)=(m10/m00,m01/m00)}src.copyTo(drawImage);for (size_t i = 0; i < contours.size(); i++){printf("centers point x:%.2f,y:%.2f\n", centers[i].x, centers[i].y);printf("contours %d Area:%.2f Arc length:%.2f \n", i, contourArea(contours[i]), arcLength(contours[i], true));//contourArea(InputArray  contour,//输入轮廓数据//bool   oriented// 默认false、返回绝对值)//arcLength(InputArray  curve,//输入曲线数据//bool   closed// 是否是封闭曲线)//考虑如何把数据显示在原图像上//double A;//A=contourArea(contours[i]);//ostringstream os;//os << A;//putText(drawImage,os.str,centers[i], CV_FONT_BLACK, 2.0, Scalar(0,0,255), 2, 8);//依次含义:原图,输入字的内容,起始位置,字体,字的大小,颜色,线条大小粗 细,连接域Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));drawContours(drawImage, contours, i, color, 2, LINE_AA, hierachy, 0, Point(0, 0));//绘制轮廓circle(drawImage, centers[i], 2, color, 2, LINE_AA);//绘制图形中心}imshow(result, drawImage);return;
}

效果图:

【OpenCV学习笔记】之图像轮廓特征与图像的矩相关推荐

  1. OpenCV学习笔记(十六)——CamShift研究 OpenCV学习笔记(十七)——运动分析和物体跟踪Video OpenCV学习笔记(十八)——图像的各种变换(cvtColor*+)imgproc

    OpenCV学习笔记(十六)--CamShift研究 CamShitf算法,即Continuously Apative Mean-Shift算法,基本思想就是对视频图像的多帧进行MeanShift运算 ...

  2. OpenCV学习笔记(十七):图像修补:inpaint()

    OpenCV学习笔记(十七):图像修补:inpaint() inpaint()函数 使用区域邻域在图像中还原选定区域. void inpaint( InputArray src, // 表示要修复的图 ...

  3. OpenCV学习笔记(十):图像金字塔Pyramid和图像缩放:pyrDown(),pyrUp(),resize()

    OpenCV学习笔记(十):图像金字塔Pyramid和图像缩放:pyrDown(),pyrUp(),resize() 一.图像金字塔定义: 图像金字塔是图像中多尺度表达的一种,最主要用于图像的分割,是 ...

  4. OpenCV学习笔记(三):图像对比度、亮度调整源码

    OpenCV学习笔记(三):图像对比度.亮度调整源码 主函数: #include <opencv2/opencv.hpp>using namespace cv;using namespac ...

  5. Opencv学习笔记(二) 提取图像中的水平线和垂直线

    提取图像中的水平线和垂直线属于基础的形态学操作的应用,原理:根据要提取图形来定义一个特定的结构元素,然后以这个结构相素去遍历图像,进行一系列形态学操作,以此过滤掉其他特征的图形,达到提取的效果. 示例 ...

  6. opencv学习笔记(三)—— 利用图像金字塔进行图像无缝拼接,cv2.pyrDown() ,cv2.pyrUp()

    原理 一般情况下,我们要处理是一副具有固定分辨率的图像.但是有些情况下,我们需要对同一图像的不同分辨率的子图像进行处理.比如,我们要在一幅图像中查找某个目标,比如脸,我们不知道目标在图像中的尺寸大小. ...

  7. 【OpenCV 学习笔记】第十一章: 图像金字塔

    第十一章: 图像金字塔 一.什么是图像金字塔¶ 同一张图片不同分辨率的子图的集合. 图像金字塔底部是待处理的高分辨率图像,也就是原始图像,顶部是低分辨率的近似图像.一般情况下,都是每向上移动一级,图像 ...

  8. opencv学习笔记(八)-- 在图像上绘制形状和文字

    文章目录 CV::Point以及CV::Scalar 画直线cv::line() 画椭圆cv::elipse() 画矩形cv::rectangle() 画圆cv::circle() 画填充多边形cv: ...

  9. 【OpenCV学习笔记】之六 手写图像旋转函数---万丈高楼平地起

    话说,平凡之处显真格,这一点也没错!  比如,对旋转图像进行双线性插值,很简单吧?  可,对我,折腾了大半天,也没有达到预期效果!  尤其是三个误区让我抓瞎好久: 1,坐标旋转公式.   这东西,要用 ...

  10. OpenCV学习笔记03:缩放裁剪图像与调整图像色调

    文章目录 一.缩放裁剪图像 (一)resize函数 (二)缩放图像 1.编写程序,实现功能 2.运行程序,查看结果 (三)裁剪图像 1.编写程序,实现功能 2.运行程序,查看结果 二.调整图像色调 ( ...

最新文章

  1. npm install是什么命令_了解npm
  2. 计算机二级html真题,计算机二级《Web程序设计》试题及答案
  3. Go语言学习笔记(十八)之文件读写
  4. flume+elasticsearch日志收集分析
  5. jquery选择器案例分享
  6. jmeter进程和线程的区别_一文搞懂进程和线程的区别
  7. Python学习笔记(三)Python安装及设置环境变量
  8. Uncaught ReferenceError: but is not defined
  9. nginx负载均衡的方法
  10. 产品01]-产品经理初步认知-产品经理定义/职责/分类
  11. 太空战机c语言源码,funcode编写的太空战机
  12. Python实现答题程序
  13. HTML与CSS案例——人物简介
  14. 十折交叉验证和混淆矩阵
  15. c++ 调用meshlab程序慢_MeshLab中插件的添加过程
  16. 世界最大最高摩天轮,迪拜之眼迎来首批游客
  17. 【机器学习|数学基础】Mathematics for Machine Learning系列之矩阵理论(18):方阵的幂级数
  18. 怒赞!7个下载UI组件包的顶级网站
  19. How to deploy a .Net assmebly for COM use through CAB on Web Page (转)
  20. Kubernetes暴漏服务类型之Nginx Ingress

热门文章

  1. Cadence手工创建PCB元件
  2. 为什么要有ID发号器、原理是什么以及如何实现?
  3. 封装基于zlib的minizip库用于解压缩zip文件
  4. 三星a5100多少钱_请问三星A5100现在啥价格?
  5. 图麟信息科技联合创始人张勋:全面商用化到来,AI全方面融入行业
  6. 性能:到底什么是性能测试
  7. 内网渗透之跨路由访问
  8. 规范化、归一化、标准化、中心化、正则化
  9. JADE学习笔记4:Agent通信
  10. 劲乐园合歌(幽灵圣典+飞吧喜鹊+唯一+v3+幽灵圣典2)铃声 劲乐园...