Рубрики
Без рубрики

Обнаружение движения на изображениях микроскопа с использованием Python и OpenCV

Есть три типа организмов, которые можно увидеть в видео выше, в первом раунде, длинный и … Tagged с помощью Python, ImageProcessing, OpenCV, микроскопия.

Есть три типа организмов, которые можно увидеть в видео выше, в первом раунде, длинная и пара Amobea

В прошлом году я познакомился с замечательным научным инструментом под названием «Foldscope». Я часами наблюдал за этим. Одним из моих любимых прошлых времен является наблюдение за цилиатами с использованием сгиба. Ресинкости – это очень простые одноклеточные организмы, которые легко найти и бывают разных форм и размеров. Большинство ресничек движутся очень быстро, и вам нужно немного навыка с микроскопом, чтобы следовать за ними на слайде. Это вдохновило меня на написание некоторого кода, который мог бы обнаружить движущиеся объекты в видео и нарисовать прямоугольники вокруг них. Удивительно, но я полагаю, что смог сделать достойную работу с до 60 линий кода Python ( https://github.com/code2k13/motiondetection )

В этом посте я расскажу о концепциях, которые я использовал для обнаружения движущихся объектов, и как совместная работа, чтобы прийти к конечным результатам.

Чтение видео с Python и OpenCV

Первое, что нам нужно сделать, это иметь возможность загружать рамки один за другим с видео. OpenCV делает эту задачу очень легкой. OpenCV имеет очень удобную функцию, называемую «CV2.VideoCapture», которая позволяет возвращать объект, который можно использовать для выявления информации о видео (например, ширина, высота, частота кадров). Тот же объект позволяет нам прочитать один кадр из видео, вызывая на нем метод read () ‘. Метод «read ()» возвращает два значения, булево, указывающее успех операции и кадр как изображение.

cap = cv2.VideoCapture("video_input.mp4") 
if cap.isOpened(): 
    width  = cap.get(3) # float
    height = cap.get(4) # float
    fps = cap.get(cv2.CAP_PROP_FPS)

Полное видео можно прочитать кадр по кадру, используя следующий код:

success = True
while success:
    success,im = cap.read() 
    if not success:
        break

Написание видео с использованием OpenCV

Писать видео с OpenCV также очень просто. Подобно функции «VideoCapture», функция «VideoWriter» может использоваться для написания видео, Frame By Frame. Эта функция ожидает пути выходного изображения, информации о коде, кадров в секунду, ширина и высота выходного изображения в качестве параметров

fourcc = cv2.VideoWriter_fourcc('m','p','4','v')
out = cv2.VideoWriter('video_output.mp4',fourcc , int(fps), (int(width),int(height)))

Напишите кадр на видео так же просто, как и звонить

out.write(image_obj)

Поиск разницы в кадрах

Приведенное выше видео было сгенерировано из кадров из исходного видео

Изображения представлены как матрицы в памяти. OpenCV имеет функцию, называемую «cv2.absdiff ()», которая может быть использована для расчета абсолютной разницы двух изображений. Это основа нашего обнаружения движения. Мы полагаемся на тот факт, что, когда что -то в видео перемещается, его Absdiff будет не нулевым для этих пикселей. Однако, если что -то стационарное и не перемещалось в двух кадрах, Absdiff будет нулевым. Итак, когда мы читаем видео кадр по кадру, мы сравниваем текущую кадр со старой кадром и рассчитываем матрицу absdiff. Размеры этой матрицы такие же, как и изображения, которые будут сравниваться.

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

После экспериментов с некоторыми подходами я обнаружил, что пороговое значение изображения DIFF с использованием средних значений работает очень хорошо.

frame_diff[frame_diff < frame_diff[np.nonzero(frame_diff)].mean()] = 0
frame_diff[frame_diff > frame_diff[np.nonzero(frame_diff)].mean()]

Использование обнаружения краев для повышения точности

Обнаружение краев с использованием фильтра «Sobel», выполненного на видео Frame Diff

По мере движения микроорганизмы они продвигают вещество вокруг них, что дает положительные пиксели после различия. Но мы хотим отличить микроорганизмы от других вещей. Также фокусируя играет важную роль здесь. Как правило, многие из непредвиденных объектов также дадут положительные разницы в кадре. В основном это размытые объекты, которые мы просто хотим игнорировать. Именно здесь обнаружение краев вступает в игру на краях и границах на изображении. Чтобы найти те, что мы используем обнаружение краев. Это может быть легко достигнуто с помощью фильтра «Sobel» из пакета Scikit Learn.

output = filters.sobel(frame_diff)

Использование обнаружения контура для обнаружения объектов

Видео, сгенерированное после выполнения обнаружения контуров на выходе фильтра Sobel

Большинство простейших, таких как килиаты, не всегда показывают четкую границу (потому что они в основном прозрачны). Поэтому, когда мы используем обнаружение краев, чтобы обнаружить формы/очертания движущихся объектов, мы получаем сломанные края. По моему опыту, обнаружение контура очень хорошо работает для группы таких сломанных краев и создал более непрерывную границу.

contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

OpenCV имеет встроенные функции для поиска контуров. Самое приятное, что функция способна найти вложенные контурные структуры и вернуть Hirearchy. Функция «CV2.findContours» возвращает иерархию контуров. Мы рассматриваем только контуры верхнего уровня (у которых нет родителя). Если для контура «idx», если «иерархия [0] [idx] [3]» возвращает -1, это означает, что это контур верхнего уровня И у него нет родителей. Все остальное, что мы игнорируем.

Создание ограничивающих коробок

Видео, показывающее ограничительные коробки, нарисованные на контурах

Создание коробок вокруг контуров может потребовать немного математики. К счастью, у OpenCV есть убедительная функция «CV2.BoundingRect», которая возвращает центральные координаты, с и высотой ограничивающего прямоугольника вокруг данного контура. Как только у нас есть это, нарисование прямоугольника на нашем кадре может быть просто вниз, используя функцию CV2.Rectangle. Мы можем передать цвет и ширину границы при привлечении прямоугольника к этой функции.

if hierarchy[0][idx][3]== -1 :
    x,y,w,h = cv2.boundingRect(contour)
    if (w*h <= (q)**2):
        continue
    image = cv2.rectangle(image, (x,y),(x+w,y+h), color, 1)

Концепция «Q»

Как я объяснил ранее, видео, снятые с использованием микроскопа, могут быть грязными. Там может многое происходит. Мы можем быть заинтересованы только в обнаружении объектов определенного размера. Это, где я представил параметр под названием «Q». Этот параметр использовался для изменения настроек для различных фильтров, с которыми я экспериментировал. В настоящее время это используется только для фильтрации ограничивающих прямых, которые меньше, чем Q^2 в области. Вы должны экспериментировать с различными значениями «Q», в зависимости от разрешения вашего видео и размера объектов, которые вас интересуют.

Вещи, чтобы улучшить

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

Полный код

Полный код вместе с примером видео доступен на GitHub: https://github.com/code2k13/motiondetection

Оригинал: “https://dev.to/code2k13/motion-detection-in-microscope-images-using-python-and-opencv-1flg”