Skip to content

Latest commit

 

History

History
132 lines (94 loc) · 4.17 KB

File metadata and controls

132 lines (94 loc) · 4.17 KB

캡처 루프에 엔진 붙이기

엔진은 카메라도 화면도 모릅니다. 프레임 버퍼를 받아 결과 구조체를 돌려줄 뿐입니다. 호스트 애플리케이션이 그 사이를 연결합니다.


최소 통합

#include "defect_engine.h"

/* 1. 시작할 때 한 번 */
SemDefectConfig config;
sem_defect_default_config(&config);
config.fail_ratio_percent = 15.0f;   /* 필요하면 조정 */

if (sem_defect_init("/path/to/model.tflite", &config) != 0) {
    return -1;
}

/* 2. 프레임마다 */
int defect_pixels = sem_defect_run(frame_rgb, frame_width, frame_height);

if (defect_pixels < 0) {
    fprintf(stderr, "inference failed\n");
}

/* 3. 결과가 필요한 곳에서 (다른 스레드여도 됨) */
SemDefectResult result;
if (sem_defect_get_latest_result(&result) == 0) {
    draw_verdict(result.is_fail ? "FAIL" : "PASS");
    draw_class(result.predicted_class,
               result.class_probabilities[result.predicted_class - 1]);
}

/* 4. 종료할 때 */
sem_defect_destroy();

프레임 버퍼 형식

sem_defect_run()interleaved RGB8 을 받습니다.

byte 0   1   2   3   4   5   ...
     R0  G0  B0  R1  G1  B1  ...

카메라가 다른 형식을 내보내면 호출 전에 변환해야 합니다.

planar RGB인 경우

일부 캡처 드라이버는 planar(RRR...GGG...BBB...)로 내보냅니다. 프레임마다 변환이 들어가므로 SIMD를 쓰는 편이 좋습니다.

/* 채널별 시작 주소 */
const uint8_t *r = buffer;
const uint8_t *g = buffer + (width * height);
const uint8_t *b = buffer + (width * height * 2);

rgb_planar_to_interleaved(r, g, b, interleaved, width, height);
sem_defect_run(interleaved, width, height);

BGR인 경우

cv::cvtColor(..., cv::COLOR_BGR2RGB) 로 변환하거나, 엔진의 cv::COLOR_RGB2GRAYCOLOR_BGR2GRAY 로 바꿉니다. 그레이스케일 변환 계수가 채널마다 다르므로(R 0.299 / G 0.587 / B 0.114) RGB와 BGR을 섞으면 결과가 달라집니다.


버퍼 수명

엔진은 프레임 버퍼를 복사하지 않고 cv::Mat 으로 감쌉니다. 대신 sem_defect_run() 이 반환한 뒤에는 그 버퍼를 참조하지 않으므로, 호출 직후 캡처 버퍼를 반납해도 안전합니다.

/* V4L2 예시 */
dequeue_buffer(fd, &buf);

sem_defect_run(buffers[buf.index].start, width, height);

queue_buffer(fd, buf.index);   /* 추론 후 즉시 반납 */

스레드 분리

현재 sem_defect_run() 은 동기 호출이라 호출한 스레드를 막습니다. 표시 루프에서 직접 부르면 추론 지연시간이 프레임레이트 상한이 됩니다.

권장 구조:

[캡처 스레드] --frame--> [추론 스레드] --result--> [표시 루프]
                                          (최신 값만 읽음)

표시 루프는 매 프레임 sem_defect_get_latest_result() 를 호출해 가장 최근에 완료된 결과를 그립니다. 추론이 표시보다 느려도 화면은 계속 갱신됩니다.

주의. get_latest_result() 는 구조체를 복사해 넘기지만, 현재 구현에는 결과를 보호하는 뮤텍스가 없습니다. 위 구조로 갈 때 엔진 내부에 락을 추가해야 합니다. SemDefectResult 는 POD이므로 뮤텍스 보유 구간은 memcpy 한 번으로 짧게 유지할 수 있습니다.


결과 해석

필드 의미
predicted_class 1 ~ 6. 데이터셋 라벨과 맞추기 위해 1부터 시작
class_probabilities[] 확률. 모델 내부에서 softmax가 적용된 값
probability_sum 위 값들의 합. 정상이면 ~1.0
defect_pixels 임계값을 넘은 픽셀 수 (최대 470×470 = 220,900)
defect_ratio 결함 면적 퍼센트. 0.0 ~ 100.0
is_fail defect_ratio >= fail_ratio_percent
latency_ms Invoke() 만 측정. 전처리/후처리 제외

class_probabilities 에 softmax를 다시 적용하지 마세요. 모델 그래프가 이미 softmax를 포함하고 있어 두 번 적용하면 분포가 평탄해집니다. 확인 방법은 design-notes.md 를 참고하세요.