• OpenCV开发笔记(五十八):红胖子8分钟带你深入了解图像的矩(图文并茂+浅显易懂+程序源码)


     

    前言

      红胖子,来也!
      做识别,有时候需求要识别面积、距离能,若双瞳之间的距离,手机的宽高等等,图像的矩就是为这些需要识别具体标量的基础之一。

     

    Demo

      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述

     

    图像的矩

    概述

      矩函数在图像分析中是必备的方法之一,应用广泛,如模式识别、目标分类、目标识别与方位估计、图像编码与重构等。一天个从一副数字图形中计算出来的矩集,通常描述了该图形形状的全局特征,并提供了大量的关于该图像不同类型的集合特性信息,比如大小、方向及形状等。

    • 一阶矩:与形状有关;
    • 二阶矩:显示曲线围绕直线平均值的扩展程度;
    • 三阶矩:关于平均值的对称性的测量;

    寻找轮廓

    计算图像所有的矩(最高到三阶)

      计算多边形和光山形状的最高达三阶的所有矩,可用来计算形状的中心、面积、主轴和其他形状特征。

    Moments moments( InputArray array, bool binaryImage = false );
    
    • 参数一:InputArray类型的array,输入参数可以是光栅图像(单通道、8位或浮点的二维数组)或二维数组(lN或NI);
    • 参数二:bool类型的binaryImage,默认值false。若此参数取true,则所有非零像素为1。此参数仅对于图像使用;
      注意:此参数的返回值是返回运行后的结果。

    计算轮廓面积函数原型

      用于计算部分轮廓的面积或者整个轮廓。

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

    用于计算封闭轮廓的周长或曲线的长度。

    double arcLength (InputArray curve , boo1 c1osed);
    
    • 参数一:InputArray类型的curve,输入的二维点集,可以为std::vector或Mat类型;
    • 参数二:bool类型的closed,一个用于指示曲线是否封闭的标识符,有默认值closed,表示曲线封闭;
     

    Demo源码

    void OpenCVManager::testMoments()
    {
        QString fileName1 =
                "E:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/15.jpg";
        int width = 400;
        int height = 300;
    
        cv::Mat srcMat = cv::imread(fileName1.toStdString());
        cv::resize(srcMat, srcMat, cv::Size(width, height));
    
        cv::String windowName = _windowTitle.toStdString();
        cvui::init(windowName);
    
        cv::Mat windowMat = cv::Mat(cv::Size(srcMat.cols * 2, srcMat.rows * 3),
                                    srcMat.type());
    
    
        int threshold1 = 200;
        int threshold2 = 100;
        while(true)
        {
            windowMat = cv::Scalar(0, 0, 0);
    
            cv::Mat mat;
            cv::Mat dstMat;
            cv::Mat grayMat;
            cv::Mat tempMat;
            cv::Mat hullMat;
            hullMat = srcMat.clone();
    
            // 原图先copy到左边
            mat = windowMat(cv::Range(srcMat.rows * 0, srcMat.rows * 1),
                            cv::Range(srcMat.cols * 0, srcMat.cols * 1));
            cv::addWeighted(mat, 0.0f, srcMat, 1.0f, 0.0f, mat);
    
            {
                // 灰度图
                cv::cvtColor(srcMat, grayMat, CV_BGR2GRAY);
                cv::cvtColor(grayMat, tempMat, CV_GRAY2BGR);
                // copy
                mat = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 2),
                                cv::Range(srcMat.cols * 0, srcMat.cols * 1));
                cv::addWeighted(mat, 0.0f, tempMat, 1.0f, 0.0f, mat);
    
                cvui::printf(windowMat,
                             srcMat.rows * 1 + 100,
                             srcMat.cols * 0 + 20,
                             "threshold1");
                cvui::trackbar(windowMat,
                               srcMat.rows * 1 + 100,
                               srcMat.cols * 0 + 50,
                               200,
                               &threshold1,
                               0,
                               255);
                cvui::printf(windowMat,
                             srcMat.rows * 1 + 100,
                             srcMat.cols * 0 + 100, "threshold2");
                cvui::trackbar(windowMat,
                               srcMat.rows * 1 + 100,
                               srcMat.cols * 0 + 130,
                               200,
                               &threshold2,
                               0,
                               255);
                // 使用边缘检测
                cv::Canny(grayMat, dstMat, threshold1, threshold2, 3);
                // copy
                mat = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 2),
                                cv::Range(srcMat.cols * 1, srcMat.cols * 2));
                cv::Mat rgbMat;
                cv::cvtColor(dstMat, rgbMat, CV_GRAY2BGR);
                cv::addWeighted(mat, 0.0f, rgbMat, 1.0f, 0.0f, mat);
    
                // 寻找轮廓
                std::vector<std::vector<cv::Point>> contours;
                cv::findContours(dstMat, contours, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);
                // 绘制轮廓
                for(int index = 0; index < contours.size(); index++)
                {
                    cv::drawContours(hullMat, contours, index, cv::Scalar(0, 0, 255), 2);
                }
                // copy
                mat = windowMat(cv::Range(srcMat.rows * 2, srcMat.rows * 3),
                                cv::Range(srcMat.cols * 0, srcMat.cols * 1));
                cv::addWeighted(mat, 0.0f, hullMat, 1.0f, 0.0f, mat);
    
                // 计算图像所有的矩
                std::vector<cv::Moments> mu(contours.size());
                for(int index = 0; index < contours.size(); index++)
                {
                    mu[index] = cv::moments(contours[index], false);
                }
                // 计算轮廓的面积
                for(int index = 0; index < contours.size(); index++)
                {
                    double area = cv::contourArea(contours[index]);
                    cvui::printf(windowMat,
                                 srcMat.cols * 1,
                                 srcMat.rows * 2 + 15 * index,
                                 "%d/%d: contorsArea = %f",
                                 index,
                                 contours.size(),
                                 area);
                    double length = cv::arcLength(contours[index], true);
                    cvui::printf(windowMat,
                                 srcMat.cols * 1 + width / 2 + 30,
                                 srcMat.rows * 2 + 15 * index,
                                 "arcLength = %f",
                                 length);
                }
            }
            // 更新
            cvui::update();
            // 显示
            cv::imshow(windowName, windowMat);
            // esc键退出
            if(cv::waitKey(25) == 27)
            {
                break;
            }
        }
    }
    
     

    工程模板:对应版本号v1.52.0

      对应版本号v1.52.0

     
  • 相关阅读:
    快速排序算法C++实现[评注版]
    浮躁的程序员
    扬长避短使用Windbg和Visual Studio高效调试调试你的代码
    程序员,代码,理想,老男孩
    Windows Server 2008 R2 如何启动kernel dbg进行双机内核调试『续bcdedit 用法详解』
    Windows Server 2008 R2 如何启动kernel dbg进行双机内核调试『配置详解』
    忙着活或忙着死[转]
    SQL2005使用游标的实例(SBO中计算到期应收账款)
    C#编写的Windows计算器源代码
    请登录真正的BBS
  • 原文地址:https://www.cnblogs.com/qq21497936/p/12933367.html
Copyright © 2020-2023  润新知