فناوری تشخیص حرکت انسات یا Human Acrion Recognition ، براساس تجزیه و تحلیل فیلم های ویدیویی برای پیش بینی یا طبقه بندی حرکات مختلف انجام شده توسط شخص در ویدیو است. از این فناوری در زمینه های وسیعی مانند نظارتی ، ورزش و تناسب اندام ، دفاعی و… استفاده می شود.
فرض کنید شما می خواهید اپلیکیشنی برای آموزش آنلاین یوگا بسازید. در این اپلیکیشن باید فهرستی از ویدیوهای از پیش ضبط شده از جلسات یوگا ، به کاربران ارائه شود. پس از تماشای یک ویدیو در برنامه ، کاربران می تواند ویدیو های تمرینات شخصی خود را آپلود کنند. سپس برنامه، نوع عملکرد آن ها را ارزیابی می کند و براساس میزان بهتر انجام دادن حرکات یوگا بازخورد ارائه می دهد.
آیا بهتر نیست به منظور خودکارسازی ارزیابی حرکات در ویدیو، از شناسایی و تشخیص حرکات با بینایی ماشین و هوش مصنوعی استفاده کنیم؟ با پردازش تصویر می توانید کار های بسیار زیادی در این زمینه انجام دهید.
اپلیکیشن مخصوص ورزش یوگا که در تصویر زیر نشان داده شده است، از تخمین حالات حرکات انسان برای شناسایی ژست ها و نوع حرکات یوگا استفاده می کند.
در این مقاله می خواهیم در مورد نحوه ساخت اپلیکیشن با هدف تشخیص حرکات و کنش های انسان و یا طبقه بندی آن ها با استفاده از Detectron2 و LSTM ( حافظه کوتاه مدت ) توضیحاتی را خدمت شما رائه دهیم.
ما یک برنامه تحت وب ایجاد خواهیم کرد که یک ویدیو را به عنوان برنامه ورودی دریافت می کند و سپس بر اساس ویدیو ورودی داده شده به آن ، یک ویدیوی خروجی ارائه کرده که حرکات شناسایی شده در آن علامت گذاری شده است. ما از چارچوب Flask برای برنامه وب و از PyTorch Lighting برای آموزش و اعتبارسنجی استفاده خواهیم کرد.
فهرست مطالب
علاوه بر Flask ، ما می خواهیم چند ابزار و اپلیکیشن مهم دیگر مانند Detectron2 ،LSTM ،مجموعه داده حرکات و… را برای رسیدن به اهداف مورد نظری که در اول مقاله مطرح شد به کار گیریم و در مورد هر کدام به تفصیل توضیح خواهیم داد.
Dectectron2
Detectron2 پلتفرم منبع باز تحقیقات هوش مصنوعی فیسبوک برای تشخیص اشیا، ژست های متراکم، ناحیه بندی و سایر وظایف تشخیص بصری است. این پلتفرم برخلاف نسخه قبلی آن که در Caffe2 پیاده سازی شده بود، اکنون بر روی برنامه PyTorch پیاده سازی شده است.
در این جا، ما از مدل از پیش آموزش دیده R50PPN در Detectron2 برای تخمین حرکات و ژست ها استفاده می کنیم. این مدل در حاضر بر روی مجموعه داده COCO که شامل بیش از ۲۰۰,۰۰۰ تصویر و ۲۵۰,۰۰۰ نفر به عنوان نمونه است، آموزش داده شده که با نقاط کلیدی مشخص شده است. همان طور که در تصویر زیر نشان داده شده است، برای هر انسان حاضر در تصویر ورودی، ۱۷ نقطه کلیدی از حرکات انسان را خروجی داده است.
اگر می خواهید در مورد اجرای داخلی الگوریتم تخمین ژست ها بیشتر بدانید، پس نگاهی به این پست بیندازید.
LSTM
شبکه LSTM، نوعی شبکه عصبی بازگشتی(RNN) است. شبکه های LSTM، قادر به یادگیری وابستگی ترتیب در مسائل پیش بینی و توالی هستند. همان طور که در شکل زیر می توانید مشاهده کنید، یک شبکه عصبی بازگشتی ، دارای یک سلسله مراتب تکراری از ماژول های شبکه عصبی است.
در شبکه عصبی (NN) :
- X0 و X1 تا Xt قسمت ورودی را تشکیل می دهد و h0 و h1 تا ht ، پیش بینی ها هستند.
- هر پیش بینی در زمان t ( یعنی ht ) بستگی به پیش بینی قبلی و ورودی اخیر یعنی Xt دارد.
شبکه عصبی بازگشتی ، اطلاعات پیشین را به یاد می آورد و از آن به طور بهینه ای برای پردازش ورودی های اخیر استفاده می کند. اما یکی از نقاط ضعف و کاستی های شبکه عصبی بازگشتی این است که نمی تواند وابستگی های طولانی مدت را به خاطر سپارد.
LSTM نیز دارای یک ساختار زنجیره ای مشابه است. اما ماژول های شبکه عصبی بازگشتی به آسانی می تواند وابستگی های طولانی مدت را هم مدیریت کند.
ما از LSTM برای کلاسه بندی حرکات بر اساس دنباله ای از نقاط کلیدی تشخیص داده شده روی ویدیو استفاده خواهیم کرد.
مجموعه داده
برای آموزش مدل LSTM ، از این مجموعه داده استفاده می کنیم.
اما این مجموعه داده چه ویژگی خاصی دارد؟ این مجموعه داده شامل تشخیص نقاط کلیدی است که با استفاده از مدل یادگیری عمیق OpenPose ، بر روی زیرمجموعه ای از مجموعه داده های پایگاه داده ، اقدامات انسانی چندوجهی برکلی (MHAD) ساخته شده اند.
OpenPose ، اولین سیستم Real-Time و چند نفره است که به طور مشترک، نقاط کلیدی بدن انسان، دست، صورت و پا (در مجموع ۱۳۵ نقطه کلیدی) را روی تصاویر تکی تشخیص می دهد.
تشخیص نقاط کلیدی روی ویدیوهای ۱۲ سوژه ( فیلمبرداری از ۴ زاویه) انجام شده و ۶ عمل زیر را در ۵ دور تکرار انجام می دهند.
مجموعه ای از ۶ عمل و حرکت انسانی (پرش، حرکات پروانه، مشت زدن، دست تکان دادن با یک دست، دست تکان دادن با دو دست، حالت کف زدن) از زیرمجموعه های MHAD است.
- پرش
- حرکت پروانه
- مشت زنی
- دست تکان دادن با یک دست
- دست تکان دادن با دو دست
- کف زدن
Flask
یک اپلیکیشن محبوب در PyTorch بر پایه وب است که برای توسعه چندین برنامه وب استفاده شده است. این برنامه به صورت داخلی از مدل Detectron2 و LSTM برای شناسایی حرکات استفاده می کند.
روش سطح بالا برای دستیابی به تشخیص حرکات
برای طبق بندی هر کنش در درجه اول نیاز به مکان یابی بخش های مختلف بدن در هر فریم داریم و در مرحله بعدی آن ، باید حرکات بخش های مختلف بدن انسان در طول زمان تجزیه و تحلیل کنیم.
قدم اول، استفاده از Detectron2 انجام می گیرد که از حرکات و کنش های بدن انسان را در هر فریم ویدیو، خروجی بدهد(۱۷ نفطه کلیدی).
قدم دوم ، آنالیز حرکات بدن در هر لحظه از زمان و انجام پیش بینی با استفاده از شبکه LSTM است. بنابراین برای طبقه بندی کنش ها، نقاط کلیدی در یک دنباله از فریم های مختلف ، به LSTM فرستاده می شود.
آموزش مدل های یادگیری ماشین برای تشخیص کنش و حرکت
- همان طور که قبلا هم گفته شد، برای تشخیص نقاط کلیدی، ما از مدل از پیش آموزش دیده R50-FPN گرفته شده از مدل های Detectron2 استفاده می کنیم. پس نیازی به هیچ گونه آموزش جانبی نیست.
- مدل LSTM که برای طبقه بندی کنش ها استفاده شده، براساس نقاط کلیدی است که آموزش آن با استفاده از PyTorch Lighting صورت گرفته است.
داده های ورودی آموزش شامل دنباله نقاط کلیدی (۱۷ نقطه کلیدی در هر فریم) و برچسب کنش های مربوطه است. از یک دنباله پیوسته ۳۲ فریمی برای شناسایی حرکات خاص استفاده شده. یک دنباله نمونه ۳۲ فریمی ، یک آرایه چند بعدی به اندازه ۳۲*۳۴ به شرح زیر خواهد بود:
هر ردیف شامل ۱۷ نقطه کلیدی است . هر نقطه کلیدی، با مقادیر ( x و y ) نشان داده می شود. بنابراین در مجموع ۳۴ مقدار در هر ردیف وجود دارد.
نکته: برخلاف ۱۸ نقطه کلیدی که توسط مدل OpenPose در مجموعه داده اصلی نشان داده شده ، برنامه ما فقط ۱۷ نقطه کلیدی دارد که توسط Detectron2 شناسایی شده است. بنابراین قبل از آموزش مدل LSTM خود، آن را تبدیل به فرمت ۱۷ نقطه کلیدی می کنیم.
ما مدل خود را در ۴۰۰ دوره آموزش داده ایم و دقت اعتبار ۰٫۹۱۳ را به دست آوردیم. منحنی های صحت اعتبارسنجی در شکل زیر نشان داده شده است. مدل آموزش دیده در پایگاه کد بررسی می شود و در هنگام استنباط از آن استفاده می شود.
استنباط
خط سیر استنباطی شامل دو مدل Detectron2 و مدل سفارشی LSTM است.
- یک ویدیوی ورودی وارد برنامه می شود که از طریق فریم ها تکرار می شود و سپس از Detectron2 برای تشخیص نقاط کلیدی در هر فریم استفاده می کند.
- در مرحله بعد ، نتایج مربوط به نقاط کلیدی ، به یک بافر به اندازه ۳۲ اضافه می شود که به صورت یک پنجره کشویی عمل می کند.
- در نهایت محتوای بافر برای شناسایی کنش ها به مدل آموزش دیده LSTM فرستاده می شود.
- بنابراین برنامه وب مبتنی بر Flask ، دارای یک رابط کابری برای پذیرش ویدیوی ورودی از سمت کاربر است.
- کنش های شناسایی شده توسط خط سیر استنباطی ما در ویدیوی تفسیرشده و به عنوان نتیجه نمایش داده می شود.
آزمایش روی پردازنده گرافیکی ( Tesla T4 ) نشان می دهد که Detectron2 به ترتیب حدود ۰٫۱۴ ثانیه و LSTM حدود ۰٫۰۰۲ ثانیه برای استنباط و استنتاج به زمان نیاز دارند. از این رو، ترکیب FPS (فریم بر ثانیه)، در خط سیر استنباطی ما به حدوئد ۶ فریم در ثانیه می رسد؛ البته اگر بخوایم تمام فریم های ویدیو را پردازش کنیم.
نرخ FPS بالا ممکن است برای برنامه ای که به صورت آفلاین تجزیه و تحلیل ویدیو را انجام می دهد، کاربردی باشد. اما اگر بخواهیم استنباط ویدیو زنده را به صورت Real-Time انجام دهیم چطور؟ به طور کلی، ویدیو های پخش زنده، دارای نرخ ۳۰ فریم در ثانیه و یا بیشتر هستند (بسته به دوربین). در چنین مواردی، خط FPS استنباط در خط لوله (Pipeline) ما باید بالا تر و یا حداقل برابر با FPS ویدیوی پخش زنده باشد تا فریم ها بدون هیچ تاخیری پردازش شوند. با وجود پایین بودن میزان نرخ فریم، شما برای بهبود FPS گزینه های زیادی پیش رو دارید.
فیلترینگ و کمی سازی مدل می تواند سرعت اجرای برنامه را تسریع کند.
- نادیده گرفتن فریم ها و استنباط در فواصل زمانی : شما می توانید چند فریم را نادیده بگیرید و فقط در فواصل زمانی مشخص ویدیو، استنباط را انجام دهید. به عنوان مثال، آزمایش ها نشان می دهد که هنگام استنباط را در هر ۵ فریم یک بار انجام دهیم، میزان نرخ FPS به ۲۷ فریم در ثانیه افزایش می یابد. اما مشاهده شد که دقت آن کاهش پیدا کرد. بنابراین برای انجام استنباط ، یک بازه زمانی مناسب باید انتخاب کنید.
- استفاده از چند رشته (ترد) : برای دریافت و استنباط ویدیو، رشته های مجزا داشته باشید.
- رشته دریافت کننده می تواند بر خواندن فریم های ویدیو پخش زنده و اضافه کردن آن ها به صف تمرکز کند.
- یک رشته کوچک جداگانه می تواند فریم ها را به منظور انجام استنباط ، از داخل صف روخوانی کند. این رشته جانبی ممکن است در هنگام پردازش فریم ها دچار تغییر شود؛ اما مانع رشته دریافت کننده برای خواندن ویدیوهای پخش زنده نخواهد شد.
کدنویسی مدل های Detectron2 و LSTM برای آنالیزهای ویدیویی در برنامه وب
بیایید اکنون نحوه کدنویسی بخش های اصلی برنامه را بررسی کنیم.
۱- مدل تخمین حالت Detectron2
همان طور که در شکل زیر نشان داده شده، ما از Detectron2 آموزش دیده استفاده می کنیم.
# obtain detectron2's default config cfg = get_cfg() # load the pre trained model from Detectron2 model zoo cfg.merge_from_file(model_zoo.get_config_file("COCO-Keypoints/keypoint_rcnn_R_50_FPN_3x.yaml")) # set confidence threshold for this model cfg.MODEL.ROI_HEADS.SCORE_THRESH_TEST = 0.5 # load model weights cfg.MODEL.WEIGHTS = model_zoo.get_checkpoint_url("COCO-Keypoints/keypoint_rcnn_R_50_FPN_3x.yaml") # create the predictor for pose estimation using the config pose_detector = DefaultPredictor(cfg)
۲- تعریف مدل LSTM
مدل LSTM با میزان ابعاد مخفی (hidden_dim) 50 مقداردهی شده و توسظ برنامه PyTorch Lighting آموزش داده شده است. ما از بهینه ساز Adam و همچنین از برنامه پیکربندی شده ReducelRonPlateau ، براساس مقدار val_loss و برای کاهش نرخ یادگیری استفاده کرده ایم.
# We have 6 output action classes. TOT_ACTION_CLASSES = 6 #lstm classifier definition class ActionClassificationLSTM(pl.LightningModule): # initialise method def __init__(self, input_features, hidden_dim, learning_rate=0.001): super().__init__() # save hyperparameters self.save_hyperparameters() # The LSTM takes word embeddings as inputs, and outputs hidden states # with dimensionality hidden_dim. self.lstm = nn.LSTM(input_features, hidden_dim, batch_first=True) # The linear layer that maps from hidden state space to classes self.linear = nn.Linear(hidden_dim, TOT_ACTION_CLASSES) def forward(self, x): # invoke lstm layer lstm_out, (ht, ct) = self.lstm(x) # invoke linear layer return self.linear(ht[-1]) def training_step(self, batch, batch_idx): # get data and labels from batch x, y = batch # reduce dimension y = torch.squeeze(y) # convert to long y = y.long() # get prediction y_pred = self(x) # calculate loss loss = F.cross_entropy(y_pred, y) # get probability score using softmax prob = F.softmax(y_pred, dim=1) # get the index of the max probability pred = prob.data.max(dim=1)[1] # calculate accuracy acc = torchmetrics.functional.accuracy(pred, y) dic = { 'batch_train_loss': loss, 'batch_train_acc': acc } # log the metrics for pytorch lightning progress bar or any other operations self.log('batch_train_loss', loss, prog_bar=True) self.log('batch_train_acc', acc, prog_bar=True) #return loss and dict return {'loss': loss, 'result': dic} def training_epoch_end(self, training_step_outputs): # calculate average training loss end of the epoch avg_train_loss = torch.tensor([x['result']['batch_train_loss'] for x in training_step_outputs]).mean() # calculate average training accuracy end of the epoch avg_train_acc = torch.tensor([x['result']['batch_train_acc'] for x in training_step_outputs]).mean() # log the metrics for pytorch lightning progress bar and any further processing self.log('train_loss', avg_train_loss, prog_bar=True) self.log('train_acc', avg_train_acc, prog_bar=True) def validation_step(self, batch, batch_idx): # get data and labels from batch x, y = batch # reduce dimension y = torch.squeeze(y) # convert to long y = y.long() # get prediction y_pred = self(x) # calculate loss loss = F.cross_entropy(y_pred, y) # get probability score using softmax prob = F.softmax(y_pred, dim=1) # get the index of the max probability pred = prob.data.max(dim=1)[1] # calculate accuracy acc = torchmetrics.functional.accuracy(pred, y) dic = { 'batch_val_loss': loss, 'batch_val_acc': acc } # log the metrics for pytorch lightning progress bar and any further processing self.log('batch_val_loss', loss, prog_bar=True) self.log('batch_val_acc', acc, prog_bar=True) #return dict return dic def validation_epoch_end(self, validation_step_outputs): # calculate average validation loss end of the epoch avg_val_loss = torch.tensor([x['batch_val_loss'] for x in validation_step_outputs]).mean() # calculate average validation accuracy end of the epoch avg_val_acc = torch.tensor([x['batch_val_acc'] for x in validation_step_outputs]).mean() # log the metrics for pytorch lightning progress bar and any further processing self.log('val_loss', avg_val_loss, prog_bar=True) self.log('val_acc', avg_val_acc, prog_bar=True) def configure_optimizers(self): # adam optimiser optimizer = optim.Adam(self.parameters(), lr=self.hparams.learning_rate) # learning rate reducer scheduler scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.5, patience=10, min_lr=1e-15, verbose=True) # scheduler reduces learning rate based on the value of val_loss metric return {"optimizer": optimizer, "lr_scheduler": {"scheduler": scheduler, "interval": "epoch", "frequency": 1, "monitor": "val_loss"}}
۳- برنامه وب
برنامه وب چندین مسیر تعریف شده برای توسعه دارد. مسیر زیر ویدیوی ورودی را پردازش می کند. از این مسیر زمانی استفاده می شود که کاربر، ویدیویی را از صفحه وب برای تجزیه و تحلیل ارسال می کند.
# route definition for video upload for analysis @app.route('/analyze/<filename>') def analyze(filename): # invokes method analyse_video return Response(analyse_video(pose_detector, lstm_classifier, filename), mimetype='text/event-stream')
۴- آنالیز ویدیویی
وب اپلیکیشن، یک ویدیدو از کاربر دریافت می کند.
عملکرد زیر از طریق ویدیو تجزیه و تحلیل می شود و شامل :
- Detectron2 برای تشخیص نقاط کلیدی و LSTM برای طبقه بندی کنش استفاده می شود. شما می توانید ملاحظه کنید که ما از پنجره بافر برای ذخیره نتایج متوالی نقاط کلیدی حاصل از فریم استفاده کرده ایم و از همان بافر ویندوز برای استنباط کلیه سطوح کنش ها استفاده می شود.
- در مرحله بعدی ، ما از Opencv برای خوانش ویدیوی ورودی استفاده کرده ایم و همچنین برای ایجاد ویدیوی خروجی با استفاده از نتایج طبقه بندی شده و نتایج تخمین ژست ها و کنش ها استفاده کرده ایم.
اگر می خواهید که نرخ FPS ویدیو به منظور انجام تجزیه و تحلیل ، نرخ بالایی داشته باشند، می توانید مقدار بالاتری را برای نادیده گرفتن شمارش فریم، پیکربندی کنید.
# how many frames to skip while inferencing # configuring a higher value will result in better FPS (frames per rate), but accuracy might get impacted SKIP_FRAME_COUNT = 0 # analyse the video def analyse_video(pose_detector, lstm_classifier, video_path): # open the video cap = cv2.VideoCapture(video_path) # width of image frame width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) # height of image frame height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # frames per second of the input video fps = int(cap.get(cv2.CAP_PROP_FPS)) # total number of frames in the video tot_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # video output codec fourcc = cv2.VideoWriter_fourcc(*'mp4v') # extract the file name from video path file_name = ntpath.basename(video_path) # video writer vid_writer = cv2.VideoWriter('res_{}'.format( file_name), fourcc, 30, (width, height)) # counter counter = 0 # buffer to keep the output of detectron2 pose estimation buffer_window = [] # start time start = time.time() label = None # iterate through the video while True: # read the frame ret, frame = cap.read() # return if end of the video if ret == False: break # make a copy of the frame img = frame.copy() if(counter % (SKIP_FRAME_COUNT+1) == 0): # predict pose estimation on the frame outputs = pose_detector(frame) # filter the outputs with a good confidence score persons, pIndicies = filter_persons(outputs) if len(persons) >= 1: # pick only pose estimation results of the first person. # actually, we expect only one person to be present in the video. p = persons[0] # draw the body joints on the person body draw_keypoints(p, img) # input feature array for lstm features = [] # add pose estimate results to the feature array for i, row in enumerate(p): features.append(row[0]) features.append(row[1]) # append the feature array into the buffer # not that max buffer size is 32 and buffer_window operates in a sliding window fashion if len(buffer_window) < WINDOW_SIZE: buffer_window.append(features) else: # convert input to tensor model_input = torch.Tensor(np.array(buffer_window, dtype=np.float32)) # add extra dimension model_input = torch.unsqueeze(model_input, dim=0) # predict the action class using lstm y_pred = lstm_classifier(model_input) prob = F.softmax(y_pred, dim=1) # get the index of the max probability pred_index = prob.data.max(dim=1)[1] # pop the first value from buffer_window and add the new entry in FIFO fashion, to have a sliding window of size 32. buffer_window.pop(0) buffer_window.append(features) label = LABELS[pred_index.numpy()[0]] #print("Label detected ", label) # add predicted label into the frame If label is not None: cv2.putText(img, 'Action: {}'.format(label), (int(width-400), height-50), cv2.FONT_HERSHEY_COMPLEX, 0.9, (102, 255, 255), 2) # increment counter counter += 1 # write the frame into the result video vid_writer.write(img) # compute the completion percentage percentage = int(counter*100/tot_frames) # return the completion percentage yield "data:" + str(percentage) + "\n\n" analyze_done = time.time() print("Video processing finished in ", analyze_done - start)
عملکرد برنامه را در هنگام اجرا مشاهده کنید
برای این مدل از ماشین های یادگیری شما نیاز به یک پردازنده گرافیکی دارید. برای این که به آسانی بتوانید عملکرد برنامه را در عمل مشاهده کنید، ما در بخش پایگاه کدهای نوتبوک Google Colab برای شما کد ها را ارائه کرده ایم. فقط کافی است که نوتبوک را در Google Colab آپلود کنید، پردازنده گرافیکی را راه اندازی کرده و نوت بوک را اجرا کنید.
و در نهایت نحوه عملکرد اپلیکیشن به این صورت خواهد بود.
جمع بندی
در پایان مقاله می خواهیم آن چه را که از این مقاله آموخته اید به طور خلاصه بررسی کنیم:
- شما درباره تمامی آن چه مربوط به شناسایی و تشخیص کنش انسان ها و همچنین درباره کاربرد های مختلف آن ها مطالبی را آموختید.
- در بخش بعدی مقاله ، ما به چگونگی ساخت برنامه ای به منظور تشخیص کنش های انسانی پرداختیم.
- شما درباره این که چرا از دو برنامه Detectron2 و LSTM به عنوان راه حل استفاده کرده ایم آموختید و همچنین قابلیت های این دو برنامه آشنا شدید.
- سپس شما درباره آموزش مدل LSTM به منظور طبقه بندی کنش ها بر اساس نقاط کلیدی با استفاده از برنامه Pytorch Lighting مطالبی آموختید. همچنین شما درباره این که چگونه دنباله های ادامه دار ۳۲ فریمی، یک کنش خاص را تشخیص می دهند را مشاهده کردید.
- در مرحله بعد، ما از ترکیبی از دو برنامه Detecdtron2 و LSTM به منظور استنباط ویدیو استفاده کردیم. شما آموختید که نتایج نمایش داده شده ، کنش های واقعی بودند که به واسطه تفسیر خط استنباطی ویدیوی ورودی شناسایی شدند.
- فهمیدید چرا FPS برای استنباط ویدیو پخش زنده Real-Time بهینه سازی می شود. به همین منظور ، شما به بررسی روش های مختلفی مانند فیلترینگ و کمی سازی مدل، نادیده گرفتن فریم ها و استنباط در بازه های زمانی مختلف و همچنین روش چند رشته ای سازی به کاوش پرداختیم.
- در مرحله بعد، شما به تفصیل در مورد کدنویسی تمام اجزای مهم برنامه به بررسی پرداختید.
- در نهایت ، شما یک گام فراتر رفتید و یک برنامه وب مبتنی بر Flask برای اسنجام استنباط بر روی ویدیوی ورودی ایجاد کردید.
امیدوارم مطالب ارائه شده در این آموزش برایتان مفید واقع شده باشد و شما توانسته باشید موارد جدیدی را در این مقاله آموخته باشید.
بیشتر بخوانید :
سلام فایل موت بوک کجا قرار گرفته؟
سلام
لینک گوگل کولب اصلاح شد
روی لینک Google Colab توی مطلب کلیک کنید به نوت بوک دسترسی پیدا میکنید