Решаем задачу поиска целевого предмета среди множества изображений по предложенному образцу. Каждая капча - это группа изображений, среди которых необходимо выбрать правильный ответ, и картинка-подсказка, в которой зашифрован ответ. На каждом из вариантов ответа изображены 3D объекты, расположенные на конвейерах в два ряда. Количество объектов вариьруется от 4 до 8 штук. Правильным ответом является изображение, на котором стрелка указывает на объект на конвейере, совпадающий с объектом, изображенным на картинке-подсказке.
В примере ниже на подсказке (изображение в нижнем ряду) изображена подставка для яйца, поэтому нужно выбрать седьмое изображение (в верхнем ряду), где стрелка указывает на тот же объект. Объекты на конвейерах расположены в случайном порядке и случайной ориентации.

Для поиска решения на входе имеем два набора.
Первый набор состоит из двух директорий: images_100 и labels_100. Всего в них находятся 100 капч с разметкой баундинг боксов для всех объектов (label=object) на изображении, включая стрелку (label=icon) и ответ (label=true_object).

Второй набор также из аналогичных двух директорий: images_train и labels_train. В них находятся 3998 капч с разметкой баундинг бокса только для ответа (label=true_object).

Разметка не имеет классификатора, т.е. все метки являются одинаковыми object без указания что это за предмет. Разметка в формате labelme.
Необходимо создать модель, которая для каждой такой капчи выбирает правильный ответ. Нужно предсказать координату точки, соответствующей ответу. Целевая метрика - точность предсказанных ответов. Точность следует считать следующим образом: если предсказанная точка лежит внутри того же патча, что и иконка на правильной орбите, то предсказание является истиной. Тогда отношение количества истинных предсказаний ко всем будет являться точностью.
Для начала разберемся с предметами, представленными на капчах. Поскольку в исходной разметке все предметы обезличены, то сперва необходимо их переразметить с классификацией, чтобы можно было обучать модель различать и искать нужные предметы.
- Из всех имеющихся изображений обоих наборов вырезаем все предметы по контуру, обозначенному в json файлах в качестве bbox разметки.
- Подаем их на отдельную утилиту, которая по структурному и цветовому хэшам ищет среди всего набора похожие между собой изображения и раскладывает их по соответсвующим папкам.
Теперь у нас есть классифицированный датасет из ~10000 картинок 15 предметов.
Для выработки пути решения отметим ключевые моменты, каждый из которых будем использовать:
- Картинка-подсказка расположена на равномерно сером тоне и сама выполнена в градациях серого.
- Картинки в зоне поиска уже цветные и расположены на неравномерном случайно-градиентном сером фоне.
- Стрелки, указывающие на варианты ответов расположены в фиксированных позициях.
- Правильные ответы локализованы в ограниченной зоне около вертикали от стрелки.
- Общий размер полотна 1600 х 400.
- Область картинки-подсказки в левом нижнем углу размерами 130 х 200.
Пайплайн решения тогда будет выглядеть так:
- Соберем и обучим первую модель YOLOv8 для распознавания предмета в зоне картинки-подсказки. Возвращать будем класс с наибольшим confidience.
- Соберем и обучим вторую модель YOLOv8 для распознавания и классификации всех предметов на полотне. Возвращать будем классы и координаты центров bbox после детекции.
- Найдем минимум евклидова расстояния между координатами центров 8 стрелок и координатами классов совпадающих с подсказкой - это и будет центр искомого предмет.
- Проверим, чтобы найденная точка находилась внутри объекта true_objects из исходной json разметки - это будет успешное предсказание. Все остальные случаи - неуспешное предсказание.
- Определим итоговую точность решения как отношение успешных предсказаний как всем попыткам. Наша цель - не менее 95%.
Сборка датасета для обучения первой модели.
- У нас есть вырезанные предметы. Для подсказки они нужны серыми - переведем их все в градации серого.
- Поскольку предметы вырезались по границам рамок из json файла, то координаты аннотаций очевидно у каждого предмета теперь будут по краям его изображения.
- Подготовим серую подложку 130 х 200 и поместим на ней в случайном месте предмет.
- Зная размер исходной картинки, размер подложки и величину смещения картинки на полотне, переопределяем координаты bbox в аннотациях.
- Сделаем сплитование 80/20 по каждому классу и получаем итоговый общий датасет.
Сборка датасета для обучения второй модели.
- Создадим подложку 1600 х 400 и заполним ее для каждого вызова случайным перлинским шумом, имитирующим фон для зоны поиска.
- В предложенных наборах мы видим примерно по 40-50 предметов на каждом исследуемом изображении, которые занимают верхнюю его половину. Будем заполнять учебную подложку полностью, поэтому будет 80-100 случайных предметов, раскиданных с зазорами между собой по полотну.
- Аналогично прошлого шага фиксируем координаты bbox каждого предмета со своим классом в аннотациях.
- Сделаем сплитование 80/20 по каждому классу и получаем итоговый общий датасет.
Тестирование и проверка точности.

Виды ошибок, которые могут быть допущены на этапе предсказания и засчитываются в сумму неуспешных предсказаний.
- Неверно определен предмет в подсказке.
- Не обнаружен никакой предмет в подсказке (no detection).
- Неверно определен предмет в зоне поиска на месте истинного ответа.
- Неверно определены оба предмета.
- Неверно записаны координаты истинного ответа true_objects в json файле:
- Координаты выходят за пределы зоны поиска - этот случай принудительно исключаю из рассмотрения и переходим к следующему входному изображению.
- Координаты правого нижнего угла меньше координат левого верхнего угла - этот случай принудительно исключаю из рассмотрения и переходим к следующему входному изображению.
- Расхождение графической метки с числовыми координатами, не попавшее в два предыдущих случая, выявить нельзя, поэтому принимаю такой случай как истинную ошибку.
- При детекции второй моделью bbox определен по правильному предмету, но не соответствует его реальным границам - возможен выход предсказанного центра за пределы целевого bbox из true_objects в json файле.
Поскольку в процессе обучения не использовались предоставленные наборы данных в исходном виде, а были сформированы полностью свои датасеты, то для тестов допустимо использовать все исходные наборы images_100 + labels_100 (100 пар) и images_train + labels_train (3998 пар) в полном объеме.
Итоговые результаты выборочных тестов на 400 картинках: Total: 400, Correct: 370, Errors: 30 (hint not detected: 2), Accuracy: 92.50%








