40 گام به سوی آینده‌ای هوشمند - مجموعه وبینارهای رایگان در حوزه هوش مصنوعی
Filter by دسته‌ها
chatGTP
آموزش هوش مصنوعی و انواع آن
آموزش‌های پایه‌ای هوش مصنوعی
اصول هوش مصنوعی
پایتون و ابزارهای یادگیری عمیق
کتابخانه‌ های یادگیری عمیق
یادگیری با نظارت
یادگیری بدون نظارت
یادگیری تقویتی
یادگیری عمیق
یادگیری نیمه نظارتی
آموزش‌های پیشرفته هوش مصنوعی
بینایی ماشین
پردازش زبان طبیعی
پردازش گفتار
چالش‌های عملیاتی
داده کاوی و بیگ دیتا
رایانش ابری و HPC
سیستم‌‌های امبدد
علوم شناختی
دیتاست
اخبار
تیتر یک
رسانه‌ها
آموزش پردازش زبان طبیعی
آموزش علوم داده
اینفوگرافیک
پادکست
ویدیو
رویدادها
کاربردهای هوش مصنوعی
کسب‌و‌کار
تحلیل بازارهای هوش مصنوعی
کارآفرینی
هوش مصنوعی در ایران
هوش مصنوعی در جهان
 ردیابی عابرین پیاده در دوربین های نظارتی با استفاده از کتابخانه Pytorch

ردیابی عابرین پیاده در دوربین های نظارتی با استفاده از کتابخانه Pytorch

مقدمه

سیستم‌های تشخیص و ردیابی عابرین پیاده در دوربین های نظارتی می‌توانند در قالب نرم‌افزارهای مختلفی ظاهر شوند. برای مثال:

  • کارکرد یکی از انواع این نرم‌افزارها به این ترتیب است که رفت‌وآمد مردم در چندین مسیر را بررسی کرده و نقشه حرارتی هر یک از آن مسیرها را تهیه می‌کند. سپس گزارشی ارائه می‌دهد که به ما نشان می‌دهد رفت‌وآمد افراد یا ترافیک انسانی در مکان‌های عمومی به چه شکل است.
  • این قبیل نرم‌افزارها می‌توانند به سازمان‌ها در کنترل و نظارت بر فاصله‌گذاری اجتماعی از طریق سیستم‌های نظارتی ویدیویی کمک کنند.
  • سیستم‌های شبیه‌سازی جمعیت می‌توانند از نتایج ارائه شده توسط این نوع از سیستم‌ها بهره ببرند.
  • شناسایی صفات عابرین پیاده یکی دیگر از حوزه‌هایی است که می‌توان در آن از این سیستم‌ها استفاده کرد.

در این مقاله، قصد دارم توضیح دهم که چطور با استفاده از کتابخانه‌ PyTorch و چارچوب flask یک لایه تعاملی Interaction layer را در سیستم ردیابی برخط عابرین پیاده در دوربین‌های نظارتی به‌کار گرفته‌ام.

در این مقاله، ابتدا به‌صورت خلاصه الگوریتم deep sort را معرفی می‌کنم و پس از آن عمدتاً به نکات طراحی وب‌سرور خواهم پرداخت. کدهای مربوط به این پروژه را می‌توانید در این لینک ملاحظه فرمایید.

مقدمه‌ای بر الگوریتم deep sort

براساس کتاب «Practical Computer Vision»، روش‌های کلاسیک ردیابی چند شیء به دو بخش تقسیم می‌شوند:

شناسایی: ابتدا تمامی اشیاء موردنظر شناسایی می‌شوند.

مطابقت: سپس اشیاء مشابه با توجه به فریم پیشین، با یک‌دیگر تطابق داده می‌شوند. پس از آن این فریم‌های تطبیق‌یافته دنبال می‌شوند تا ردپای یک شیء به دست آید.

اما این روش در الگوریتم deep sort به سه مرحله تقسیم می‌شود:

  1. شناسایی: در این مرحله برای محاسبه و شناسایی اشیاء از یک متود شناسایی اشیاء مبتنی بر شبکه عصبی پیچشی (Convolutional neural network (CNN   استفاده می‌شود (در این پروژه ما از YOLO You Only Look Once algorithm استفاده کردیم).
  2. برآورد: مرحله میانی این رویکرد که پیش از مرحله مطابقت قرار می‌گیرد، برآورد مدل است. در این مرحله وضعیت مسیر و ردپای هر یک از اشیاء به عنوان یک بردار با ۸ مقدار تعریف می‌شود که عبارتند از: مرکز کادر (x,y)، مقیاس کادر (s)، نسبت ابعاد کادر (a) و مشتقات آن‌ها در طول زمان که همان نرخ زمانی تغییر موقعیت است. سپس این وضعیت‌ها با استفاده از فیلتر کالمن Kalman filter  در قالب یک سیستم پویا مدل‌سازی می‌شوند. اگر در چندین فریم متوالی ردی از شی شناسایی نشود، آن شیء خارج از فریم یا گمشده درنظر گرفته می‌شود. و ردیابی کادر‌ جدیدی که شناسایی شده، آغاز خواهد شد.
  3. مطابقت: در مرحله آخر، با داشتن وضعیت پیش‌بینی‌شده توسط اطلاعات پیشین در فیلتر کالمن و کادر جدید شناسایی‌شده در فریم کنونی، شیء جدید با شیء که در فریم‌های پیشین ردیابی شده بود، مقایسه و مطابقت داده می‌شود. این کار با اعمال الگوریتم هانگاریان Hungarian algorithm  بر تطبیق نمودار دو بخشی bipartite graph matching   انجام می‌شود. همچنین می‌توان با فرمول‌بندی فاصله به تطبیق وزن داد و این فرآیند را تقویت کرد.

ردیابی عابرین پیاده در دوربین های نظارتی

برای آشنایی بیشتر با الگوریتم deep sort، پیشنهاد می‌کنم صفحات ۱۲۶ تا ۱۲۹ از کتاب «Practical Computer Vision» و این وبلاگ را مطالعه نمایید.

انگیزه

مدتی بود که در وبلاگ‌های مختلف به دنبال کدهای متن‌باز برنامه‌های شناسایی عابرین پیاده در ویدیوهای پخش زنده بودم و متأسفانه نتوانستم منبعی پیدا کنم که هم هوش مصنوعی و هم بخش‌های مربوط به سمت سرور را شامل شود. بنابراین، تصمیم گرفتم کدهای مربوطه را بنویسم به این امید که سایرین بتوانند با کمک این پروژه ساده، پروژه‌های پیشرفته‌تری تعریف کنند.

RTSP چیست؟

پروتکل پخش زنده (Real-Time Streaming Protocol (RTSP) (RTSP یک پروتکل برای کنترل شبکه در سیستم‌های ارتباطی است که به منظور کنترل پخش ویدیویی از سرورهای رسانه‌ای طراحی شده است. من در این نوشتار آموزشی فرض را بر این گذاشته‌ام که به لینک مربوط به پخش زنده دوربین‌هایی که قصد دارید این سرویس را روی آن‌ها آزمایش کنید، دسترسی دارید. درغیر این صورت، می‌توانید از ویدیوهای وب‌سایت earthcam.com استفاده کنید.

طراحی معماری

رویکرد ابتدایی

من در حوزه طراحی الگو و مهندسی سخت‌افزار تجربه کمی دارم، به همین دلیل در تلاش اول به این ساختار رسیدم:

اما فوراً متوجه ضعف‌های این رویکرد شدم:

ردیابی عابرین پیاده در دوربین های نظارتی

  • مسئله از دست رفتن بسته‌های داده‌ای در شبکه Network packet loss مواجه هستیم. این موضوع باعث می‌شود ویدیوی نهایی دارای تصاویری نامنظم بوده و تکه تکه باشد.
  • در این ساختار برای به‌کارگیری برنامه‌های هوش مصنوعی از ماژول subprocess و فرمان بَش استفاده کردم که باعث شد هیچ کنترلی بر روی برنامه مذکور نداشته باشم (زیرا تنها راه متوقف کردن این فرآیند، پیدا کردن PID Process Identifier فرآیند هوش مصنوعی بود).
  • در این ساختار، من توانایی تعویض دوربین ورودی بر روی دوربین دیگری را نداشتم. درواقع برای تغییر و تعویض دوربین باید لایه تعاملی را مجدداً راه‌اندازی می‌کردم (زیرا آغاز و پایان فرآیند هوش مصنوعی تنها با از کار انداختن و دوباره راه انداختن لایه تعاملی می باشد و بدون متوقف کردن لایه تعاملی نمی‌توان فرآیند هوش مصنوعی را متوقف کرد).
  • همچنین، برای هر درخواست جدید، تمام سرویس باید از ابتدا شروع به کار می‌کرد و پس از چند درخواست جدید، سرور به دلیل درخواست بیش‌ازحد منابع از کار می‌افتاد.

به این ترتیب، من متوجه شدم که اغلب مشکلات به دلیل همبستگی شدید فرمان‌های هوش مصنوعی با ماژول‌های لایه تعاملی است و تصمیم گرفتم که یک ماژول غیر همزمان async module  به نام رِدیس (Redis) را به مدل اضافه کنم تا از شدت این همبستگی بکاهد.

بهبود رویکرد ابتدایی با افزودن ماژول ذخیره‌ساز

به لطف مقاله آقای آدریان رزبروک به نام «Deep learning in production with Keras, Redis, Flask, and Apache»، متوجه اهمیت استفاده از ماژول ردیس برای ذخیره‌سازی فریم‌ها در وب‌سرور شدم و به ساختار زیر رسیدم:

هر یک دایره‌های سیاه‌رنگ در تصویر بالا نشان‌دهنده یکی از مراحل زیر است:

ردیابی عابرین پیاده در دوربین های نظارتی

  1. وقتی وب‌سرور روشن شود، با دادن ورودی‌های پیش‌فرض به سرویس شناسایی عابرین پیاده، آن را راه‌اندازی می‌کند.
  2. سرویس شناسایی عابرین پیاده لینک پروتکل پخش زنده (RTSP) را به عنوان ورودی به دوربین نظارتی می‌دهد و با استفاده از نخ‌ها ورودی‌های ویدیویی را می‌خواند.
  3. پس از تمام شدن کار الگوریتم هوش مصنوعی با هر فریم، فریم خروجی در ردیس ذخیره می‌شود (در هر مرحله، فریم جدید با خروجی مرحله پیشین جایگزین می‌شود).
  4. لایه تعاملی فریم‌های پردازش‌شده را از ردیس دریافت می‌کند.
  5. لایه تعاملی امکان پخش فرآیند شناسایی عابرین را از طریق لینک ۰.۰.۱:۸۸۸۸/ برای کاربران فراهم می‌کند.

این ساختار چگونه عملکرد سیستم را بهبود می‌بخشد؟

  • در این سیستم همواره با مشکل از دست رفتن بسته‌های داده‌ای مواجهیم. برای تقویت پایداری robustness سیستم برای مواجهه با این مشکل، فرآیند خواندن محتوای دوربین توسط نخ‌ها انجام می‌گیرد.
  • از آن‌جا که کنترل فرآیند هوش مصنوعی به طور کامل در اختیار لایه تعاملی است، این لایه می‌تواند بدون هیچ مشکلی فرایند پردازش را به روی دوربین دیگری تعویض کند.
  • Redis به عنوان یک ماژول غیرهمزمان می‌تواند لایه تعاملی را از فرآیند هوش مصنوعی جدا سازد. به این ترتیب، لایه تعاملی دیگر یک مرحله از فرآیند هوش مصنوعی را بارها و بارها تکرار نخواهد کرد و ما قادر خواهیم شد تا این چارچوب را در مقیاس گسترده‌تر به‌کار بگیریم و سیستم شناسایی عابرین پیاده را به‌طور هم‌زمان روی چندین دوربین اجرا کنیم.

کدنویسی

من در این پروژه از کتابخانه‌های زیر استفاده کرده‌ام:

    Python 3.7

    Opencv-python

    Sklearn

    Torch > 0.4

    Torchvision >=0.1

    Pillow

    Easydict

    Redis

    Dotenv

    Flask

من این پروژه را روی سیستم عامل Ubuntu 16.04 و GPU مدل Nvidia GeForce GTX 2080 اجرا کردم.

برای عملیات ذخیره‌سازی نیز ماژول Redis را نصب کردم و آن را روی پورت ۶۳۷۹ اجرا کردم. آموزش کامل نصب Redis را می‌توانید در این لینک مشاهده نمایید.

مرحله اول کدنویسی: ضبط ویدیو در پروتکل پخش زنده

در مرحله اول تنها سعی کردم فریم‌های ویدیو را ضبط کرده و در ردیس ذخیره کنم. اشیای cv2.VideoCapture در کتابخانه OpenCV به‌طور پیش‌فرض می‌توانند به داده‌هایی که دوربین تولید می‌کند، رسیدگی کنند. اما براساس این نوشتار، ظاهراً احتمال از دست رفتن بسته‌های داده‌ای در این ماژول وجود دارد. بنابراین، من از نخ‌ها برای غلبه بر این مشکل استفاده کردم. در کادر زیر می‌توانید کد اولیه را ملاحظه فرمایید:

مرحله دوم کدنویسی: افزودن کد سرویس شناسایی عابرین پیاده

import cv2 
from concurrent.futures import ThreadPoolExecutor
from redis import Redis

redis_cache = Redis('127.0.0.1')

class RealTimeTracking(object):
    def __init__(self, src):

        self.vdo = cv2.VideoCapture(self.args.input)
        self.status, self.frame = None, None
        self.output_frame = None
        self.thread = ThreadPoolExecutor(max_workers=1)
        self.thread.submit(self.update)

    def update(self):
        while True:
            if self.vdo.isOpened():
                (self.status, self.frame) = self.vdo.read()

    def run(self):
        print('streaming started ...')
        while True:
            try:
                redis_cache.set('frame', frame_to_bytes)
            except AttributeError:
                pass

خواندن فریم‌های RTSP با استفاده از نخ‌ها برای حل مسئله از دست رفتن بسته‌های داده‌ای


کد سرویس شناسایی عابرین پیاده در ویدیوهای ساده را می‌توانید در این لینک مشاهده کنید. با ترکیب این کد و کدی که در مرحله اول نوشتم، به کد زیر میرسیم:

import warnings
from os import getenv
import sys
from os.path import dirname, abspath

sys.path.append(dirname(dirname(abspath(__file__))))

import torch
from deep_sort import build_tracker
from detector import build_detector
import cv2
from utils.draw import compute_color_for_labels
from concurrent.futures import ThreadPoolExecutor
from redis import Redis

redis_cache = Redis('127.0.0.1')


class RealTimeTracking(object):
    """
    This class is built to get frame from rtsp link and continuously
    assign each frame to an attribute namely as frame in order to
    compensate the network packet loss. then we use flask to give it
    as service to client.
    Args:
        args: parse_args inputs
        cfg: deepsort dict and yolo-model cfg from server_cfg file
    """

    def __init__(self, cfg, args):
        # Create a VideoCapture object
        self.cfg = cfg
        self.args = args
        use_cuda = self.args.use_cuda and torch.cuda.is_available()

        if not use_cuda:
            warnings.warn(UserWarning("Running in cpu mode!"))

        self.detector = build_detector(cfg, use_cuda=use_cuda)
        self.deepsort = build_tracker(cfg, use_cuda=use_cuda)
        self.class_names = self.detector.class_names

        self.vdo = cv2.VideoCapture(self.args.input)
        self.status, self.frame = None, None
        self.im_width = int(self.vdo.get(cv2.CAP_PROP_FRAME_WIDTH))
        self.im_height = int(self.vdo.get(cv2.CAP_PROP_FRAME_HEIGHT))

        self.output_frame = None

        self.thread = ThreadPoolExecutor(max_workers=1)
        self.thread.submit(self.update)

    def update(self):
        """
        Repeatedly reading frames from camera using threads
        """
        while True:
            if self.vdo.isOpened():
                (self.status, self.frame) = self.vdo.read()

    def run(self):
        """
        Until the in_progress flag is not set as off, keep reading and processing
        pedestrian detection.
        """
        print('streaming started ...')
        while getenv('in_progress') != 'off':
            try:
                frame = self.frame.copy()
                self.detection(frame=frame)
                frame_to_bytes = cv2.imencode('.jpg', frame)[1].tobytes()
                redis_cache.set('frame', frame_to_bytes)
            except AttributeError:
                pass
        print('streaming stopped ...')


    def detection(self, frame):
        """
        Detection, tracking and drawing the bboxes on pedestrians
        """
        im = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        # do detection
        bbox_xywh, cls_conf, cls_ids = self.detector(im)
        if bbox_xywh is not None:
            # select person class
            mask = cls_ids == 0

            bbox_xywh = bbox_xywh[mask]
            bbox_xywh[:, 3:] *= 1.2  # bbox dilation just in case bbox too small
            cls_conf = cls_conf[mask]

            # do tracking
            outputs = self.deepsort.update(bbox_xywh, cls_conf, im)

            # draw boxes for visualization
            if len(outputs) > 0:
                self.draw_boxes(img=frame, output=outputs)

    @staticmethod
    def draw_boxes(img, output, offset=(0, 0)):
        # Draws bboxes on the detcted pedestrians
        for i, box in enumerate(output):
            x1, y1, x2, y2, identity = [int(ii) for ii in box]
            x1 += offset[0]
            x2 += offset[0]
            y1 += offset[1]
            y2 += offset[1]

            # box text and bar
            color = compute_color_for_labels(identity)
            label = '{}{:d}'.format("", identity)
            t_size = cv2.getTextSize(label, cv2.FONT_HERSHEY_PLAIN, 2, 2)[0]
            cv2.rectangle(img, (x1, y1), (x2, y2), color, 3)
            cv2.rectangle(img, (x1, y1), (x1 + t_size[0] + 3, y1 + t_size[1] + 4), color, -1)
            cv2.putText(img, label, (x1, y1 + t_size[1] + 4), cv2.FONT_HERSHEY_PLAIN, 2, [255, 255, 255], 2)
        return img

کدهای تشخیص عابرین پیاده


در ادامه به تشریح برخی از تغییرات مهم می‌پردازیم:

  • در خط ۶۷ و در تابع in_progress، flag، متغیری است که بعدها در py مقداردهی خواهد شد. در این‌جا هرگاه بخواهیم اجرای کد هوش مصنوعی را متوقف کنیم، کافی است مقدار این متغیر را off تعریف می‌کنیم و هرگاه بخواهیم فرآیند هوش مصنوعی آغاز شود مقدار on  را برای آن تعریف می‌کنیم. این ترفند ما را قادر می‌سازد تا سرویس هوش مصنوعی را در سایر فرآیندها (برای مثال، rtsp_server که نخ اصلی درحال اجراست) آغاز کرده یا متوقف سازیم.
  • در خطوط ۷۸ تا ۹۸ تابعdetection به کدها اضافه شده است. این تابع وظیفه شناسایی، برآورد و مطابقت عابرین را در الگوریتم deep sort برعهده دارد.
  • در خطوط ۱۰۰ تا ۱۱۷ نیز تابع draw_bboxes را افزودیم تا کادرهای مرزی و کد شناسایی برای عابرین تعریف شود.

مرحله سوم کدنویسی: اضافه کردن وب‌سرور

اساساً در وب‌سرور برای اجرای این برنامه به ۲ ابزار احتیاج داریم. یک ابزار برای بازیابی فریم‌های ذخیره‌شده در Redis و تبدیل آن‌ها به لینک HTTP. و یک ابزار دیگر که به ما امکان فعال‌سازی و متوقف کردن سرویس هوش مصنوعی را بدهد. به‌منظور تهیه ابزار اول یک قالب HTML به نام index.html ساختم و سپس آن را در مسیر templates قرار دادم. با استفاده از این قالب می‌توان تصاویری که توسط وب‌سرور تهیه شده‌اند را به کاربران نمایش داد.

<html lang="en">
  <head>
    <title>Camera #1 </title>
  </head>
  <body>
    <h1>Floor 2 </h1>
    <img src="{{ url_for('video_feed') }}">
  </body>
</html>

سمت کاربر


و برای پیکربندی پارامترهای deep sort و مدل تشخیص عابر پیاده YOLO، فایل کدهای server_cfg.py را نیز به کدهای پیشین اضافه کردم:

"""
Configuring deep learning models parameters in dictionary variables.
"""
import sys
from os.path import dirname, abspath, isfile

sys.path.append(dirname(dirname(abspath(__file__))))

from dotenv import load_dotenv
from utils.asserts import assert_in_env
from os import getenv
from os.path import join

load_dotenv('.env')
# Configure deep sort info
deep_sort_info = dict(REID_CKPT=join(getenv('project_root'), getenv('reid_ckpt')),
                      MAX_DIST=0.2,
                      MIN_CONFIDENCE=.3,
                      NMS_MAX_OVERLAP=0.5,
                      MAX_IOU_DISTANCE=0.7,
                      N_INIT=3,
                      MAX_AGE=70,
                      NN_BUDGET=100)
deep_sort_dict = {'DEEPSORT': deep_sort_info}

# Configure yolov3 info

yolov3_info = dict(CFG=join(getenv('project_root'), getenv('yolov3_cfg')),
                   WEIGHT=join(getenv('project_root'), getenv('yolov3_weight')),
                   CLASS_NAMES=join(getenv('project_root'), getenv('yolov3_class_names')),
                   SCORE_THRESH=0.5,
                   NMS_THRESH=0.4
                   )
yolov3_dict = {'YOLOV3': yolov3_info}

# Configure yolov3-tiny info

yolov3_tiny_info = dict(CFG=join(getenv('project_root'), getenv('yolov3_tiny_cfg')),
                        WEIGHT=join(getenv('project_root'), getenv('yolov3_tiny_weight')),
                        CLASS_NAMES=join(getenv('project_root'), getenv('yolov3_class_names')),
                        SCORE_THRESH=0.5,
                        NMS_THRESH=0.4
                        )
yolov3_tiny_dict = {'YOLOV3': yolov3_tiny_info}


check_list = ['project_root', 'reid_ckpt', 'yolov3_class_names', 'model_type', 'yolov3_cfg', 'yolov3_weight',
              'yolov3_tiny_cfg', 'yolov3_tiny_weight', 'yolov3_class_names']

if assert_in_env(check_list):
    assert isfile(deep_sort_info['REID_CKPT'])
    if getenv('model_type') == 'yolov3':
        assert isfile(yolov3_info['WEIGHT'])
        assert isfile(yolov3_info['CFG'])
        assert isfile(yolov3_info['CLASS_NAMES'])
        model = yolov3_dict.copy()

    elif getenv('model_type') == 'yolov3_tiny':
        assert isfile(yolov3_tiny_info['WEIGHT'])
        assert isfile(yolov3_tiny_info['CFG'])
        assert isfile(yolov3_tiny_info['CLASS_NAMES'])
        model = yolov3_tiny_dict.copy()
    else:
        raise ValueError("Value '{}' for model_type is not valid".format(getenv('model_type')))

پیکربندی مدل یادگیری عمیق


من در تمامی پروژه‌هایم یک فایل .env ایجاد می‌کنم و اطلاعات مربوط به فایل‌های ایستا از جمله وزن‌های مدل، فایل‌های پیکربندی و دیتاست‌ها را در آن قرار می‌دهم.

  • در خط ۱۶ و ۲۸ مدل‌های YOLO و deep sort را با استفاده از آدرس محل نگهداری‌شان در فایل .env بازیابی کرده‌ام. زمان‌هایی که می‌خواهم سرویس‌ها را به بخش سرور ببرم، این ترفند برای من بسیار کارآمد است. درادامه متغیرهای model و deep_sort_dict را نیز به فایل py اضافه می‌کنم.

و درنهایت کد وب‌سرور به این شکل خواهد بود:

"""
This code handles the pedestrian detection service on specified camera.
Also provides stream images for clients.
"""

from os.path import join
from os import getenv, environ
from dotenv import load_dotenv
import argparse
from threading import Thread

from redis import Redis
from flask import Response, Flask, jsonify, request, abort

from rtsp_threaded_tracker import RealTimeTracking
from server_cfg import model, deep_sort_dict
from config.config import DevelopmentConfig
from utils.parser import get_config

redis_cache = Redis('127.0.0.1')
app = Flask(__name__)
environ['in_progress'] = 'off'


def parse_args():
    """
    Parses the arguments
    Returns:
        argparse Namespace
    """
    assert 'project_root' in environ.keys()
    project_root = getenv('project_root')
    parser = argparse.ArgumentParser()

    parser.add_argument("--input",
                        type=str,
                        default=getenv('camera_stream'))

    parser.add_argument("--model",
                        type=str,
                        default=join(getenv('model_type')))

    parser.add_argument("--cpu",
                        dest="use_cuda",
                        action="store_false", default=True)
    args = parser.parse_args()

    return args


def gen():
    """
    Returns: video frames from redis cache
    """
    while True:
        frame = redis_cache.get('frame')
        if frame is not None:
            yield b'--frame\r\n'b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n'


def pedestrian_tracking(cfg, args):
    """
    starts the pedestrian detection on rtsp link
    Args:
        cfg:
        args:
    Returns:
    """
    tracker = RealTimeTracking(cfg, args)
    tracker.run()


def trigger_process(cfg, args):
    """
    triggers pedestrian_tracking process on rtsp link using a thread
    Args:
        cfg:
        args:
    Returns:
    """
    try:
        t = Thread(target=pedestrian_tracking, args=(cfg, args))
        t.start()
        return jsonify({"message": "Pedestrian detection started successfully"})
    except Exception:
        return jsonify({'message': "Unexpected exception occured in process"})


@app.errorhandler(400)
def bad_argument(error):
    return jsonify({'message': error.description['message']})


# Routes
@app.route('/stream', methods=['GET'])
def stream():
    """
    Provides video frames on http link
    Returns:
    """
    return Response(gen(),
                    mimetype='multipart/x-mixed-replace; boundary=frame')


@app.route("/run", methods=['GET'])
def process_manager():
    """
    request parameters:
    run (bool): 1  -> start the pedestrian tracking
                ۰  -> stop it
    camera_stream: str -> rtsp link to security camera
    :return:
    """
    # data = request.args
    data = request.args
    status = data['run']
    status = int(status) if status.isnumeric() else abort(400, {'message': f"bad argument for run {data['run']}"})
    if status == 1:
        # if pedestrian tracking is not running, start it off!
        try:
            if environ.get('in_progress', 'off') == 'off':
                global cfg, args
                vdo = data.get('camera_stream')
                if vdo is not None:
                    args.input = int(vdo)
                environ['in_progress'] = 'on'
                return trigger_process(cfg, args)
            elif environ.get('in_progress') == 'on':
                # if pedestrian tracking is running, don't start another one (we are short of gpu resources)
                return jsonify({"message": " Pedestrian detection is already in progress."})
        except Exception:
            environ['in_progress'] = 'off'
            return abort(503)
    elif status == 0:
        if environ.get('in_progress', 'off') == 'off':
            return jsonify({"message": "pedestrian detection is already terminated!"})
        else:
            environ['in_progress'] = 'off'
            return jsonify({"message": "Pedestrian detection terminated!"})


if __name__ == '__main__':
    load_dotenv()
    app.config.from_object(DevelopmentConfig)

    # BackProcess Initialization
    args = parse_args()
    cfg = get_config()
    cfg.merge_from_dict(model)
    cfg.merge_from_dict(deep_sort_dict)
    # Start the flask app
    app.run()

برنامه وب‌سرور که کنترل سرویس مبتنی بر هوش مصنوعی را برعهده دارد


حال بیایید این کد را با جزییات بررسی کنیم:

  • در خطوط ۲۳ تا ۲۵ سرور flask، ردیس و flag تابع in_progress را تعریف و مقداردهی کرده‌ام.
  • در خطوط ۲۶ تا ۴۹ تابع argument parser را تعریف کرده‌ام.
  • در خط ۵۲ تا ۵۹ نیز تابع gen فریم‌های ذخیره‌شده در بخش شناسایی عابرین پیاده را به ما برمی‌گرداند. من از تابع stream نیز به‌منظور ارائه فریم‌های پردازش‌شده به کاربران استفاده کرده‌ام که فریم‌ها را به قالب html درمی‌آورد (در خطوط ۹۵ تا ۱۰۰).
  • در خطوط ۶۲ تا ۷۱، تابع pedestrian_tracking فرآیند ردیابی عابرین پیاده را آغاز می‌کند. برای اجرای این اقدام نیز از تابع trigger_process استفاده کرده‌ام (در خطوط ۷۴ تا ۸۷).
  • سرانجام در خطوط ۱۰۶ تا ۱۴۰ تابع process_manager ، تابع اصلی است که از طریق آدرس ۰.۰.۱:۸۸۸۸/run درخواست GET را از سوی کاربران دریافت می‌کند. هر درخواست مربوط به این لینک دارای حداکثر ۲ پارامتر است. اولین پارامتر run می‌باشد که دستور آغاز (زمانی که مقدار آن برابر ۱ قرار گیرد) یا توقف (زمانی که مقدار صفر برای آن تعریف شود) را می‌دهد. پارامتر بعدی camera_stream است که درواقع همان لینک RTSP شامل محتوای ویدیویی دوربین بوده و مقدار آن درنهایت برابر ورودی ویدیویی جدید است که به سرویس شناسایی عابرین پیاده داده می‌شود (خطوط ۱۲۲ تا ۱۲۸).
  • زمانی که سرویس شناسایی عابرین در چند دوربین در حال اجرا باشد، آغاز یک سرویس جدید غیرممکن است. بنابراین، پاسخ هر درخواستی که در آن مقدار run مساوی ۱ باشد، با عبارت pedestrian detection is already in progress پاسخ داده می‌شود (خط ۱۳۱). همین اتفاق در زمان ارسال درخواست متوقف کردن سرویس نیز رخ خواهد داد (خط ۱۳۷).

در آخر باید چند مجوز و سند نیز به این تابع اضافه شود که آن‌ها را در Github قرار خواهم داد.

چکیده

در این مقاله سرویس شناسایی عابرین پیاده را به روشی ساده روی دوربین‌های نظارتی اجرا کردیم و آموختیم که نحوه طراحی معماری در تعمیم‌پذیری Scalability این برنامه تا چه حد تأثیرگذار است. در این پروژه یک ابزار ذخیره‌سازی به نام ردیس به ما کمک کرد تا بتوانیم با جداسازی فرآیند شناسایی عابرین از بخش وب‌سرور، ساختار بهتری طراحی کنیم. همچنین، یک API ساده تهیه کردیم که با استفاده از آن توانستیم فرآیند شناسایی عابرین و ورودی‌های آن را کنترل کنیم.

در آخر باید از آقای آدریان رزبروک بابت پست‌ها عالی وبلاگ‌شان (به ویژه این پست) که مرا در مسیر اجرای این پروژه راهنمایی کرد، تشکر کنم. همچنین باید از آقای ژیانگ پی نیز بابت در دسترس قرار دادن رویکرد خود در زمینه شناسایی عابرین به صورت متن‌باز، تشکر کنم.

انواع کاربردهای هوش مصنوعی در صنایع مختلف را در هوشیو بخوانید

میانگین امتیاز / ۵. تعداد ارا :

مطالب پیشنهادی مرتبط

اشتراک در
اطلاع از
0 نظرات
بازخورد (Feedback) های اینلاین
مشاهده همه دیدگاه ها
[wpforms id="48325"]