현행 자산(C#·Delphi 현장 프로그램, Java·PHP 서버)을 존속시키면서, 엣지 AI 표준화 → 클라우드 플랫폼화 → 지능화로 점진적 전환 아키텍처
현장은 망 단절시 자율 동작하고, 클라우드는 멀티사이트 통합관제와 데이터 사업 담당
루프/영상 트리거·주야간 IR·번호판 검출+인식 온디바이스 처리
1대 = 6면 검지·주차면별 차량번호 인식·연기·불꽃(전기차 화재) AI 감지
불법주정차·차량탑재형 이동단속·탄력요금 근거 데이터 수집
Jetson/NPU·ONNX (Open Neural Network Exchange) Runtime / TensorRT·저조도·역광 보정·이벤트+썸네일만 상행(대역폭 최소화)
C# WPF·Delphi 자산 유지·차단기/전광판/정산기 I/O(RS-485·시리얼)·Local DB·요금정책 캐시
배리어프리 UX·사전정산·카드/간편결제·감면(경형·저공해·장애인) 자동 적용
레거시(C#·Delphi) ↔ 신규 AI 모듈을 gRPC/REST 어댑터로 연결 — 전면 재개발 없이 AI 탑재
인증·과금·버전 관리·사이트별 테넌시
입·출차 / 정산 / 멤버십(정기권) / 디바이스·OTA — Java·PHP 자산 점진 전환
MariaDB(운영)·TimescaleDB(시계열 점유율)·Redis(실시간 상태)·S3/MinIO(영상·증적)
Kafka 파티션=현장ID(순서보장)·실시간 점유율 집계·이상탐지 파이프라인
멀티사이트 대시보드·인식률 KPI·원격 장애 대응(24h 관제센터)
내 차 찾기·사전정산·잔여면 안내·전기차 충전 연동
노상주차 데이터 연계·탄력요금·단속 증적 제공
위 계층구조를 물리(HW)·논리(SW) 관점으로 도식화한 상세 아키텍처 (이미지 클릭하면 원본 크기로 확대)
버튼을 누르면 가상 차량이 게이트에 진입하고, 검출 → 전처리(Otsu 이진화) → 문자분할(투영 프로파일) → 인식(정규화 템플릿 매칭)
전체 단계를 브라우저에서 실제 연산
양산제품은 검출·인식을 딥러닝(YOLO + CRNN)으로 대체, 파프라인 구조
아래의 입차 시뮬레이션을 Click 하세요.
검출박스는 시뮬레이션, 양산은 YOLO 계열 검출기 사용, 이후 단계는 실제 픽셀 연산
임계값 자동 산출 대기중…
분할 대기중…
숫자 슬롯은 0–9, 한글 슬롯은 용도문자 집합으로 탐색 공간을 제한(번호판 문법 사전지식) — 실제 LPR에서도 쓰는 후처리 기법
| 시각 | 구분 | 게이트 | 차량번호 | 신뢰도 | 차종/등록 | 처리 | 요금 |
|---|
현장 LPR 정확도는 촬영 조건에 좌우 아래 파라미터로 노이즈·번호판 기울기·오염·저조도를 주입해 인식이 어디서 무너지는지 직접 확인하세요. 값을 바꾼 뒤 재인식을 누르면 위 파이프라인이 그 조건으로 다시 동작
양산 대응: 적외선(IR) 조명·HDR 센서·다중 프레임 융합·검출단 데이터 증강(augmentation) 재학습으로 이 구간 방어
(중요) 정확도 + 지연시간·처리량 SLA 현재 조건으로 배치를 돌려 p50/p95 지연·초당 처리량·정인식률과 단계별 시간분해 측정
단계별 비중을 보면 최적화 우선순위(예: 분할·인식) 확인 — 프로파일링 기반 개발관리의 축소판
구조 이해를 위해서 Traditional Computer Vision으로 구현
양산 넥스파 제품수준은 딥러닝 검출·인식으로 대체되며, 관리해야 할 지점이 달라짐.
초음파·지자기 센서와 달리 영상방식은 주차면별 차량번호까지 인식하므로 내 차 찾기·영상보안·데이터 사업으로 확장 카메라 아이콘(📷)에 마우스를 올리면 전방위 카메라 1대가 검지하는 6면 표시
전방위 카메라 8대 = 48면 검지(1:6)·면별 상태는 카메라 영상분석 결과를 시뮬레이션한 값
단순 모니터링을 넘어 예측(만차·수요)·예방(화재·위반)·자동화(OTA·원격조치)로 운영비를 낮추는 관제 화면 컨셉 이벤트는 시뮬레이션 데이터
현장 프로그램은 C#·Delphi, 서버·웹은 Java·PHP 계열로 파악. 어댑터 기반 공존 전략으로 리스크없이 AI를 제품화하는 방향 제안
| 영역 | 현행 | (신규·전환) | 전환 전략 |
|---|---|---|---|
| 영상·인식 엔진 | C/C++ 계열 영상분석 엔진 | ONNX Runtime/TensorRT 표준 추론 + 딥러닝(YOLO·CRNN) | 기존 엔진에 추론 모듈 링크(라이브러리 단위 교체) |
| 현장 관제·정산 UI | C# WinForms/WPF·Delphi | 존속 + Edge Adapter(gRPC/REST)로 AI 이벤트 수신 | 재개발 없이 AI 기능만 증분 탑재 |
| 중앙 서버·웹 | Java·PHP | Spring Boot MSA + React 관제·PHP는 유지보수 모드 | 스트랭글러 패턴(신규 기능부터 MSA로) |
| AI 학습·배포 | – | Python(PyTorch) → ONNX → OTA·MLOps 파이프라인 | 인식률 KPI 대시보드와 함께 도입 |
| 데이터 | 현장별 로컬 DB | MariaDB + TimescaleDB + Redis·표준 스키마/사전 | DA 표준화(용어·코드) 선행 후 통합 |
아래 코드는 아키텍처의 핵심 연동 지점을 보여주는 골격 코드. 사내 환경 확인 후 세부 파라미터는 조정 필요
# 1) 검출기: 현장 수집 데이터(주·야간/역광/오염 포함) 파인튜닝
from ultralytics import YOLO
import torch, torch.nn as nn
det = YOLO("yolov8n.pt")
det.train(data="plate_det.yaml", epochs=120, imgsz=960, batch=32,
hsv_v=0.5, degrees=4.0, mosaic=0.6, project="runs/plate")
det.export(format="onnx", opset=17, half=True, dynamic=True) # → Edge 배포
# 2) 인식기: CTC 기반 CRNN (숫자 10 + 한글 용도문자 클래스)
class CRNN(nn.Module):
def __init__(self, ncls=45): # 44 + CTC blank
super().__init__()
self.cnn = nn.Sequential(
nn.Conv2d(1,64,3,1,1), nn.BatchNorm2d(64), nn.ReLU(), nn.MaxPool2d(2,2),
nn.Conv2d(64,128,3,1,1),nn.BatchNorm2d(128), nn.ReLU(), nn.MaxPool2d((2,1),(2,1)),
nn.Conv2d(128,256,3,1,1),nn.BatchNorm2d(256),nn.ReLU())
self.rnn = nn.LSTM(256*8, 256, 2, bidirectional=True, batch_first=True)
self.fc = nn.Linear(512, ncls)
def forward(self, x): # x: (B,1,32,W)
f = self.cnn(x); B,C,H,W = f.shape
f = f.permute(0,3,1,2).reshape(B,W,C*H) # 시퀀스화
y,_ = self.rnn(f)
return self.fc(y) # (B,T,ncls) → CTCLoss
model = CRNN()
# ... DataLoader / CTCLoss 학습 루프 수행 후:
torch.onnx.export(model, torch.randn(1,1,32,160), "lpr_rec.onnx",
opset_version=17, input_names=["input"], output_names=["logits"],
dynamic_axes={"input": {0:"batch", 3:"width"}})
// Jetson/x86 공용. CUDA 가용 시 EP 추가로 GPU 가속.
#include <onnxruntime_cxx_api.h>
#include <opencv2/opencv.hpp>
#include <memory>
#include <string>
class LprEngine {
public:
LprEngine(const std::string& det_path, const std::string& rec_path)
: env_(ORT_LOGGING_LEVEL_WARNING, "lpr") {
Ort::SessionOptions so;
so.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_ALL);
// OrtSessionOptionsAppendExecutionProvider_CUDA(so, 0); // GPU 사용 시
det_ = std::make_unique<Ort::Session>(env_, det_path.c_str(), so);
rec_ = std::make_unique<Ort::Session>(env_, rec_path.c_str(), so);
}
// 반환: {번호판 문자열, 신뢰도}. 미검출 시 {"", 0}
std::pair<std::string, float> Recognize(const cv::Mat& bgr) {
cv::Mat blob = Letterbox(bgr, 960); // 종횡비 보존 리사이즈
auto boxes = RunDetect(blob); // NMS 포함
if (boxes.empty()) return {"", 0.f};
cv::Mat plate = WarpCrop(bgr, boxes[0]); // 4점 원근보정 → 32xW
return RunRecognize(plate); // CTC greedy decode + 문법 검증
}
private:
Ort::Env env_;
std::unique_ptr<Ort::Session> det_, rec_;
// Letterbox / RunDetect / WarpCrop / RunRecognize 구현부:
// - NHWC→NCHW 변환, 정규화, IoU-NMS, softmax, ^\d{2,3}[가-힣]\d{4}$ 검증
};
// 인식 성공 → gRPC로 현장서버(C#) 통지 → 차단기 OPEN (아래 C# 모듈과 연동)
using Grpc.Net.Client;
using Nexpa.Edge.V1; // lpr_events.proto 생성 코드
public sealed class EdgeEventListener : BackgroundService
{
private readonly ILogger<EdgeEventListener> _log;
private readonly GateController _gate; // 기존 차단기 제어(시리얼/RS-485) 래퍼 — Delphi 모듈도 동일 패턴
private readonly IUplinkQueue _cloudQ; // 클라우드 업링크 버퍼(망 단절 시 재전송)
public EdgeEventListener(ILogger<EdgeEventListener> log, GateController gate, IUplinkQueue q)
=> (_log, _gate, _cloudQ) = (log, gate, q);
protected override async Task ExecuteAsync(CancellationToken ct)
{
using var ch = GrpcChannel.ForAddress("https://edge-01.local:7443");
var client = new LprService.LprServiceClient(ch);
using var st = client.Subscribe(new SubscribeRequest { Gate = "IN-01" }, cancellationToken: ct);
await foreach (var ev in st.ResponseStream.ReadAllAsync(ct))
{
_log.LogInformation("LPR {Plate} conf={Conf:P1}", ev.Plate, ev.Confidence);
if (ev.Confidence >= 0.90 && !await IsBlacklistedAsync(ev.Plate, ct))
await _gate.OpenAsync(ev.Gate, ct); // 차단기 개방
else
await _gate.HoldForManualAsync(ev.Gate, ct); // 저신뢰 → 수동확인 전환
await _cloudQ.EnqueueAsync(ev, ct); // MQTT/Kafka 상행(비동기)
}
}
private Task<bool> IsBlacklistedAsync(string plate, CancellationToken ct)
=> Task.FromResult(false); // Local DB 조회 — 오프라인에서도 판정 가능
}
@RestController
@RequestMapping("/api/v1/events")
@RequiredArgsConstructor
public class ParkingEventController {
private final KafkaTemplate<String, ParkingEvent> kafka;
private final SiteAuthService auth; // 현장 단말 mTLS/토큰 검증
@PostMapping("/lpr")
public ResponseEntity<Void> ingest(@RequestHeader("X-Site-Token") String token,
@Valid @RequestBody ParkingEvent ev) {
auth.verify(token, ev.siteId());
kafka.send("parking.lpr", ev.siteId(), ev); // 파티션 키 = 현장ID (순서 보장)
return ResponseEntity.accepted().build();
}
@KafkaListener(topics = "parking.lpr", groupId = "occupancy-svc")
void onEvent(ParkingEvent ev) {
// 점유율 집계(TimescaleDB) → WebSocket 브로드캐스트 → 만차예측 피처 적재
}
}
record ParkingEvent(@NotBlank String siteId,
@NotBlank String gate,
@Pattern(regexp = "^\\d{2,3}[가-힣]\\d{4}$") String plate,
double confidence,
Instant occurredAt,
String direction) {}
유행 기술의 나열이 아니라, 각 기술이 하나의 경영지표
허브로서 온톨로지 — MLOps 학습 데이터, 디지털트윈 입력, 멀티사이트 통합관제가 모두 동일한 개념 모델을 참조해야 각 기술이 연관성 갖음
테넌트 모듈화로 신규 지자체·사업자 수주 시 인프라 복제. 변수만 교체.
폐쇄망 대응 ansible-pull, Windows 관제 PC는 WinRM. 현장 오픈 2주 → 2일.
FIWARE / NGSI-LD 기반 공통 모델. 사이트·벤더별 용어 차이를 흡수.
저신뢰 샘플 능동수집 → 재학습 → 카나리 OTA. 인식률을 관리 지표로 전환.
SUMO 기반 대기행렬 시뮬레이션으로 설비 대수를 정량 근거로 제안.
Edge · IaC · Platform · Ontology · MLOps · Digital Twin · Service · 레거시 공존 8개 계층의 데이터 흐름
수동확인 전환율을 원가로 환산해 보고하면, 연구개발이 비용센터가 아니라 이익기여로 인식. 1%p 감소가 곧 관제 인력공수 절감
킬러 시나리오: EV 화재 대피 시뮬레이션 — 넥스파 전방위 카메라 화재감지와 직결. 발화 지점별 연기 확산·대피 동선·유도등 제어를 사전 검증해 공공·대형건물 수주 신뢰도 확보
시뮬레이션은 초기 내재화 부담이 커 교통공학 연구실 협업 후 단계적 흡수 권장