WMStoGeoJSON

범죄주의구간하고 여성밤치안안전 데이터가 api 로 제공 되는데, WMS(이미지)로 제공되고, 정형 데이터가 존재하지 않아서, 이를 프로젝트에서 사용하기 위해 GeoJSON 데이터로 변환을 해서 저장을 해야 했다.

GPT에게 물어보니, 지역을 쪼개서 타일마다 WMS를 받아, 유효픽셀만 남겨서 색을 기준으로 등급화해서 GeoJSON 데이터로 만들면 된다고 한다.. 뭐 쉽네? 라고 생각했는데, 코드 겁나 길다. 지피티가 중간에 끊기면 이어서 작업하도록 하는 로직까지 만들어 주었다. 굿

생각보다 갑자기 멈추는 경우가 종종 있었다. 데이터의 정확도는 눈으로 봤을 때는 정확한데 실제 데이터와 수치적인 비교도 나중에 해봐야 겠다.

전체 흐름(한 줄 요약)

서울 bbox를 타일로 쪼갠다 → 타일마다 WMS PNG를 받는다 → (halo 제거) 유효 픽셀만 남긴다 → 색 강도로 등급화한다 → 영역(contour)을 폴리곤으로 만든다 → GeoJSON으로 합친다


1) WMS로 PNG 받기

1-1. 필요한 파라미터

WMS GetMap 요청은 기본적으로 아래가 핵심이야:

  • layers: 여성안심길 레이어
  • styles: 보통 빈 문자열(문서 예시가 이 형태)
  • bbox: 현재 타일 영역(minx,miny,maxx,maxy)
  • width,height: 이미지 해상도(512 추천)
  • format=image/png
  • transparent=TRUE
  • srs=EPSG:4326 (bbox 좌표계와 맞춰야 함)

1-2. 실패 응답 처리

SafeMap은 가끔 JSON/XML로 에러를 주거나 500이 나기도 해.

그래서 “이미지(PNG)면 처리 / 아니면 스킵 + 로그” 패턴이 안정적임.


2) 서울 bbox를 타일로 쪼개기

서울 전체 bbox를 한 번에 호출하면 해상도/정밀도가 깨지고,

대부분 WMS 서버도 요청 크기를 크게 받으면 불안정해.

그래서 아래처럼 “도 단위(deg)” 스텝으로 격자를 만들고,

각 격자(tile)를 하나의 bbox로 요청하는 구조가 좋음.

  • STEP_DEG=0.02 정도면 서울이 400~500장 수준으로 쪼개짐
  • 너무 조밀(0.01)하면 요청량 폭증
  • 너무 성기면(0.03+) 도로 데이터가 뭉개짐

3) PNG에서 “유효 픽셀”만 남기기(핵심)

여성안심길은 “도로 기반 + 그라데이션(번짐) + 투명도 단계”가 많아.

그래서 단순히 alpha>0로 쓰면 번짐(halo)까지 전부 잡혀서

서울 전체가 점으로 도배되는 것처럼 보일 수 있음.

그래서 보통 아래 2단계로 컷을 한다:

3-1. alpha 컷(halo 제거)

  • 예: alpha >= 110
  • 더 심하면 130~160까지 올림

3-2. 채도 컷(옅은 색 제거, sat 모드일 때)

  • HSV로 변환해서 S(saturation)가 너무 낮은 픽셀은 제거
  • 예: sat >= 25

이 2개만 제대로 해도 “이상한 지도” 대부분 해결됨.


4) 색 강도를 “안전도 등급”으로 바꾸기

WMS PNG는 원래 숫자가 아니라 “시각화된 색”이라서

우리가 픽셀 값에서 안전도 수준을 추정해야 해.

추천 방식은 HSV의 채도(S) 기반:

  • 빨강/주황처럼 진한 영역 → 채도 높음 → 높은 등급
  • 흐릿한 영역 → 채도 낮음 → 낮은 등급

4-1. 서울 공통 thresholds 학습

타일마다 색 분포가 조금씩 달라서,

샘플 타일 몇 장에서 픽셀 metric 분포를 모아서

서울 전체 공통 경계를 만든 다음 전체에 적용하는 방식이 안정적이야.

  • 샘플 60장 정도
  • 픽셀 metric을 모은 뒤 분위수로 경계 생성
  • 여성안심길은 보통 “10등급 느낌”이어서 10레벨 추천

5) 영역을 폴리곤으로 벡터화하기

유효 픽셀 마스크를 만들었으면:

  1. morphology(열기/닫기)로 작은 구멍/끊김 보정
  2. findContours로 영역 경계 추출
  3. 경계를 단순화(approxPolyDP)
  4. 픽셀 좌표 → lon/lat로 변환해서 Polygon 생성
  5. 폴리곤 내부 metric 대표값(p80 같은 것)으로 등급 확정
  6. GeoJSON Feature로 저장

여기서 “도로 기반” 특성상 작은 찌꺼기 폴리곤이 많이 생기기 쉬우니

MIN_AREA_PX를 꽤 높게 주는 게 좋아(120~400에서 튜닝).


6) 대량 수집 안정화(중요)

타일 수집은 오래 걸릴 수 있고 중간에 끊길 수 있으니:

  • 처리한 타일 idx를 progress.json에 저장
  • 실패 타일은 fail.ndjson에 저장
  • 성공 feature는 features.ndjson에 계속 append

마지막에 ndjson을 모아서 GeoJSON으로 합치는 구조로 가면,

중간에 죽어도 이어서 돌리기 쉬움.

results matching ""

    No results matching ""