美文网首页
椭圆检测算法程序阅读笔记

椭圆检测算法程序阅读笔记

作者: 陌上尘离 | 来源:发表于2018-05-25 10:51 被阅读0次

Main.cpp


#include <cv.h>
#include <highgui.h>
#include "EllipseDetectorYaed.h"
#include <fstream>
using namespace std;
using namespace cv;

定义了如下所示一些列函数


保存椭圆
void SaveEllipses(const string& workingDir, const string& imgName, const vector<Ellipse>& ellipses /*, const vector<double>& times*/)
{
    string path(workingDir + "/" + imgName + ".txt");
    ofstream out(path, ofstream::out | ofstream::trunc);
    if (!out.good())
    {
        cout << "Error saving: " << path << endl;
        return;
    }

    // Save execution time
    //out << times[0] << "\t" << times[1] << "\t" << times[2] << "\t" << times[3] << "\t" << times[4] << "\t" << times[5] << "\t" << "\n";

    unsigned n = ellipses.size();
    // Save number of ellipses
    out << n << "\n";

    // Save ellipses
    for (unsigned i = 0; i < n; ++i)
    {
        const Ellipse& e = ellipses[i];
        out << e._xc << "\t" << e._yc << "\t" << e._a << "\t" << e._b << "\t" << e._rad << "\t" << e._score << "\n";
    }
    out.close();
}

输入为两个字符串和一个代表椭圆的vector,其中,字符串分别为目录和存储椭圆图片的名称;

函数目的:

1.将椭圆图片命名并保存在制定路径
2.输出椭圆个数,输出椭圆的中心及a,b(e._rad与e._score暂时未知)


加载测试的(没太看懂)
// Should be checked
bool LoadTest(vector<Ellipse>& ellipses, const string& sTestFileName, vector<double>& times, bool bIsAngleInRadians = true)
{
    ifstream in(sTestFileName);
    //ifstream in("c:\\pdos.def");//以输入方式打开文件
    if (!in.good())
    {
        cout << "Error opening: " << sTestFileName << endl;
        return false;
    }
    //如果打开失败,报错

    times.resize(6);
    in >> times[0] >> times[1] >> times[2] >> times[3] >> times[4] >> times[5];

    unsigned n;
    in >> n;

    ellipses.clear();

    if (n == 0) return true;

    ellipses.reserve(n);

    while (in.good() && n--)
    {
        Ellipse e;
        in >> e._xc >> e._yc >> e._a >> e._b >> e._rad >> e._score;
        //默认进不去这个if
        if (!bIsAngleInRadians)
        {
            e._rad = e._rad * float(CV_PI / 180.0);
        }

        e._rad = fmod(float(e._rad + 2.0*CV_PI), float(CV_PI));

        if ((e._a > 0) && (e._b > 0) && (e._rad >= 0))
        {
            ellipses.push_back(e);
        }
    //有测试图片时,把椭圆里ab,rad为正值的pushback入ellipse
    }
    in.close();

    // Sort ellipses by decreasing score
    sort(ellipses.begin(), ellipses.end());

    return true;
}

加载GT(好的测试)

void LoadGT(vector<Ellipse>& gt, const string& sGtFileName, bool bIsAngleInRadians = true)
{
    ifstream in(sGtFileName);
    if (!in.good())
    {
        cout << "Error opening: " << sGtFileName << endl;
        return;
    }
    //检查报错

    unsigned n;
    in >> n;

    gt.clear();
    gt.reserve(n);

    while (in.good() && n--)
    {
        Ellipse e;
        in >> e._xc >> e._yc >> e._a >> e._b >> e._rad;

        if (!bIsAngleInRadians)
        {
            // convert to radians
            e._rad = float(e._rad * CV_PI / 180.0);
        }

        if (e._a < e._b)
        {
            float temp = e._a;
            e._a = e._b;
            e._b = temp;

            e._rad = e._rad + float(0.5*CV_PI);
        }

        e._rad = fmod(float(e._rad + 2.f*CV_PI), float(CV_PI));
        e._score = 1.f;
        gt.push_back(e);
    }
    in.close();
}

和上段的代码相似


测试重叠部分
bool TestOverlap(const Mat1b& gt, const Mat1b& test, float th)
{
    float fAND = float(countNonZero(gt & test));
    //对二值化图像执行countNonZero,可得到非零像素点数
    float fOR = float(countNonZero(gt | test));
    float fsim = fAND / fOR;

    return (fsim >= th);
}

输入的Mat1b是unchar型的mat,输入了两个mat和一个float(阈值)

函数功能:

两图重叠部分大于一定阈值时输出为true


int Count(const vector<bool> v)
{
    int counter = 0;
    for (unsigned i = 0; i < v.size(); ++i)
    {
        if (v[i]) { ++counter; }
    }
    return counter;
}
函数功能:

输出输入的vector<bool>中true的个数


// Should be checked !!!!!
std::tuple<float, float, float> Evaluate(const vector<Ellipse>& ellGT, const vector<Ellipse>& ellTest, const float th_score, const Mat3b& img)
{
    float threshold_overlap = 0.8f;
    //float threshold = 0.95f;
    //给交叠区域一个阈值

    unsigned sz_gt = ellGT.size();
    unsigned size_test = ellTest.size();

    unsigned sz_test = unsigned(min(1000, int(size_test)));

    vector<Mat1b> gts(sz_gt);
    vector<Mat1b> tests(sz_test);

    for (unsigned i = 0; i < sz_gt; ++i)
    {
        const Ellipse& e = ellGT[i];

        Mat1b tmp(img.rows, img.cols, uchar(0));
        ellipse(tmp, Point(e._xc, e._yc), Size(e._a, e._b), e._rad * 180.0 / CV_PI, 0.0, 360.0, Scalar(255), -1);
        //绘制椭圆,ellipse是opencv函数
        gts[i] = tmp;
    }

    for (unsigned i = 0; i < sz_test; ++i)
    {
        const Ellipse& e = ellTest[i];

        Mat1b tmp(img.rows, img.cols, uchar(0));
        ellipse(tmp, Point(e._xc, e._yc), Size(e._a, e._b), e._rad * 180.0 / CV_PI, 0.0, 360.0, Scalar(255), -1);
        tests[i] = tmp;
        //同理绘制椭圆
    }

    Mat1b overlap(sz_gt, sz_test, uchar(0));
    for (int r = 0; r < overlap.rows; ++r)
    {
        for (int c = 0; c < overlap.cols; ++c)
        {
            overlap(r, c) = TestOverlap(gts[r], tests[c], threshold_overlap) ? uchar(255) : uchar(0);
        }
    }
int counter = 0;

    vector<bool> vec_gt(sz_gt, false);

    for (int i = 0; i < sz_test; ++i)
    {
        const Ellipse& e = ellTest[i];
        for (int j = 0; j < sz_gt; ++j)
        {
            if (vec_gt[j]) { continue; }

            bool bTest = overlap(j, i) != 0;
            //若overlap非0则为真,也即交叠区域大于阈值为真

            if (bTest)
            {
                vec_gt[j] = true;
                break;
            }
        }
    }

    int tp = Count(vec_gt);//计算了交叠区域里为true的个数
    int fn = int(sz_gt) - tp;//不交叠的个数
    int fp = size_test - tp; // 不交叠的个数

    float pr(0.f);
    float re(0.f);
    float fmeasure(0.f);

    if (tp == 0)
    {
        if (fp == 0)
        {
            pr = 1.f;
            re = 0.f;
            fmeasure = (2.f * pr * re) / (pr + re);
        }
        else
        {
            pr = 0.f;
            re = 0.f;
            fmeasure = 0.f;
        }
    }
    else
    {
        pr = float(tp) / float(tp + fp);
        re = float(tp) / float(tp + fn);
        fmeasure = (2.f * pr * re) / (pr + re);
    }

    return make_tuple(pr, re, fmeasure);
    //返回交叠个数分别占两组椭圆的总个数的比例
}

std::tuple是类似pair的模板。每个pair的成员类型都不相同,但每个pair都恰好有两个成员。不同std::tuple类型的成员类型也不相同,但一个std::tuple可以有任意数量的成员。每个确定的std::tuple类型的成员数目是固定的,但一个std::tuple类型的成员数目可以与另一个std::tuple类型不同。

参考网页:https://blog.csdn.net/fengbingchun/article/details/72835446

函数功能

返回交叠个数分别占两组椭圆的总个数的比例(似乎用于评测)


单张图片测试主函数
// Test on single image
int main2()
{
    string images_folder = "你的路径";
    string out_folder = "你的路径";
    //路径
    
    vector<string> names;

    glob(images_folder + "Lo3my4.*", names);
    //glob() 函数返回匹配指定模式的文件名或目录。

    for (const auto& image_name : names)
    {
        string name = image_name.substr(image_name.find_last_of("\\") + 1);
        name = name.substr(0, name.find_last_of("."));

        Mat3b image = imread(image_name);
        Size sz = image.size();
        
        // Convert to grayscale
        Mat1b gray;
        cvtColor(image, gray, CV_BGR2GRAY);
        
        // Parameters Settings (Sect. 4.2)
        //设置一系列参数
        int iThLength = 16;//小于该阈值的圆弧舍弃
        float   fThObb = 3.0f;//小圆弧舍弃
        float   fThPos = 1.0f;
        float   fTaoCenters = 0.05f;//舍弃中心太远的圆弧对
        int     iNs = 16;
        float   fMaxCenterDistance = sqrt(float(sz.width*sz.width + sz.height*sz.height)) * fTaoCenters;

        float   fThScoreScore = 0.7f;

        // Other constant parameters settings. 

        // Gaussian filter parameters, in pre-processing
        Size    szPreProcessingGaussKernelSize = Size(5, 5);
        double  dPreProcessingGaussSigma = 1.0;

        float   fDistanceToEllipseContour = 0.1f;   // (Sect. 3.3.1 - Validation)
        float   fMinReliability = 0.5;  // Const parameters to discard bad ellipses


        CEllipseDetectorYaed* yaed = new CEllipseDetectorYaed();
        yaed->SetParameters(szPreProcessingGaussKernelSize,
            dPreProcessingGaussSigma,
            fThPos,
            fMaxCenterDistance,
            iThLength,
            fThObb,
            fDistanceToEllipseContour,
            fThScoreScore,
            fMinReliability,
            iNs
            );


        // Detect
        vector<Ellipse> ellsYaed;
        Mat1b gray2 = gray.clone();
        yaed->Detect(gray2, ellsYaed);

        vector<double> times = yaed->GetTimes();
        cout << "--------------------------------" << endl;
        cout << "Execution Time: " << endl;
        cout << "Edge Detection: \t" << times[0] << endl;
        cout << "Pre processing: \t" << times[1] << endl;
        cout << "Grouping:       \t" << times[2] << endl;
        cout << "Estimation:     \t" << times[3] << endl;
        cout << "Validation:     \t" << times[4] << endl;
        cout << "Clustering:     \t" << times[5] << endl;
        cout << "--------------------------------" << endl;
        cout << "Total:          \t" << yaed->GetExecTime() << endl;
        cout << "--------------------------------" << endl;


        
        Mat3b resultImage = image.clone();
        yaed->DrawDetectedEllipses(resultImage, ellsYaed);
        
        imwrite(out_folder + name + ".png", resultImage);

        imshow("Yaed", resultImage);

        waitKey();

        int yghds = 0;
    }

    return 0;
}

设置参数,把参数放入类中,进入Detect函数,得到存放椭圆的<vector>ellsYaed
利用DrawDetectedEllipses函数绘画所有椭圆,将椭圆绘制后的图片存储。


Detect函数:

void CEllipseDetectorYaed::Detect(Mat1b& I, vector<Ellipse>& ellipses)
{
    Tic(1); //prepare data structure

    // Set the image size
    _szImg = I.size();

    // Initialize temporary data structures
    Mat1b DP = Mat1b::zeros(_szImg);        // arcs along positive diagonal
    Mat1b DN = Mat1b::zeros(_szImg);        // arcs along negative diagonal

    // Initialize accumulator dimensions
    ACC_N_SIZE = 101;//N=B/A
    ACC_R_SIZE = 180;//R = rho = atan(K)
    ACC_A_SIZE = max(_szImg.height, _szImg.width);//A,3个ACC_都为int

    // Allocate accumulators
    accN = new int[ACC_N_SIZE];
    accR = new int[ACC_R_SIZE];
    accA = new int[ACC_A_SIZE];

    // Other temporary 
    VVP points_1, points_2, points_3, points_4; //vector of points, one for each convexity class,vector<vector<point>>
    unordered_map<uint, EllipseData> centers;   //hash map for reusing already computed EllipseData

    Toc(1); //prepare data structure

    // Preprocessing
    // From input image I, find edge point with coarse convexity along positive (DP) or negative (DN) diagonal
    PrePeocessing(I, DP, DN);//高斯处理后用canny3提取边缘,对每一个边缘求方向,相角大于0的点dp=255,小于0,dn=255

    // Detect edges and find convexities
    DetectEdges13(DP, points_1, points_3);//角度为+的一类,然后分类1,3类圆弧
    DetectEdges24(DN, points_2, points_4);

    Toc(1); //preprocessing


    // DEBUG
    Mat3b out(I.rows, I.cols, Vec3b(0,0,0));
    for(unsigned i=0; i<points_1.size(); ++i)
    {
        //Vec3b color(rand()%255, 128+rand()%127, 128+rand()%127);
        Vec3b color(255,0,0);
        for(unsigned j=0; j<points_1[i].size(); ++j)
            out(points_1[i][j]) = color;
    }

    for(unsigned i=0; i<points_2.size(); ++i)
    {
        //Vec3b color(rand()%255, 128+rand()%127, 128+rand()%127);
        Vec3b color(0,255,0);
        for(unsigned j=0; j<points_2[i].size(); ++j)
            out(points_2[i][j]) = color;
    }
    for(unsigned i=0; i<points_3.size(); ++i)
    {
        //Vec3b color(rand()%255, 128+rand()%127, 128+rand()%127);
        Vec3b color(0,0,255);
        for(unsigned j=0; j<points_3[i].size(); ++j)
            out(points_3[i][j]) = color;
    }

    for(unsigned i=0; i<points_4.size(); ++i)
    {
        //Vec3b color(rand()%255, 128+rand()%127, 128+rand()%127);
        Vec3b color(255,0,255);
        for(unsigned j=0; j<points_4[i].size(); ++j)
            out(points_4[i][j]) = color;
    }


    // time estimation, validation  inside

    Tic(2); //grouping
    //find triplets,论文中的三元组
    Triplets124(points_1, points_2, points_4, centers, ellipses);//大致看了一下,通过三元组获得椭圆与椭圆中心,函数中有设置阈值进行圆弧的额筛选
    Triplets231(points_2, points_3, points_1, centers, ellipses);
    Triplets342(points_3, points_4, points_2, centers, ellipses);
    Triplets413(points_4, points_1, points_3, centers, ellipses);
    Toc(2); //grouping  
    // time estimation, validation inside
    _times[2] -= (_times[3] + _times[4]);

    Tac(4); //validation
    // Sort detected ellipses with respect to score
    sort(ellipses.begin(), ellipses.end());
    Toc(4); //validation


    // Free accumulator memory
    delete[] accN;
    delete[] accR;
    delete[] accA;

    Tic(5);
    // Cluster detections
    ClusterEllipses(ellipses);//聚类,存出相似椭圆中socre高的那个
    Toc(5);

};
函数功能:输出提取到的椭圆

这是论文内容中比较重要的函数,引用了很多自定义函数,建议看一下源代码。

相关文章

  • 椭圆检测算法程序阅读笔记

    Main.cpp 定义了如下所示一些列函数 保存椭圆 输入为两个字符串和一个代表椭圆的vector,其中,字符串分...

  • 2018-01-15 椭圆检测与拟合

    椭圆检测与拟合 欢迎到YangHan's Notebook 椭圆检测与拟合 获得更佳阅读体验。 实验目标 调⽤Cv...

  • 椭圆检测

    Hough变换检测椭圆 附带matlab与opencv代码 QT+opencv学习笔记(5)——霍夫直线检测、圆检...

  • 区块链椭圆加密及使用

    相关文章: [区块链] 密码学——椭圆曲线密码算法(ECC) 椭圆曲线算法:入门 ECC椭圆曲线详解(有具体实例)...

  • 椭圆加密简介

    椭圆加密算法 区块链入门时候最难理解的应该就时候这个椭圆加密算法,椭圆加密算法用于生成公钥生成,现在国密SM2算法...

  • Bresenham算法画椭圆及Open Gl实现

    Bresenham算法画椭圆Bresenham算法画直线Bresenham算法画圆 输入椭圆的长半轴a和短半轴b。...

  • Java 实现 ECC 非对称加密算法加解密和签名验签

    一、ECC 椭圆曲线算法简介 ECC是椭圆曲线算法,其加密算法叫ECIES,签名算法叫ECDSA。JDK 并不支持...

  • sm2算法理解

    sm2算法是国密标准的非对称算法标准。基于ecc的扩展 椭圆曲线算法 破解难度高于rsa算法。椭圆曲线方程:y2=...

  • 【dp笔记】LIS

    课程笔记:程序设计与算法(二)算法基础:dp Longest Ordered Subsequence Time L...

  • 目标检测领域算法持续跟踪

    更新记录 推荐阅读 正文 1. 目标检测算法简介 1.1. 传统算法概述 传统目标检测的方法一般分为三个阶段:首先...

网友评论

      本文标题:椭圆检测算法程序阅读笔记

      本文链接:https://www.haomeiwen.com/subject/ingljftx.html