Unity/Barracuda & Sentis

[Unity Sentis] ObjectDetection (Yolo v7 tiny) Bounding Box 구현의 이해

pnltoen 2024. 6. 8.
반응형

서론

Uday 2024 발표에 참여하느라 글 작성이 늦게 되었습니다.

 

이전 글 [Unity Sentis] ObjectDetection Yolo v7 (tiny) 모델 분석하기에서 기본적인 Sentis 사용법과 어떻게 output이 출력되는지 확인하였습니다.

 

[Unity Sentis] ObjectDetection (Yolo v7 tiny) 모델 분석하기 - Onnx excute

Sentis yolo v7 tiny Unity Technologies 서론 이전 포스팅인 Object Detection 모델 (Yolo v7 tiny) 실행하기에서 Yolo v7 Tiny 모델을 실행하여, 미리 준비한 동영상을 실행할 수 있는 것을 확인하였습니다. [Unity Sentis]

pnltoen.tistory.com

 

(n,7)의 출력을 확인하였으니 이번에는 Bounding Box를 그리는 부분과 관련하여, 조금 더 상세하게 알아보고자합니다.

 

Onnx Export 부분

이와 관련해서 설명하기 전에 onnx export를 확인해야 합니다. (참고 : skykim/torch-to-onnx-zoo)

 

GitHub - skykim/torch-to-onnx-zoo: Examples of converting PyTorch models to ONNX

Examples of converting PyTorch models to ONNX. Contribute to skykim/torch-to-onnx-zoo development by creating an account on GitHub.

github.com

 

 

 

Onnx Inference 부분을 보면 x0, y0, x1, y1으로 되어 있는 것을 확인할 수 있습니다. 기본 Yolo style의 x,y,w,h가 아님으로 이 부분을 유의해주시길 바랍니다.

 

How to convert bounding box (x1, y1, x2, y2) to YOLO Style (X, Y, W, H)

I'm training a YOLO model, I have the bounding boxes in this format:- x1, y1, x2, y2 => ex (100, 100, 200, 200) I need to convert it to YOLO format to be something like:- X, Y, W, H => 0.436...

stackoverflow.com

 

OpenCV의 경우 cv.rectangle과 cv2.putText가 있지만, 유니티는 OpenCV2에 있는 함수가 있지 않고 플러그인을 사용할 경우, 성능에 좋지 않기 때문에 직접 box를 그려줘야합니다. 

 

Bounding Box 그리기

Hugging Face 모델에서는 하나의 sprite를 선택해주면 해당 스프라이트를 아래의 과정을 통해 그려주고 있습니다.

박스를 그리기에 앞서 다시 한번 output 값들을 살펴보도록 하겠습니다.

 

 

  • Bounding Box의 중심점 계산 (X,Y)
  • 이 후 가로 및 세로 비율 계산 후 곱셈
  • label의 경우 기존 labels를 split 후 label 번호에 맞는 문자열 추출

 

코드는 아래에서 확인할 수 있습니다.

 

            var box = new BoundingBox
            {
                centerX = ((output[n, 1] + output[n, 3])*scaleX - displayWidth) / 2,
                centerY = ((output[n, 2] + output[n, 4])*scaleY - displayHeight) / 2,
                width = (output[n, 3] - output[n, 1])*scaleX,
                height = (output[n, 4] - output[n, 2])*scaleY,
                label = labels[(int)output[n, 5]],
                confidence = Mathf.FloorToInt(output[n, 6] * 100 + 0.5f)
            };
            DrawBox(box, n);

 

이 후 기존에 선언한 struch BoundingBox에 해당 값을 입력합니다.

 

BoxPool의 이해

메모리적 관점에서 보았을 때 유니티에서 매 프레임별 오브젝트를 생성하고 destory하는 것 보다 SetActive를 통해 활성화 후 초기화를 하는 방식을 사용하는 것이 좋습니다. 따라서 코드를 살펴보면, box마다 id를 할당해주고 각 id가 이전에 없었던 (지금까지의 최대 박스 개수보다 많아졌을 경우)에는 새로운 박스를 그리고 그렇지 않을 경우 새로운 속성을 부여합니다.

 

        GameObject panel;
        if (id < boxPool.Count)
        {
            panel = boxPool[id];
            panel.SetActive(true);
        }
        else
        {
            panel = CreateNewBox(Color.yellow);
        }
        panel.transform.localPosition = new Vector3(box.centerX, -box.centerY);

        RectTransform rt = panel.GetComponent<RectTransform>();
        rt.sizeDelta = new Vector2(box.width, box.height);
        
        var label = panel.GetComponentInChildren<Text>();
        label.text = box.label + " (" + box.confidence + "%)";

 

좌표 축 Translation

 

간혹 input이미지는 640x640이기 때문에 다른 해상도에서는 사용할 수 없는 것 아닌가? 하는 질문이 있을 수 있습니다.

하지만 이는 결과적으로 해상도에 따른 scale 값을 곱해주기 때문에 상쇄할 수 있습니다.

 

예로 center X의 코드는 다음과 같이 작성되어 있습니다.

 

centerX = ((output[n, 1] + output[n, 3]) // 640x640 기준 centerX 위치
centerX = ((output[n, 1] + output[n, 3])*scaleX) // 해상도에 따른 보정
centerX = ((output[n, 1] + output[n, 3])*scaleX - displayWidth) / 2 // 좌표계 이동

 

처음 output[n, 1] + output[n,3]은 쉽게 이해가 가능할 것으로 생각됩니다.

여기서, scaleX 값만 곱해서 박스를 그려보면 실제 화면에는 아무것도 나타나지 않습니다. 이는 유니티의 UI 밖에 그려지기 때문에 overlay 방식에서 UI Canvas 밖의 부분은 렌더링하지 않기 때문입니다.

 

예로 사진으로 표현하면 다음과 같습니다.

 

 

기본적으로 Onnx Inference시 사용했던 openCV의 경우 좌표축을 고려할 필요 없이 함수로 실행이 되지만 output 값을 놓고 본다면, Yolo와 openCV에서 그리는 방식은 x 값의 범위가 [0, Width]임을 고려해야합니다.

 

하지만 유니티의 경우 [-Width, Width] 즉 FullHD를 기준으로 했을 때 [0, 1920]이 아닌 [-960, 960]입니다. 따라서 displayWidth를 고려하고 이를 2로 나눠서 translation 해줘야합니다.

 

 

결론

Unity Sentis에서 어떻게 output이 출력되고 어떠한 방식으로 box를 그리는지, 이 때 무엇을 고려해야하는지에 대해 알아보았습니다. 실제 위와같이 진행해보면 간헐적으로 1명의 사람이 여러 박스로 인식되는 것을 확인할 수 있습니다. 위와 관련해서 어떻게 수정할 수 있는지 IOU (Intersection with Union)과 Custom Layer를 추 후 포스팅에서 알아보도록 하겠습니다.

반응형

댓글