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

폴크(FOLC)

알고리즘 - Edge 추출 방법 ( Optimally Oriented Flux ) 본문

머신 비전/머신 비전 알고리즘 테크닉 CPP

알고리즘 - Edge 추출 방법 ( Optimally Oriented Flux )

folcjin 2026. 4. 20. 08:56
728x90
반응형

OOF는 국소적인 미분 연산의 한계를 넘어, 영역 기반의 에너지 흐름을 분석함으로써 복잡하고 밀집된 구조물에서 가장 신뢰할 수 있는 선 추출이 가능하다. 

 

목적: 이미지에서 가늘고 길게 이어진 구조를 검출
적용 분야: 혈관, 신경 섬유, 기관지, 섬유 패턴 분석 등
핵심 아이디어:
- 픽셀 주변의 Hessian 행렬(2차 미분) 분석 + 인접 구조물의 간섭 활용
- 고유값 패턴으로 선형성 판단의 약점을 보완하고자 개발됨

 

장점
- 인접 구조 간섭에 강함
- 방향 정보 추출 가능
- scale 추정이 가능
- 분석적 계산 가능

한계
- 반지름 범위 설정이 중요
- 노이즈에 완전히 자유롭지 못함
- 분기점과 고곡률 구조는 후처리가 필요함.

 

 

소스 코드

// C++14 / OpenCV 4.x
#include <opencv2/opencv.hpp>
#include <algorithm>
#include <vector>
#include <cmath>

#include <opencv2/opencv.hpp>
#include <iostream>
#include <complex>

using namespace cv;
using namespace std;

// OOF 필터 함수
void applyOOF(const Mat& src, Mat& response, float radius) {
    Mat gray;
    if (src.channels() == 3) cvtColor(src, gray, COLOR_BGR2GRAY);
    else gray = src.clone();

    // 1. 입력을 float 형으로 변환 및 FFT를 위한 패딩
    Mat floatSrc;
    gray.convertTo(floatSrc, CV_32F, 1.0 / 255.0);
    
    int m = getOptimalDFTSize(floatSrc.rows);
    int n = getOptimalDFTSize(floatSrc.cols);
    Mat padded;
    copyMakeBorder(floatSrc, padded, 0, m - floatSrc.rows, 0, n - floatSrc.cols, BORDER_CONSTANT, Scalar::all(0));

    // 2. FFT 수행
    Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)};
    Mat complexI;
    merge(planes, 2, complexI);
    dft(complexI, complexI);

    // 3. 주파수 도메인에서 OOF 필터(Bessel 기반) 생성 및 적용
    // OOF 커널: 1/r * (sin(r*w) / w - cos(r*w)) 형태의 근사치 사용
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            float u = (i > m / 2) ? (float)i - m : (float)i;
            float v = (j > n / 2) ? (float)j - n : (float)j;
            float w = sqrt(u * u + v * v);

            if (w > 0) {
                // 주파수 영역에서의 OOF 가중치 계산
                float filterValue = (sin(radius * w) / (radius * w) - cos(radius * w)) / (w * w);
                
                complexI.at<Vec2f>(i, j)[0] *= filterValue;
                complexI.at<Vec2f>(i, j)[1] *= filterValue;
            }
        }
    }

    // 4. 역 FFT (Inverse DFT)
    idft(complexI, complexI);
    split(complexI, planes);
    
    // 5. 결과 후처리 (고유값 분석 대용으로 크기 계산)
    magnitude(planes[0], planes[1], response);
    response = response(Rect(0, 0, gray.cols, gray.rows));
    
    normalize(response, response, 0, 255, NORM_MINMAX, CV_8U);
}

 

#include <opencv2/opencv.hpp>
int main() {
    cv::Mat gray = cv::imread("input.png", cv::IMREAD_GRAYSCALE);
    
    cv::Mat oofResult;

    applyOOF(gray, oofResult, 5.f);

    // 보기 좋게 0~255로 변환해 저장
    cv::Mat vis; oofResult.convertTo(vis, CV_8U, 255.0);
    cv::imwrite(" oofResult.png", vis);
    return 0;
}

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