NTA

Компьютерное зрение в поиске атмосферных осадков

Компьютерное зрение решает задачи поиска, отслеживания и классификации объектов в самых разнообразных областях: промышленности, медицине, сфере безопасности. Одно из возможных новых применений компьютерного зрения — выявление атмосферных осадков при помощи видеокамер наружного наблюдения. О том, как можно реализовать такой алгоритм и поговорим.

При дожде или снегопаде капли дождя или снежинки оставляют на видеокадрах треки — протяженные линии. Особенно ярко этот эффект проявляется в темное время суток при активации инфракрасной подсветки видеокамер.

Таким образом, если в кадре есть некоторое количество линий, ориентированных преимущественно вертикально, то можно предположить, что есть атмосферные осадки: дождь или снег. Далее подробно рассмотрим алгоритм, реализующий эту идею.

Алгоритм выявления атмосферных осадков

Для начала проведем подготовительную работу: импортируем библиотеки opencv и numpy, инициализируем захват кадров из видеофайла с именем, записанным в переменной fname, и создадим экземпляр класса backSub для исключения фона.

import cv2 as cv import numpy as np cap = cv2.VideoCapture(fname) backSub = cv2.createBackgroundSubtractorMOG2(25, 16, False)

Все дальнейшие действия будем выполнять в цикле, последовательно считывая кадры исходного видеофайла.

while True: ret, im_src = cap.read() if not ret: break

Считанный кадр im_src представляет собой RGB-изображение разрешением 1920x1080 пикселей.

Далее выполним несколько операций обработки исходного видеокадра.

Первая операция — вычитание фона.

fg_mask = backSub.apply(frame)

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

Теперь выполним фильтрацию на основе морфологической операции открытия с ядром 3x3.

kernel = np.ones((3,3),np.uint8) filtered = cv.morphologyEx(fg_mask, cv.MORPH_OPEN, kernel)

В результате с изображения исчезнут отдельные мелкие артефакты.

Далее с помощью функции findContours выделим контуры.

cnt_all, hierarchy = cv.findContours(filtered,\ cv.RETR_EXTERNAL,\ cv.CHAIN_APPROX_SIMPLE)

Для иллюстрации выполним обводку найденных контуров.

Исключим самые маленькие по площади контуры. В качестве минимальной площади контура выберем значение 16.

min_area = 16 cnt_sel_by_area = [] for cnt in cnt_all: if cv.contourArea(cnt, False) >= min_area: cnt_sel_by_area.append(cnt)

Результат:

Для того, чтобы выбрать контуры, соответствующие протяженным объектам, рассчитаем коэффициент формы — отношение квадрата периметра контура к площади контура с коэффициентом пропорциональности 1 / (4⨯pi). Для круглых контуров этот коэффициент минимален и равен единице. Чем более вытянут контур, тем больше значение этого коэффициента. В качестве порогового значения установим 4, затем выберем контуры с коэффициентом формы, превышающим выбранный порог.

shape_coef_min = 4 cnt_sel_by_shape = [] for cnt in cnt_sel_by_area: peri = cv.arcLength(cnt, True) area = cv.contourArea(cnt) shape_coef = (peri ** 2) / area / (4 * np.pi) if shape_coef >= shape_coef_min: cnt_sel_by_shape.append(cnt)

Визуально оценим результат этого действия:

Переходим к отбору контуров по направлению. Для того, чтобы определить ориентацию контуров относительно вертикали, используем аппроксимацию контуров прямыми линиями с помощью функции fitLine. Среди возвращаемых этой функцией значений есть координаты направляющего вектора прямой vx и vy. Оценить угол между прямой и вертикалью можно через скалярное произведение направляющего вектора прямой и направляющего вектора оси ординат. Значение этого угла может лежать в диапазоне от 0 до 180 градусов. Для удобства приведем это значение в диапазон 0..90 угловых градусов. Установим в качестве порога максимального отклонения значение 30 градусов и выберем контуры, удовлетворяющие этому условию.

max_angle = 30 cnt_sel = [] for cnt in cnt_sel_by_shape: vx, vy, x, y = cv.fitLine(cnt, cv.DIST_L2, 0, 0.01, 0.01).flatten() vect_line = np.array([vx, vy]) vect_y_axis = np.array([0, 1]) dot_product = np.dot(vect_line, vect_y_axis) angle = np.rad2deg(np.arccos(dot_product)) angle = min(angle, 180 - angle) if angle <= max_angle: cnt_sel.append(cnt)

Результат отбора контуров проиллюстрирован на следующем изображении. Здесь зеленым цветом отмечены выбранные контуры, а красным — исключенные.

Выполним последнее действие: рассчитаем количество выбранных контуров

n_cnt_curr = len(cnt_sel)

Для иллюстрации нанесём выбранные контуры на исходный видеокадр.

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

decision_thr = 3

Далее можно сравнивать количество контуров в кадре с пороговым значением и делать предположение о наличии осадков. Однако, при таком прямолинейном подходе есть риск получения нескольких изменяющихся прогнозов в секунду. Поэтому имеет смысл выполнить усреднение количества контуров во времени. Для усреднения воспользуемся экспоненциальным сглаживанием с параметром 0,1.

alpha = 0.1 n_cnt_avg = n_cnt_curr * alpha + n_cnt_avg * (1 - alpha) n_cnt_avg_int = int(round(n_cnt_avg))

Далее сравним усредненное значение с пороговым и сделаем вывод о наличии осадков.

is_precipitation = n_cnt_avg_int >= decision_thr concl_dict_ru = {True: 'есть осадки', False: 'нет осадков'} conclusion = concl_dict_ru[is_precipitation]

Проиллюстрируем промежуточные расчеты, динамику количества контуров и гипотезу о наличии осадков.

Видео с демонстрацией работы описанного алгоритма можно здесь или здесь. Кадр из демонстрации приведен ниже.

Код размещен в репозитории автора.

Таким образом, был рассмотрен один из способов определения атмосферных осадков с помощью методов компьютерного зрения. Данный способ имеет две особенности. Первая заключается в том, что наилучшим условием применения является сочетание пониженной освещенности и оснащенности видеокамеры инфракрасной подсветкой. Вторая состоит в наличии ряда гиперпараметров, требующих подбора.

0
Комментарии
Читать все 0 комментариев
null