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

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

作者: 陌上尘离 | 来源:发表于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);
    
    };
    
    函数功能:输出提取到的椭圆

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

    相关文章

      网友评论

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

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