반응형
250x250
Notice
Recent Posts
Recent Comments
Link
«   2025/07   »
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
Archives
Today
Total
관리 메뉴

폴크(FOLC)

치수 계산하기 - subpixel - edge direction 본문

카테고리 없음

치수 계산하기 - subpixel - edge direction

folcjin 2025. 6. 19. 14:40
728x90
반응형

edge 방향을 탐지하는 것은 **gradient의 부호(sign)**를 기반으로 각 edge가 어떤 밝기 변화 방향으로 이동하는지를 판별하는 것입니다. 이는 **양의 gradient (dark → bright)**와 **음의 gradient (bright → dark)**를 구분함으로써, Line & Space 구조의 시작점/끝점, 혹은 선폭(CD) 측정의 정확한 기준 edge 구분이 가능하다

개념: gradient의 부호로 edge 방향 구분

  • G(x)=I(x+1)−I(x−1)G(x) = I(x+1) - I(x-1)
  • G(x)>0G(x) > 0: 양의 gradient → 밝아지는 edge (dark → bright)
  • G(x)<0G(x) < 0: 음의 gradient → 어두워지는 edge (bright → dark)

 

예제

  • #include <opencv2/opencv.hpp>
    #include <iostream>
    using namespace std;
    using namespace cv;

    enum class EdgeDirection { POSITIVE, NEGATIVE };

    struct EdgePoint {
        float position;
        EdgeDirection direction;
    };

    // Subpixel edge + 방향 판별
    vector<EdgePoint> detectEdgesWithDirection(const vector<float>& profile) {
        vector<EdgePoint> edges;

        for (size_t i = 1; i < profile.size() - 1; ++i) {
            float prev = profile[i - 1];
            float curr = profile[i];
            float next = profile[i + 1];

            float grad = 0.5f * (next - prev);

            // 극값 조건 + 방향 확인
            if ((curr > prev && curr > next) || (curr < prev && curr < next)) {
                float denom = prev - 2 * curr + next;
                if (fabs(denom) < 1e-5) continue;

                float offset = 0.5f * (prev - next) / denom;
                EdgeDirection dir = (grad > 0) ? EdgeDirection::POSITIVE : EdgeDirection::NEGATIVE;

                edges.push_back({i + offset, dir});
            }
        }

        return edges;
    }

    void detectEdge1DWithDirection(const Mat& gray, int rowIdx) {
        vector<float> profile(gray.cols);
        for (int x = 0; x < gray.cols; ++x)
            profile[x] = static_cast<float>(gray.at<uchar>(rowIdx, x));

        // 잡음 제거
        GaussianBlur(profile, profile, Size(3,1), 0.5);

        auto edgePoints = detectEdgesWithDirection(profile);

        // 출력
        for (const auto& pt : edgePoints) {
            string dirStr = (pt.direction == EdgeDirection::POSITIVE) ? "↑ (Dark→Bright)" : "↓ (Bright→Dark)";
            cout << "Edge at x = " << pt.position << " : " << dirStr << endl;
        }

        // 시각화
        Mat vis;
        cvtColor(gray, vis, COLOR_GRAY2BGR);
        for (const auto& pt : edgePoints) {
            Scalar color = (pt.direction == EdgeDirection::POSITIVE) ? Scalar(0,255,0) : Scalar(0,0,255);
            circle(vis, Point((int)pt.position, rowIdx), 3, color, -1);
        }

        imshow("1D Edge Direction", vis);
        waitKey(0);
    }

    int main(int argc, char** argv) {
        if (argc < 2) {
            cout << "Usage: ./EdgeDirection1D <image_path>" << endl;
            return -1;
        }

        Mat img = imread(argv[1], IMREAD_GRAYSCALE);
        if (img.empty()) {
            cerr << "Image load failed!" << endl;
            return -1;
        }

        int rowToAnalyze = img.rows / 2;
        detectEdge1DWithDirection(img, rowToAnalyze);

        return 0;
    }
728x90
반응형
사업자 정보 표시
사업자 등록번호 : -- | TEL : --