| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
- public
- parameter
- Unity
- edge
- digitalRead
- UNO
- Pointer
- mfc
- Read
- flutter
- subpixel
- Class
- file access
- memory
- APP
- Binary
- detect
- SERIAL
- Gradient
- Contour
- sensor
- wpf
- Filtering
- atmega328
- Android
- aduino
- Encapusulation
- c++
- compare
- stream
- Today
- Total
폴크(FOLC)
알고리즘 - Defect 추출 방법 ( Constant False Alarm Rate ) 본문
CFAR(Constant False Alarm Rate, 정상 오경보율 유지 기법) 알고리즘은 레이더나 소나 시스템에서 가장 핵심이 되는 '적응형 표적 탐지 기술'입니다. 레이더가 물체를 완벽히 찾아내려면 고정된 기준이 아니라 환경에 맞춰 스스로 변하는 똑똑한 기준선(임계값)이 필요한데, 이를 가능하게 하는 것이 바로 CFAR입니다.
- 주변 환경의 잡음 수준이 변해도, 오경보가 발생할 확률을 일정하게 유지하면서 목표물을 검출하는
기본 개념
CFAR는 특정 거리 셀 또는 주파수 셀에서 목표물이 있는지 판단할 때, 그 셀 주변의 신호들을 이용해 배경 잡음 수준을 추정합니다.
동작 구조
C: CUT, G: Guard Cell, R: Reference Cell
┌───────────────┐
│ R R R R R R R R R R │
│ R R R R R R R R R R │
│ R R G G G G G G R R │
│ R R G G C G G G R R │
│ R R G G G G G G R R │
│ R R R R R R R R R R │
│ R R R R R R R R R R │
└───────────────┘
각 요소의 의미는 다음과 같습니다.
1) CUT : 현재 검사 중인 셀입니다. 이 셀에 목표물이 있는지 판단합니다.
2) Guard Cell, 보호 셀 : CUT 바로 주변의 셀입니다. 목표물 신호가 한 셀에만 완벽히 들어가지 않고 주변 셀로 퍼질 수 있기 때문에, CUT 바로 옆 셀들을 잡음 추정에 사용하지 않습니다.
즉, 보호 셀은 목표물 신호가 잡음 추정값을 오염시키지 않도록 제외하는 영역입니다.
3) Reference Cell, Training Cell, 참조 셀 : 배경 잡음이나 클러터 수준을 추정하는 데 사용하는 셀입니다.
이 셀들의 평균, 중앙값, 순위값 등을 이용해 잡음 수준을 계산합니다.
처리 절차
1단계: 검사할 셀 선택 -- 거리-도플러 맵, 거리 프로파일, 영상 등에서 한 셀을 CUT로 선택합니다.
2단계: 보호 셀 제외 -- CUT 주변의 일정 개수 셀은 보호 셀로 설정하여 잡음 추정에서 제외합니다.
3단계: 참조 셀 선택 -- 보호 셀 바깥쪽의 셀들을 참조 셀로 사용합니다.
4단계: 잡음 수준 추정 -- 참조 셀들의 전력값을 이용해 배경 잡음 또는 클러터 전력을 추정합니다.
5단계: 임계값 계산 -- 추정한 잡음 전력에 스케일 계수 α 를 곱해 임계값을 만듭니다.
T=α⋅P^noise
6단계: 검출 판단 -- CUT 전력이 임계값보다 크면 목표물로 판단합니다.
PCUT > T : 이면 목표물 검출, PCUT ≤ T : 이면 목표물 없음으로 판단
*. sample code
void calcCFAR2D(const Mat& srcImage, int guardY, int guardX, int refY, int refX, double alpha)
{
int height = srcImage.rows;
int width = srcImage.cols;
cv::Mat imgFloat;
srcImage.convertTo(imgFloat, CV_32F);
cv:: Mat detection = cv:: Mat::zeros(height, width, CV_8U);
cv:: Mat dstImage = cv:: Mat::zeros(height, width, CV_32F);
int winY = guardY + refY;
int winX = guardX + refX;
int totalWindowHeight = 2 * winY + 1;
int totalWindowWidth = 2 * winX + 1;
int guardWindowHeight = 2 * guardY + 1;
int guardWindowWidth = 2 * guardX + 1;
int totalCellCount = totalWindowHeight * totalWindowWidth;
int guardCellCount = guardWindowHeight * guardWindowWidth;
int referenceCellCount = totalCellCount - guardCellCount;
if (referenceCellCount <= 0)
{
return detection;
}
for (int y = winY; y < height - winY; ++y)
{
for (int x = winX; x < width - winX; ++x)
{
float cut = imgFloat.at<float>(y, x);
double totalSum = 0.0;
double guardSum = 0.0;
// 전체 CFAR 윈도우 합
for (int yy = y - winY; yy <= y + winY; ++yy)
{
for (int xx = x - winX; xx <= x + winX; ++xx)
{
totalSum += imgFloat.at<float>(yy, xx);
}
}
// Guard 영역 + CUT 영역 합
for (int yy = y - guardY; yy <= y + guardY; ++yy)
{
for (int xx = x - guardX; xx <= x + guardX; ++xx)
{
guardSum += imgFloat.at<float>(yy, xx);
}
}
// Reference 영역 평균
double referenceSum = totalSum - guardSum;
double noiseEstimate = referenceSum / referenceCellCount;
// CFAR 임계값
double threshold = alpha * noiseEstimate;
detection.at<float>(y, x) = static_cast<float>(threshold);
// 검출 판단
if (cut > threshold)
{
dstImage.at<uchar>(y, x) = 255;
}
}
}
}