Opencv学习之图像的矩

来源:互联网 发布:淘宝如何设为公益宝贝 编辑:程序博客网 时间:2024/05/29 03:21

Opencv学习之图像的矩
一个从一幅数字图形中计算出来的矩集,通常描述了该图像形状的全局特征,并提供了大量的关于该图像不同类型的几何特性信息,比如大小、位置、方向及形状等。一阶矩与形状有关,二阶矩显示曲线围绕直线平均值的扩展程度,三阶矩则是关于平均值的对称性的测量。由二阶矩和三阶矩可以导出一组共7个不变矩。而不变矩是图像的统计特性,满足平移、伸缩、旋转均不变的不变性,在图像识别领域得到了广泛的应用。
一般由moments、contourArea、arcLength这三个函数配合求取图像的矩:
*使用moments计算图像所有的矩(最高到3阶)
*使用contourArea来计算轮廓面积
*使用arcLength来计算轮廓或曲线长度

矩的计算–moments函数

函数用于计算多边形和光栅形状的最高达三阶的所有矩。矩用来计算形状的重心、面积,主轴和其他形状特征,如7Hu不变量等。
Moments moments(inputArray array, bool binaryImage=false)
*第一个参数,输入参数,可以是光栅图像(单通道,8位或浮点的二维数组)或二维数组(1N或N1)。
*第二个参数,默认值false,若此参数取true,则所有非零像素为1.此参数仅对图像使用。

计算轮廓面积–contourArea函数

函数用于计算整个轮廓或部分轮廓的面积
double contourArea(inputArray contour, bool oriented=false)
*第一个参数,输入的向量,二维点(轮廓顶点)。
*第二个参数,面向区域标识符,若为true,该函数返回一个带符号的面积值,其正负取决于轮廓的方向(顺时针还是逆时针)。根据这个特性我们可以根据面积的符号来确定轮廓的位置。需要注意的是,这个参数有默认值false,表示以绝对值返回,不带符号。

计算轮廓长度–arcLength函数

函数用于计算封闭轮廓的周长或曲线的长度。
double arcLength(inputArray curve,bool closed)
*第一个参数,输入的二维点集。
*第二个参数,一个用于指示曲线是否封闭的标识符,默认值closed,表示曲线封闭。

#include<opencv2/highgui/highgui.hpp>#include<opencv2/imgproc/imgproc.hpp>#include<iostream>using namespace cv;using namespace std;//全局变量声明Mat g_srcImage,g_grayImage,g_cannyMat_output;int g_nThresh=50;int g_nThresh_max=255;RNG g_rng(12345);vector<vector<Point>>g_vContours;vector<Vec4i>g_vHierarchy;//全局函数声明void on_ThreshChange(int ,void *);//主函数int main(){    //载入源图像    g_srcImage=imread("/Users/new/Desktop/3.jpg");    if(!g_srcImage.data){printf("读取源图像srcImage错误~!\n");return false;}    //转换为灰度图像并进行平滑降噪    cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);    blur(g_grayImage, g_grayImage, Size(3,3));    //创建新的窗口以及阈值滑动条    namedWindow("image[origin]");    imshow("image[origin]", g_srcImage);    createTrackbar("threshold: ", "image[origin]", &g_nThresh, g_nThresh_max,on_ThreshChange);    //初始化回调函数    on_ThreshChange(0, 0);    waitKey(0);    return 0;}//回调函数定义void on_ThreshChange(int ,void *){    //使用canny边缘检测    Canny(g_grayImage, g_cannyMat_output, g_nThresh, g_nThresh*2,3);    //找到轮廓    findContours(g_cannyMat_output, g_vContours, g_vHierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE,Point(0,0));    //计算矩    vector<Moments>mu(g_vContours.size());    for(unsigned int i=0;i<g_vContours.size();++i)    {        mu[i]=moments(g_vContours[i],false);    }    //计算中心矩    vector<Point2f>mc(g_vContours.size());    for(unsigned int i=0;i<g_vContours.size();++i)    {        mc[i]=Point2f(static_cast<float>(mu[i].m10/mu[i].m00),static_cast<float>(mu[i].m01/mu[i].m00));    }    //绘制轮廓    Mat drawing=Mat::zeros(g_cannyMat_output.size(), CV_8UC3);    for(unsigned int i=0;i<g_vContours.size();++i)    {        //随机生成颜色值        Scalar color=Scalar(g_rng.uniform(0,255),g_rng.uniform(0,255),g_rng.uniform(0,255));        //绘制外层和内层轮廓        drawContours(drawing, g_vContours, i, color,2,8,g_vHierarchy,0,Point());        //绘制圆        circle(drawing, mc[i], 4, color,-1,8,0);    }    namedWindow("image[renderings]");    imshow("image[renderings]",drawing);    //通过m00计算轮廓面积并且和opencv函数比较    printf("\t 输出内容:面积和轮廓长度\n");    for(unsigned int i=0;i<g_vContours.size();++i)    {        printf(">通过m00计算出轮廓[%d]的面积:(M_00)=%.2f \n Opencv函数计算出的面积=%.2f,长度:%.2f \n\n",i,mu[i].m00,contourArea(g_vContours[i]),arcLength(g_vContours[i],true));        Scalar color=Scalar(g_rng.uniform(0,255),g_rng.uniform(0,255),g_rng.uniform(0,255));        drawContours(drawing, g_vContours, i, color,2,8,g_vHierarchy,0,Point());        circle(drawing,mc[i],4,color,-1,8,0);    }}

这里写图片描述
这里写图片描述

这里写图片描述
这里写图片描述

这里写图片描述
这里写图片描述

Opencv技巧

(1)计算矩:moments也是一个类型,计算矩先要定义vectormu(g_vContours.size());