Ответы пользователя по тегу OpenCV
  • Почему не корректно работает код?

    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 попробуй.
    Ответ написан
    Комментировать
  • Почему не работает detectMultiScale python?

    Vindicar
    @Vindicar
    RTFM!
    face_cascade = "C:\mine\haarcascade_frontalface_alt.xml"
    ...
    face_cascade.detectMultiScale(

    У тебя face_cascade - это строка. Чего ты ожидаешь-то от неё? Класс строки понятия не имеет ни про какие каскады Хаара.
    Сдаётся мне, ты пропустил этап собственно загрузки каскада из указанного файла. А именно, вызов конструктора cv2.CascadeClassifier().
    Ответ написан
    1 комментарий
  • OpenCV не видит камеру. Что делать?

    Vindicar
    @Vindicar
    RTFM!
    Сколько камер на том компе, где не работает?
    Потому что параметр VideoCapture() - это, условно, номер камеры в списке камер. Если на компе только одна камера, то номер должен быть 0, если две, то номера будут 0 и 1, и так далее.
    Способа открыть камеру по имени сам opencv не предоставляет, хотя вроде есть сторонние пакеты, которые это исправляют - в плане получения списка камер в том же порядке, в каком их индексы будут использоваться VideoCapture().
    Ответ написан
    1 комментарий
  • Почему возникает ошибка error: (-215:Assertion failed) !_src.empty() in function 'cv::cvtColor'?

    Vindicar
    @Vindicar
    RTFM!
    _, image = cap.read()
    Не _, а success_code, то бишь признак успешности чтения. Проверь, читается ли у тебя вообще кадр с камеры.
    Ответ написан
    Комментировать
  • Как поменять начало координат на выделеной области cv2?

    Vindicar
    @Vindicar
    RTFM!
    Не очень понятно, что ты имеешь ввиду. cv2 всегда сообщает клики в координатах окна. Они, как правило, совпадают с координатами внутри показанного в окне изображения: та же точка отсчёта, то же направление осей, масштаб 1:1. Единственное отличие - если ты увеличил размер окна, клик может оказаться за пределами показанного изображения.

    Если тебе нужна другая координатная система, пересчитывай координаты сам.
    Ответ написан
    Комментировать
  • Как сопоставить два изображения чтобы убрать сдвиг?

    Vindicar
    @Vindicar
    RTFM!
    cv2.goodFeaturesToTrack() чтобы найти "узнаваемые точки" на каждом изображении.
    cv2.calcOpticalFlowPyrLK() чтобы понять, насколько они сдвинулись. Далее выбираешь точки вокруг интересующего объекта, вычитаешь из их позиций их предыдущие позиции, усредняешь, получаешь вектор среднего смещения за кадр. На основании этого вектора уже что-то делаешь с изображением.
    Например, если тебе нужно сглаживать резкие рывки, может иметь смысл отслеживать значение среднего смещения от кадра к кадру. Если смещение в каком-то кадре резко изменилось (заметно отличается от среднего за предыдущие N кадров), значит, кадр нужно сдвинуть.
    Ответ написан
  • Как наложить одно изображение на другое без размытия, смешивания и прозрачности?

    Vindicar
    @Vindicar
    RTFM!
    Если нужно заменить прямоугольник пикселей, то это делается тривиально:
    img1[top1:bottom1, left1:right1] = img2[top2:bottom2, left2:right2]

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

    Если же нужно работать с альфа-каналом, то для начала его неплохо бы прочитать.
    image = cv2.imread('image.png', cv2.IMREAD_UNCHANGED)

    UNCHANGED не преобразует в BGR, а грузит как есть, в том числе альфа канал.
    И тогда нужно будет сделать что-то типа
    mask = image[..., 3] > 0  # если считаем, что чем меньше - тем прозрачнее
    background[top:bottom, left:right][mask] = image[mask]  # не забываем про равенство размера!
    Ответ написан