일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- file access
- public
- Contour
- Class
- stream
- UNO
- subpixel
- Android
- SERIAL
- sensor
- Filtering
- Gradient
- c++
- parameter
- wpf
- mfc
- Read
- Encapusulation
- memory
- Unity
- aduino
- edge
- atmega328
- APP
- flutter
- Pointer
- digitalRead
- Binary
- compare
- Gaussian
- Today
- Total
폴크(FOLC)
치수 계산하기 - subpixel 본문
Sub-pixel Edge Detection 기반의 고정밀 CD측정은 pixel-level 경계 검출의 한계를 넘어, 곡선 보간, Edge fitting, 또는 gradient interpolation 등을 이용하여 실제 구조의 경계선을 소수점 단위까지 정밀하게 추정하는 방법이다
원리
- Edge 검출: Sobel 또는 Canny로 초기 edge map 생성
- Gradient interpolation: 엣지 픽셀 주변에서 1차 또는 2차 곡선을 피팅하여 정확한 edge 위치를 소수점 단위로 추정
- Edge pair 매칭: 좌/우 또는 위/아래 edge 쌍을 찾아 거리 계산
- 실측 크기 변환 (선택): pixel 단위를 μm 등으로 변환
예제
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
// subpixel edge 위치 추정 (1D interpolation)
double interpolateSubpixel(const Mat& grad, int row, int col) {
if (col <= 0 || col >= grad.cols - 1)
return col; // 경계선일 경우 단순 pixel 위치 반환
double g0 = grad.at<float>(row, col - 1);
double g1 = grad.at<float>(row, col);
double g2 = grad.at<float>(row, col + 1);
double denominator = g0 - 2 * g1 + g2;
if (abs(denominator) < 1e-5) return col;
double offset = 0.5 * (g0 - g2) / denominator;
return col + offset;
}
// Edge로부터 CD 측정
double measureSubpixelCD(const Mat& grad, const Mat& edges, int row) {
vector<double> edgePositions;
for (int col = 1; col < edges.cols - 1; ++col) {
if (edges.at<uchar>(row, col) > 0) {
double subpixelCol = interpolateSubpixel(grad, row, col);
edgePositions.push_back(subpixelCol);
}
}
if (edgePositions.size() < 2) return -1.0;
// 가장 바깥쪽 edge를 CD 측정용으로 사용
return abs(edgePositions.front() - edgePositions.back());
}
int main(int argc, char** argv) {
if (argc < 2) {
cout << "Usage: ./SubpixelCD <image_path>" << endl;
return -1;
}
Mat src = imread(argv[1], IMREAD_GRAYSCALE);
if (src.empty()) {
cerr << "Failed to load image!" << endl;
return -1;
}
// Sobel 경사도 계산 (x 방향)
Mat gradX;
Sobel(src, gradX, CV_32F, 1, 0, 3);
// Canny edge
Mat edges;
Canny(src, edges, 50, 150);
// 관심 영역의 수평 중간 라인 기준 CD 측정
int midRow = src.rows / 2;
double cd = measureSubpixelCD(gradX, edges, midRow);
if (cd > 0)
cout << "Subpixel Critical Dimension (CD): " << cd << " pixels" << endl;
else
cout << "Failed to detect valid edge pair." << endl;
return 0;
}