Programming/Image Processing

[OpenCV] 가장 긴 직선의 각도를 반환하는 함수(소스코드)

DevMonster 2014. 2. 21. 11:53

때로는 이미지나 영상에서 가장 긴 직선이 이미지 회전의 기준이 되기도 한다.
Hough Transform을 이용하여 직선성분을 검출한다.
검출된 직선 중 가장 긴 직선을 기준으로 회전된 각도를 반환한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
double    getRotationAngle(const IplImage* src)
{
    // Only 1-Channel
    if(src->nChannels != 1)
        return 0;
 
    // 직선이 잘 검출될 수 있도록 팽창
    cvDilate((IplImage*)src, (IplImage*)src);
 
    // 저장영역 생성
    CvMemStorage* storage = cvCreateMemStorage(0);
    CvSeq* seqLines;
 
    // Image의 직선영역을 seq에 저장(rho, theta)
    seqLines = cvHoughLines2((IplImage*)src, storage, CV_HOUGH_PROBABILISTIC, 1, CV_PI/180, 50, 30, 3); // 인자들 수정해야함
 
    // 직선들의 거리를 구해서 가장 긴 직선을 기준으로 이미지 0 or 90도로 회전
    double    longDistance        = 0;    // 직선 중 가장 긴 길이
    int        longDistanceIndex    = 0;    // 직선 중 가장 긴 길이 인덱스
    for (int i = 0; i < seqLines->total; i++){
        CvPoint* lines = (CvPoint*)cvGetSeqElem(seqLines, i);
        double euclideanDistance;        // sequence에 저장된 line들의 Euclidean distance를 저장
        euclideanDistance = (lines[1].x - lines[0].x) * (lines[1].x - lines[0].x) + (lines[1].y - lines[0].y) * (lines[1].y - lines[0].y);
        euclideanDistance = sqrt(euclideanDistance);
 
        // 가장 긴 Euclidean distance를 저장 
        if(longDistance < euclideanDistance){
            longDistanceIndex    = i;
            longDistance        = euclideanDistance;
        }
 
        //// 직선영역 제거
        //cvLine((IplImage*)src, lines[0], lines[1], CV_RGB(0, 0, 0), 3, CV_AA);
    }
    //// check the longest line
    //CvPoint* lines = (CvPoint*)cvGetSeqElem(seqLines, longDistanceIndex);
    //cvLine((IplImage*)src, lines[1], lines[0], CV_RGB(125, 125, 125), 3, CV_AA);
    //cout<<"pt1("<<lines[0].x<<", "<<lines[0].y<<")   pt2("<<lines[1].x<<", "<<lines[1].y<<")"<<endl;
 
    // 회전된 각도 계산
    CvPoint*    lines    = (CvPoint*)cvGetSeqElem(seqLines, longDistanceIndex);
    int            dx        = lines[1].x - lines[0].x;                    
    int            dy        = lines[1].y - lines[0].y;
    double        rad        = atan2((double)dx, (double)dy);    // 회전된 각도(radian)
    double        degree    = abs(rad * 180) / CV_PI;            // 회전된 각도(degree) 저장
    
    // 회전된 각도보정 
    if(degree>90)
        degree-=90;
    
    // 메모리 해제
    cvClearSeq(seqLines);
    cvReleaseMemStorage(&storage);
 
    return degree;
}


728x90
반응형