Задать вопрос
@helyp

Как найти паттерн на картинке с OpenCV?

У меня есть этикетки, мне нужно найти найти их с помощью OpenCV , в прил.1. сама этикетка, в прил.2. изображение на котором нужно ее найти, в прил.3. что находит программа.
Программа показывает на неизвестно что, но это наиболее хороший результат по сравнению с cv2.TM_CCORR и cv2.TM_CCOEFF

import cv2
import numpy as np
# Load the original image, template image, and convert to grayscale
original_image = cv2.imread("pics/outputImage.jpg",cv2.IMREAD_GRAYSCALE)
template_image = cv2.imread("pics/LED.jpg",cv2.IMREAD_GRAYSCALE)
# Perform template matching using cv2.TM_SQDIFF
result = cv2.matchTemplate(original_image, template_image, cv2.TM_SQDIFF)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
top_left = min_loc
bottom_right = (top_left[0] + template_image.shape[1], top_left[1] + template_image.shape[0])
# Create a copy of the original image for visualization
matched_image = original_image.copy()
cv2.rectangle(matched_image, top_left, bottom_right, (0, 255, 0), 2)
# Display the images
cv2.imshow('pics/Original Image', original_image)
cv2.imshow('pics/Template Image', template_image)
cv2.imshow('pics/Matched Image (TM_SQDIFF)', matched_image)
cv2.waitKey(0)
cv2.destroyAllWindows()


прил.1.
673e2a8b291d4918365566.jpeg
прил.2.
673e2af3c89e6958311093.jpeg
прил.3.
673e2ffd91fb3391454582.png
  • Вопрос задан
  • 95 просмотров
Подписаться 1 Средний Комментировать
Решения вопроса 1
@dim5x
ЗИ, ИБ. Помогли? Поблагодарите. Отметьте ответом.
673e7b80e4dfd963850969.png
Код:
spoiler
import cv2
import numpy as np

def find_and_draw_template(template_path, original_image_path):
    # Загрузка шаблона
    template = cv2.imread(template_path)
    template_gray = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)

    # Создание объекта ORB
    orb = cv2.ORB_create()
    bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)

    # Обнаружение ключевых точек и вычисление дескрипторов для шаблона
    keypoints_template, descriptors_template = orb.detectAndCompute(template_gray, None)

    # Обработка изображения
    image = original_image_path.copy()
    image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    # Обнаружение ключевых точек и вычисление дескрипторов для изображения
    keypoints_image, descriptors_image = orb.detectAndCompute(image_gray, None)

    # Сопоставление дескрипторов
    matches = bf.match(descriptors_template, descriptors_image)
    matches = sorted(matches, key=lambda x: x.distance)

    # Отладочная информация
    print(f"Общее количество найденных соответствий: {len(matches)}")

    # Отбор лучших соответствий
    good_matches = matches[:75]
    print(f"Количество хороших соответствий: {len(good_matches)}")

    # Проверка на наличие хороших соответствий
    if len(good_matches) >= 4:
        # Получение координат ключевых точек
        src_pts = np.float32([keypoints_template[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2)
        dst_pts = np.float32([keypoints_image[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2)

        # Нахождение матрицы гомографии
        M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
        print("Гомография найдена.")

        # Получение углов шаблона
        h, w = template_gray.shape[:2]
        pts = np.float32([[0, 0], [0, h - 1], [w - 1, h - 1], [w - 1, 0]]).reshape(-1, 1, 2)

        # Преобразование углов шаблона
        dst = cv2.perspectiveTransform(pts, M)

        # Обводим рамкой найденные области
        image = cv2.polylines(image, [np.int32(dst)], isClosed=True, color=(0, 255, 0), thickness=3)
    else:
        print("Недостаточно хороших соответствий для нахождения гомографии.")

    return image

# Пример использования функции
template_file = 'LED.jpg'              # Шаблон
original_image_file = 'outputImage.jpg'  # Исходное изображение

# Загрузка и обработка изображения
original_image = cv2.imread(original_image_file)
result_image = find_and_draw_template(template_file, original_image)

# Масштабируем изображение для отображения - не обязательно, у меня не вмещалось в просмотр
scale_percent = 50  # Процент уменьшения размера
width = int(result_image.shape[1] * scale_percent / 100)
height = int(result_image.shape[0] * scale_percent / 100)
resized_image = cv2.resize(result_image, (width, height), interpolation=cv2.INTER_AREA)

# Отображение результата
cv2.imshow('Detected Templates', resized_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
Vindicar
@Vindicar
RTFM!
Во-первых, оформи код, нечитаемо. Кнопка </> в помощь.
Во-вторых, matchTemplate(), насколько я знаю, не-инвариантна к поворотам и масштабу. Иными словами, поворот или изменение размера целевого объекта сломают сопоставление.
В-третьих, на показанном кадре более одного экземпляра целевого объекта. Так предполагается или нет? Если предполагается, сколько экземпляров ожидается? Потому что разница очень большая с точки зрения методики.

Варианта тут три.
1. пытаться обучать под задачу нейронку. А лучше дообучить существующую, скажем, YOLOv5. Но тебе потребуется минимум несколько сотен размеченных изображений объекта в разных комбинациях, плюс в 2-3 раза больше похожих изображений без целевого объекта. Готовить такую базу будет утомительно, да и само обучение требует понимания что ты делаешь.
2. попробовать зафиксировать угол поворота или масштаб (т.е. допустить, что он всегда одинаков). Тогда другой параметр можно будет подбирать. Например, мы фиксируем масштаб и делаем 16 изображений объекта в разных поворотах, а потом поочерёдно ищем каждый вариант на кадре. Потом анализируем силу откликов - сколько их, насколько они сильные и т.д. Скорее всего, будет медленно
3. взять за основу поиск по локальным особенностям. Он справляется с масштабом и поворотом, но не справляется с несколькими экземплярами объекта. Это можно забороть, если использовать скользящее окно. Иными словами, находим на кадре узнаваемые точки - локальные особенности (желательно достаточно много и достаточно плотно), используя алгоритмы вроде ORB или SIFT. Затем выбираем те из них, которые попадают в прямоугольную рамку-окно. Затем сверяем эти особенности с особенностями объекта, используя RANSAC или подобный метод. Если получилось хороше совпадение - значит, в этой рамке есть объект или значительная его часть, и мы можем оценить его позицию в кадре в целом. Повторяем процесс, сдвигая рамку, пока оно не "обойдёт" всё изображение. Тоже может быть небыстро, так как нам требуется неоднократный поиск по картинке.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы
Greenway Global Новосибирск
от 150 000 ₽
SpectrumData Екатеринбург
от 200 000 до 300 000 ₽
Akronix Санкт-Петербург
от 150 000 до 200 000 ₽
22 янв. 2025, в 04:08
6000 руб./за проект
21 янв. 2025, в 23:55
20000 руб./за проект
21 янв. 2025, в 23:35
80000 руб./за проект