Zephyrnet Logosu

Amazon SageMaker Studio Lab kullanarak çok kameralı olayları analiz edin ve görselleştirin

Tarih:

Ulusal Futbol Ligi (NFL), Amerika Birleşik Devletleri'ndeki en popüler spor liglerinden biridir ve dünyanın en değerli spor ligi. NFL, BioCore ve AWS, futbol oyununu daha güvenli hale getirmek için sporla ilgili yaralanmaların teşhisi, önlenmesi ve tedavisi konusunda insan anlayışını geliştirmeye kararlıdır. NFL Oyuncu Sağlığı ve Güvenliği çalışmaları hakkında daha fazla bilgi şu adreste mevcuttur: NFL web sitesi.

The AWS Profesyonel Hizmetleri ekibi, bilgisayar görüşü (CV) tekniklerini kullanarak oyun çekimlerinden kask etkilerini belirlemeye yönelik makine öğrenimi (ML) tabanlı çözümler sağlamak için NFL ve Biocore ile ortaklık kurdu. Her oyundan birden fazla kamera görüntüsüyle, bu görüntülerin her birinden kask etkilerini belirlemek ve kask etkisi sonuçlarını birleştirmek için çözümler geliştirdik.

Birden fazla kamera görüntüsü kullanmanın ardındaki motivasyon, etki olayları yalnızca tek bir görünümle yakalandığında bilginin sınırlandırılmasından gelir. Tek bir bakış açısıyla, bazı oyuncular birbirlerini kapatabilir veya sahadaki diğer nesneler tarafından engellenebilir. Bu nedenle, daha fazla perspektif eklemek, makine öğrenimi sistemimizin tek bir görünümde görünmeyen daha fazla etkiyi tanımlamasını sağlar. Birleştirme sürecimizin sonuçlarını ve ekibin model performansını değerlendirmeye yardımcı olmak için görselleştirme araçlarını nasıl kullandığını göstermek için çoklu görünüm algılama sonuçlarını görsel olarak üst üste bindirecek bir kod tabanı geliştirdik. Bu süreç, birden çok görünümde algılanan yinelenen etkileri kaldırarak bireysel oyuncuların yaşadığı gerçek etki sayısını belirlemeye yardımcı olur.

Bu gönderide, halka açık veri kümesini kullanıyoruz. NFL – Impact Detection Kaggle yarışması ve iki görünümü birleştirme sonuçlarını göster. Veri kümesi, her karede kask sınırlama kutuları ve her videoda bulunan etki etiketlerini içerir. Özellikle, ID ile videoları tekilleştirmeye ve görselleştirmeye odaklanıyoruz. 57583_000082 uç bölge ve yan çizgi görünümlerinde. indirebilirsiniz son bölge ve yan çizgi videolarıVe ayrıca zemin gerçeği etiketleri.

Önkoşullar

Çözüm aşağıdakileri gerektirir:

SageMaker Studio Lab'ı kullanmaya başlayın ve gerekli paketleri kurun

Not defterini şu adresten çalıştırabilirsiniz: GitHub deposundan veya SageMaker Studio Lab'dan. Bu yazıda not defterini bir SageMaker Studio Lab ortamından çalıştırıyoruz. SageMaker Studio Lab'ı ücretsiz olması, güçlü CPU ve GPU kullanıcı oturumları ve ortamınızı otomatik olarak kaydederek kaldığınız yerden devam etmenizi sağlayacak 15 GB kalıcı depolama sağlaması nedeniyle seçiyoruz. SageMaker Studio Lab'ı kullanmak için, yeni bir hesap isteyin ve kurun. Hesap onaylandıktan sonra aşağıdaki adımları tamamlayın:

  1. Airdrop formunu doldurun : aws-samples GitHub deposu.
  2. içinde README bölümü, seçim Studio Lab'ı açın.

sagemaker-stüdyo-düğmesi

Bu sizi SageMaker Studio Lab ortamınıza yönlendirir.

  1. CPU bilgi işlem türünüzü seçin, ardından Çalışma Zamanını Başlat.
  2. Çalışma zamanı başladıktan sonra, seçin Projeye Kopyala, Jupyter Lab ortamıyla yeni bir pencere açar.

Artık not defterini kullanmaya hazırsınız!

  1. Açılış fuse_and_visualize_multiview_impacts.ipynb ve not defterindeki yönergeleri izleyin.

Not defterindeki ilk hücre, pandalar ve OpenCV gibi gerekli Python paketlerini kurar:

%pip install pandas
%pip install opencv-contrib-python-headless

Daha iyi görselleştirme deneyimi için gerekli tüm Python paketlerini içe aktarın ve panda seçeneklerini ayarlayın:

import os
import cv2
import pandas as pd
import numpy as np
pd.set_option('mode.chained_assignment', None)

Etkilerin yanı sıra açıklamalı kask sınırlama kutularıyla birlikte CSV dosyasını almak ve ayrıştırmak için pandalar kullanıyoruz. NumPy'yi esas olarak dizileri ve matrisleri değiştirmek için kullanıyoruz. Python'da görüntü verilerini okumak, yazmak ve değiştirmek için OpenCV kullanıyoruz.

İki görünümden elde edilen sonuçları birleştirerek verileri hazırlayın

İki perspektifi birleştirmek için, train_labels.csv örnek olarak Kaggle yarışmasından alınmıştır, çünkü hem son bölgeden hem de yan çizgiden gelen temel gerçek etkilerini içerir. Aşağıdaki işlev, giriş veri setini alır ve giriş veri setindeki tüm oynatmalar için yinelenenleri kaldırılmış birleştirilmiş bir veri çerçevesi çıkarır:

def prep_data(df): df['game_play'] = df['gameKey'].astype('str') + '_' + df['playID'].astype('str').str.zfill(6) return df def dedup_view(df, windows): # define view df = df.sort_values(by='frame') view_columns = ['frame', 'left', 'width', 'top', 'height', 'video'] common_columns = ['game_play', 'label', 'view', 'impactType'] label_cleaned = df[view_columns + common_columns] # rename columns sideline_column_rename = {col: 'Sideline_' + col for col in view_columns} endzone_column_rename = {col: 'Endzone_' + col for col in view_columns} sideline_columns = list(sideline_column_rename.values()) # create two dataframes, one for sideline, one for endzone label_endzone = label_cleaned.query('view == "Endzone"') label_endzone.rename(columns=endzone_column_rename, inplace=True) label_sideline = label_cleaned.query('view == "Sideline"') label_sideline.rename(columns=sideline_column_rename, inplace=True) # prepare sideline labels label_sideline['is_dup'] = False for columns in sideline_columns: label_endzone[columns] = np.nan label_endzone['is_dup'] = False # iterrate endzone rows to find matches and dedup for index, row in label_endzone.iterrows(): player = row['label'] frame = row['Endzone_frame'] impact_type = row['impactType'] sideline_row = label_sideline[(label_sideline['label'] == player) & ((label_sideline['Sideline_frame'] >= frame - windows // 2) & (label_sideline['Sideline_frame'] <= frame + windows // 2 + 1)) & (label_sideline['is_dup'] == False) & (label_sideline['impactType'] == impact_type)] if len(sideline_row) > 0: sideline_index = sideline_row.index[0] label_sideline['is_dup'].loc[sideline_index] = True for col in sideline_columns: label_endzone[col].loc[index] = sideline_row.iloc[0][col] label_endzone['is_dup'].loc[index] = True # calculate overlap perc not_dup_sideline = label_sideline[label_sideline['is_dup'] == False] final_output = pd.concat([not_dup_sideline, label_endzone]) return final_output def fuse_df(raw_df, windows): outputs = [] all_game_play = raw_df['game_play'].unique() for game_play in all_game_play: df = raw_df.query('game_play ==@game_play') output = dedup_view(df, windows) outputs.append(output) output_df = pd.concat(outputs) output_df['gameKey'] = output_df['game_play'].apply(lambda x: x.split('_')[0]).map(int) output_df['playID'] = output_df['game_play'].apply(lambda x: x.split('_')[1]).map(int) return output_df

Fonksiyonu çalıştırmak için, konumu sağlamak için aşağıdaki kod bloğunu çalıştırıyoruz. train_labels.csv verileri ve ardından ek bir sütun eklemek ve yalnızca etki satırlarını çıkarmak için veri hazırlığı gerçekleştirin. Fonksiyonu çalıştırdıktan sonra çıktıyı dataframe değişkenine kaydediyoruz. fused_df.

# read the annotated impact data from train_labels.csv
ground_truth = pd.read_csv('train_labels.csv') # prepare game_play column using pipe(prep_data) function in pandas then filter the dataframe for just rows with impacts
ground_truth = ground_truth.pipe(prep_data).query('impact == 1') # loop over all the unique game_plays and deduplicate the impact results from sideline and endzone
fused_df = fuse_df(ground_truth, windows=30)

Aşağıdaki ekran görüntüsü temel gerçeği göstermektedir.

Aşağıdaki ekran görüntüsü, birleştirilmiş veri çerçevesi örneklerini gösterir.

Grafik ve video kodu

Etki sonuçlarını birleştirdikten sonra, oluşturulan fused_df sonuçları uç bölge ve yan çizgi videolarımıza bindirmek ve iki görünümü birleştirmek için. Bunun için aşağıdaki işlevi kullanıyoruz ve gerekli girdiler uç bölge videosuna, yan çizgi videosuna, fused_df dataframe ve yeni oluşturulan video için son çıktı yolu. Bu bölümde kullanılan işlevler, SageMaker Studio Lab'da kullanılan not defterinin işaretleme bölümünde açıklanmaktadır.

def get_video_and_metadata(vid_path): vid = cv2.VideoCapture(vid_path) total_frame_number = vid.get(cv2.CAP_PROP_FRAME_COUNT) width = int(vid.get(cv2.CAP_PROP_FRAME_WIDTH)) height = int(vid.get(cv2.CAP_PROP_FRAME_HEIGHT)) fps = vid.get(cv2.CAP_PROP_FPS) return vid, total_frame_number, width, height, fps def overlay_impacts(frame, fused_df, game_key, play_id, frame_cnt, h1): # look for duplicates duplicates = fused_df.query(f"gameKey == {int(game_key)} and playID == {int(play_id)} and is_dup == True and Sideline_frame == @frame_cnt") frame_has_impact = False if len(duplicates) > 0: for duplicate in duplicates.itertuples(index=False): if frame_cnt == duplicate.Sideline_frame: frame_has_impact = True if frame_has_impact: cv2.rectangle(frame, #frame to be edited (int(duplicate.Sideline_left), int(duplicate.Sideline_top)), #(x,y) of top left corner (int(duplicate.Sideline_left) + int(duplicate.Sideline_width), int(duplicate.Sideline_top) + int(duplicate.Sideline_height)), #(x,y) of bottom right corner (0,0,255), #RED boxes thickness=3) cv2.rectangle(frame, #frame to be edited (int(duplicate.Endzone_left), int(duplicate.Endzone_top)+ h1), #(x,y) of top left corner (int(duplicate.Endzone_left) + int(duplicate.Endzone_width), int(duplicate.Endzone_top) + int(duplicate.Endzone_height) + h1), #(x,y) of bottom right corner (0,0,255), #RED boxes thickness=3) cv2.line(frame, #frame to be edited (int(duplicate.Sideline_left), int(duplicate.Sideline_top)), #(x,y) of point 1 in a line (int(duplicate.Endzone_left), int(duplicate.Endzone_top) + h1), #(x,y) of point 2 in a line (255, 255, 255), # WHITE lines thickness=4) else: # if no duplicates, look for sideline then endzone and add to the view sl_impacts = fused_df.query(f"gameKey == {int(game_key)} and playID == {int(play_id)} and is_dup == False and view == 'Sideline' and Sideline_frame == @frame_cnt") if len(sl_impacts) > 0: for impact in sl_impacts.itertuples(index=False): if frame_cnt == impact.Sideline_frame: frame_has_impact = True if frame_has_impact: cv2.rectangle(frame, #frame to be edited (int(impact.Sideline_left), int(impact.Sideline_top)), #(x,y) of top left corner (int(impact.Sideline_left) + int(impact.Sideline_width), int(impact.Sideline_top) + int(impact.Sideline_height)), #(x,y) of bottom right corner (0, 255, 255), #YELLOW BOXES thickness=3) ez_impacts = fused_df.query(f"gameKey == {int(game_key)} and playID == {int(play_id)} and is_dup == False and view == 'Endzone' and Endzone_frame == @frame_cnt") if len(ez_impacts) > 0: for impact in ez_impacts.itertuples(index=False): if frame_cnt == impact.Endzone_frame: frame_has_impact = True if frame_has_impact: cv2.rectangle(frame, #frame to be edited (int(impact.Endzone_left), int(impact.Endzone_top)+ h1), #(x,y) of top left corner (int(impact.Endzone_left) + int(impact.Endzone_width), int(impact.Endzone_top) + int(impact.Endzone_height) + h1 ), #(x,y) of bottom right corner (0, 255, 255), #YELLOW BOXES thickness=3) return frame, frame_has_impact def generate_impact_video(ez_vid_path:str, sl_vid_path:str, fused_df:pd.DataFrame, output_path:str, freeze_impacts=True): #define video codec to be used for VIDEO_CODEC = "MP4V" # parse game_key and play_id information from the name of the files game_key = os.path.basename(ez_vid_path).split('_')[0] # parse game_key play_id = os.path.basename(ez_vid_path).split('_')[1] # parse play_id # get metadata such as total frame number, width, height and frames per second (FPS) from endzone (ez) and sideline (sl) videos ez_vid, ez_total_frame_number, ez_width, ez_height, ez_fps = get_video_and_metadata(ez_vid_path) sl_vid, sl_total_frame_number, sl_width, sl_height, sl_fps = get_video_and_metadata(sl_vid_path) # define a video writer for the output video output_video = cv2.VideoWriter(output_path, #output file name cv2.VideoWriter_fourcc(*VIDEO_CODEC), #Video codec ez_fps, #frames per second in the output video (ez_width, ez_height+sl_height)) # frame size with stacking video vertically # find shorter video and use the total frame number from the shorter video for the output video total_frame_number = int(min(ez_total_frame_number, sl_total_frame_number)) # iterate through each frame from endzone and sideline for frame_cnt in range(total_frame_number): frame_has_impact = False frame_near_impact = False # reading frames from both endzone and sideline ez_ret, ez_frame = ez_vid.read() sl_ret, sl_frame = sl_vid.read() # creating strings to be added to the output frames img_name = f"Game key: {game_key}, Play ID: {play_id}, Frame: {frame_cnt}" video_frame = f'{game_key}_{play_id}_{frame_cnt}' if ez_ret == True and sl_ret == True: h, w, c = ez_frame.shape h1,w1,c1 = sl_frame.shape if h != h1 or w != w1: # resize images if they're different ez_frame = cv2.resize(ez_frame,(w1,h1)) frame = np.concatenate((sl_frame, ez_frame), axis=0) # stack the frames vertically frame, frame_has_impact = overlay_impacts(frame, fused_df, game_key, play_id, frame_cnt, h1) cv2.putText(frame, #image frame to be modified img_name, #string to be inserted (30, 30), #(x,y) location of the string cv2.FONT_HERSHEY_SIMPLEX, #font 1, #scale (255, 255, 255), #WHITE letters thickness=2) cv2.putText(frame, #image frame to be modified str(frame_cnt), #frame count string to be inserted (w1-75, h1-20), #(x,y) location of the string in the top view cv2.FONT_HERSHEY_SIMPLEX, #font 1, #scale (255, 255, 255), # WHITE letters thickness=2) cv2.putText(frame, #image frame to be modified str(frame_cnt), #frame count string to be inserted (w1-75, h1+h-20), #(x,y) location of the string in the bottom view cv2.FONT_HERSHEY_SIMPLEX, #font 1, #scale (255, 255, 255), # WHITE letters thickness=2) output_video.write(frame) # Freeze for 60 frames on impacts if frame_has_impact and freeze_impacts: for _ in range(60): output_video.write(frame) else: break frame_cnt += 1 output_video.release() return

Bu işlevleri çalıştırmak için, aşağıdaki kodda gösterildiği gibi, adlı bir video oluşturan bir giriş sağlayabiliriz. output.mp4:

generate_impact_video('57583_000082_Endzone.mp4', '57583_000082_Sideline.mp4', fused_df, 'output.mp4')

Bu, aşağıdaki örnekte gösterildiği gibi bir video oluşturur; burada kırmızı sınırlayıcı kutular, hem uç bölge hem de yan çizgi görünümlerinde bulunan etkilerdir ve sarı sınırlayıcı kutular, uç bölge veya yan çizgide yalnızca bir görünümde bulunan etkilerdir.

Sonuç

Bu gönderide, NFL, Biocore ve AWS ProServe ekiplerinin birden çok görünümden elde edilen sonuçları birleştirerek etki algılamayı iyileştirmek için nasıl birlikte çalıştıklarını gösterdik. Bu, ekiplerin hata ayıklamasına ve modelin niteliksel olarak nasıl performans gösterdiğini görselleştirmesine olanak tanır. Bu süreç kolayca üç veya daha fazla görünüme kadar ölçeklendirilebilir; projelerimizde yedi farklı görünümden faydalandık. Videoları tek bir görünümden izleyerek kask etkilerini algılamak, görüntü engeli nedeniyle zor olabilir, ancak birden çok görünümden gelen etkileri algılamak ve sonuçları birleştirmek, model performansımızı iyileştirmemize olanak tanır.

Bu çözümü denemek için şu adresi ziyaret edin: aws-samples GitHub deposu ve bakın Fuse_and_visualize_multiview_impacts.ipynb not defteri. Benzer teknikler, imalat, perakende ve güvenlik gibi, birden çok görünüme sahip olmanın hedefleri daha kapsamlı bir görünümle daha iyi tanımlaması için makine öğrenimi sistemine fayda sağlayacağı diğer sektörlere de uygulanabilir.

NFL Oyuncu Sağlığı ve Güvenliği hakkında daha fazla bilgi için şu adresi ziyaret edin: NFL web sitesi ve NFL Açıklaması: Oyuncu Sağlığı ve Güvenliğinde Yenilik.


yazarlar hakkında

Chris Boomhower AWS Profesyonel Hizmetler'de Makine Öğrenimi Mühendisidir. Chris, çeşitli sektörlerde denetimli ve denetimsiz Makine Öğrenimi çözümleri geliştirmede 6 yıldan fazla deneyime sahiptir. Bugün, zamanının çoğunu spor, sağlık ve tarım sektörlerindeki müşterilerin ölçeklenebilir, uçtan uca Makine Öğrenimi çözümleri tasarlamasına ve oluşturmasına yardımcı olmaya harcıyor.

Ben Fenker AWS Profesyonel Hizmetlerinde Kıdemli Veri Bilimcisidir ve müşterilerin spordan sağlık hizmetlerine ve üretime kadar uzanan sektörlerde makine öğrenimi çözümleri oluşturmasına ve dağıtmasına yardımcı olmuştur. Doktorası var. Texas A&M Üniversitesi'nden fizik ve 6 yıllık endüstri deneyimi. Ben beyzboldan, kitap okumaktan ve çocuklarını büyütmekten hoşlanıyor.

Sam Huddleston NFL'nin Dijital Sporcu programında Teknoloji Lideri olarak hizmet veren Biocore LLC'de Baş Veri Bilimcisidir. Biocore, Charlottesville, Virginia merkezli birinci sınıf mühendislerden oluşan bir ekiptir ve kendini yaralanmaların anlaşılmasına ve azaltılmasına adamış müşterilere araştırma, test, biyomekanik uzmanlık, modelleme ve diğer mühendislik hizmetleri sağlar.

Jarvis Lee AWS Profesyonel Hizmetlerinde Kıdemli Veri Bilimcisidir. Beş yılı aşkın bir süredir AWS'de çalışıyor ve müşterilerle makine öğrenimi ve bilgisayarla görme sorunları üzerinde çalışıyor. İş dışında bisiklete binmekten hoşlanıyor.

Tyler Mullenbach AWS Professional Services ile Makine Öğrenimi için Küresel Uygulama Lideridir. Profesyonel Hizmetler için Makine Öğreniminin stratejik yönünü yönlendirmekten ve müşterilerin Makine Öğrenimi teknolojilerinin benimsenmesi yoluyla dönüştürücü ticari başarıları gerçekleştirmelerini sağlamaktan sorumludur.

kevin şarkı AWS Profesyonel Hizmetler'de Veri Bilimcisidir. Biyofizik alanında doktora derecesine sahiptir ve bilgisayarlı görü ve makine öğrenimi çözümleri oluşturma konusunda 5 yıldan fazla endüstri deneyimine sahiptir.

Betty Zhang veri ve teknoloji alanında 10 yıllık deneyime sahip bir veri bilimcisidir. Tutkusu, şirketler için dönüşümsel değişikliklere yön verecek yenilikçi makine öğrenimi çözümleri oluşturmaktır. Boş zamanlarında seyahat etmeyi, okumayı ve yeni teknolojileri öğrenmeyi seviyor.

spot_img

En Son İstihbarat

spot_img