RANSAC 알고리즘을 써서 주어진 2차원 점집합에서 원을 추정한다. 원을 만들기 위해서는 최소한 3점이 필요하고, 또 일직선에 있지 않아야 한다. 이렇게 만들어진 원은 세 점을 꼭짓점으로 하는 삼각형의 외접원(circumcircle)이다. 주어진 외접원에서 크게 벗어나지 않는 inliers를 찾는다(추가로 이 inliers에 대해 최소자승법으로 원의 중심과 반지름을 다시 구해서 보다 정밀하게 추정하는 과정을 넣을 수도 있다). 무작위로 선택된 세 점에 대해 위의 과정을 반복 시행해서 구한 원 중에서 가장 많은 inliers를 포함하는 원을 결과로 사용한다.

// 참고: http://en.wikipedia.org/wiki/RANSAC

red = inliers


// 2024.5.31 재작성;
double dist_deviate(const CfPt& pts, double cparam[3]) {
    double dx = pts.x - cparam[0];
    double dy = pts.y - cparam[1];
    return fabs(hypot(dx, dy) - cparam[2]);
}
int circumcircle(CfPt pts[3], double cparam[3]) {
    double x1 = pts[0].x, x2 = pts[1].x, x3 = pts[2].x;
    double y1 = pts[0].y, y2 = pts[1].y, y3 = pts[2].y;
    double bax = x2 - x1, bay = y2 - y1;
    double cax = x3 - x1, cay = y3 - y1;
    double E = bax * (x1 + x2) + bay * (y1 + y2);
    double F = cax * (x1 + x3) + cay * (y1 + y3);
    double G = 2. * (bax * (y3 - y2) - bay * (x3 - x2));
    if (G == 0.) return 0;    //error;
    //assert(fabs(G)>small_epsilon); //to prevent collinear or degenerate case;
    cparam[0] = (cay * E - bay * F) / G; //cx;
    cparam[1] = (bax * F - cax * E) / G; //cy;
    cparam[2] = hypot(cparam[0]-x1, cparam[1]-y1); //rad;
    return 1;
};
int num_sampling3(double prob_fail, double inlier_ratio) {
    return int(log(prob_fail)/log(1-pow(inlier_ratio, 3))); 
}
std::vector<int> Ransac_CircleFit(std::vector<CfPt>& points, double circle_param[3]) {
    if (points.size() < 3)
        return std::vector<int> (); //return null_vector;

    CfPt center; double inv_scale;
    // normalize input points for the sake of numerical stability;
    std::vector<CfPt> nor_pts = normalize(points, inv_scale, center);
    // distance threshold;
    double distance_thresh = sqrt(double(points.size())) * inv_scale;
    //ransac
    int sample_num = 1000;	//number of sample
    int ransac_count = 0;
    const double prob_fail = 0.01;
    double best_cparam[3] = {0};
    std::vector<int> best_inliers;
    while (sample_num > ransac_count) {
        // pick random 3 indices:[0,points.size()-1];
        int triple[3];
        random_triple(points.size()-1, triple);
        CfPt selected[3];
        for (int i = 0; i < 3; i++) 
            selected[i] = nor_pts[triple[i]];
        // circumcircle of 3 points;
        if (circumcircle(selected, circle_param)) {
            // find inliers;
            std::vector<int> inliers;
            inliers.reserve(points.size());
            for (int i = nor_pts.size(); i-->0;) {
                // error measure = algebric distance;
                double deviation = dist_deviate(nor_pts[i], circle_param);
                if (fabs(deviation) < distance_thresh)
                    inliers.push_back(i);
            }
            if (inliers.size() > best_inliers.size()) {			
                // update sampling_num;
                sample_num = num_sampling3(prob_fail, double(inliers.size())/points.size());
                // update best_inliers;
                best_inliers.swap(inliers);
                // update best circle param;
                for (int i = 0; i < 3; i++) 
                    best_cparam[i] = circle_param[i];
            }
        }
        if (++ransac_count > 1500) {
            TRACE("error! ransac_count exceed!\n");
            break;
        }
    }
    // recover original coordinate and scale;
    denormalize(best_cparam, best_cparam, inv_scale, center);
    if (best_cparam[0] > 0 && best_cparam[1] > 0) {
        for (int i = 0; i < 3; i++)
            circle_param[i] = best_cparam[i];
        TRACE("circle_found(%d, %d)\n", sample_num, ransac_count);
        // more accurate estimation needed at this stage;
    } else 
        best_inliers.clear();
    return best_inliers;
}

https://kipl.tistory.com/207

 

Least Squares Fitting of Circles

점집합을 일반적인 2차 곡선으로 피팅하는 경우에 방정식은$$ a x^2 + by^2 + cxy +d x + ey +f = 0$$의 계수를 주어진 데이터를 이용하여서 구해야 한다. 실제 문제에서는 타원, 포물선 쌍곡 선등의 타입

kipl.tistory.com

https://kipl.tistory.com/357

 

Circle Fitting: Pratt

주어진 점집합을 원으로 피팅하기 위해 이차식$$A(x^2 + y^2) + Bx + Cy +D =0$$을 이용하자. 원의 경우는 $A=0$인 경우는 직선을 나타내고, $A\ne0$인 경우가 원을 표현한다. 물론 $A=1$로 설정을 할 수 있으

kipl.tistory.com

 

728x90

'Image Recognition' 카테고리의 다른 글

Chamfer Match  (0) 2008.08.01
Retinex Algorithm  (2) 2008.07.26
KMeans Algorithm  (0) 2008.07.19
Robust Line Fitting  (0) 2008.07.08
EM: Binarization  (0) 2008.07.01
Posted by helloktk
,