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

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

Ответ написан
Комментировать
Ваш ответ на вопрос

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

Похожие вопросы