آموزش اتصال به وبکم با OpenCV
در این پست یک آموزش جذاب داریم؛ آموزش اتصال به وبکم با OpenCV. در پایان این پست شما قادر خواهید بود که به وبکم سیستم خود متصل شده و از آن ویدئو دریافت کنید. با من همراه باشید.
فراخوانی کتابخانه OpenCV
در اولین قدم باید کتابخانه OpenCV را فراخوانی کنیم. برای این کار کافی است بنویسیم:
import cv2
من از سیستم شخصی برای کدنویسی استفاده میکنم که در حال حاضر ورژن OpenCV آن 4.9.0 است. برای اینکه بفهمید یک کتابخانه چه ورژنی دارد، خیلی ساده، از متد __version__ استفاده کنید:
print(cv2.__version__)
4.9.0
واضح است دیگر؟ برویم سراغ بخش اصلی آموزش اتصال به وبکم با OpenCV.
دستور VideoCapture در OpenCV
برای اتصال به وبکم کافی است از VideoCapture استفاده کنیم که یک کلاس پایتونی است. دقت کنید که حروف V و C باید به شکل capital یا بزرگ نوشته شوند. حالا در ورودی، شماره وبکم را باید وارد کنیم. اگر سیستم شما یک وبکم دارد، عدد 0 را باید وارد کنید. با توضیحات گفته شده، بیایید یک آبجکت بسازیم:
cap = cv2.VideoCapture(0)
با اجرای این دستور شما به وبکم متصل خواهید شد. با گذاشتن یک نقطه (Dot) کنار cap میتوانید مشاهده کنید که متدها و اتریبیوتهای زیادی دارد. در ادامه چند مورد از این متدها را با هم بررسی میکنیم.
متد isOpened در OpenCV
بعد از اجرای دستوری که در بخش قبل نوشتیم، شاید این سوال برای شما ایجاد شده که از کجا بفهمیم اتصال به وبکم به درستی صورت گرفته یا نه؟ یکی از متدهایی که نشان میدهد این اتصال به درستی صورت گرفته یا نه، متد isOpened است. برای این کار کافی است بنویسید:
cap.isOpened()
True
خروجی این متد، در صورتی که اتصال به درستی انجام شده باشد، True و اگر اتصال به درستی انجام نشده باشد False است. مشاهده میکنید که خروجی ما True است، یعنی اتصال به درستی انجام شده است.
خواندن تصویر از وبکم با متد read
با استفاده از متد read میتوانید از وبکم تصویر دریافت کنید:
cap.read()
با اجرای این دستور، مشاهده میکنید که یک Tuple در خروجی دارید که دو عضو دارد. اولین خروجی (در مستندات این مقدار را retval میگویند که مخفف return value است.) یک مقدار بولین و دومین خروجی (Image) هم تصویر بوده که به صورت یک آرایه نامپای است. حالا retval چه موقعی True و چه موقعی False است؟ زمانی که ورودی دوم یعنی Image، به هر دلیلی None شود، retval برابر با False خواهد شد، در غیر اینصورت True خواهد بود.
خب حالا بیایید تصویر را نمایش دهیم. ابتدا کد قبلی را به این شکل تغییر میدهم تا تصویر در یک متغیر جداگانه ذخیره شود:
retval, frame = cap.read()
من نام متغیر را frame گذاشتم چون در واقع یک فریم از ویدئو هست. حالا بیایید با OpenCV این تصویر را نمایش دهیم. برای این کار کدهای زیر را بنویسید:
cv2.imshow("webcam", frame) cv2.waitKey() cv2.destroyAllWindows()
با اجرای این کدها، تصویر وبکم نمایش داده خواهد شد. حالا بیایید خط به خط این کد را بررسی کنیم. خط اول دستور imshow است که یک تصویر را نمایش میدهد. ورودی اول، نام پنجرهای است که باز میشود و ورودی دوم یک آرایه (همان تصویر) است. اما مساله این است که صرفا با اجرای این خط، هیچ تصویری نمایش داده نخواهد شد! یک پنجره باز میشود و اگر روی آن کلیک کنید عبارت Not Responding در عنوان آن ظاهر خواهد شد.
حالا چاره چیست؟ خط دوم! waitKey صبر میکند تا یک کلید فشرده شود. با این کار، پنجره باز شده، فریز میشود تا یک کلید را بزنیم. تا اینجا اگر این دو خط را فقط اجرا کنیم، میبینیم که تصویر نمایش داده میشود، اما باز برای بستن پنجره معضل داریم! همان آش است و همان کاسه. راه حل این مشکل هم خط سوم از کد است، destroyAllWindows. این دستور پنجرههای باز شده را میبندد.
حالا شما میتوانید یک تصویر از وبکم بگیرید و آن را نمایش دهید. حالا بعد از باز شدن تصویر، هر کلیدی را بزنید، خیلی شیک و مجلسی تصویر شما بسته خواهد شد!
بسته شدن تصویر بعد از یک زمان مشخص
در کد قبلی، بعد از اینکه یک کلید را بزنیم، پنجره بسته خواهد شد. اگر در ورودی waitKey یک عدد وارد کنیم، بعد از آن زمان مشخص، پنجره بسته خواهد شد. زمان هم بر حسب میلی ثانیه است. مثلا:
cv2.imshow("webcam", frame) cv2.waitKey(100) cv2.destroyAllWindows()
در کد بالا، تصویر نمایش داده شده و بعد از 100 میلی ثانیه، به صورت خودکار پنجره بسته خواهد شد.
چطور ویدئو از وبکم بگیریم؟
خب تا اینجا یک فریم از وبکم را دیدیم، چطور ویدئو بگیریم؟ لطفا این تمرینی که میگویم را همین الان انجام دهید. کد زیر را پشت سر هم تند تند اجرا کنید:
retval, frame = cap.read() cv2.imshow("webcam", frame) cv2.waitKey(100) cv2.destroyAllWindows()
با اجرای این کد میبینید که ما با تکرار کد بالا میتوانیم تقریبا یک ویدئو داشته باشیم! پس به حلقه نیاز داریم.
قدم اول: حلقه while و خواندن تصویر
با حلقه while شروع میکنیم. شرط آن را روشن بودن وبکم میگذاریم. شرط را روشن بودن وبکم میگذاریم. در حلقه هم اولین کاری که باید انجام دهیم، خواندن تصویر با read است. به این صورت:
while cap.isOpened(): retval, frame = cap.read()
به این صورت میتوانیم یک حلقه بینهایت داشته باشیم.
قدم دوم: متوقف کردن برنامه زمانی که تصویر None باشد
همین اول بهتر است برای زمانی که تصویر به درستی کپچر نشده و retval برابر با False است فکری کنیم. یک شرط اضافه میکنیم که اگر این حالت پیش بیاید، حلقه متوقف شود:
while cap.isOpened(): retval, frame = cap.read() if not retval: break
قدم سوم: نمایش تصویر
حالا باید فریم دریافتی را نمایش دهیم:
while cap.isOpened(): retval, frame = cap.read() if not retval: break cv2.imshow("webcam", frame) cv2.waitKey() cv2.destroyAllWindows()
با اجرای این کد، یک فریم از تصویر نمایش داده میشود و با زدن یک کلید، پنجره بسته شده و تصویر دیگری نمایش داده خواهد شد. این خیلی باب میل ما نیست. طبیعتا بهتر است تصاویر پشت سر همدیگر نمایش داده شوند.
قدم چهارم: بهتر کردن نحوه نمایش ویدئو
برای حل این مشکل، اولین کاری که انجام میدهیم این است که destroyAllWindows را به خارج از حلقه منتقل میکنیم تا فقط بعد از اتمام نمایش ویدئو، پنجره تصویر بسته شود:
while cap.isOpened(): retval, frame = cap.read() if not retval: break cv2.imshow("webcam", frame) cv2.waitKey() cv2.destroyAllWindows()
مشکل دیگری که وجود دارد این است که ما باید حتما یک کلیدی را بزنیم تا فریم بعدی نشان داده شود. خب، این هم ساده است. کافی است یک عدد در ورودی waitKey وارد کنیم که بعد از آن زمان، فریم بعدی را نمایش دهد. یک میلی ثانیه برای اینکار مناسب است:
while cap.isOpened(): retval, frame = cap.read() if not retval: break cv2.imshow("webcam", frame) cv2.waitKey(1) cv2.destroyAllWindows()
با اجرای کد بالا میبینید که مشکل حل شده و کد ما به درستی کار میکند. تا اینکه تصمیم میگیریم پنجره را ببندیم! باز هم به مشکل میخوریم. هر بار که پنجره را ببندیم، مجدد باز میشود. طبیعتا شما میتوانید به صورت دستی برنامه را متوقف کنید ولی این اصلا حرفهای نیست. حالت ایدهآل این است که با زدن یک کلید، نمایش متوقف شود. اما چطور؟
قدم پنجم: متوقف کردن برنامه با استفاده از خروجی waitKey
این گره با دستان waitKey باز میشود. خروجی waitKey نشاندهنده unicode کلیدی است که کاربر وارد کرده است. در حالتی که در ورودی آن یک زمان وارد کنیم، خروجی آن همیشه -1 است که نشان میدهد هیچ کلیدی فشرده نشده. اما به محض اینکه یک کلید فشرده شود، خروجی این دستور معادل unicode همان کلید خواهد بود. مثلا اگر کلید q را فشار دهید، خروجی این دستور مقدار 113 خواهد بود که unicode حرف q است.
با دانستن این مساله و نوشتن یک عبارت شرطی، این مشکل هم قابل حل است. کافی است خروجی waitKey را در یک متغیر ذخیره کرده و سپس اگر این کلید معادل unicode حرف q بود، برنامه متوقف شود:
while cap.isOpened(): retval, frame = cap.read() if not retval: break cv2.imshow("webcam", frame) key = cv2.waitKey(1) if key == 113: break cv2.destroyAllWindows()
البته این هم خیلی حرفهای نیست. با دستور ord میتوان مقدار unicode هر حرف یا عدد را به دست آورد. پس از این دستور استفاده میکنیم:
while cap.isOpened(): retval, frame = cap.read() if not retval: break cv2.imshow("webcam", frame) key = cv2.waitKey(1) if key == ord('q'): break cv2.destroyAllWindows()
خاموش کردن وبکم
بعد از اینکه کدهای بالا اجرا شدند و پنجره را بستیم، مشاهده میکنید که LED کنار وبکم هنوز روشن است. بله چون وبکم روشن است. برای خاموش کردن وبکم از متد release استفاده کنید، به این شکل:
cap.release()
با اجرای این کد وبکم خاموش خواهد شد.
جمعبندی
در این پست توانستیم با استفاده از OpenCV از وبکم ویدئو دریافت کنیم. به چالشهای متعددی برخورد کردیم ولی قدم به قدم این مشکلات را رفع نمودیم. کد نهایی ما به این شکل است:
import cv2 cap = cv2.VideoCapture(0) while cap.isOpened(): retval, frame = cap.read() if not retval: break cv2.imshow("webcam", frame) key = cv2.waitKey(1) if key == ord('q'): break cv2.destroyAllWindows() cap.release()
امیدوارم از این آموزش خوشتان آمده باشد. لطفا حتما نظرتان در مورد این آموزش را برای ما کامنت کنید. تا آموزشهای بعدی، خدانگهدار.
مطالب زیر را حتما مطالعه کنید
تصویر دیجیتال چیست؟
آموزش OpenCV
2 دیدگاه
به گفتگوی ما بپیوندید و دیدگاه خود را با ما در میان بگذارید.
سلام ، خیلی ساده و جامع توضیح دادید ، درود بر شما
بسیار عالی بود توضیحات. لذت بردم