2026-10-03

NaGeoAI 실제 QGIS 실습 6 | 영상분류 실행과 JSON 숫자 배열 검증

본 실습에서는 NaGeoAI의 영상분류 기능을 QGIS 데스크톱에서 실행하고, 생성된 JSON 파일의 구조와 확률값을 검증하였다. 주차장 예제 영상 한 장을 입력으로 사용하였으며, 실행 완료와 분류 의미의 타당성을 구분하여 설명한다. 모든 그림은 2026년 10월 3일 해당 PC에서 실제 수행한 화면이다.

1. 실습 목적과 적용 범위

영상분류(image classification)는 입력 영상 전체에 하나의 범주를 부여하는 작업이다. 앞선 객체탐지 실습처럼 차량별 경계상자를 생성하지 않으며, 토지피복 픽셀 분류도 수행하지 않는다. 이번 실습의 목적은 입력 영상 확인 → 모델 추론 → JSON 저장 → 수치 검증의 절차를 재현하는 데 있다.

2. 프로그램 설치와 환경 확인

실행 환경은 Windows, QGIS 3.44.12, NaGeoAI 1.9.1에 JSON 직렬화 수정을 적용한 로컬 설치본이다. 모델은 google/vit-base-patch16-224이며, 실제 로그에서 CUDA 사용을 확인하였다.

  1. NaGeoAI-1.9.1.zip 다운로드를 클릭하여 ZIP을 내려받는다. 압축을 풀지 않는다.
  2. QGIS의 플러그인 → 플러그인 관리 및 설치 → ZIP에서 설치에서 ZIP을 선택하고 설치한다. 기존 설치가 있으면 버전과 활성화 상태를 먼저 확인한다.
  3. QGIS를 다시 열고 NaGeoAI 최초 실행 환경 설정에서 필요한 AI 환경의 설치 상태를 확인한다. 누락된 항목만 설치·다운로드하며, 이미 설치된 항목은 건너뛴다. 이번 영상분류에는 OpenSR 모델을 사용하지 않는다.
  4. 인터넷에 연결된 상태에서 영상분류 모델을 처음 실행하면 모델 파일을 받는다. 이후에도 모델 설정 확인을 위한 네트워크 요청이 발생할 수 있으므로, 캐시가 있다고 해서 모든 요청이 생략되는 것은 아니다.

이번에는 플러그인을 재설치하지 않았다. 따라서 새 설치 화면을 촬영한 것으로 표시하지 않고 설치 절차를 글로 안내한다. 아래의 5개 그림은 입력·설정·실행·검증 화면이다.

JSON 저장 수정 사항

공개 v1.9.1 ZIP에는 이번 로컬 직렬화 수정이 아직 반영되지 않았다. 기존 default=str 방식은 NumPy 확률 배열을 문자열로 저장할 수 있다. 이번 검증본은 workers/geoai_task_worker.py의 image_classification 결과 저장 부분을 다음과 같이 수정하고 QGIS를 다시 시작하였다. 같은 숫자 배열 결과를 재현하려면 해당 수정이 필요하다. 수정 전 파일은 별도로 백업한다.

json.dump(result, report, ensure_ascii=False, indent=2,
          default=lambda value: value.tolist() if hasattr(value, "tolist") else str(value),
          allow_nan=False)

3. 예제 파일 다운로드와 입력 확인

사용 자료는 Source Cooperative의 OpenGeos GeoAI 예제 parking-lot.tif이다. 원본 예제 파일 다운로드를 눌러 저장한다. 이 PC에서는 D:\QGIS_Plugin\SampleData\NaGeoAI 폴더에 보관하였다. 실습 화면의 공개 사용은 사용자의 승인을 받았으며, 이를 원본 영상의 일반적인 자유 재배포 허가로 확대하여 해석하지 않는다. 원본 영상과 모델 파일은 이번 GitHub 업로드에 포함하지 않았다. 촬영일과 개별 원본 라이선스는 확인되지 않았으므로 별도의 현장·시기 분석 근거로 사용하지 않는다.

원본 QGIS_Play.qgz는 덮어쓰지 않고 QGIS_Play_NaGeoAI_20261003_classification_check.qgz 복사본을 열었다. 예제 영상은 별도 파일로 추가해야 한다. 일반적인 입력 방법은 레이어 → 레이어 추가 → 래스터 레이어 추가이다. 이번 실제 실행에서는 QGIS의 Python 콘솔에서 다음 명령으로 영상을 추가하였다. 분류 처리는 콘솔이 아니라 NaGeoAI 패널의 실행 버튼으로 수행하였다.

sample = iface.addRasterLayer('D:/QGIS_Plugin/SampleData/NaGeoAI/parking-lot.tif', 'parking-lot')
QgsProject.instance().setCrs(sample.crs())
iface.mapCanvas().setExtent(sample.extent())
iface.mapCanvas().refresh()

유효한 입력 레이어, EPSG:3857, 1,659×938 픽셀, RGB 3밴드, uint8 자료형을 확인하였다. X·Y 픽셀 간격은 각각 0.1492789632, 0.1493203625 투영좌표 단위이다. EPSG:3857의 간격을 현장 지상거리 정확도로 직접 해석하지 않는다. 미국 예제 영상의 표시를 위해 실습 복사본의 프로젝트 CRS만 EPSG:3857로 변경하였고 원본 EPSG:5187 프로젝트는 보존하였다.

QGIS 주차장 입력 영상과 CRS 크기 밴드 픽셀 간격 검증
그림 1. QGIS에서 주차장 영상이 표시되고 콘솔에서 입력 메타데이터를 확인한 화면. 배경지도는 분석 입력으로 사용하지 않았다. (클릭하면 원본 크기로 확인할 수 있다.)

4. NaGeoAI 영상분류 입력값 설정

  1. NaGeoAI 도구 모음의 추가 분석을 열고 기능 목록에서 영상분류를 선택한다.
  2. 입력 영상에 D:/QGIS_Plugin/SampleData/NaGeoAI/parking-lot.tif를 지정한다. 지도에 보이는 레이어와 이 파일이 같은 자료인지 확인한다.
  3. Hugging Face 모델에 google/vit-base-patch16-224를 입력한다.
  4. 출력 경로를 D:/QGIS_Plugin/SampleData/NaGeoAI/verification/classification_gui_20261003_approved.json으로 지정한다. 기존 결과를 보존하기 위해 새로운 파일명을 사용하였다.
  5. 이 기능의 출력은 비공간 JSON이므로 공간 결과를 지도에 추가는 해제하였다.
NaGeoAI 영상분류 입력 파일 모델 결과 JSON 설정
그림 2. 실제 영상분류 설정. 입력 파일, 모델 식별자, 새 JSON 출력 경로를 확인한다. (클릭하면 원본 크기로 확인할 수 있다.)

5. 실행과 완료 로그 확인

실행 버튼을 누르면 패널에 영상분류 시작 메시지가 표시되고, 실행 중 버튼이 비활성화된다. 로그의 네트워크 응답 한 줄만으로 성공을 판단하지 않는다. 처리가 끝난 뒤 CUDA 모델 적재 메시지, 결과 요약, 출력 파일 경로를 확인하고 실제 파일 존재 여부를 검사한다.

NaGeoAI 실행 직후 영상분류 시작 메시지
그림 3. 실행 버튼을 누른 직후의 실제 화면. 영상분류 시작 메시지와 비활성화된 실행 버튼이 보인다. (클릭하면 원본 크기로 확인할 수 있다.)
CUDA 영상분류 완료 로그와 JSON 파일 경로
그림 4. 실제 처리 완료 로그. Model loaded on cuda, 클래스 요약 및 결과 JSON 경로를 확인하였다. 지도에 보이는 영상은 입력 영상이며 분류 결과 지도가 아니다. (클릭하면 원본 크기로 확인할 수 있다.)

6. 출력 파일 구조와 수치 검증

완료 후 QGIS Python 콘솔에서 생성된 파일을 다시 읽어 probabilities의 자료형, 개수, 합계, 최상위 클래스 점수 및 유한값 여부를 검사하였다. 파일 검사는 외부 Python 환경에서도 동일하게 수행하였으나, 그림 5는 실제 QGIS 콘솔 화면이다.

import json, math
result = json.load(open('D:/QGIS_Plugin/SampleData/NaGeoAI/verification/classification_gui_20261003_approved.json', encoding='utf-8'))
probs = result['probabilities']
print(type(probs).__name__, len(probs), sum(probs))
print(result['class'], probs[result['class']])
print(all(math.isfinite(p) for p in probs))
검사항목실제 확인값
probabilities 자료형list — JSON 숫자 배열
확률값 개수1,000
확률값 합계1.000000021433607
모든 값의 유한성True
최상위 클래스782 — screen, CRT screen
최상위 점수0.20161251723766327
QGIS 콘솔의 JSON 숫자 배열 1000개와 확률 합계 검증
그림 5. 실제 결과 JSON을 다시 읽어 검사한 화면. 클래스 782, list 1,000개, 합계 및 유한성 True를 확인한다. (클릭하면 원본 크기로 확인할 수 있다.)

7. 결과의 해석과 한계

확률값 합계의 1과의 차이는 약 2.14×10−8로, 이 검사는 저장된 숫자 배열의 수치적 일관성을 확인하는 절차이다. 지표의 합계가 1에 가깝다는 사실은 분류의 의미적 정확성을 입증하지 않는다.

실제 입력에는 주차장·차량·건물이 보이지만 최상위 출력은 screen, CRT screen이었다. 점수 약 0.2016은 모델의 해당 범주 점수이지, 주차장 분류 정확도 20.16%라는 뜻이 아니다. 기본 모델은 일반 ImageNet 범주를 대상으로 하므로 이 출력으로 주차장, 차량 수, 토지피복 또는 재난 피해를 판단해서는 안 된다. 항공영상에 맞춘 모델과 독립적인 정답자료를 확보하여 비교·검증할 필요가 있다. 토지피복 지도가 목적이라면 의미론적 분할 등 픽셀 단위 작업과 구분해야 한다.

8. 저장과 종료

실습 복사본을 QGIS에서 저장한 뒤 실습에 사용한 QGIS 창을 정상 종료하였다. 저장 후 복사본의 갱신 시각과 크기 변화를 확인하고, 원본 QGIS_Play.qgz의 SHA-256이 실행 전 값과 동일함을 확인하였다. 결과 JSON은 별도 파일로 보관하였다. 프로젝트 파일만 복사하면 입력 래스터가 자동으로 포함되는 것은 아니므로 재실행 시 데이터 경로도 함께 확인한다.

참고 자료

작성·검증일: 2026년 10월 3일. 그림은 공개 GitHub 저장소의 커밋 SHA에 고정된 주소로 연결하였다. 이번 글은 실행·저장 검증을 기록한 실습이며, 항공영상 분류 성능 평가 보고서가 아니다.

댓글 없음:

댓글 쓰기

GeoAI 위성·드론 영상 분석, 재난대응 산업이 뜬다 | 재난안전과 GeoAI

GeoAI 위성·드론 영상 분석 기술이 재난대응 산업의 중심으로 떠오르고 있다. 누리호 5차 발사, 위성·드론 영상 분석 스타트업, ArcGIS 경사지 위험 분석 서비스까지 오늘의 관련 소식을 정리했다. 📌 3줄 요약 아크넥사는 위성·드론 영상을...