Привет, ребята. Это последнее обнаружение нарушений правил дорожного движения в моем выпускном проекте. Я так рада поделиться тем, как я это сделала. Это система обнаружения нарушений правил парковки. Не буду врать, логику и условия, которые я здесь использовал, немного сложно понять, особенно то, как это запрограммировано. Но не волнуйтесь. Потерпите меня до этого объяснения, и я гарантирую вам, что вы поймете это как сыр. (Возможно, следует использовать лучшую метафору). Кто знает, может быть, вы могли бы построить лучшую версию этого.

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





Вы можете найти все коды и репозитории по следующей ссылке GitHub;

https://github.com/hasantha-nirmal/Traffic_Violation_Detection_Yolov4_Deep-Sort

Давайте начнем, хорошо?

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

Что ж, самое простое решение — ввести таймеры для каждого отдельного автомобиля. Исходя из этого, мы можем не только убедиться, что транспортное средство находится в этой запретной зоне в течение определенного периода времени, но также мы можем определить, как долго оно находится там. Разве это не здорово? Я имею в виду, что мы можем полностью использовать ту же систему для систематической системы парковки, вместо того, чтобы брать билеты и все такое. Вводя интересующие области в виде парковочных мест, просто используя одну камеру видеонаблюдения, мы можем не только одновременно отслеживать и определять, как долго это конкретное транспортное средство занимает это парковочное место, но также мы можем рассчитать, сколько каждый отдельный автомобиль должен платить за парковка.

Хорошо, вернемся к обнаружению нарушений. Как я упоминал ранее, ключевым словом здесь являются таймеры. Но одновременный учет множества транспортных средств наверняка усложнит задачу. Но, к счастью, у нас есть способ реализовать нашу систему, предполагая, что в интересующей области есть только одно транспортное средство, но на самом деле существует несколько одновременных транспортных средств, которые одновременно совершают это нарушение. Вы можете получить представление об этом механизме в моей статье по обнаружению нарушений скорости.

# Координаты парковки; #line 113
parking_co = []

#blanked = np.zeros((658,1024), dtype=np.uint8)
blanked = np.zeros((2048 , 1024), dtype=np.uint8)
#pts = np.array(([156, 704], [2, 893], [476, 932], [270, 708]))
pts = np.array(([513, 716], [321, 943], [884, 979], [630, 701]))
#blanked = np.zeros((720,1280), dtype=np.uint8)
#pts = np.array(([38, 433], [95, 322], [1246, 570], [1065, 709]))
cv2.fillPoly (пробел, np.int32([pts]), 255)

Во-первых, позвольте мне показать вам, как выбрать пиксельные координаты парковочного места, которые нас интересуют. Сначала я ввел пустой массив с именем parking_co, а затем создал нулевой массив, такой же, как разрешение видео. (Одна из рамок ширины и высоты). Затем выберите координаты формы многоугольника, который вы выбрали в качестве области интереса (ROI). Атрибуты, видимые в массиве pts, представляют собой координаты края выбранного нами полигона. Но этого недостаточно. Нам нужны координаты пикселей, которые покрывают внутреннюю область этого многоугольника, чтобы мы могли определить, когда координаты транспортного средства (ограничивающей рамки) пересекаются с ними. Для этого я использовал функцию OpenCV под названием fillPoly и задал координаты массива pts в качестве одного из его атрибутов.

Затем я извлек координаты x и y из пустой маски, которая теперь заполнена значениями пикселей интересующей области.

x_cord = np.where(blanked == 255)[1] #line 124
y_cord = np.where(blanked == 255)[0]

Теперь у нас есть все координаты точек пикселей в интересующей области или месте, где запрещена стоянка транспортных средств. Затем возьмем координаты ограничивающей рамки самого автомобиля. Но опять же, это поднимает проблему. Если камера находится слишком близко к этой интересующей области, когда транспортное средство приближается к этой области, его ограничивающая рамка занимает очень большое количество координатных точек, и при одновременном присутствии транспортных средств этот процесс необходимо повторять для каждого кадра видео. , частота кадров резко падает. Итак, я привел аргумент для этого случая, что если транспортное средство/ограничивающий прямоугольник пересекает эту область интереса, он, безусловно, также пересекается с нижней линией ограничивающего прямоугольника. Таким образом, как и в случае с нарушением линии полосы движения, вместо того, чтобы брать все координаты ограничивающей рамки транспортного средства, я взял только координату нижней линии ограничивающей рамки, что не только соответствует моему аргументу, но и увеличивает частоту кадров (производительность). ).

#Обратите внимание: если камера находится далеко, эта проблема может не возникнуть, и вы можете использовать всю ограничивающую рамку без каких-либо проблем с производительностью.

#строка 284

bbox_bottom_line_co = list(zip(*line(*(int(bbox[0])+50,int(bbox[3])), *(int(bbox[2])-50,int(bbox[3 ])))))

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

Хорошо всем. Теперь начинается сложная часть. Так что держитесь крепче.!!

#строка 294

if len(intersection(parking_co, bbox_bottom_line_co)) › 0:
frame_matrix.append((str(frame_num) + class_name + str(t),
(
str(int( bbox[0])).zfill(4), str(int(bbox[1])).zfill(4), str(int(bbox[2])).zfill(4),
str( int(bbox[3])).zfill(4))))

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

chk_index = str(frame_matrix).find(str(frame_num — 1) + class_name + str(t))

Затем он немедленно проверяет с предыдущим кадром, произошло ли такое же пересечение для того же транспортного средства. Если это пересечение произошло впервые, это условие не выполняется, и программа переходит к следующему кадру без дальнейшего взаимодействия. Но представьте, если это второй кадр после пересечения транспортным средством интересующей области, то для этой переменной chk_index действительно получено значение.

if bool(chk_index + 1) == True:
previous_bbox_co_str = str(frame_matrix)[
(chk_index — 1) + len(str(frame_num — 1)) + len(class_name + str (t)) + 5:(chk_index — 1) + len(str(frame_num — 1)) + len(class_name + str(t)) + 5 + 30]

Логическое значение (chk_index+1) дает положительное значение. Причина добавления 1 заключается в том, что это возможно для конкретного транспортного средства, сведения о его регистрации начинаются с самого начала массива и, следовательно, значение его размещения в массиве равно 0. Если это произошло, bool( 0) делает условие ложным, даже если оно истинно. Если такой записи в журнале нет, chk_index просто возвращает -1, а при добавлении +1 дает желаемый результат False.

Когда это условие выполняется, как вы можете видеть, они получают сведения журнала предыдущего кадра о ограничивающей рамке в другую переменную с именем previous_bbox_co_str.

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

# Проверка неподвижности транспортного средства #line 99
def immobile(bbox, previous_bbox_str):
previous_bbox0 = int(previous_bbox_str[1:5])
previous_bbox1 = int(previous_bbox_str[9 :13])
предыдущая_bbox2 = int(предыдущая_bbox_str[17:21])
предыдущая_bbox3 = int(предыдущая_bbox_str[25:29])

total = abs(bbox[0] — предыдущая_bbox0) + абс(bbox[1] — предыдущая_bbox1) + абс(bbox[2] — предыдущая_bbox2) + абс(
bbox[3] — предыдущая_bbox3)
если итого ‹= 4:
> вернуть True
иначе:
вернуть False

Поэтому здесь я использовал previous_bbox_co_str в качестве атрибута функции, а также текущие координаты ограничивающей рамки. Я взял разницу соответствующих значений xmin, ymin, xmax и ymax, и если абсолютная разница меньше 4, я вывел True, поскольку транспортное средство неподвижно, и False в качестве меры противодействия.

Имейте в виду, что YOLO имеет тенденцию давать колеблющиеся координаты ограничивающей рамки, даже если транспортное средство или любой объект полностью остановлены. Чтобы избежать этого и сделать этот процесс надежным, я предлагаю вам использовать здесь более высокое значение для переменной total. Чем выше значение, тем более устойчива программа к случайным колебаниям ограничивающих рамок.

Итак, если функция выводит, что транспортное средство неподвижно (неподвижно), то я сразу же проверяю, есть ли какая-либо предыдущая зарегистрированная запись в cache_matrix, и если нет, я добавляю текущее время(t_start), тип транспортного средства(class_name) и идентификатор отслеживания( ул(т)).

if str((class_name + str(t))) не в str(cache_matrix): #line 310
t_start = datetime.now()
cache_matrix.append((str(t_start), class_name + str(t)))
print(cache_matrix)

В следующем условии я проверил, находится ли транспортное средство в матрице кеша. (Теперь есть). Также проверьте, нет ли того же транспортного средства в viol_matrix. (Потому что я ввел матрицу нарушений для зарегистрированных транспортных средств, которые были неподвижны и превысили лимит времени.). Если нет, я немедленно получаю значение t_start для этого конкретного автомобиля и проверяю разницу во времени, используя текущее время.

index = (str(cache_matrix).find(str((class_name + str(t))))) #line 318
t_start_cm = str(cache_matrix)[index — 28:index — 11]
t_spending = (datetime.now() — datetime.strptime(t_start_cm,
'%y-%m-%d %H:%M:%S')).total_seconds()

Если разница во времени(t_spending) увеличилась больше, чем нужно, я записывала данные в электронную таблицу, которая включала время первого пересечения транспортного средства(t_start_cm), тип транспортного средства (class_name) и идентификатор отслеживания транспортного средства (str(t)). В этом случае для демонстрации я установил таймер на 10 секунд.

sheet.write(row_num, 0, str(t_start_cm), style) #line 328
# sheet.write(row_num, 1, str(round(t_spending, 2)), style)
sheet.write(row_num, 1, str(class_name) + str(t), style)
row_num += 1
workbook.save('outputs/xlsx/parking/details.xls')

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

viol_matrix.append((str((class_name + str(t))))) #line 334
# print(t_start_cm, t_spending, datetime.now())
cropped = image.crop ((int(bbox[0]), int(bbox[1]), int(bbox[2]), int(bbox[3])))
croped.save(
'outputs/ caps_of_detections/parking/' + str(
class_name) + str(t) + str('.jpg'))

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

#Избегайте переполнения буфера #строка 353
if len(frame_matrix)›10⁷:
frame_matrix=[]

Большое спасибо за чтение. :). Не стесняйтесь оставлять комментарии или вопросы.