Несмотря на то, что существует множество статей, объясняющих, как развернуть модель YOLOv5, в большинстве из них не выполняется предварительная обработка (изменение размера и дополнение) изображений должным образом. Хотя YOLO предоставляет пример сценария для развертывания, если вам просто нужна чистая минимальная реализация, которая работает с OpenCV, вам придется копаться в коде, чтобы получить то, что вам нужно.

К счастью, я уже сделал это за вас, и весь код, который вам нужен, будет в этой статье.

Примечание. Хотя ваша модель может работать достаточно хорошо даже с неправильной предварительной обработкой, если вы хотите добиться той же точности тестирования/проверки, которую вы получили во время обучения, вы должны подготовить изображения точно так, как ожидает модель.

Распространенные ошибки

1. Прямое изменение размера

Из того, что я видел, многие люди просто напрямую изменяют размер изображения до формы, на которой была обучена модель. Если ваши изображения не имеют соотношение сторон 1:1 ( ширина = высота ), это означает, что вы либо сожмете, либо растянете изображение в одном из направлений, что приведет к недоступности функций, которые, скорее всего, повредят. производительность.

2. Асимметричное заполнение

Еще одна распространенная ошибка — заполнение только одной стороны изображения. Хотя это не тормозит никаких геометрических функций, оно по-прежнему будет создавать изображения, на которых ваша модель не обучалась. По моему опыту, это обычно влияет на меньшие модели YOLOv5.

Решение

Основная идея заключается в том, что мы хотим изменить размер изображения, не нарушая его исходное соотношение сторон, а затем симметрично заполнить меньший размер с обеих сторон.

Ниже вы можете найти код OpenCV для этого:

Шаг 1 Прочитайте изображение

img = cv2.imread("cat.jpg")

Шаг 2 (применяется только в том случае, если вы тренировались на изображениях в градациях серого)

# Convert image to grayscale
im = cv2.cvtColor(im0, cv2.COLOR_BGR2GRAY)
# Stack 3 copies of the same channels to create 3 channels
im = cv2.merge((im,im,im))

Шаг 3. Измените размер, сохранив соотношение сторон.

shape = im.shape[:2]  # current shape [height, width]
new_shape = (640, 640) # the shape the model was trained with

# Scale ratio (new / old). 
# We take the min to maintain aspect ratio.
# The smaller side will be padded later
r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])

ratio = r, r  # width, height ratios
new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r))

# Resize the image
im = cv2.resize(im, new_unpad, interpolation=cv2.INTER_LINEAR)

Шаг 4. Пэд

# color used for padding
color = (114, 114, 114) 
dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1]  # wh padding

# divide padding into 2 sides
dw /= 2  
dh /= 2

 # compute padding on all corners
top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1))
left, right = int(round(dw - 0.1)), int(round(dw + 0.1))
im = cv2.copyMakeBorder(im, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color)  # add border

Если вам интересно, почему мы сначала не дополняем, а затем не изменяем размер, ответ прост: быстрее дополнить меньшее изображение, чем большее.

Вот и все... Если эта короткая статья оказалась вам полезной, вы можете подписаться на меня для получения аналогичного контента.