در این مقاله میخواهیم یک پروژه جالب و کاربردی را با هم تعریف کنیم و مرحله به مرحله تا گرفتن خروجی جلو ببریم. حتما در سیستم خودتان انجام دهید ممکن است ایده های تازه و بدردبخوری از داخلش دربیاید.
اما قضیه از چه قرار است؟
یک پروژه بینایی ماشین که شما هم بعد از خواندن مقاله بگوئید که چقدر میتواند کاربردی باشد یا که نه!
با هم در محیط ژوپیتر نوت بوک یک فایل پایتون ایجاد میکنیم و با استفاده پکیج پردازش تصویر و بینایی ماشین بسیار محبوب opencv سعی میکنیم اشیا را بر اساس رنگشان دسته بندی و تعدادشان را شمارش کنیم و در صفحه، نمایش دهیم.
رنگ اشیا و تعدادشان را میتوانیم برای نمایش در یک lcd کوچک از طریق پورت سریال به آردوینو بفرستیم تا به نحوی نتیجه کارمان را در دنیای خارج از کامپیوترمان هم ببینیم. فکر نمیکنم در این مطلب این را هم بتوانیم جا دهیم شاید در یک مقاله جداگانه انجامش دادیم. اگر بنظرتان جالب آمد در کامنت ها بگوئید.
اگر نمیدانید چطور باید ژوپیتر نوت بوک را روی سیستم تان نصب کنید به مقاله زیر مراجعه کنید:
https://sisoog.com/ai-environment-setup-anaconda-numpy-tensorflow-jupyter/
حالا نیاز داریم که ماژول opencv را نصب کنیم. من از نسخه پایتون 3.9.12 و نسخه نامپای 1.21.5 استفاده میکنم. نسخه opencv سازگار با این دو، نسخه 4.5.2.54 است.
با زدن کد پایین در محیط دستوری ماژول نصب خواهد شد:
|
1 |
pip install opencv-python==4.5.2.54 |
اگر روی لپتاپ کد میزنید احتمال قوی دوربین لپتاپ تان کار میکند پس مشکلی از بابت دریافت تصاویر بصورت ریل-تایم نخواهید داشت.
اگر روی کامپیوتر کد میزنید و وبکم دارید شما هم مثل مورد بالا مشکلی نخواهید داشت.
اگر با لپتاپ کار میکنید و وبکم دستگاه تان هم به هر دلیلی کار نمیکند و کامپیوترتان هم وبکم ندارد؛ اما موبایل اندرویدی دارید میتوانید نرم افزارهایی از اینترنت پیدا کنید که دوربین موبایل را با دستگاه ویندوزی به اشتراک میگذارد.
نرم افزار نمونه(من هم از این استفاده میکنم):
https://soft98.ir/internet/1871-droidcam.html
دقت کنید در حین استفاده از نرم افزار، موبایل و کامپیوتر هر دو به یک شبکه متصل باشند. مثلا هر دو به شبکه وای فای خانگی وصل هستند.
اما اگر نه دوربین دارید نه وبکم نه موبایل اندرویدی باز نگران نباشید. میتوانید با تغییراتی در کد از عکس ها یا ویدیوهای موجود در سیستمتان به عنوان داده استفاده کنید.
هیچ بهانه ای قابل قبول نیست و هیچ کمبودی نباید ما را از کار کردن جا بزارد.
من از ژوپیتر نوت بوک برای کد زدن استفاده خواهم کرد. اما اگر ترجیح شما محیط دیگری است مشکلی نیست.
برای وارد شدن به محیط ژوپیتر کافی است در محیط دستوری ویندوز، دستور زیر را وارد کنید:
|
1 |
jupyter notebook |
اگر از محیط دستوری ویندوز استفاده میکنید دقت کنید هنگام نصب مفسر پایتون گزینه add to path را فعال کرده باشید در غیر این صورت اگرچه پایتون را نصب کرده اید اما نخواهید توانست به صورت بالا از ژوپیتر استفاده کنید.
با زدن دستور بالا یک سرور محلی روی سیستم تان اجرا خواهد شد و بطور خودکار محیط ژوپیتر روی مرورگر پیش فرض تان در یک صفحه بالا خواهد آمد چیزی شبیه به تصویر پایین:

روی new بزنید و python 3 را کلیک کنید.

در محیط باز شده با کلیک روی عبارت Untitled برای پروژه خود یک نام انتخاب کنید. دقت کنید پس از وارد کردن نام دلخواه از پسوند ipynb. استفاده کنید.
کار را با وارد کردن ماژول های مورد نیاز شروع میکنیم.
دقت کنید که هر تکه کد را در یک بلوک جداگانه بنویسید. برای اضافه کردن بلوک در محیط ژوپیتر از علامت + در نوار ابزار استفاده کنید.
|
1 2 |
import numpy as np import cv2 as cv |
ماژول های opencv و numpy را وارد پروژه کردیم. بلوک را با زدن دکمه ترکیبی شیفت/اینتر اجرا کنید اگر اروری رخ نداد به درستی وارد پروژه شده اند.
حالا دوربین یا وبکم را برای دریافت تصاویر ریل-تایم آماده میکنیم.
|
1 2 3 4 |
cap=cv.VideoCapture(0) if not cap.isOpened(): print("Error: can not open camera") exit() |
اما کسانی که میخواهند از دوربین موبایل شان به عنوان منبع دریافت تصویر استفاده کنند بایستی بعد از اجرای نرم افزار مربوطه در موبایل که لینک دانلودش را در بالا گذاشتم؛ یک آدرس وب را که در صفحه اصلی مشاهده میکنند را به عنوان پارامتر به متود راه اندازی دوربین بجای عدد صفر بدهند این کار را بصورت زیر انجام دهید و با خط اول کد عوض کنید:
|
1 2 |
url="http://192.168.1.102:4747/video" # put your own ip (find it on driodcam app main page) cap=cv.VideoCapture(url) |
فرض میکنیم میخواهیم روی دو رنگ سفید و سبز کار کنیم. که البته شما میتوانید به سلیقه خودتان روی رنگ های دیگر هم کار کنید.
ممکن است اشیا شامل طیف مختلفی از رنگ سبز یا سفید باشند یعنی یکی سبز پررنگ باشد دیگری کمی کمرنگ تر. که بصورت زیر تعریفشان خواهیم کرد.هر رنگ شامل یک آستانه بالا و یک آستانه پایین است.برای این کار از متود array در نامپای استفاده میکنیم.
از سیستم رنگی HSV برای تعریف رنگ ها استفاده میکنیم.
(سیستم های رنگی مختلفی وجود دارند مانند: RGB,BGR,HSV و …)اگر علاقه مند به اطلاعات بیشتر بودید به این مقاله یک سر بزنید:
https://snowball.digital/blog/color-systems-cmyk-pantone-rgb-and-ral-explained
بلوک کد تعریف طیف رنگ ها:
|
1 2 3 4 5 |
green_lower = np.array([35, 100, 100]) green_upper = np.array([85, 255, 255]) white_lower = np.array([0, 0, 180]) white_upper = np.array([180, 30, 255]) |
میتوانیم شروع کنیم به نوشتن قسمت اصلی کد:کل الگوریتم قرار است داخل یک حلقه بینهایت (کسایی که الکترونیکی هستند: منظورم همان super loop است که در برنامه نویسی میکرو ها هم استفاده میشود)اجرا شود که فقط یک شرط خروج خواهد داشت که خواهیم توانست با فشردن یک کلید روی کیبورد فرایند را متوقف کنیم.
کل کد را داخل یک بلوک میاورم. و جلوی هر خط توضیحات مربوطه را مینویسم.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
while True: # main loop. true means loop will continue for ever ret,frame=cap.read() # get frame from camera if not ret: # ret could be true: frame captured , false: frame did not capture print("Error: can not receive frame. exiting...") break # break the wile loop if frame did not capture kernel=(5,5) # a 5 by 5 matrix blur=cv.GaussianBlur(frame,kernel,0) # reducing image noise # change frames color space to hsv from bgr. by defult opencv read images in bgr color space hsv = cv.cvtColor(blur, cv.COLOR_BGR2HSV) # make mask depend on defined colors range (white and green)(for example we used white color first) mask_white = cv.inRange(hsv, white_lower, white_upper) mask_white = cv.morphologyEx(mask_white, cv.MORPH_CLOSE, kernel) # apply some noise reducing methodes on created mask mask_white = cv.morphologyEx(mask_white, cv.MORPH_OPEN, kernel) contours, hierarchy=cv.findContours(mask_white,cv.RETR_TREE,cv.CHAIN_APPROX_NONE) #find objects in mask for contour in contours: # for loop to drowing line around detected objects area=cv.contourArea(contour) if area > 300 : # change to detect bigger or samller objects in white color cv.drawContours(frame,contour,-1,(0,255,0),3) font = cv.FONT_HERSHEY_SIMPLEX # set font to put numbers of detected objects text="total count: "+str(len(contours)) # get number of objects with len(contours) cv.putText(frame,text,(50,50),font,1,(0,255,0),2) # put number of objects on main frame cv.imshow("video",frame) # itd clear enough. showing frame contain lines around white objects if cv.waitKey(1) & 0xFF == ord('q'): # to exit from the while loop we can set a char like 'q' to press break cap.release() # stop capturing camera cv.destroyAllWindows() # destroy all current showing windows |
کد ما آمده استفاده است با اجرا کردن بلوک میتوانید بصورت زنده کارکرد را ببینید.
یک پس زمینه با رنگ دلخواه مانند سیاه یا قرمز یا … ایجاد کنید و چند شی سفید رنگ(تکه های سفید کاغذ مثال خوبی است) رویش قرار دهید و دوربین را بصورت ثابت رویش بگیرید نتیجه را مشاهده خواهید کرد.
همچنین میتوانید اندازه شیی که تشخیص میدهید را داخل کد تنظیم کنید مثلا اشیا با اندازه بزرگتر از x را تشخیص دهید و کوچکتر ها را صرف نظر کنید.
این خط را داخل کد اصلی پیدا کنید و عدد 300 را تغییر دهید تا نتیجه را ببینید:
|
1 2 |
if area > 300 : # change to detect bigger or samller objects in white color cv.drawContours(frame,contour,-1,(0,255,0),3) |
با توجه به کیفیت دوربین و شرایط نوری محیط و همچنین لرزش تصویر ممکن است نتیجه نمایش داده شده با یک یا دو واحد اختلاف همراه باشد که ایرادی ندارد. چون در پروژه واقعی شرایط بالا کاملا تحت کنترل هستند. هرچند که همینطور هم دقت و سرعت بالایی را شاهد خواهیم بود.

میز من قرمز رنگ است و تعدادی تکه کاغذ سفید روی میز قرار دادم و نتیجه اجرای کد در تصویر بالا قابل مشاهده است.
یک مثال هم برای کسانی که به دوربین دسترسی ندارند و یا به هر دلیلی میخواهند از تصاویر موجود در حافظه کامپیوترشان استفاده کنند کد به شکل زیر باید تغییر کند.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
src="test.png" #make sure your image is in your project path and name is currect (test) frame=cv.imread(src) # get frame from camera kernel=(5,5) # a 5 by 5 matrix blur=cv.GaussianBlur(frame,kernel,0) # reducing image noise # change frames color space to hsv from bgr. by defult opencv read images in bgr color space hsv = cv.cvtColor(blur, cv.COLOR_BGR2HSV) # make mask depend on defined colors range (white and green)(for example we used white color first) mask_white = cv.inRange(hsv, white_lower, white_upper) mask_white = cv.morphologyEx(mask_white, cv.MORPH_CLOSE, kernel) # apply some noise reducing methodes on created mask mask_white = cv.morphologyEx(mask_white, cv.MORPH_OPEN, kernel) contours, hierarchy=cv.findContours(mask_white,cv.RETR_TREE,cv.CHAIN_APPROX_NONE) #find objects in mask for contour in contours: # for loop to drowing line around detected objects area=cv.contourArea(contour) if area > 300 : # change to detect bigger or samller objects in white color cv.drawContours(frame,contour,-1,(0,255,0),3) font = cv.FONT_HERSHEY_SIMPLEX # set font to put numbers of detected objects text="total count: "+str(len(contours)) # get number of objects with len(contours) cv.putText(frame,text,(50,50),font,1,(0,255,0),2) # put number of objects on main frame cv.imshow("test",frame) # itd clear enough. showing frame contain lines around white objects cv.waitKey(0) # press any key on keyboard to destroy window cv.destroyAllWindows() # destroy all current showing windows |
تصویر نمونه(دانلود و استفاده کنید.):

نتیجه بعد از اجرای کد:

همانطور که در مثال میبینید اشیا سفید فارغ از شکل شی تشخیص و شمارش شده اند درحالی که از اشیا قرمز رنگ صرف نظر شده است.
حالا هر طور که دوست دارید پارامتر ها را تغییر دهید و نتایج جدید را مشاهده کنید.
برای ذخیره کردن تصویر خروجی از کد زیر استفاده کنید.
|
1 |
cv.imwrite("save_frame.jpg", frame) |
دیدید که فقط از روش های پردازش تصویر استفاده کردیم. حالا اگر مسئله پیچیده تر شود و نتوان دیگر فقط با روش پردازش تصویر کار را انجام داد چه؟
مثلا اگر بخواهیم اشیا را بر اساس چیزی که هستند دسته بندی کنیم چه؟آن موقع میرویم سراغ هوش مصنوعی و چیزهایی مثل میوه یا حیوانات را دسته بندی میکنیم.
مطلب به پایان رسید نظرات تان را بنویسید اگر ایده جدیدی به سرتان زده یا …
سیسوگ با افتخار فضایی برای اشتراک گذاری دانش شماست. برای ما مقاله بنویسید.