Ответы пользователя по тегу OpenCV
  • Как найти паттерн на картинке с OpenCV?

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

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

    Vindicar
    @Vindicar
    RTFM!
    Тебе модель, скорее всего, отдаст экземпляр класса Detections.
    Если его посмотреть, там есть несколько полезных методов, например, render(), который возвращает список обработанных изображений с отрисованными объектами. А ещё у него есть свойства imgs, xywh и names, чтобы получить обработанные изображения, рамки и классы найденного. Экспериментируй с ними
    Не забываем, что модель рассчитана на подачу пачки изображений, просто эта пачка может содержать и только одно изображение. Отсюда и множественное число, и постоянные массивы.
    Ответ написан
    Комментировать
  • Как склеить 2 и более изображения с помощью поиска локальных особенностей?

    Vindicar
    @Vindicar
    RTFM!
    Можно сделать так:
    1. Вычисляешь матрицу преобразования, которому нужно подвергнуть изображение 2, чтобы склеить его с изображением 1 (далее, 2->1).
    2. Вычисляешь матрицу преобразования 3->2.
    3. Склеиваешь 3 с 2, используя матрицу 3->2.
    4. Склеиваешь сумму 3 и 2 с 1, используя матрицу 2->1.
    Альтернативно, ты можешь подвергнуть 3 преобразованию 3->2, а потом 2->1 (либо последовательно, либо перемножив их матрицы), чтобы перевести его в систему отсчёта изображения 1, и склеить их непосредственно.

    Таким образом можно построить дерево преобразований, где все изображения приводятся к ракурсу "корневого" изображения. Большой плюс этого подхода в том, что нам не требуется физически соединять все изображения в одно огромное полотно - если мы рассчитали матрицу преобразования для каждого изображения, мы можем преобразовывать каждое изображение тогда, когда оно требуется. Но можно и соединить, почему бы нет.

    Ещё я не вполне понял, что ты имеешь ввиду под "панорамное изображение".
    Но я подозреваю, это может быть вызвано тем, что на выбранном корневом (первом) изображении ракурс отличается от "нормального" - строго перпендикулярного целевой плоскости. Тогда тебе нужно выбрать такое изображение, на котором ты можешь более-менее точно определить целевую плоскость. ТУт может помочь какой-нибудь маркер типо QR-кода, aruco-маркера, да хоть банальный шахматный шаблон (с ним, кстати, проще всего). Главное, чтобы его размер был известен, и он был прямоугольный. Тогда можно будет рассчитать преобразование для этого изображения, которое исправит перспективу. Мы будем "смотреть прямо" на плоскость, где расположен этот шаблон. Это исправленное изображение и будет для нас корневым, к которому мы будем "пристёгивать" остальные.
    Ответ написан
    Комментировать
  • Хочу написать python Бота который играет в сапер за меня, и наверное мне нужно наставление более опытного?

    Vindicar
    @Vindicar
    RTFM!
    1. Ввод данных
    Окей, гугл, как сделать скриншот в питоне

    2. Предобработка данных
    Используя что-то типа opencv matchTemplate(), превращаешь скриншот в двухмерный массив, описывающий игровое поле.

    3. Принятие решения
    Имея двухмерный массив, описывающий поле, определи, где надо ставить мину. Если решение принять не удаётся - определи, какую клетку надо открывать.

    4. Реализация решения
    Зная номер клетки, выполнить щелчок по ней. См. pyautogui.
    Ответ написан
    Комментировать
  • Распознавание капчи на python, как улучшить результат?

    Vindicar
    @Vindicar
    RTFM!
    Ну так ты хреначишь BGR2GRAY+пороговое преобразование с фиксированным порогом, и думаешь что оно само сработает? Волшебную кнопку ждёшь?
    Попробуй перегнать в HSV и поэкспериментируй с каналами, посмотри, какой наиболее информативный. Используй алгоритм Otsu для определения порога.
    Попробуй разбить текст на символы, например, через connected components with stats. Если символы не касаются друг друга, должно сработать. Если касаются, то будет сложнее - нужно будет как-то разделять их ДО порогового преобразования.
    Потом уже пробуй распознать каждый символ. Если шрифт всегда один и тот же, то может и pytesseract не понадобится, просто собери образцы символов и ищи их через generalized Hough-Guil.
    Ответ написан
    Комментировать
  • Как выделить элемент не останавливая воспроизведение видео (OPENCV)?

    Vindicar
    @Vindicar
    RTFM!
    Ну а как ты себе представляешь быстрое задание И позиции И примерного размера объекта?
    А оно должно быть быстрым, так как объект может двигаться по кадру.

    Ты можешь притормаживать видео, пока пользователь держит зажатой левую клавишу мыши.
    Тогда у тебя будет реакция на нажатие левой клавиши (останавливаем видео, фиксируем одну вершину прямоугольника, содержащего объект) и на отпускание левой клавиши (фиксируем противоположную вершину, извлекаем область, содержащую объект, начинаем его отслеживать и продолжаем видео).
    Ответ написан
    Комментировать
  • Как решить module 'cv2' has no attribute 'TrackerCSRT_create'?

    Vindicar
    @Vindicar
    RTFM!
    Как ставил OpenCV? Там несколько пакетов. opencv-python содержит только основные возможности, а целый ряд вещей вынесен в opencv-contrib-python. Плюс ряд алгоритмов доступен не во всех версиях, так что выясни, начиная с какой версии поддерживается этот алгоритм, и какая версия стоит у тебя.
    Ответ написан
    Комментировать
  • Почему не корректно работает код?

    Vindicar
    @Vindicar
    RTFM!
    for i in range(len(zones)):
                        pin = i + 2  # Номер пина соответствует номеру зоны + 1
                        if i+1 in in_zones:
                            # Если объект находится в зоне, зажигаем светодиод
                            board.digital[pin].write(1)
                        else:
                            pin = i + 2
                            # Если объект не находится в зоне, гасим светодиод  <--- НАПРАСНО
                            board.digital[pin].write(0)

    Косяк вот тут. Если текущий объект не находится в зоне, это не значит что никакой другой, ранее найденный объект не находится в этой зоне.
    Сделай массив bool по числу зон, в начале итерации выставь все элементы в false. По ходу итерации выставляй элемент в true если в зоне найден человек.
    В конце итерации выставляй светодиоды по элементам массива.
    Ответ написан
    1 комментарий
  • Можно ли задать условия для работы opencv?

    Vindicar
    @Vindicar
    RTFM!
    Ну и в чём вопрос? У тебя в коде уже есть проверка на силу совпадения (сравнение найденного максимума силы с некоторым порогом). Если тебе нужно выполнять другое действие, то добавь ветку else туда.
    Если тебе нужно просто крутить цикл, и выполнять действие, когда изображение найдётся, можешь завернуть в цикл while тело red() или даже просто вызывать её саму в цикле. Условие завершения цикла обдумай сам, я без понятия что ты хочешь сделать.
    Ответ написан
    Комментировать
  • Как распознать тип движения с помощью opencv?

    Vindicar
    @Vindicar
    RTFM!
    Можешь познакомиться с этой лекцией, там есть интересные идеи.
    Ответ написан
    Комментировать
  • Ошибка: cv2.error: OpenCV(4.8.0) :-1: error: (-5:Bad argument) in function 'cvtColor', как исправить?

    Vindicar
    @Vindicar
    RTFM!
    Почитать документацию на cvtColor() и осознать, что она принимает на вход объект изображения, а не VideoCapture(), который ты ей передаёшь. Так что тебе придётся преобразовывать в нужную цветовую систему каждый кадр отдельно.

    А еще почитать доки на VideoCapture(), в частности, про метод read(). Пример кода там есть.
    Ответ написан
    Комментировать
  • Как произвольно трансформировать изображение в Python?

    Vindicar
    @Vindicar
    RTFM!
    Скажи спасибо, что я делал такую лабораторную работу X)
    Код
    # -*- coding: utf-8 -*-
    import sys
    import numpy  # pip install numpy
    import cv2  # pip install opencv-python
    
    def loadImg(fname : str) -> numpy.ndarray:  # грузит файл
        data = numpy.fromfile(fname, dtype=numpy.uint8)
        img = cv2.imdecode(data, cv2.IMREAD_COLOR)
        if img is None:
            raise IOError("Not an image file")
        return img
    
    class Clicker:  # класс для выбора точек на экране
        def __init__(self, name: str, image: numpy.ndarray):
            self.wnd = name
            self.image = image
            self.clicks = []
            self.markersize = 5
            self.markercolor = (255,0,255)
            cv2.namedWindow(self.wnd, cv2.WINDOW_AUTOSIZE)
            cv2.setMouseCallback(self.wnd, self._click)
        
        def draw(self):  # рисует точки на изображении и выводит их на экран
            copy = self.image.copy()
            color = self.markercolor
            radius = self.markersize
            for x,y in self.clicks:
                cv2.circle(copy, (x,y), radius, color, 1)
                cv2.line(copy, (x-radius,y), (x+radius,y), color, 1)
                cv2.line(copy, (x,y-radius), (x,y+radius), color, 1)
            cv2.imshow(self.wnd, copy)
        
        def _click(self, event, x, y, flags, param):
            if event == cv2.EVENT_LBUTTONDOWN:  # левый клик - поставить точку
                self.clicks.append((x,y))
            elif event == cv2.EVENT_RBUTTONDOWN:  # правый клик - сбросить последнюю точку
                if self.clicks:
                    del self.clicks[-1]
            else:
                return
            self.draw()
        
        def close(self):
            cv2.destroyWindow(self.wnd)
        
        def __enter__(self):
            self.draw()
            return self
        
        def __exit__(self, exctype, excvalue, traceback):
            self.close()
    
    try:
        image = loadImg('times-square.jpg')  # изображение, внутрь которого вписываем другое
        poster = loadImg('lena.png')  # изображение, которое вписываем в первое
    except IOError:
        print('Ошибка загрузки файла.')
        sys.exit(1)
    # эта часть только для ручного ввода координат
    # если они уже есть, то это не нужно.
    with Clicker('Select area', image) as clicker:
        # четыре точки ставятся строго по часовой, начиная слева-сверху 
        while len(clicker.clicks) < 4:  # пока не получили четыре точки - угла
            if cv2.waitKey(100) == 27:
                print('Отменено')
                sys.exit(0)
        pts = numpy.array(clicker.clicks, dtype=numpy.float32)  # координаты углов тут
    # вписываем изображение
    height, width = poster.shape[:2]
    srcpoints = numpy.array([  # углы вставляемого изображения в том же порядке по часовой
        (0,0),
        (width-1, 0),
        (width-1, height-1),
        (0, height-1),
    ], dtype=numpy.float32)
    # матрица преобразования сопоставляет четыре точки второго изображения с точками первого
    # по сути, она позволяет перейти от второго изображения к первому
    matrix = cv2.getPerspectiveTransform(srcpoints, pts)  # порядок аргументов важен, иначе переход будет наоборот
    # применяем матрицу ко второму изображению. Но теперь надо убрать чёрные поля.
    warped = cv2.warpPerspective(poster, matrix, (image.shape[1], image.shape[0]))
    # делаем маску для переноса пикселей с warped на image
    # мы хотим перенести только пиксели, на которые пришлись пиксели второго изображения
    mask = numpy.zeros(image.shape, dtype=numpy.uint8)  # рисовать можно только на обычном изображении
    # закрашиваем пиксели внутри выбранного ранее четырёхугольника
    cv2.fillPoly(mask, pts.reshape(1, -1, 2).astype(numpy.int32), (1,1,1))
    mask.dtype = bool  # а для переноса нам нужна логическая маска
    # маска готова, переносим. numpy рулит, правда ведь?
    image[mask] = warped[mask]
    # показываем результат
    cv2.imshow('Result', image)
    cv2.waitKey()


    Если коротко: находишь точки, которым надо сопоставить углы "вставыша". Перечисляешь их в том же порядке, что и эти углы. Находишь матрицу перспективного преобразования. Применяешь матрицу к вставышу, получаешь чёрное изображение, на котором вставыш расположен в нужном месте. Переносишь пиксели с этого изображения на картинку с экраном.
    Ответ написан
    3 комментария
  • Почему возникает ошибка при работе с Python и OpenCV?

    Vindicar
    @Vindicar
    RTFM!
    1. Не принимать предупреждения за ошибки.
    2. Работать на машине, где видяха поддерживает одну из указанных библиотек, и поставить на неё эту библиотеку.
    Ответ написан
    Комментировать
  • Как создать триггер cv2 Python?

    Vindicar
    @Vindicar
    RTFM!
    1. Выясни, что возвращает haar_cascade.detectMultiScale(), если в кадре нет лица - None или пустой массив?
    2. Храни флаг "на прошлом кадре было лицо", обновляй его в конце тела цикла while True
    3. После детекта лица проверяй, если на прошлом кадре лица не было, а на новом есть - делай отправку уведомления.

    А вот как подружить ТГ бота с этим циклом - уже второй вопрос. Я бы запустил приведённый код в потоке и использовал queue.Queue для связи потока с анализом видео и потока с ботом. Т.е. когда обнаружил лицо, кидаешь кадр в очередь. А в основном потоке периодически проверяешь очередь на предмет наличия новых кадров.
    Альтернативно, если бот асинхронный, можно переделать цикл на корутину, добавив небольшую задержку через await asyncio.sleep() и заменив requests на aiohttp. Не очень изящное решение, но может и сойдёт.
    Ответ написан
    Комментировать
  • Что делать если при открытии png файла с прозрачным фоном через OpenCV появляются гличи?

    Vindicar
    @Vindicar
    RTFM!
    Во-первых, скриншот в студию.
    Во-вторых, IMREAD_GRAYSCALE отрывает файлу канал прозрачности напрочь. Что там на самом деле было в прозрачных пикселях - фз.
    Попробуй IMREAD_UNCHANGED, тогда у тебя будет дополнительный канал прозрачности, который ты можешь сам принять к сведению - например, залить все прозрачные пиксели нужным цветом, или ещё что.
    Ответ написан
    Комментировать
  • Почему не работает код?

    Vindicar
    @Vindicar
    RTFM!
    if time <= time_15:

    По логике должно быть if time > time_15:
    Ответ написан
    Комментировать
  • Почему не работает код?

    Vindicar
    @Vindicar
    RTFM!
    В твоём коде показано, как определить класс объекта. Смотри, как формируется prediction_text.
    А дальше просто. Храни в глобальной переменной время, когда был сохранён последний снимок объекта с желаемым классом.
    Если у тебя на текущем кадре есть объект с желаемым классом, проверь текущее время. Если прошло 30 секунд с последнего сохранения - сохрани новый снимок, и обнови время последнего сохранения на текущее.
    Ответ написан
    Комментировать
  • Как настроить нейронную сеть на python?

    Vindicar
    @Vindicar
    RTFM!
    Почему ты делаешь np.mean(result)?
    Если я верно помню, softmax-слой даст наибольший отклик в элементе, соответствующем выбранному классу. Т.е. нужно сделать argmax по этому слою, чтобы узнать ответ сети.

    P.S.: обалдеть, я и не знал что в питоне есть оператор @.
    Ответ написан
  • Как создать свой каскад для распознавания объектов?

    Vindicar
    @Vindicar
    RTFM!
    Я создавал лабораторную по этой теме, могу привести инструкцию.
    1. Загрузите набор утилит opencv(гугл-диск, но я советую поискать самостоятельно), в частности opencv_createsamples и opencv_traincascade, а также необходимые им DLL-библиотеки. Распакуйте их в рабочий каталог в корне диска, без русских букв и пробелов в названии. Здесь и далее предполагается, что C:\MyDirName - ваш рабочий каталог.
    2. Подготовьте фото вашего объекта. Используйте контрастный объект без движущихся частей, и желательно не дающий бликов. Для этой цели хорошо подходят логотипы.
    3. Подготовьте отрицательные примеры (не менее 100 изображений). Для этого можно снять короткое видео помещения, затем написать программу, которая разделяет это видео на отдельные кадры. Рекомендуется поместить их в отдельный подкаталог negatives.
    4. Подготовьте файлы, содержащие список файлов в этом каталоге. Их можно сгенерировать следующей парой команд в терминале:
      dir C:\MyDirName\negatives\*.jpg /B /S >C:\MyDirName\negatives\negatives_abs.txt

      dir C:\MyDirName\negatives\*.jpg /B >C:\MyDirName\negatives\negatives_rel.txt

    5. Создайте пустые подкаталоги C:\MyDirName\positives и C:\MyDirName\training. Поместите ваше изображение - положительный пример в каталог C:\MyDirName\ и назовите его positive.jpg. В качестве положительного примера желательно разместить ваш объект на светлом фоне, если он тёмный, и наоборот.
    6. Сгенерируйте положительные примеры с помощью утилиты opencv_createsamples. Команда будет выглядеть примерно следующим образом:
      C:\MyDirName\opencv_createsamples.exe -info positives\info.lst -img positive.jpg -bg negatives\negatives_rel.txt -maxxangle 0.1 -maxyangle 0.1 -maxzangle 0.1 -bgcolor 0 -bgthresh 0 -w 50 -h 50 -num 100

      Параметры:
      -info - выходной файл.
      -img - входное изображение - положительный пример
      -bg - фоновые изображения. Положительный пример будет наложен на них (в оттенках серого).
      -max?angle - допустимые углы поворота примера. Утилита выполнит перспективное преобразование примера перед наложением.
      -bgcolor и -bgthresh задают яркость (среднее и диапазон изменения) для "прозрачного цвета". Например, если ваш объект на белом фоне, задайте эти параметры равными 240 и 15 (диапазон яркости 225-255). Задав оба параметра равными 0, вы отключите эту функцию и все цвета будут непрозрачными.
      -w и -h задают минимальный размер для размещаемой копии вашего образца.
      -num - количество примеров, которые стоит генерировать. Не должно превышать количество изображений в каталоге.
      Утилита должна вывести ряд сообщений вида "Open background image", а в конце вывести "Done".
    7. Сгенерируйте vec файл следующей командой:
      C:\MyDirName\opencv_createsamples.exe -info positives\info.lst -num 100 -w 20 -h 20 -vec positives\positives.vec

      где info.lst был сгенерирован в ходе пункта 6.
      -w и -h задают минимальный размер для объекта, распознаваемого в ходе работы каскада.
      -num - количество сгенерированных примеров. Столько же, сколько и в пункте 6.
    8. Проведите обучение каскада с помощью утилиты opencv_traincascade. Команда будет иметь примерно следующий вид:
      C:\MyDirName\opencv_traincascade.exe -data training -vec positives\positives.vec -bg negatives\negatives_abs.txt -numStages 100 -numPos 100 -numNeg 100 -featureType haar -w 20 -h 20 -minHitRate 0.999 -maxFalseAlarmRate 0.4 -precalcValBufSize 4048 -precalcIdxBufSize 4048 -numThreads 24 -acceptanceRatioBreakValue 10e-5

      -data - каталог для рабочих данных, который вы создали в пункте 5.
      -vec - индекс, который был создан в пункте 7.
      -bg - файл со списком отрицательных примеров (используйте абсолютные пути!)
      -numPos и -numNeg - количество положительных примеров (пункт 6) и отрицательных примеров (пункт 3).
      -numStages - максимальное количество этапов каскада. Итоговый каскад может содержать меньшее количество этапов.
      -featureType - определяет тип признаков. Признаки Хаара обучаются медленнее, но зато более точны.
      -w и -h задают минимальный размер для объекта, распознаваемого в ходе работы каскада. Должны строго совпадать с заданными в пункте 7.
      -minHitRate и -maxFalseAlarmRate задают качество работы одного каскада.
      -acceptanceRatioBreakValue определяет момент, когда каскад перестаёт обучаться.
      -precalcValBufSize и -precalcIdxBufSize задают потребление памяти процессом.
      -numThreads определяет число рабочих потоков.
    9. По итогам обучения в каталоге training должен появиться файл cascade.xml, который можно загружать так же, как типовые каскады, поставляемые с opencv. Обратите внимание, что если вы хотите запустить обучение с начала, нужно очистить содержимое каталога training, иначе утилита будет дообучать существующий каскад.
    Ответ написан
    5 комментариев
  • Как бот должен понимать что нужно нажимать кнопку во время qte?

    Vindicar
    @Vindicar
    RTFM!
    Template matching попробуй.
    Ответ написан
    Комментировать