机器视觉_图像算法(六)——形状矩(Hu)

图像形状矩:

一个从一幅数字图形中计算出来的矩集,通常描述了该图像形状的全局特征,并提供了大量的关于该图像不同类型的几何特性信息,比如大小、位置、方向及形状等。一阶矩与形状有关,二阶矩显示曲线围绕直线平均值的扩展程度,三阶矩则是关于平均值的对称性的测量。由二阶矩和三阶矩可以导出一组共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);

    }
}

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

智能之心

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值