축구 영상 분석을 위한 팀 및 심판 인원 분류 기술

1. 문제 정의 및 목표 설정

경기장 내 등장하는 인원은 주로 두 팀(파란색, 하얀색)과 심판으로 구성되며, 이 중 골키퍼는 제외하고 분류 대상으로 삼는다. 본 작업의 목적은 영상에서 각 인물을 정확히 식별하여 2차원 시각화 패널에 표시하는 것이다.

  • 분류 대상:
    • 파란 팀 선수
    • 하얀 팀 선수
    • 심판

2. 학습 방식 선택 및 구현 전략

2.1 Keras 기반 딥러닝 모델 설계

이전 단계에서 수집한 이미지 데이터를 바탕으로 자체 설계된 신경망을 학습시키는 방법을 우선적으로 적용한다.

2.1.1 환경 및 라이브러리 준비

pip install tensorflow==2.0
pip install opencv-python numpy scikit-learn matplotlib
pip install keras h5py onnx

2.1.2 데이터 로드 및 전처리

각 클래스별 이미지를 불러와 정규화하고, 레이블을 원-핫 인코딩 형태로 변환한다.

BLUE, WHITE, REFEREE = 0, 1, 2

def load_dataset():
    data, labels = [], []
    for path, label in [
        ("./blue/*.jpg", BLUE),
        ("./white/*.jpg", WHITE),
        ("./referee/*.jpg", REFEREE)
    ]:
        files = glob.glob(path)
        for f in files:
            img = cv2.imread(f)
            img = cv2.resize(img, (80, 80))
            data.append(img)
            lbl = np.zeros(3)
            lbl[label] = 1
            labels.append(lbl)
    return np.array(data), np.array(labels)

2.1.3 모델 아키텍처 설계

간단한 인셉션 모듈을 사용해 복합적인 특징 추출 능력을 갖춘 네트워크를 구현한다.

def create_inception_block(x, filters):
    conv1x1 = layers.Conv2D(filters[0], (1,1), activation='relu', padding='same')(x)
    conv3x3 = layers.Conv2D(filters[1], (3,3), activation='relu', padding='same')(x)
    conv5x5 = layers.Conv2D(filters[2], (5,5), activation='relu', padding='same')(x)
    pool = layers.MaxPooling2D((3,3), strides=(1,1), padding='same')(x)
    return layers.Concatenate(axis=-1)([conv1x1, conv3x3, conv5x5, pool])

input_layer = layers.Input(shape=(80, 80, 3))

layer = layers.Conv2D(20, 5, padding='same', activation='relu')(input_layer)
layer = create_inception_block(layer, [2, 4, 6])
layer = create_inception_block(layer, [4, 8, 12])

layer = layers.MaxPooling2D(pool_size=(2,2))(layer)
layer = layers.Flatten()(layer)

layer = layers.Dense(256, kernel_initializer='he_normal', kernel_regularizer=regularizers.l1(0.01))(layer)
layer = layers.ReLU()(layer)
layer = layers.Dropout(0.5)(layer)

output = layers.Dense(3, activation='softmax')(layer)

model = models.Model(input_layer, output)

2.1.4 학습 및 평가

이미지 증강을 통해 일반화 성능을 향상시키고, 검증 세트를 활용해 학습 진행 상황을 시각화한다.

datagen = ImageDataGenerator(
    rotation_range=30,
    width_shift_range=0.2,
    height_shift_range=0.2,
    zoom_range=0.2,
    fill_mode='nearest'
)

model.compile(optimizer='adam',
              loss='categorical_crossentropy',
              metrics=['accuracy'])

history = model.fit(
    datagen.flow(X_train, Y_train, batch_size=128),
    validation_data=(X_val, Y_val),
    epochs=50,
    steps_per_epoch=len(Y_train)//128
)

2.1.5 모델 저장

학습 완료 후 모델 구조와 가중치를 파일로 저장한다.

model.save_weights("classifier.h5")
model_json = model.to_json()
with open("classifier.json", "w") as f:
    f.write(model_json)

2.2 H5 모델 ONNX 형식 변환

Keras 모델을 ONNX 포맷으로 변환하여 다양한 플랫폼에서 추론 가능하게 한다.

import tf2onnx
import tensorflow as tf

model = tf.keras.models.load_model("classifier.h5")
model.save("temp_model")

# ONNX 변환
tf2onnx.convert.from_keras(model, output_path="classifier.onnx")

3. YOLOv7 기반 모델 학습 준비

더 정교한 객체 감지 성능을 위해 YOLOv7를 활용한 분류 모델도 병행 개발한다.

3.1 설정 파일 수정

  • predefined_classes.txt: BLUE, WHITE, REFEREE
  • coco.yaml: nc: 3, names: ['BLUE', 'WHITE', 'REFEREE']
  • yolov7.yaml: nc: 3

3.2 데이터 레이블링 지침

모든 프레임에서 출현하는 선수와 심판을 포함해 정확하게 박스를 그려야 하며, 일부 생략 시 성능 저하 발생 가능.

4. 실시간 시스템 통합

4.1 추론 인터페이스 정의

public interface IClassifier
{
    bool UseOnnx { get; set; }

    void LoadModel();

    NDarray Predict(NDarray? inputs);
}

4.2 ONNX 기반 추론 구현

public class OnnxClassifier : IClassifier
{
    private InferenceSession session;

    public bool UseOnnx { get; set; } = true;

    public void LoadModel()
    {
        session = new InferenceSession(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets/classifier.onnx"));
    }

    public NDarray Predict(NDarray? inputs)
    {
        var inputTensor = inputs?.ToDenseTensor();
        var input = NamedOnnxValue.CreateFromTensor<float>("input_11", inputTensor);
        var results = session.Run(new List<NamedOnnxValue> { input });
        var output = results.Last().AsEnumerable<float>().ToArray();
        var resultArray = np.array(output).reshape(inputs!.shape.Dimensions[0], 3);
        return np.argmax(resultArray, axis: 1);
    }
}

4.3 전체 워크플로우 예시

먼저 경기자 위치를 감지한 다음, 감지된 영역을 자르고 분류 모델에 전달한다.

[Fact]
public void TestPlayerClassification()
{
    var detector = new YoloDetector();
    var classifier = new OnnxClassifier();

    using var frame = LoadImage("field_2.jpg");
    var predictions = detector.Detect(frame);

    NDarray rois = null;
    foreach (var pred in predictions)
    {
        var roi = frame.GetSubRect(pred.BoundingBox).Resize(80, 80);
        var ndarray = roi.ToNDarray();
        rois = rois == null ? ndarray : np.concatenate(rois, ndarray);
    }

    var labels = classifier.Predict(rois);
    Assert.True(labels.item<int>(0) >= 0);
}

태그: YOLOv7 keras onnx object classification Computer Vision

6월 27일 17:37에 게시됨