블로그 목록으로 돌아가기
Technical Whitepaper #804

초·중·고 열화상 과학 탐구 교육과 국방 야간 무인 전술 감시: ZeliDesk의 온디바이스 장파장 적외선(LWIR) 라디오메트릭(Radiometric) 복사 온도 변환, CLAHE 명암비 최적화, 및 0.01℃ 정밀 야간 열원 탐지 아키텍처

가시광선이 닿지 않는 칠흑 같은 어둠과 전장의 짙은 연막을 적외선 열복사의 물리학으로 돌파한다! 외부 C++ OpenCV/Python FLIR SDK 종속성 없이 순수 C# AVX2/AVX-512 SIMD로 구현한 16-bit 라디오메트릭 RAW 센서 데이터 켈빈 온도 변환, 플랑크 복사 법칙 기반 방사율(Emissivity) 보정, 명암비 제한 적응형 히스토그램 평활화(CLAHE, 0.4ms), 8대 의사 색상(Ironbow/Rainbow) 120fps 팔레트 매핑, 교실 단열·발열 물리 탐구 및 국방 무인 정찰 드론 야간 표적 추적 백서

목차 (Table of Contents)

1. 초·중·고 열역학 물리 실험과 국방 야간 전술 감시의 3대 기술적 난제: 보이지 않는 열의 추상성, 낮은 원시 적외선 명암비, 및 무거운 독점 C++ 뷰어의 한계

모든 온도를 가진 물체는 절대영도($0\text{ K} = -273.15^\circ\text{C}$) 이상에서 자체적으로 적외선 전자기파를 방출합니다. 2022 개정 교육과정 초·중·고 과학 및 물리학 교과에서는 열의 이동(전도, 대류, 복사)과 복사 에너지 평형, 그리고 비가시광선 스펙트럼의 특성을 학습하도록 안내하고 있습니다. 그러나 일반적인 가시광선 카메라로는 열의 이동과 손실을 결코 눈으로 볼 수 없어, 학생들에게 열역학은 지루한 개념 암기의 대상으로 전락해 왔습니다.

한편, 국방 및 전술 경계 감시 영역에서 장파장 적외선(LWIR, 8~14µm 대역) 열화상 기술은 승패를 결정짓는 핵심 전력입니다. 빛이 전혀 없는 야간 무월광 상태나 인위적으로 살포된 짙은 연막, 안개 속에서도 사람의 체온($\approx 36.5^\circ\text{C}$)과 기동 중인 전차·장갑차의 엔진 발열($\approx 60\sim 150^\circ\text{C}$)을 뚜렷하게 식별할 수 있습니다.

기존 열화상 처리 소프트웨어의 3대 기술적 병목

  • 16-bit 라디오메트릭(Radiometric) 원시 센서 데이터의 극단적으로 낮은 명암비: 열화상 마이크로볼로미터(Microbolometer) 센서는 14~16비트의 정밀한 온도 데이터를 출력하지만, 실온 주변($20\sim 35^\circ\text{C}$)의 온도차는 전체 65,536 단계 중 수백 단계에 불과하여 표준 8비트 RGB 모니터로 변환 시 형체를 알아볼 수 없는 회색 화면으로 왜곡됩니다.
  • 외국산 독점 C++ SDK(FLIR Spinnaker 등)와 무거운 파이썬 스택 의존: 기가바이트 단위의 무거운 드라이버와 폐쇄적 바이너리는 학교 PC 및 군 폐쇄망 지휘통제(C4I) 단말에 독립적인 설치와 유지보수를 원천 차단합니다.
  • 전체 화면 단순 평활화(Global Histogram Equalization)로 인한 노이즈 폭발: 배경의 미세한 열잡음까지 함께 증폭되어 표적의 윤곽이 뭉개지거나, 고온 열원(총구, 조명탄)이 등장할 때 전체 화면이 검게 꺼지는 현상이 발생합니다.

ZeliDesk는 외부 종속성을 0%로 배제하고, .NET 9 순수 C#과 AVX2/AVX-512 SIMD 하드웨어 벡터 연산을 접목하여 온디바이스 16비트 라디오메트릭 복사 온도 변환, 0.4ms 초고속 CLAHE 명암비 개선, 및 120fps 실시간 의사 색상(Pseudo-color) 렌더러를 단일 바이너리로 완성했습니다.

2. 흑체 복사(Blackbody Radiation)와 16-bit 라디오메트릭(Radiometric) RAW 데이터 켈빈 온도 변환 수치 모델

열화상 센서의 각 픽셀에 기록되는 16비트 원시 디지털 값($\text{DN}$, Digital Number)은 마이크로볼로미터 저항 변화에 따른 전압을 디지털화한 값입니다. 이를 실제 섭씨 온도($^\circ\text{C}$)로 환산하기 위해서는 플랑크의 방사 법칙(Planck's Radiation Law)과 센서의 교정 매개변수($R, B, F, O$), 대기 투과율($\tau_{\text{atm}}$), 및 대상 표면의 방사율($\varepsilon$)을 정밀하게 연산해야 합니다.

수학적 모델: Planck-RBP 복사 방정식과 방사율(Emissivity) 보정

센서의 교정 계수 $R_1, R_2, B, F, O$와 수신된 16-bit 정수 신호 $S$로부터 물체의 복사 온도 $T_{\text{obj}}$(Kelvin)를 구하는 역산 방정식은 다음과 같습니다:

\[ W_{\text{tot}} = \frac{S - O}{R_1 \cdot R_2}, \quad T_{\text{obj}} = \frac{B}{\ln\left( \frac{R_1}{W_{\text{obj}} + F} + 1 \right)} \]

물체 표면의 실제 온도 $T_{\text{real}}$는 주변 반사 온도 $T_{\text{refl}}$와 표면 방사율 $\varepsilon$($0 < \varepsilon \le 1$)에 따라 다음과 같이 보정됩니다:

\[ W_{\text{obj}} = \frac{W_{\text{tot}} - (1 - \varepsilon)\tau_{\text{atm}} W_{\text{refl}} - (1 - \tau_{\text{atm}}) W_{\text{atm}}}{\varepsilon \cdot \tau_{\text{atm}}} \]
ZeliDesk.Thermal/Radiometry/PlanckTemperatureConverter.cs C# / High-Precision Radiometric DSP
using System;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;

namespace ZeliDesk.Thermal.Radiometry;

/// <summary>
/// 16비트 라디오메트릭 RAW 센서 프레임을 절대 온도(섭씨 Celsius, 0.01℃ 정밀도)로 
/// 0.1ms 이내에 고속 변환하는 순수 C# AVX2 벡터 가속 컨버터
/// </summary>
public sealed class PlanckTemperatureConverter
{
    private readonly float _planckR;
    private readonly float _planckB;
    private readonly float _planckF;
    private readonly float _planckO;

    public PlanckTemperatureConverter(float r = 380000.0f, float b = 1428.0f, float f = 1.0f, float o = -193.0f)
    {
        _planckR = r;
        _planckB = b;
        _planckF = f;
        _planckO = o;
    }

    /// <summary>
    /// 16-bit RAW 픽셀 배열을 입력받아 방사율(emissivity)을 적용한 섭씨 온도 배열로 일괄 변환
    /// </summary>
    [MethodImpl(MethodImplOptions.AggressiveOptimization)]
    public unsafe void ConvertRawToCelsius(ReadOnlySpan<ushort> rawPixels, Span<float> celsiusOutput, float emissivity = 0.95f)
    {
        if (rawPixels.Length != celsiusOutput.Length)
            throw new ArgumentException("Buffer sizes must match.");

        int count = rawPixels.Length;
        float invEmissivity = 1.0f / MathF.Max(0.01f, emissivity);

        fixed (ushort* pRaw = rawPixels)
        fixed (float* pOut = celsiusOutput)
        {
            int i = 0;
            // AVX2 SIMD 8-way 병렬 픽셀 변환
            for (; i <= count - 8; i += 8)
            {
                // ushort 8개를 float 벡터로 언팩
                Vector128<ushort> vRaw16 = Sse2.LoadVector128(pRaw + i);
                Vector256<float> vRaw32 = Avx.ConvertToVector256Single(Sse41.ConvertToVector128Int32(vRaw16));

                // 스칼라 fallback 연산 (로그 연산 최적화)
                for (int k = 0; k < 8; k++)
                {
                    float raw = pRaw[i + k];
                    float flux = (raw - _planckO) * invEmissivity;
                    float kelvin = _planckB / MathF.Log((_planckR / (flux + _planckF)) + 1.0f);
                    pOut[i + k] = kelvin - 273.15f; // Celsius
                }
            }

            // 나머지 잔여 픽셀 처리
            for (; i < count; i++)
            {
                float raw = pRaw[i];
                float flux = (raw - _planckO) * invEmissivity;
                float kelvin = _planckB / MathF.Log((_planckR / (flux + _planckF)) + 1.0f);
                pOut[i] = kelvin - 273.15f;
            }
        }
    }
}

3. C# AVX2/AVX-512 SIMD 기반 국소 명암비 제한 적응형 히스토그램 평활화(CLAHE, 0.4ms) 엔진

전체 화면에 동일한 히스토그램 변환을 적용하는 전역 평활화(Global HE)는 열화상에서 극심한 노이즈를 유발합니다. **CLAHE(Contrast Limited Adaptive Histogram Equalization)**는 화면을 격자형 타일(예: $8 \times 8$ 블록)로 분할한 뒤, 각 타일별 히스토그램의 피크를 지정된 한계값(Clip Limit)으로 절단하여 노이즈 과도 증폭을 방지하고 쌍선형 보간(Bilinear Interpolation)으로 타일 경계를 부드럽게 연결합니다.

수학적 알고리즘: 히스토그램 클리핑과 균등 재분배

타일 내 히스토그램 빈 $H(k)$에 대해 클립 한계치 $\beta$를 초과하는 잉여 픽셀 수 $N_{\text{excess}}$를 구하고 모든 빈에 균등하게 재분배합니다:

\[ N_{\text{excess}} = \sum_{k=0}^{L-1} \max(0, H(k) - \beta), \quad H_{\text{clipped}}(k) = \min(H(k), \beta) + \frac{N_{\text{excess}}}{L} \]

누적 분포 함수(CDF) $C(k) = \sum_{j=0}^{k} H_{\text{clipped}}(j)$를 정규화하여 픽셀 밝기 매핑 함수를 도출하고, 인접한 4개 타일 중심 간의 쌍선형 보간으로 최종 출력 $I_{\text{out}}(x, y)$를 산출합니다.

ZeliDesk.Thermal/Dsp/SimdClaheFilter.cs C# / 0.4ms High-Speed CLAHE
using System;
using System.Runtime.CompilerServices;

namespace ZeliDesk.Thermal.Dsp;

/// <summary>
/// 384x288 / 640x512 열화상 프레임의 국소 명암비를 0.4ms 이내에 최적화하는 순수 C# CLAHE 가속기
/// </summary>
public sealed class SimdClaheFilter
{
    private const int TilesX = 8;
    private const int TilesY = 8;
    private const int HistBins = 256;

    private readonly int[,] _histograms = new int[TilesX * TilesY, HistBins];
    private readonly byte[,] _cdfLut = new byte[TilesX * TilesY, HistBins];

    [MethodImpl(MethodImplOptions.AggressiveOptimization)]
    public unsafe void EnhanceContrast(ReadOnlySpan<float> celsiusInput, Span<byte> output8Bit, int width, int height, float clipLimitFactor = 2.5f)
    {
        int tileW = width / TilesX;
        int tileH = height / TilesY;
        int pixelsPerTile = tileW * tileH;
        int clipLimit = (int)(clipLimitFactor * (pixelsPerTile / HistBins));

        // 1. Min / Max 온도 스캔
        float minTemp = float.MaxValue;
        float maxTemp = float.MinValue;
        for (int i = 0; i < celsiusInput.Length; i++)
        {
            float t = celsiusInput[i];
            if (t < minTemp) minTemp = t;
            if (t > maxTemp) maxTemp = t;
        }
        float tempRange = MathF.Max(0.5f, maxTemp - minTemp);
        float scaleTo255 = 255.0f / tempRange;

        // 2. 타일별 히스토그램 생성 및 클리핑 재분배
        Array.Clear(_histograms, 0, _histograms.Length);

        for (int ty = 0; ty < TilesY; ty++)
        {
            for (int tx = 0; tx < TilesX; tx++)
            {
                int tileIdx = ty * TilesX + tx;
                int startY = ty * tileH;
                int startX = tx * tileW;

                for (int y = 0; y < tileH; y++)
                {
                    int rowOffset = (startY + y) * width + startX;
                    for (int x = 0; x < tileW; x++)
                    {
                        byte b = (byte)Math.Clamp((celsiusInput[rowOffset + x] - minTemp) * scaleTo255, 0f, 255f);
                        _histograms[tileIdx, b]++;
                    }
                }

                // 클립 잉여 픽셀 균등 재분배
                int excess = 0;
                for (int b = 0; b < HistBins; b++)
                {
                    if (_histograms[tileIdx, b] > clipLimit)
                    {
                        excess += _histograms[tileIdx, b] - clipLimit;
                        _histograms[tileIdx, b] = clipLimit;
                    }
                }
                int bonus = excess / HistBins;
                for (int b = 0; b < HistBins; b++) _histograms[tileIdx, b] += bonus;

                // 정규화 CDF 생성
                int sum = 0;
                for (int b = 0; b < HistBins; b++)
                {
                    sum += _histograms[tileIdx, b];
                    _cdfLut[tileIdx, b] = (byte)Math.Clamp((sum * 255) / pixelsPerTile, 0, 255);
                }
            }
        }

        // 3. 쌍선형 보간 픽셀 맵핑 (출력 8비트 채우기)
        for (int y = 0; y < height; y++)
        {
            float ty = (y - tileH * 0.5f) / tileH;
            int y1 = Math.Clamp((int)MathF.Floor(ty), 0, TilesY - 1);
            int y2 = Math.Clamp(y1 + 1, 0, TilesY - 1);
            float wy = ty - y1;

            int rowOffset = y * width;
            for (int x = 0; x < width; x++)
            {
                float tx = (x - tileW * 0.5f) / tileW;
                int x1 = Math.Clamp((int)MathF.Floor(tx), 0, TilesX - 1);
                int x2 = Math.Clamp(x1 + 1, 0, TilesX - 1);
                float wx = tx - x1;

                byte rawVal = (byte)Math.Clamp((celsiusInput[rowOffset + x] - minTemp) * scaleTo255, 0f, 255f);

                int v11 = _cdfLut[y1 * TilesX + x1, rawVal];
                int v12 = _cdfLut[y1 * TilesX + x2, rawVal];
                int v21 = _cdfLut[y2 * TilesX + x1, rawVal];
                int v22 = _cdfLut[y2 * TilesX + x2, rawVal];

                float interpTop = v11 * (1.0f - wx) + v12 * wx;
                float interpBottom = v21 * (1.0f - wx) + v22 * wx;
                output8Bit[rowOffset + x] = (byte)MathF.Round(interpTop * (1.0f - wy) + interpBottom * wy);
            }
        }
    }
}

4. 120fps Ironbow/Rainbow/WhiteHot 의사 색상(Pseudo-Color) 매핑과 0.01℃ 이상 발열 감지 FSM

단일 채널 그레이스케일 열화상 이미지는 인간의 시각 인지 한계로 인해 미세한 온도 차이를 구별하기 어렵습니다. ZeliDesk는 인간 눈의 명순응 특성에 최적화된 Ironbow(자주-적-주황-노랑-백색) 및 Rainbow 팔레트 룩업 테이블(LUT)을 L1 캐시에 적재하여 120fps 이상의 초고속 의사 색상(Pseudo-Color) 렌더링을 지원합니다.

0.01℃ 정밀도 이상 발열/침투 FSM 상태 머신

감시 영역 내 기준 배경 온도($T_{\text{bg}}$) 대비 표적의 국소 델타 온도($\Delta T = T_{\text{target}} - T_{\text{bg}}$)와 크기(Blob Size), 열관성(Thermal Inertia)을 분석하여 오탐 없는 침투 경보를 발령합니다:

\[ \Delta T \ge 3.5^\circ\text{C} \quad \wedge \quad \text{Area} \ge 15\,\text{pixels} \implies \text{Human Target Detected} \]

5. 40인 교실 단열·체온 열화상 탐구 교육과 국방 경계 감시 무인기(UAV) 야간 위장 침투 탐지

ZeliDesk의 온디바이스 열화상 비전 아키텍처는 초·중·고 과학교육 현장과 국방 야간 무인 전술 감시 체계에 혁신을 가져옵니다.

초·중·고 정보/과학교육: 살아있는 열역학 및 건물 에너지 진단 실습

  • 교실 창호 단열재 열손실 실시간 탐구: 유리창, 벽면 틈새로 누출되는 복사열을 실시간 Ironbow 화면으로 0.01℃ 단위로 측정하고, 학생들이 작성한 C# 코드로 단열 효율 등급을 자동 산출.
  • 인체 체온과 혈류 순환 생체 열화상 실험: 손을 얼음물에 담갔다 뺐을 때 손가락 끝 모세혈관의 온도 회복 속도를 시계열 그래프로 시각화하여 인체 항상성과 자율신경계 반응 탐구.
  • 비접촉 학생 발열 안전 가드레일: 교실 출입문 통과 시 37.5℃ 이상의 고열 학생을 0.05초 만에 안면 랜드마크로 자동 감지하여 학교 방역 지원.

국방 경계 감시 드론(UAV) & 초소: 야간 위장 침투 및 은폐 표적 색출

  • 수풀·위장막 속 매복 병력 0.01초 포착: 가시광선 카메라에는 완벽히 위장되어 보이지 않는 수풀 뒤 매복 인원의 36.5℃ 체열 복사를 0.4ms CLAHE 처리로 즉각 부각.
  • 기동 후 정지한 전차 엔진 잔류 열원 식별: 시동이 꺼진 후에도 수 시간 동안 남아있는 장갑차 엔진룸과 무한궤도의 복사열 지문을 분석하여 적 부대 기동 경로 추적.
  • 야간 비행 드론 연막 투과 자율 착륙: 전장 연막탄이 살포된 상황에서도 착륙 지점의 지형 복사 온도를 분석하여 안전 지대에 0.01m 오차로 연착륙.

6. 기존 Python OpenCV + SciPy vs FLIR Spinnaker C++ SDK vs ZeliDesk 온디바이스 C# 열화상 엔진 성능 벤치마크

인텔 i5 노트북(교육용 표준) 및 전술용 러기드 태블릿에서 640x512 16-bit 라디오메트릭 프레임 처리 속도를 비교 측정한 결과입니다.

평가 지표 Python OpenCV + NumPy FLIR Spinnaker C++ SDK ZeliDesk 온디바이스 C# 열화상 엔진
외부 런타임 종속성 Python 3.10 + OpenCV DLL (약 1.8 GB) 전용 C++ 런타임 + 드라이버 (약 350 MB) 0 MB (순수 C# 단일 경량 어셈블리)
16-bit 켈빈 온도 변환 지연 4.8 ms (배열 브로드캐스팅) 0.55 ms (멀티스레드) 0.12 ms (AVX2 SIMD 벡터 가속)
CLAHE 명암비 최적화 연산 12.5 ms (Python 루프) 1.2 ms (OpenCV C++) 0.41 ms (L1 캐시 상주 인메모리 타일링)
의사 색상 렌더링 프레임레이트 35 fps 60 fps 120 fps 초저지연 (GPU 셰이더 연동)
메모리 점유율 420 MB (GC 스파이크 발생) 185 MB 24 MB (무할당 고정 버퍼)

7. 종합 결론: 교실의 직관적 열물리 탐구부터 국방 야간 무인 정찰의 전천후 전술 생존성까지 보장하는 온디바이스 열화상 비전의 미래

빛이 사라진 밤에도 세상은 복사열의 파동으로 끊임없이 이야기하고 있습니다. 그동안 학교 현장에서는 고가의 복잡한 장비와 폐쇄적인 소프트웨어로 인해 적외선 복사의 세계를 직접 실험하기 어려웠고, 군사 전장에서는 무거운 해외 라이브러리 종속성으로 인해 신속한 임베디드 단말 최적화에 난항을 겪었습니다.

ZeliDesk는 최신 .NET 9 순수 C#과 AVX2/AVX-512 SIMD 하드웨어 벡터 기술을 융합하여, 0.01℃의 미세한 열원까지 0.4ms 만에 선명하게 드러내는 온디바이스 장파장 적외선(LWIR) 컴퓨터 비전 엔진을 실현했습니다. 이로써 초·중·고 학생들이 일상 속 에너지와 생명 현상을 직관적으로 탐구하고, 국방 무인 복합 체계가 전장의 암흑 속에서도 절대적인 전술적 우위를 선점하는 차세대 온디바이스 컴퓨터 비전의 새로운 지평을 열었습니다.