تشخیص حالت دست با رزبری پای (بازی سنگ کاغذ قیچی)

محتویات
همه ما حداقل یک بار بازی سنگ، کاغذ و قیچی را انجام داده ایم. این یک بازی بسیار ساده است که در آن هر بازیکن یکی از سه مورد (سنگ ، کاغذ و قیچی) را انتخاب می کند. قوانین زیر در این بازی وجود دارد:
- کاغذ سنگ را می زند
- قیچی کاغذ را می برد
- سنگ قیچی را می زند
بنابراین در آموزش امروز ، ما یاد خواهیم گرفت که چگونه می توانیم با استفاده از OpenCV و Tensorflow بازی سنگ، کاغد و قیچی را با Raspberry Pi اجرا کنیم. این پروژه شامل سه مرحله است:
- جمع آوری داده ها
- آموزش مدل
- تشخیص حرکت
در مرحله اول ، ما تصاویر سنگ، کاغذ ، قیچی و پوچ را جمع آوری می کنیم. این مجموعه داده شامل 800 تصویر متعلق به چهار کلاس است. در مرحله دوم ، ما تشخیص دهنده را برای تشخیص حرکات انجام شده توسط کاربر آموزش خواهیم داد ، و در مرحله آخر ، از داده های مربی برای تشخیص حالت دست کاربر استفاده خواهیم کرد. با شناسایی حرکت کاربر ، رزبری پای یک حرکت را به صورت تصادفی انجام می دهد و پس از مقایسه هر دو حالت دست، برنده اعلام می شود.
قطعات مورد نیاز
- رزبری پای
- ماژول دوربین Pi
در اینجا ، ما فقط به ماژول دوربین RPi 4 و برد Pi با OpenCV و Tensorflow نصب شده نیاز داریم. OpenCV در اینجا برای پردازش تصویر دیجیتال استفاده می شود. رایج ترین کاربردهای پردازش تصویر دیجیتال ، تشخیص شی ، تشخیص چهره و شمارنده افراد است.
نصب OpenCV
قبل از نصب OpenCV و سایر وابستگی ها ، Raspberry Pi باید کاملاً به روز باشد. برای به روزرسانی رزبری پای به آخرین نسخه از دستورات زیر استفاده کنید:
sudo apt-get update
سپس از دستورات زیر برای نصب وابستگی های مورد نیاز برای نصب OpenCV در Raspberry Pi خود استفاده کنید.
sudo apt-get install libhdf5-dev -y sudo apt-get install libhdf5-serial-dev –y sudo apt-get install libatlas-base-dev –y sudo apt-get install libjasper-dev -y sudo apt-get install libqtgui4 –y sudo apt-get install libqt4-test –y
پس از آن ، از دستور زیر استفاده کنید تا OpenCV را روی Raspberry Pi خود نصب کنید.
pip3 install opencv-contrib-python==4.1.0.25
نصب imutils: بسته imutils برای سهولت کارکردهای پردازش تصویر مانند ترجمه ، چرخش ، تغییر اندازه ، اسکلت بندی و نمایش تصاویر Matplotlib با OpenCV استفاده می شود. برای نصب imutils از دستور زیر استفاده کنید:
pip3 install imutils
نصب Tensorflow: برای نصب Tensorflow از دستور زیر استفاده کنید:
sudo pip3 install https://github.com/lhelontra/tensorflow-on-arm/releases/download/v2.2.0/tensorflow-2.2.0-cp37-none-linux_armv7l.whl
sklearn (Scikit-learn): این یک کتابخانه پایتون است که طیف وسیعی از الگوریتم های یادگیری نظارت شده و بدون نظارت را از طریق یک رابط ثابت در پایتون فراهم می کند. در اینجا ما قصد داریم از آن برای ساخت یک مدل یادگیری ماشین استفاده کنیم که می تواند حرکات دست را تشخیص دهد. برای نصب sklearn در Raspberry Pi از دستور زیر استفاده کنید.
pip3 install sklearn
SqueezeNet: این یک مدل شبکه عصبی برای بینایی رایانه است. SqueezeNet یک مدل شبکه عصبی کوچک است که در بالای فریم ورک یادگیری عمیق کافه اجرا می شود. در اینجا ، ما از SqueezeNet به دلیل کوچک بودن و دقت آن استفاده کردیم. استقرار این مدل در سخت افزارهایی با حافظه محدود امکان پذیرتر است. با استفاده از دستور زیر keras_squeezenet را نصب کنید:
pip3 install keras_squeezenet
برنامه نویسی رزبری پای برای تشخیص حرکت دست
همانطور که قبلا ذکر شد ، ما قصد داریم این پروژه را در سه فاز تکمیل کنیم. مرحله اول جمع آوری اطلاعات است. مورد دوم آموزش تشخیص و سوم شناخت حرکت انجام شده توسط کاربر است. پوشه پروژه شامل موارد زیر است:
- Dataset: این پوشه حاوی تصاویر مربوط به تصاویر کاغذ، قیچی، سنگ و پوچ است.
- image.py: یک اسکریپت ساده پایتون برای جمع آوری تصاویر برای ساخت مجموعه داده است.
- training.py: این مجموعه داده ورودی را می پذیرد و Squeezenet را روی آن تنظیم می کند تا مدل تشخیص حرکت ما را ایجاد کند (game-model.h5).
- game.py: این اسکریپت سنگ، کاغذ و قیچی را با استفاده از داده های مربی تشخیص می دهد و همچنین برای رزبری پای یک حرکت را شانسی انجام میدهد.
پوشه کامل پروژه و سورس کد ها را میتوانید از انتهای صفحه دانلود کنید.
1. جمع آوری داده ها
در مرحله اول پروژه ، ما می خواهیم یک Dataset ایجاد کنیم که دارای 200 تصویر برای هر کلاس (سنگ، کاغذ، قیچی و هیچ چیز) باشد. Image.py یک اسکریپت ساده پایتون است که از OpenCV برای جمع آوری تصاویر حرکات استفاده می کند. فایل image.py را در پوشه باز کرده و کد داده شده را جایگذاری کنید. سپس با استفاده از دستور زیر شروع به جمع آوری تصاویر می کنیم:
python3 image.py 200
کهنگامی که اسکریپت را راه اندازی کردید ، کلید “r” را فشار دهید تا تصاویر مربوط به حرکت Rock را بگیرید و سپس “a” را فشار دهید تا روند شروع شود. شما باید “p” را برای کاغذ ، “s” را برای قیچی و “n” را برای هیچ چیز فشار دهید.
برنامه جمع آوری تصویر در زیر توضیح داده شده است:
اسکریپت با فراخوانی کردن بسته های مورد نیاز شروع می شود.
import cv2 import os import sys
خط بعدی کد ، استدلال سیستم را می پذیرد و برای وارد کردن تعداد نمونه هایی که می خواهیم جمع آوری کنیم استفاده می شود.
num_samples = int(sys.argv[1])
سپس وارد مسیر داده ای شوید که تمام این تصاویر در آنجا ذخیره می شود.
IMG_SAVE_PATH = 'images'
خطوط زیر پوشه فهرست تصویر را ایجاد می کند.
try: os.mkdir(IMG_SAVE_PATH) except FileExistsError: pass
سپس با استفاده از تابع cv2.rektangle یک مستطیل درست کنید. هنگام اجرای اسکریپت باید دستان خود را درون این جعبه مستطیل قرار دهید.
cv2.rectangle(frame, (10, 30), (310, 330), (0, 255, 0), 2)
سپس در خطوط بعدی فشار کلید را تشخیص دهید. اگر کلید فشرده شده “r” است ، نام لیبل را “rock” تنظیم کنید و پوشه ای به نام rock را در داخل فهرست تصویر ایجاد کنید. اگر کلید فشرده شده “p” است ، نام لیبل را paper و به همین شکل نام ها را قرار دهید.
k = cv2.waitKey (1) if k == ord('r'): name = 'rock' IMG_CLASS_PATH = os.path.join(IMG_SAVE_PATH, name) os.mkdir(IMG_CLASS_PATH) if k == ord('p'): name = 'paper' IMG_CLASS_PATH = os.path.join(IMG_SAVE_PATH, name) os.mkdir(IMG_CLASS_PATH) if k == ord('s'): name = 'scissors' IMG_CLASS_PATH = os.path.join(IMG_SAVE_PATH, name) os.mkdir(IMG_CLASS_PATH) if k == ord('n'): name = 'nothing' IMG_CLASS_PATH = os.path.join(IMG_SAVE_PATH, name) os.mkdir(IMG_CLASS_PATH)
اگر دکمه شروع فشرده شد ، یک Region of Interest (ROI) در اطراف مستطیلی که قبلا ایجاد کردیم ایجاد کنید و با استفاده از مسیری که قبلاً وارد شده تمام تصاویر را در داخل فهرست ذخیره کنید.
roi = frame[25:335, 8:315] save_path = os.path.join(IMG_CLASS_PATH, '{}.jpg'.format(counter + 1)) print(save_path) cv2.imwrite(save_path, roi) counter += 1 font = cv2.FONT_HERSHEY_SIMPLEX cv2.putText(frame,"Collecting {}".format(counter), (10, 20), font, 0.7, (0, 255, 255), 2, cv2.LINE_AA) cv2.imshow("Collecting images", frame)
2. آموزش مدل
اکنون که تصاویر را جمع آوری کردیم ، می توانیم آنها را به شبکه عصبی منتقل کنیم و مراحل آموزش را برای شناسایی خودکار حرکت انجام شده توسط کاربر آغاز کنیم. بنابراین فایل train.py را در پوشه game باز کرده و کد داده شده را جای گذاری کنید. سپس با استفاده از دستور زیر فرایند آموزش را شروع کنید:
python3 training.py
اسکریپت پایتون برای آموزش Recognizer در زیر توضیح داده شده است:
اسکریپت Training.py با وارد کردن بسته های مورد نیاز شروع می شود. از خطوط بعدی پس از وارد کردن بسته ها ، برای تعیین مسیر به فهرست تصویر و نقشه کلاس استفاده می شود.
IMG_SAVE_PATH = 'images' CLASS_MAP = { "rock": 0, "paper": 1, "scissors": 2, "nothing": 3 }
اکنون تمام تصاویر را در اسکریپت پایتون بارگیری کنید تا بتوانیم آموزش را شروع کنیم. مراحل پیش پردازش شامل تبدیل تصاویر به RGB از BGR ، تغییر اندازه تصاویر به 227 × 227 پیکسل و تبدیل آنها به قالب آرایه است.
for directory in os.listdir(IMG_SAVE_PATH): path = os.path.join(IMG_SAVE_PATH, directory) if not os.path.isdir(path): continue for item in os.listdir(path): if item.startswith("."): continue img = cv2.imread(os.path.join(path, item)) img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img = cv2.resize(img, (227, 227)) dataset.append([img, directory])
اکنون ، تابع get model را فراخوانی می کنیم و مدل را با بهینه ساز Adam کامپایل می کنیم.
model = get_model() model.compile( optimizer=Adam(lr=0.0001), loss='categorical_crossentropy', metrics=['accuracy'] )
پس از این ، آموزش مدل را شروع کنید و پس از پایان آموزش ، مدل را به عنوان “game-model.h5” ذخیره کنید.
model.fit(np.array(data), np.array(labels), epochs=15) model.save("game-model.h5")
3. تشخیص حرکت دست
اکنون ، در مرحله آخر پروژه خود ، از داده های مربی برای طبقه بندی هر حالت دست از ویدیوی زنده استفاده خواهیم کرد. بنابراین فایل game.py را در باز کرده و کد داده شده را جای گذاری کنید. کد پایتون در ادامه توضیح داده شده است:
همانند اسکریپت training.py ، این اسکریپت با وارد کردن بسته های مورد نیاز نیز شروع می شود. از خطوط بعدی پس از وارد کردن بسته ها برای ایجاد عملکرد معکوس class-map استفاده می شود.
REV_CLASS_MAP = { 0: "rock", 1: "paper", 2: "scissors", 3: "nothing" }
تابع calculate_winner حرکت دست کاربر و حرکت رزبری پای را بررسی و مقایسه میکند و در نهایت برنده اعلام میشود. برای تعیین برنده از قوانین بازی سنگ کاغذ قیچی استفاده میشود.
def calculate_winner(user_move, Pi_move): if user_move == Pi_move: return "Tie" elif user_move == "rock" and Pi_move == "scissors": return "You" elif user_move == "rock" and Pi_move == "paper": return "Pi" elif user_move == "scissors" and Pi_move == "rock": return "Pi" elif user_move == "scissors" and Pi_move == "paper": return "You" elif user_move == "paper" and Pi_move == "rock": return "You" elif user_move == "paper" and Pi_move == "scissors": return "Pi"
سپس در خط بعدی مدل آموزش دیده را بارگیری کرده و جریان ویدئو را شروع کنید
model = load_model("game-model.h5") cap = cv2.VideoCapture(0)
در داخل loop، دو مستطیل در سمت چپ و راست قاب ایجاد کنید. مستطیل سمت چپ برای حرکت کاربر و مستطیل سمت راست برای حرکت رزبری پای است. سپس ناحیه تصویر درون مستطیل کاربر را به فرمت RGB تبدیل کرده و اندازه آن را به 227 × 227 تغییر می دهد.
cv2.rectangle(frame, (10, 70), (300, 340), (0, 255, 0), 2) cv2.rectangle(frame, (330, 70), (630, 370), (255, 0, 0), 2) roi = frame[70:300, 10:340] img = cv2.cvtColor(roi, cv2.COLOR_BGR2RGB) img = cv2.resize(img, (227, 227))
حال ، از الگویی که قبلاً آموزش دادیم استفاده کنید و حرکت را تشخیص دهید. حرکت تشخیص داده شده را با تصاویر مقایسه و نام حرکت را چاپ میکنیم.
pred = model.predict(np.array([img])) move_code = np.argmax(pred[0]) user_move_name = mapper(move_code)
در خط بعدی بررسی کنید که آیا کاربر حرکت می کند یا خیر. در غیر این صورت ، اجازه دهید رزبری پای حرکت تصادفی خود را انجام دهد و سپس از تابع calculate_winner برای تصمیم گیری در مورد برنده استفاده کنید. اگر حرکت کاربر “هیچ چیز (nothing)” نیست ، منتظر بمانید تا کاربر یک حرکت را انجام دهد.
if prev_move != user_move_name: if user_move_name != "nothing": computer_move_name = choice(['rock', 'paper', 'scissors']) winner = calculate_winner(user_move_name, computer_move_name) else: computer_move_name = "nothing" winner = "Waiting..." prev_move = user_move_name
در این خطوط ، از تابع cv2.putText برای نمایش حرکت کاربر ، حرکت رزبری پای و نمایش نام برنده برنده در قاب استفاده کرده ایم.
font = cv2.FONT_HERSHEY_SIMPLEX cv2.putText(frame, "Your Move: " + user_move_name, (10, 50), font, 1, (255, 255, 255), 2, cv2.LINE_AA) cv2.putText(frame, "Pi's Move: " + computer_move_name, (330, 50), font, 1, (255, 255, 255), 2, cv2.LINE_AA) cv2.putText(frame, "Winner: " + winner, (100, 450), font, 2, (0, 255, 0), 4, cv2.LINE_AA)
اکنون ، حرکت رزبری پای را در داخل مستطیلی که قبلاً ایجاد کردیم نمایش خواهیم داد. برد رزبری پای به صورت تصادفی یکی از تصویری را که در پوشه “test_img” ذخیره شده انتخاب می کند.
if computer_move_name != "nothing": icon = cv2.imread( "test_img/{}.png".format(computer_move_name)) icon = cv2.resize(icon, (300, 300)) frame[70:370, 330:630] = icon
حالا که همه چیز آماده است ، همانطور که در زیر نشان داده شده است، ماژول دوربین Raspberry Pi Camera را به رزبری پای وصل کنید:
سپس اسکریپت game.py را اجرا کنید. پس از چند ثانیه ، باید پنجره مشاهده تصویر دوربین خود را با دو مستطیل مشاهده کنید. مستطیل سمت چپ برای حرکت کاربر و سمت راست برای حرکت رزبری پای است. بنابراین ، دست خود را درون مستطیل تنظیم کنید و حرکتی انجام دهید. با تشخیص حالت دست شما، Raspberry Pi نیز حرکتی انجام می دهد و پس از مقایسه هر دو حرکت ، برنده اعلام میشود.
به این ترتیب می توانید بازی سنگ کاغذ قیچی را با استفاده از رزبری پای، OpenCV و python بازی کنید.
موارد موجود در فایل : سورس کامل و تصاویر مورد نیاز
برای دانلود فایل ها باید حساب کاربری داشته باشید ثبت نام / ورود