| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
- Encapusulation
- Gaussian
- compare
- Class
- flutter
- subpixel
- mfc
- SERIAL
- public
- aduino
- atmega328
- memory
- edge
- Contour
- digitalRead
- stream
- Filtering
- Read
- APP
- Gradient
- sensor
- Android
- Pointer
- Unity
- UNO
- Binary
- c++
- wpf
- parameter
- file access
- Today
- Total
폴크(FOLC)
치수 계산하기 - robust edge detection 본문
Gaussian Smoothing
노이즈를 제거하여 edge 검출의 안정성을 향상시키기 위한 가우시안 필터 적용.
1차 미분 (1st Derivative)
프로파일의 기울기를 계산하여 edge 후보 위치를 검출.
Zero-Crossing 위치 검출
1차 미분 결과가 양→음 또는 음→양으로 바뀌는 지점을 zero-crossing으로 판단.
Subpixel Interpolation
Zero-crossing 근처의 값을 가지고 2차 (Quadratic) 보간을 통해 subpixel 수준의 edge 위치를 계산.
예제
#include <iostream>
#include <vector>
#include <cmath>
// Gaussian smoothing (1D)
std::vector<double> gaussianSmooth(const std::vector<double>& input, double sigma) {
int radius = static_cast<int>(std::ceil(3 * sigma));
int size = 2 * radius + 1;
std::vector<double> kernel(size);
std::vector<double> output(input.size());
// Generate kernel
double sum = 0.0;
for (int i = -radius; i <= radius; ++i) {
kernel[i + radius] = std::exp(-0.5 * (i * i) / (sigma * sigma));
sum += kernel[i + radius];
}
for (auto& k : kernel) k /= sum;
// Apply convolution
for (size_t i = 0; i < input.size(); ++i) {
double acc = 0.0;
for (int j = -radius; j <= radius; ++j) {
int idx = std::clamp<int>(i + j, 0, input.size() - 1);
acc += input[idx] * kernel[j + radius];
}
output[i] = acc;
}
return output;
}
// Compute 1st derivative
std::vector<double> computeDerivative(const std::vector<double>& profile) {
std::vector<double> deriv(profile.size(), 0.0);
for (size_t i = 1; i < profile.size() - 1; ++i) {
deriv[i] = (profile[i + 1] - profile[i - 1]) / 2.0;
}
return deriv;
}
// Quadratic interpolation for subpixel zero-crossing
double quadraticSubpixel(const std::vector<double>& deriv, int idx) {
double y1 = deriv[idx - 1];
double y2 = deriv[idx];
double y3 = deriv[idx + 1];
double denom = (y1 - 2 * y2 + y3);
if (std::abs(denom) < 1e-10) return idx; // avoid divide by zero
double delta = 0.5 * (y1 - y3) / denom;
return idx + delta;
}
// Main edge detection
std::vector<double> detectEdgesSubpixel(const std::vector<double>& input, double sigma) {
std::vector<double> smoothed = gaussianSmooth(input, sigma);
std::vector<double> deriv = computeDerivative(smoothed);
std::vector<double> edgePositions;
for (size_t i = 1; i < deriv.size() - 1; ++i) {
if (deriv[i] * deriv[i + 1] < 0) {
double subpixelPos = quadraticSubpixel(deriv, i);
edgePositions.push_back(subpixelPos);
}
}
return edgePositions;
}
// Example
int main() {
std::vector<double> profile = {0, 0, 1, 3, 7, 12, 7, 3, 1, 0, 0};
double sigma = 1.0;
std::vector<double> edges = detectEdgesSubpixel(profile, sigma);
for (double e : edges) {
std::cout << "Edge at: " << e << std::endl;
}
return 0;
}