آموزش OpenCV
بهنام خدا، ســــــــلام… خوشحالم که یک وبلاگ دیگر را شروع کردم. در این پست طولانی میخواهم شما را با OpenCV جذاب و کاربردی آشنا کنم. از الفبای OpenCV شروع میکنیم و تا سطح خوبی پیش میرویم. برو بریم…
صحبت خودمانی از OpenCV
در این بخش حرف علمی ندارم. صرفا بخشی از خاطراتم با OpenCV را میخواهم تعریف کنم! دوست داشتید، مطالعه کنید. اگر هم دوست ندارید، از این بخش بپرید.
خاطرات زیادی با OpenCV دارم و بخشی از این خاطرات با درد و رنج همراه هست! اولین بار در مقطع ارشد، در درس بینایی کامپیوتر با موجودی بهنام OpenCV آشنا شدم. تا قبل آن، من و اکثر دوستانم تنها به متلب مسلط بودیم. پایتون هم هنوز بین محققان و دانشجویان شناخته شده نبود. من و دوستانم دانشجوی برق الکترونیک دیجیتال بودیم که میخواستیم در حوزه بینایی کامپیوتر کار کنیم و به همین خاطر از دانشکده کامپیوتر درس بینایی کامپیوتر را انتخاب کرده بودیم.
به استاد گفتیم که ما برقی هستیم و اجازه بده ما تمرینها را با متلب ارائه دهیم، اما قبول نکرد! آن موقعها OpenCV نسخه پایتونی نداشت و باید حتما با ++C کدنویسی میزدیم. دو ورژن از OpenCV وجود داشت که یکی خیلی خیلی سخت بود! اما متاسفانه ورژن دیگرش هم خیلی سخت بود! 🙄
از کدنویسی سخت آن بگذریم، راهاندازی OpenCV در محیط ویژوال استودیو خودش یک پروژه بود! برای ما که با این چیزها آشنا نبودیم، اوضاع اصلا خوب نبود. منابع اینترنتی محدود بود و نمیدانم چرا دوستان کامپیوتری چندان کمکمان نمیکردند. تا مدتها دغدغه ما این بود که بتوانیم OpenCV را به ویژوال استودیو اضافه کنیم که تازه بتوانیم کدنویسی را شروع کنیم. موعد تحویل تمرین سری اول رسیده بود و ما همچنان درگیر راهاندازی بودیم! بالاخره بعد از هفتهها توانستیم راهاندازی کنیم! لحظه راهاندازی را هرگز یادم نمیرود. تقریبا شبیه ماجرای بازگشت میمون فضانورد از فضا بود!
تا همین جای کار هم خسته شده بودیم، اما مساله این بود که تازه اول راه بودیم و باید شروع میکردیم به یادگیری ++C و OpenCV… یک کتاب اسکنشده فارسی آموزش ++C از آقای جعفرنژاد قمی به دستمان رسید. خیلی ساده و روان آموزش داده بود. ما هم که به واسطه تسلط بر متلب، کانسپت برنامهنویسی را میدانستیم، سریع ++C را در حد نیاز یاد گرفتیم و رفتیم سراغ OpenCV…
برای OpenCV یکی دو کتاب نسبتا خوب وجود داشت. با همانها شروع کردیم و در ابتدای کار اصلا یک خط کد هم نمیتوانستیم بنویسیم و دائما کپی پیست میکردیم. به انتهای درس رسیدیم و کل تابستان هم درگیر تمرینها و مسابقه درس بینایی کامپیوتر بودیم. اما خوشبختانه آخر کار اوضاعمان بهتر شده بود. خیلی درد و رنج داشت، اما یک مهارت و ابزار خوب به ما اضافه شده بود. بعدها من در کارم از OpenCV خیلی استفاده کردم و پروژههای سطح بالایی را با آن پیادهسازی کردم.
قبل از یادگیری عمیق، فریمورک OpenCV با ++C به شدت در کارهای عملی استفاده میشد. بعد از رشد پایتون در حوزه هوش مصنوعی، نسخه پایتون OpenCV هم آمد. امروزه، اکثرا OpenCV را با نسخه پایتونی میشناسند، اما نسخه ++C آن بسیار کاربردی است و رقیبی هم ندارد.
OpenCV چیست؟
OpenCV مخفف عبارت Open Source Computer Vision هست. یعنی یک کتابخانه متن باز در حوزه بینایی کامپیوتر…
نصب OpenCV در پایتون
برای نصب OpenCV در پایتون، ابتدا باید cmd را در ویندوز باز کنید. سپس عبارت زیر را در cmd بنویسید:
pip install opencv-python
با اجرای کد بالا، کتابخانه OpenCV در پایتون نصب خواهد شد. برای استفاده از کتابخانه OpenCV در پایتون، نصب آن کافی نیست و باید آن را فراخوانی یا import کنیم. برای این کار از دستور import استفاده میکنیم:
import cv2
با اجرای دستور بالا کتابخانه OpenCV در پایتون فراخوانی خواهد شد. دقت کنید، اسم کتابخانه OpenCV در پایتون cv2 است. با استفاده از دستور زیر میتوانید ورژن OpenCV را چک کنید:
print(f'OpenCV version: {cv2.__version__}')
OpenCV version: 4.5.5
فراخوانی و نمایش تصویر در OpenCV
یکی از ابتداییترین کارهایی که معمولا در OpenCV انجام میدهیم، فراخوانی و نمایش تصویر هست. ابتدا درمورد فراخوانی تصویر توضیح میدهم و سپس به نمایش تصویر میرسیم.
فراخوانی تصویر
با استفاده از دستور imread میتوانید به راحتی تصاویر با فرمتهای مختلف مانند JPEG BMP PNG و غیره را فراخوانی کنید. بیایید یک نمونه تصویر فراخوانی کنیم. میتوانید از اینجا چند نمونه تصویر دانلود و در سیستم خود تست کنید.
# Load an image from a file image = cv2.imread('images/image-2.jpg')
بیایید با متغیر image که شامل تصویر ماست کمی کار کنیم. جنس این متغیر چیست؟ برای فهمیدن این مساله باید بنویسیم:
type(image)
numpy.ndarray
جالب شد! نامپای اینجا چه کار میکند؟ تصاویر بعد از فراخوانی، از جنس آرایه نامپای هستند. یادتان باشد این تصاویر رنگی رنگی، پیکسلی و رنگ و لعابدار، بعد از بارگذاری فقط یک آرایه چندبعدی هستند. بسته به نوع تصویر، ممکن هست با آرایه دو بعدی یا سهبعدی مواجه شویم. چگونه میتوانیم ابعاد تصویر را ببینیم؟ با استفاده از shape.:
image.shape
(600, 602, 3)
میدانید منظور از ابعاد چیست؟ همان رزولوشن تصویر که میگوییم مثلا این تصویر 2000×3000 هست. در اینجا تصویر ما 602 در 600 هست. 602 سطر و 600 ستون دارد. فعلا به عدد 3 توجه نکنید! بعدا بیشتر درمورد آن توضیح میدهم.
پرینت کردن image هم خالی از لطف نیست!
print(image)
array([[[29, 25, 14], [29, 25, 14], [29, 25, 14], ..., [29, 25, 14], [29, 25, 14], [29, 25, 14]]], dtype=uint8)
مشاهده میکنید که انباری از اعداد داریم. هرکدام از این اعداد معادل یک پیکسل در تصویر هستند. البته، نکات مهمی در خروجی بالا مشاهده میشود. دیتاتایپ تصویر، unit8 هست؛ یعنی، اعداد درون این آرایه، اعداد صحیح (Integer) بدون علامت (Unsigned) 8 بیتی هستند. بنابراین، اعداد درون این ماتریس باید اعدادی بین 0 تا 255 باشد. نهایتا 256 حالت داریم! اغلب تصاویری که فراخوانی میکنیم، چنین ساختاری دارند. یکسری تصاویر خاص مانند تصاویر پزشکی یا تصاویر ماهوارهای ممکن هست دیتاتایپ متفاوتی داشته باشند.
هشدار یکی از اشتباهات رایج در بارگذاری تصویر، مسیر اشتباه از تصویر هست. اگر مسیر اشتباه باشد، OpenCV اصلا به روی خودش نمیآورد و هیچ خطایی به شما نشان نمیدهد. وقتی آدرس درست نباشد، None را در متغیر مدنظر میریزد! اینطور نیست که بگوید آدرس اشتباه هست. این باعث میشود که افراد فکر کنند چون خطایی نداریم، پس تصویر به درستی فراخوانی شده! با کد زیر میتوانید خروجی تصویر را چک کنید:
# Load an image from a file image = cv2.imread('image-0.jpg') # Check if the image was loaded successfully if image is not None: print('Image loaded successfully') else: print('Failed to load image')
نمایش تصویر
برای نمایش تصویر بارگذاریشده باید از دستور imshow استفاده کنیم. دستور imshow دو ورودی دریافت میکند:
- عنوان این تصویر هنگام نمایش (نام دلخواه)
- تصویر (نام متغیری که تصویر در آن ریخته شده!)
این هم نحوه استفاده از این دستور:
# Display the loaded image cv2.imshow('Loaded Image', image) cv2.waitkey(0)
و این هم نتیجه 😍:
نکته 1 اگر در محیطی مانند Pycharm یا VSCode کدنویسی میکنید. حتما باید دستور ()cv2.waitkey را بنویسید تا نتیجه را به شما نشان دهد. عددی که داخل پرانتز این دستور نوشته میشود، زمان انتظار هست. اگر عدد صفر باشد، پنجره نمایش تصویر بهصورت دائمی باز خواهد بود. اما اگر مثلا عدد 1000 بنویسید، بعد از 1 ثانیه بهصورت خودکار بسته میشود.
نکته 2 اگر در محیطهای نوتبوکی کد را اجرا میکنید، بدانید که دستور ()cv2.imshow در این محیط کار نمیکند. برای نمایش تصویر از دستور plt.imshow(img) استفاده کنید. ()plt.imshow یکی از دستورات فریمورک matplotlib هست.
import matplotlib.pyplot as plt plt.imshow(image) plt.axis('off')
نکته 3 احتمالا بعد از اجرای دستورهای نکته 2 میبینید که تصویر شما آبی است و با تصویری که ما نمایش دادیم متفاوت است. دلیل این کار این است که matplotlib تصاویر را به صورت RGB میخواند و پردازش میکند، ولی OpenCV تصاویر را به صورت BGR میبیند! 🤯😵 بنابراین شما برای اینکه تصویر را با matplotlib نمایش دهید نیاز به یک خط کد دارید که تصویر را از BGR به RGB تبدیل کند:
import matplotlib.pyplot as plt image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) plt.imshow(image_rgb) plt.axis('off')
نکته 4 باید دقت کنید که در OpenCV شوخی کردم بابا نکته 4 نداریم دیگه 😜
بسیارخب! تا اینجا فراخوانی و نمایش یک تصویر را یاد گرفتید. باتوجه به اینکه در OpenCV با دادههای تصویری سروکار داریم، پیشنهاد میکنم قبل از مطالعه ادامه مباحث، پست تصویر دیجیتال چیست؟ را مطالعه کنید.
ریسایز تصویر با OpenCV
ریسایز تصویر یکی از کارهای رایج در کار با تصاویر هست. اتفاقا از جمله کارهایی هست که بسیار از کاربرهای کامپیوتر با آن آشنا هستند و با نرمافزارهای ساده مانند Paint هم میتوان چنین کاری را انجام داد. اما میخواهم به زبان علم پردازش تصویر درباره ریسایز صحبت کنم؛ ریسایز تصویر، یعنی تغییر رزولوشن (HxW) تصویر… مثلا، میخواهیم یک تصویر به ابعاد 300×300 را به تصویری به ابعاد 100×100 یا به ابعاد 600×600 تبدیل کنیم.
نکته به ریسایزی که منجر به بزرگ شدن تصویر شود، نمونهبرداری افزایشی (Up sampling) و به ریسایز منجر به کوچک شدن تصویر، نمونهبرداری کاهشی (Down sampling) گفته میشود.
تذکر اگرچه میتوانیم با ریسایز، تصویر را بزرگ کنیم، اما معمولا کیفیت تصویر به صورت قابل توجه افت میکند. بنابراین، معمولا در کدنویسی از ریسایز برای کاهش رزولوشن تصویر استفاده میکنیم. عجب! خب کاهش رزولوشن تصویر هم باعث افت کیفیت تصویر میشود! پس چرا ریسایز افزایشی هست ولی ریسایز کاهشی نیست؟ چون معمولا از ریسایز کاهشی برای کاهش هزینه محاسبات و مصرف رَم استفاده میشود.
حالا با این مقدمه، بیایید ببینیم ریسایز تصویر با OpenCV چگونه انجام میشود. با استفاده از دستور ()cv2.resize میتوانیم به راحتی ریسایز انجام دهیم. اما ورودیهای این دستور:
- src: تصویر ورودی که میخواهیم آن را ریسایز کنیم.
- dsize: سایزی که میخواهیم تصویر را به آن ریسایز کنیم.
- interpolation: تکنیک درونیابی
طبیعتا، دو آرگومان اول واضح هست. اما آرگومان درونیابی؟! ببینید، واقعیت این هست که این آرگومان وابسته به تئوری و ریاضیات هست. یعنی باید اول مفهوم آن را یاد بگیرید تا بتوانید به بهترین شکل از این دستور استفاده کنید. اما اینجا تمرکزم روی بحث تئوری نیست. به صورت خلاصه، برای ریسایز تصویر، تکنیکهای مختلفی در پردازش تصویر وجود دارد. در اینجا، لیستی از رایجترین تکنیکهای ریسایز تصویر فراهم شده که بسته به اهدافتان میتوانید یکی از آنها را انتخاب کنید. بیایید مرور کنیم:
- INTER_NEAREST: یکی از سادهترین روشهای درونیابی براساس نزدیکترین همسایگی
- INTER_LINEAR: روش دوخطی (Bilinear) که بازهم ساده و کمهزینه هست. گزینه پیشفرض هم همین هست.
- INTER_CUBIC: روش کیوبیک که از دو روش اول بهتر هست، اما هزینه محاسبات بیشتری هم دارد. یعنی زمانبرتر هست. زمانبرتر؟! 🤔
- INTER_LANCZOS4: روش لَنکزوس حتی از روش کیوبیک هم هزینه بیشتری دارد.
- موارد دیگری هم هست که بگذریم…
حالا بیایید با یک مثال، نحوه استفاده از این دستور را تمرین کنیم. کد زیر، تصویر ورودی را به ابعاد 250*300 ریسایز میکند. مشاهده میکنید که من تنها دو ورودی تصویر و سایز را مشخص کردهام و درونیابی را تغییر ندادهام.
image_resized = cv2.resize(image, (300, 250)) image_resized.shape
(250, 300, 3)
مشاهده میکنید که ریسایز انجام شده است. اما نکتهای که باید دقت کنید این است که در بخش سایز، اولین عددی که وارد میکنید، عرض تصویر و دومین عدد باید ارتفاع تصویر باشد. ارتفاع تصویر همان تعداد سطرهای آرایهی تصویر بوده و عرض تصویر همان تعداد ستونهای آرایهی تصویر است.
حالا بیایید چند نمونه خروجی از تصویر ریسایز ببینیم؛ از چپ به راست، ابتدا تصویر اصلی را میبینید. سپس، تصاویر ریسایز شده با ابعاد مختلف را مشاهده میکنید. هم تصاویر کوچک و هم تصاویر بزرگ دیده میشود.
تصویر اصلی | تصویر ریسایز شده |
تصویر اصلی با ابعاد 602*600 |
تصویر ریسایز شده با ابعاد 300*300 cv2.resize(image0, (300, 300)) |
تصویر اصلی با ابعاد 750*938 |
تصویر ریسایز شده با ابعاد 100*400 cv2.resize(image1, (100, 400)) |
تصویر اصلی با ابعاد 468*500 |
تصویر ریسایز شده با ابعاد 680*700 cv2.resize(image2, (700, 680)) |
اما نکته مهمی که وجود دارد این هست که بعضی از تصاویر از حالت نرمال خود خارج شدهاند. چرا اینطور شده؟ دلیلش این هست که نسبت ابعاد (Aspect Ratio) را به هم ریختهایم. به سطر دوم از جدول بالا نگاه کنید. نسبت ارتفاع به پهنا در تصویر اصلی ما، 938/750 یعنی 1.25 هست، درحالیکه این نسبت ارتفاع به پهنا در تصویر ریسایز شده برابر با 4 است. وقتی این نسبت را تغییر دهیم، خروجی ما دِفُرمه میشود. همه اینها را در نرمافزارها هم میتوان دید. یک آیکن برای حفظ نسبت ارتفاع به پهنا دارند.
کراپ (برش) تصویر با OpenCV
وقتی از ریسایز صحبت میکنیم، حتما باید از برش (crop) تصویر هم بگوییم. خب، خوشبختانه این مفهوم هم جدید نیست و بسیاری از ما قبلا با گوشی و کامپیوتر تصویر را برش زدهایم و بخشهای غیرضروری یا نامناسب را حذف کردهایم. مثلا، شکل زیر:
خبر خوب اینکه، برای برش تصویر نیازی به opencv نداریم! شاید کسانی که به نامپای مسلط هستند، میدانند که چه میگویم. ببینید، ما بالاتر نشان دادیم که وقتی تصویری با opencv خوانده میشود، یک آرایه نامپای هست. این یعنی، ما میتوانیم با استفاده از تکنیک اسلایس در نامپای، به راحتی تصاویر را برش بزنیم. در برش تصویر، ما به بُعد کانال کاری نداریم. پس آن عدد 3 را کنار بگذارید. ما باید محدوده مدنظرمان روی بُعد ارتفاع و پهنای تصویر مشخص کنیم. بهصورت کلی، فرمول برش تصویر به شکل زیر است:
cropped_image = image[hs:he, ws:we, :]
در فرمول بالا، hs و he بهترتیب به ابتدا و انتهای بازه برش در ارتفاع اشاره میکنند. بهصورت مشابه، ws و we هم به ابتدای و انتهای بازه پهنا اشاره دارند. حالا بیایید، یک نمونه مثال ببینیم:
img = cv2.imread('image-1.jpg') cropped_img = img[110:480, 75:450, :] cropped_img2 = cv2.cvtColor(cropped_img, cv2.COLOR_BGR2RGB) print(f'Original Image: {img.shape}, Cropped Image: {cropped_img.shape}') plt.imshow(img); plt.imshow(cropped_img2);
این هم خروجی:
تمرین در بالا من یک گل را جدا کردم. شما هم یکی از آن دو گل را انتخاب کنید و برش بزنید.
این هم از برش تصویر که انصافا ساده بود…
چرخش تصویر
یکی دیگر از عملگرهای پایهای در پردازش تصویر، چرخش تصویر به اندازه یک زاویه مشخص هست. خوشبختانه OpenCV برای این چرخش تصویر یک دستور آماده بنام cv2.rotate دارد. همانطور که در زیر نشان داده شده، این دستور به دو ورودی نیاز دارد:
- src: تصویری که میخواهیم بچرخانیم.
- rotateCode: کد چرخش تصویر با سه حالت زیر:
- cv2.ROTATE_90_CLOCKWISE معادل با 90 درجه چرخش ساعتگرد
- cv2.ROTATE_180 معادل با 180 درجه چرخش
- cv2.ROTATE_90_COUNTERCLOCKWISE معادل با 90 درجه چرخش پادساعتگرد
rotated_image = cv2.rotate(src, rotateCode)
احتمالا سوالی که برایتان پیش آمده این هست که نمیتوانیم مثلا به اندازه دلخواه بچرخانیم؟ مثلا 10 درجه؟ با این دستور نمیتوانیم. اما در همین بخش راهکار چرخش به اندازه دلخواه را هم میگویم. حالا یک مثال از چرخش هم ببینیم. با کد زیر یک تصویر با چرخش 90 درجه ساختهایم:
# Load the input image image = cv2.imread('input_image.jpg') # Rotate the image by 90 degrees clockwise rotated_image = cv2.rotate(image, cv2.ROTATE_90_CLOCKWISE)
نکته بدون استفاده از دستور rotate هم میتوانیم تصویر را به اندازه 90 180 90- بچرخانیم. یک نمونه را من میگویم و بقیه موارد را خودتان فکر کنید و راهش را پیدا کنید. با یک ترنسپوز ماتریس به سادگی میتوانیم تصویر را 90 درجه بچرخانیم.
چرخش تصویر به اندازه دلخواه با OpenCV
برای چرخش تصویر به اندازه دلخواه، مثلا 10 یا 20 درجه، باید از دو دستور cv2.getRotationMatrix2D و cv2.warpAffine استفاده کنید. میدانم، اسمهایشان کمی ترسناک است! اما کار با آنها ساده است. راهکار هم این است:
- ابتدا دستور cv2.getRotationMatrix2D را مینویسیم و بعد
- خروجی دستور بالا را همراه با تصویر اصلی به cv2.warpAffine میدهیم.
- تمام!
ورودیهای دستور cv2.getRotationMatrix2D چگونه است؟ سه ورودی دارد:
- center: مرکز چرخش (همان مرکز تصویر که باید پیدایش کنیم.)
- angle: همان زاویه مدنظر ما برای چرخش
- scale: فاکتور مقیاس که میتواند تصویر را مقیاس کند (کوچکتر و بزرگتر)
cv2.getRotationMatrix2D(center, angle, scale)
خروجی این دستور هم یک ماتریس 2 در 3 هست که ماتریس چرخش نام دارد. این ماتریس چرخش را باید به دستور cv2.warpAffine بدهیم.
ورودیهای دستور cv2.warpAffine زیاد است و ما همه آنها را توضیح نمیدهیم. تنها چند موردی که نیاز داریم:
- src: تصویر ورودی
- M: ماتریس چرخش
- dst: سایز تصویر خروجی
- flags: روش درونیابی یا Interpolation (همانهایی که در ریسایز دیده بودیم.)
cv2.warpAffine(src, M, dsize, dst, flags, borderMode, borderValue)
خب، حالا که با دستورات موردنیاز آشنا شدید، توضیحات و کد زیر را دقیق بخوانید:
- مرکز تصویر را با استفاده از image.shape و تقسیم بدست آوردیم.
- این مرکز تصویر را همراه با درجه دلخواه و مقیاس 1 به دستور cv2.getRotationMatrix2D دادیم.
- خروجی cv2.getRotationMatrix2D را rotation_matrix نامگذاری کردیم.
- تصویر اصلی، ماتریس چرخش، سایز تصویر و روش درونیابی را به دستور cv2.warpAffine دادیم.
- خروجی rotated_image هم تصویر چرخیده هست.
import numpy as np # Load the input image image = cv2.imread('image-0.jpg') # Define the rotation angle (in degrees) angle = 45 # Get the image center and rotation matrix height, width = image.shape[:2] image_center = (width/2, height/2) rotation_matrix = cv2.getRotationMatrix2D(image_center, angle, 1.0) # Perform the affine transformation rotated_image = cv2.warpAffine(image, rotation_matrix, (width, height), flags=cv2.INTER_LINEAR)
این هم خروجی کد بالا:
ممکن است این سوال برایتان ایجاد شود که “آخه چنین چیزی به چه دردی میخوره؟؟” کاربردهای همین عملگر پایهای پردازش تصویر بسیار جالب و زیاد است:
- قابل استفاده در تشخیص اشیا در تصویر
- اصلاح تصاویر چرخیده (یعنی حین تصویربرداری چرخش داشتیم.)
- تصاویر پانوراما (یک نمونه تصویر پانوراما در زیر آوردیم.)
در این تصویر پانوراما یک مجموعه تصاویر کوچکتر در موقعیت درستی کنار هم قرار گرفتهاند.
تا اینجای کار، درباره مطالب زیر صحبت کردیم:- خواندن و نمایش تصویر
- مشاهده خواص تصویر، مانند سایز تصویر، فضای رنگی و غیره
- دستکاری تصویر مانند ریسایز، برش و چرخش تصویر
حالا برویم سراغ بخش بعدی آموزش OpenCV که بسیار جالب هست…
رسم شکل هندسی در اوپن سی وی
شاید باورتان نشود، رسم شکل هندسی در اوپن سی وی بسیار بسیار پرکاربرد است. در OpenCV دستوراتی داریم که به ما این امکان را میدهد که کارهای زیر را انجام دهیم:
- رسم خط روی تصویر
- رسم دایره روی تصویر
- رسم مستطیل روی تصویر
- رسم بیضی روی تصویر
- نوشتن متن روی تصویر
توجه در بالا کلمه “رسم” را به کار بردم؛ اما مساله این هست که این رسمها با آنچه در متپلات داریم، متفاوت هست. اشکال هندسی به خود تصویر اضافه میشوند و اینطور نیست که صرفا در نمایش ظاهر شوند. شاید حرفم کمی مبهم باشد، احتمالا در ادامه این ابهام رفع میشود.
در ادامه، درمورد تکتک کارهای بالا صحبت کردهام.
رسم خط روی تصویر
با استفاده از دستور ()cv2.line میتوانیم به یک تصویر خط اضافه کنیم. سینکتس این دستور به شکل زیر است:
cv.line(image, p0, p1, color, thickness)
آرگومان ورودی دستور بالا:
- image: تصویری که میخواهیم به آن خط اضافه شود.
- p0: نقطه شروع خط (x, y)
- p1: نقطه پایان (x, y)
- color: رنگ خط
- thickness: ضخامت خط
حالا بیایید یک مثال هم ببینیم؛ در مثال زیر، یک تصویر خالی (تصویر تماما سیاه) ساختهام و بعد روی آن دو خط رسم کردهام:
RED = (0, 0, 255) YELLOW = (0, 255, 255) p0 = (10, 10) p1 = (300, 90) p2 = (400, 10) img = np.zeros((100, 500, 3), np.uint8) cv2.line(img, p0, p1, RED, 2) cv2.line(img, p1, p2, YELLOW, 5) cv2_imshow(img)
اما شرح کد بالا:
- اول دو متغیر RED و YELLOW برای رنگ خطها تعیین کردهایم. براساس همان BGR که قبلا گفتیم.
- سه نقطه p2 p1 p0 برای آغاز و پایان خطوط ساختهایم. نقطهها باید بهصورت دوبعدی تعریف شوند.
- یک تصویر تماما سیاه ساختهایم. خیلی ساده با یک دستور نامپای…
- اولین خط: از p0 تا p1 با رنگ قرمز و پهنای خط 2
- دومین خط: از p1 تا p2 با رنگ زرد و پهنای خط 5
بدون اینکه شکل را ببینیم، میتوانیم حدس بزنیم که دو خط در یک نقطه (p1) مشترک هستند. همچنین، خط زرد ضخامت بیشتری نسبت به خط قرمز دارد. و اما خروجی:
رسم دایره روی تصویر
اگر رسم خط را متوجه شدید، احتمالا در این بخش و بخشهای بعدی مشکلی نخواهید داشت. برای رسم یک دایره به چه چیزهایی نیاز داریم؟ 1) مرکز دایره 2) شعاع دایره. رسم دایره روی تصویر در اوپن سی وی هم به همین صورت است. سینتکس دستور را در ادامه آوردهام:
cv2.circle(image, center_coordinates, radius, color, thickness)
نمیخواهم درمورد آرگومانهای ورودی دستور توضیح دهم. چون بسیار ساده و واضح هست. یک مثال ببینیم:
BLUE = (255, 0, 0) c0 = (250, 50) img = np.full((100, 500, 3), 255, np.uint8) cv2.circle(img, c0, 10, BLUE, 2) cv2.circle(img, c0, 20, BLUE, 2) cv2.circle(img, c0, 30, BLUE, 2) cv2.circle(img, c0, 40, BLUE, 2) cv2.circle(img, c0, 50, BLUE, 2) cv2.circle(img, c0, 60, BLUE, 2) cv2_imshow(img)
این هم خروجی جالب کد بالا:
رسم مستطیل در OpenCV
دیگر تکراری شده! چون دستورات رسم اشکال بسیار ساده و شبیه هم هستند. برای رسم یک مستطیل باید از دستور با ورودیهای زیر استفاده کنیم:
cv2.rectangle(image, p0, p1, color, thickness)
ورودیها را باهم مرور کنیم:
- image: تصویر ورودی که میخواهیم روی آن مستطیل بکشیم.
- p0: مختصات گوشه بالا-چپ مستطیل (x, y)
- p1: مختصات گوشه پایین-راست مستطیل (x, y)
- color: رنگ مرز (Border) مستطیل
- thickness: ضخامت مرز مستطیل
در کد زیر، یک مستطیل دور چهره شخص موجود در تصویر رسم شده است:
CYAN = (255, 255, 0) p0 = (25, 50) p1 = (140, 200) img = cv2.imread('/content/images/image-3.jpg') cv2.rectangle(img, p0, p1, CYAN, 2) cv2_imshow(img)
این هم نتیجه کار:
نکته شاید بخواهید مستطیل توپر رسم کنید. برای این کار باید آرگومان thickness را برابر با 1- یا cv.FILLED قرار دهید. در چنین شرایطی، رنگ درجشده در آرگومان color برای رنگآمیزی کل مستطیل استفاده خواهد شد.
نکته دستور Rectangle در OpenCV بسیار پرکاربرد هست. چون میتوانیم از مدلها و الگوریتمهای بینایی کامپیوتر برای تشخیص اشیا در تصویر استفاده کنیم و سپس موقعیت آنها را با مستطیل رسم نماییم. کاری که در الگوریتم یولو هم انجام میشود.
تمرین روی چهره سایر افراد موجود در تصویر بالا، مستطیل بکشید. روی چهره دوم و چهارم مستطیل توخالی به رنگ قرمز و رزد بکشد. روی تصویر سوم و پنجم هم مستطیل توپر به رنگ سفید و خاکستری رسم کنید.
اگر دوست دارید یولو را هم یاد بگیرید، لینک روبرو را مطالعه کنید: آموزش یولو 8
حالا برویم سراغ یک مورد جذاب و کاربردی دیگر!
افزودن متن به تصویر با اوپن سی وی
ادامه دارد…
مطالب زیر را حتما مطالعه کنید
تصویر دیجیتال چیست؟
1 دیدگاه
به گفتگوی ما بپیوندید و دیدگاه خود را با ما در میان بگذارید.
فوقالعاده روون و ساده و کاربردی. واقعا خسته نباشید و ممنون!