مدتها پیش، من شروع به نوشتن پیرامون بینایی ماشین و پردازش تصویر کردم (برای مثال، یکی از نتایجی که از این موضوع گرفتم راهاندازی جامعه بینایی ماشین بود) و کم کم تلاشم بر این شد که هوش مصنوعی و یادگیری عمیق و یادگیری ماشین و … هم وارد ماجرا کنم چرا که دونستن OpenCV و به طور کلی بینایی ماشین، چیز خاصی نیست و دانش خاصی به ما اضافه نمیکنه. البته اشتباه نکنید، این که شما یک ابزار خوب مثل OpenCV و کار باهاش رو بلد باشید، خیلی هم خوبه اما کافی نیست.
خلاصه پس از مدتی، شروع کردم به مطالعه الگوریتمهای مختلفی که برای تشخیص اشیا و یا مکانیابی اشیا نوشته شده بودند، اونها رو مطالعه کردم و یکی یکی این ابزارها رو سعی کردم امتحان کنم تا ببینم هرکدوم چطور دارند کار میکنند و … . در این میان با YOLO و مفهومی که داشت، آشنا شدم ولی مشکلاتی سر راه بود که در همین مطلب بهشون اشاره میشه. اما نسخه ۵ یولو، یه جورایی شد رفیق راهم (که خب توضیح دادم چرا دوستش دارم) و در بسیاری از پروژهها مثل حل مسائل ریاضی و همچنین تحلیل مدارات الکتریکی، کمک بسزایی به پیشبرد پروژه کرد.
حالا اگر نوبتی هم باشه، نوبت یک پروژه جدید و باحال دیگره که با YOLOv5 انجام بشه. در اینجا لازمه اشاره کنم که مدلهای هوش مصنوعی صرفا ابزار هستند و گاهی ما ممکنه اصلا نیازی به هوش مصنوعی برای حل مساله نداشته باشیم. مورد بعدی این که ما از ابزار چطور، کجا و چگونه استفاده کنیم خودش امر مهمیه و عموم مقالات مهندسی، پایاننامههای رشتههای مهندسی و …؛ همه در این تلاش هستند که یا این ابزارها را بهینه کنند یا این که روش مناسبی برای استفاده از این ابزارها پیدا کنند.
پروژهای که این بار انجام دادم چه بود؟ این پروژه این بار سامانه تشخیص پلاک خودرو با کمک YOLOv5 است که در نگاه اول، به نظر چیز سادهای میرسه اما در عمل خیلی ساده نیست و در حین پیادهسازی، نیاز داشتم که سادهترش کنم. اما بذارید ایده کلی رو با هم بررسی کنیم. ایده کلی ما این بود که سیستمی داشته باشیم که حضور و غیاب به کمک پلاک خودرو را ممکن کند. حالا این مورد کجاها میتونه استفاده بشه؟ خیلی جاها. پارکینگهای عمومی، جاهایی که خودروها تا ثبت نشده باشند نمیتونن وارد باشن، پلیس راهنمایی و رانندگی و … .
در این پست، با هم به تفصیل به بررسی این پروژه میپردازیم و میبینیم که این پروژه بینایی ماشین چطور انجام شده. سعی کردم که مطلب تا حد خوبی فرمتی مشابه تحقیقات و پایاننامههای دانشگاهی هم داشته باشه تا دوستانی که نیازمند نوشتن چنین مطلبی هستند هم بدون تغییرات زیاد بتونن از مطالب این پست خاص استفاده کنند.
طرح کلی مساله
مساله کلی ما در اینجا اینه که نرمافزاری توسعه بدیم که بتونه نوشته روی پلاک خودروهای ما رو بخونه و اون رو با محتوایی که در یک دیتابیس خاص داریم، تطابق بده. در اینجا ما میتونیم سناریویی فرضی داشته باشیم به این شکل که «فرض کنیم یک پارکینگ داریم که خودروها باید قبل از حضور، پلاکشون رو ثبت کنند و موقع ورود، پلاک خوانده میشه و چنانچه مطابقتی بیش از ۷۰٪ با حداقل یکی از پلاکهای درون دیتابیس پارکینگ داشت؛ مجوز ورود صادر خواهد شد». این سناریوی فرضی به ما کمک میکنه که در ادامه، بهتر پیادهسازی رو انجام بدیم.
پس مشخصا ما نیاز به سیستمی داریم که بتونه تصویر از پلاک دریافت کنه، محتوای متنی تصویر رو استخراج کنه و اون رو با متونی که پیشتر در یک دیتابیس ذخیره کردیم تطابق بده و خروجی مورد نظر ما (مجوز ورود) رو صادر کنه. برای این که بتونیم فرایندی که میخواهیم رو سادهتر کنیم، در اینجا چند مورد لحاظ شده:
- محتوای متنی پلاک فقط محدود به اعدادیه که درون پلاک داریم.
- برای سادگی بیشتر پروژه، بخش سختافزاری سیستم در نظر گرفته نشده.
- برای سادگی باز هم بیشتر، از قسمت دیتابیس و تطابق چشمپوشی کردیم.
در واقع، پیادهسازی پیش روی شما صرفا پیادهسازی از نویسهخوان نوری (OCR) و در حقیقت قسمت مرتبط با بینایی ماشین و YOLOv5 در این پروژه بوده که خود همان هم، بخش زیادی از این پروژه رو شامل میشد.
کارهای پیش تر انجام شده
در این بخش، کارهایی که پیشتر در این زمینه انجام شدند رو با هم بررسی میکنیم. چرا که در بخش انتخاب ابزار احتمالا نیاز به این داشته باشیم که به این قسمت برگردیم و مواردی رو بررسی کنیم. به هرحال در طی جستجوهای انجام شده توسط شخص من، دو پروژه خیلی نظرم رو جلب کردند که در ادامه به معرفی اونها میپردازم.
پلاک خوان دیوار
وبسایت یا اپلیکیشن دیوار برای خیلی از ماها، نام آشناییه. خیلی از افراد هستند که از طریق این اپلیکیشن اقدام به خرید و فروش خودرو هم میکنند و برای تامین امنیت صاحبان خودرو در این پلتفرم، اقدام به طراحی و تولید مدل مشابهی کردند که بهشون کمک کنه تا بتونند پلاکها رو با قالب مناسب وبسایت دیوار، جایگزین کنند تا همه قادر به دیدن پلاک خودروها نباشند. دوستانی که در این پروژه در دیوار همکاری داشتند خوشبختانه مراحل کارشون رو خیلی دقیق و جالب در این پست ویرگولیشون، توضیح دادند و به نظرم بد نیست که همینجا توقف کوچکی کنید و پست این دوستان رو مطالعه کنید؛ سپس برگردید و ادامه این پست رو بخونید.
پروژه تشخیص پلاک با پایتون (با استفاده از OpenCV و KNN)
این یکی پروژه هم یکی از پروژههای خوبی در زمینه بینایی ماشین و تشخیص پلاکه که یکی از کاربران آپارات، با پیروی از یک شخص خارجی – که در یوتوب کار مشابهی انجام داده – پیادهسازیش کرده. یک ویدئوی دو ساعت و نیمه که به نظرم ارزش دیدن و فکر کردن داره.
در بخش بعدی، اشاره خواهم کرد که چرا این روش رو اتخاذ نکردم و ترجیح دادم که از YOLOv5 استفاده کنم. برای دیدن این ویدئو، میتونید از این لینک استفاده کنید.
انتخاب ابزار و تکنولوژی
در این بخش، به تفصیل قراره تمامی ابزارهایی که پیش روی ما بود رو بررسی کنیم. در واقع این یکی از روتینهای تحقیقات علمیه که قبل از توضیح کامل ابزاری که استفاده کردیم، توضیح بدیم چرا از یک سری از ابزارها، استفاده نکردیم. این مورد به افرادی که بعد از ما قراره روی اون موضوع کار کنند کمک میکنه تا اول سراغ ابزارهایی که قدیمی شدند یا به هر دلیلی «به درد نخور» هستند نرن و دوم اگر قرار باشه ابزار متفاوتی از ما رو انتخاب کنند، بتونن یکی از همینها رو بررسی کنند (حالا ممکنه اصلا کل بررسی سر به درد نخور بودن ابزار باشه!).
استفاده از Tesseract
تسرکت یکی از نرمافزارهای آزاد مشهور در زمینه OCR محسوب میشه که امتیازات ویژه خودش رو هم داره. برای مثال شاید بشه گفت بزرگترین امتیازش اینه که بدون مشکل روی همه سیستمعاملهای مرسوم دنیا نصب و اجرا میشه و مهم نیست شما مک داشته باشید یا ویندوز یا گنو/لینوکس؛ به سادگی میتونید اجراش کنید و ازش استفاده کنید. مورد بعدی که باعث میشه افراد به سمت تسرکت برن هم اینه که کتابخونهای برای استفاده مستقیم در پایتون داره و این خودش یک امتیاز بزرگه که نرمافزاری که به صورت stand-alone اجرا میشه رو بشه با یک wrapper ساده وارد زبان برنامهنویسی مورد علاقمون کنیم.
در عین حال تسرکت مدعیه که زبانهای مختلفی – من جمله فارسی – رو پشتیبانی میکنه و اینجا میخوایم دلیل عدم استفاده از این ابزار رو دقیقا در همینجا پیدا کنیم. تسرکت، نیاز داره که با فونتهای مختلف آموزش داده بشه و پیدا کردن فونتی مشابه فونتهای مورد استفاده در پلاک خودروهای ایران، کاری تقریبا ناممکنه. البته بعضی از تایپفیسها مثل تایپفیس فونت رویا تقریبا به فونت مورد استفاده در پلاک خودروهای ایران نزدیکه و شاید بشه باهاش کاری کرد. اما این بحث آموزش تسرکت و نتیجه نگرفتن احتمالی باعث خط خوردن تسرکت از لیست شد.
استفاده از KNN
خود کتابخانه OpenCV تابعی برای آموزش یک طبقهبند KNN یا K-Nearest Neighbor ارائه میکنه که در ویدئویی که در بخش قبل لینک دادیم هم استفاده شده. این مورد هم مشکلات خاص خودش رو داشت و از لیست حذف شد. یکی از واضحترین دلایل این بود که ممکن بود این روش خاص، در اعداد شبیه به هم کمی مشکل ایجاد کنه. در کل، علیرغم این که الگوریتم K نزدیکترین همسایه، الگوریتم مورد اطمینانی در یادگیری ماشین کلاسیک محسوب میشه، ریسک خطای مدل نهایی رو هم میتونه بالا ببره.
استفاده از EasyOCR
کتابخانه EasyOCR یکی از محبوبترین کتابخانهها در میان مهندسین بینایی ماشین در دنیاست. یکی از دلایلش اینه که با سرعت خوبی (بخصوص با داشتن GPU) میتونه متون رو تشخیص بده و از همه مهمتر، دور متون مورد نظر ما Bounding Box قرار بده. این کتابخانه هم زبانهای زیادی مثل انگلیسی، آلمانی، نروژی و … رو پشتیبانی میکنه اما نقطه قوتش نسبت به Tesseract اینجاست که در زبانهای فارسی و عربی هم بدون نیاز به استفاده از فونت و …؛ میتونه تشخیص خوبی بده.
با این وجود، مدلی که EasyOCR ازش استفاده میکنه هنوز به خوبی برای زبان فارسی fine-tune نشده و پروژه حال حاضر رو نمیتونه به سرانجام برسونه. به همین دلیل، این ابزار هم از لیست ابزارهای مورد استفاده در پروژه ما، خط میخوره. البته این هم باید اشاره کرد که EasyOCR نرمافزاری آزاده که میشه بهش کمک کرد و بهبودش بخشید (روشش رو اینجا میتونید پیدا کنید).
استفاده از سیستمها و سرویسهای OCR ایرانی
در سالهای اخیر، با توجه به این که افراد زیادی به خوندن کتابها و جزوههای الکترونیکی و اسکنشده روی آوردن، خیلی از شرکتها و گروههای فعال در زمینه متنکاوی و … هم بیکار نبودند و سیستمهای OCR خوبی توسعه دادند که به صورت خاص، برای زبان فارسی کار میکنند.
اما دو مشکل بزرگ اینجا داشتیم. اولین مشکل این که اکثر این سرویسها آنلاین هستند و خیلی از کاربران نهایی این پروژه (مثل یک سازمان دولتی) احتمالا حاضر به این نمیشه که دادههای خودروهاش و کارمندانش رو به یک سرور شخص ثالث ارسال کنه. مشکل دوم هم این بود که اکثر نسخههای آفلاین گرونقیمت هستند. البته شاید بشه مشکل سومی هم اینجا لحاظ کرد و اون اینه که خیلیهاشون امکان این که در یک کد پایتونی بشه ازشون استفاده کرد هم فراهم نمیکنند. پس این گزینه هم کاملا از لیست ما خط خورد.
توسعه CNN اختصاصی
این روش همیشه برای من نقش پلن ب رو داره که اگر مدلی مثل YOLOv5 برای نیازم پاسخگو نبود، سراغش بیام. اما چرا در این پروژه سراغش نرفتم؟ چون که توسعه برای OCR میتونست به شدت زمان، هزینه و انرژی مصرف کنه و حقیقتا چون این پروژه قرار نبود پروژه پولساز باشه یا برای هدفی مثل پایاننامه و … انجام بشه، ارزش این که شبکه عصبی اختصاصی براش توسعه بدیم رو نداشت.
استفاده از YOLOv5
در نهایت، لازم بود که از مدلی مثل YOLOv5 استفاده بشه برای این که بتونیم OCR مخصوص پلاک رو توسعه بدیم. چرا YOLOv5 و چرا سایر نسخههای یولو نه؟ پیشتر این مورد رو به تفصیل توضیح دادم اما توضیح کوتاه ماجرا میشه سهلالوصول بودن نتیجه transfer learning و fine-tuning این مدل خاص. این مدل، یعنی YOLOv5 به سادگی میتونه روی سیستم شخصی من (مکبوک پرو آخر ۲۰۱۹ با سیستم عامل مک) و روی گوگل کولب اجرا بشه. همچنین انتقالش به سایر سیستمها هم راحت انجام میشه و از این نظر، خیالم میتونست راحت باشه.
گذشته از بحث سختافزار و پلتفرم، YOLOv5 به شدت سریع و با دقته، و این مورد میتونه خودش یک امتیاز مثبت بزرگ برای استفاده از این مدل خاص در کاری مثل پروژه خواندن پلاک با YOLOv5 باشه!
جمعآوری و پیشپردازش داده مورد نیاز
بعد از این که ابزارها و تکنولوژیهای مورد نیازمون رو پیدا کردیم، لازم بود تا دادههای مورد نیاز پروژه هم پیدا کنیم. اولین و سادهترین راه (مطابق این مطلب) این بود که خودمون دست به کار شیم و از پلاک خودروها، عکاسی کنیم. اما این قضیه میتونه دردسرساز بشه چرا که خیلیها خوششان نمیاد که کسی از ماشینشون عکاسی کنه. به همین دلیل، در اینترنت جستجو کردم و به دیتاست مورد استفاده در این مطلب رسیدم. در این دیتاست ۳۱۷ عکس از پلاک خودروهای ایران وجود داره که این خودش عالیه! یک حجم خوب از پلاک خودرو که میدونیم دردسری هم برای ما ایجاد نمیکنه.
پس از این که دادههای مورد نظر خریداری و دانلود شد، نوبت به لیبل زدن بود. لیبلهای ما اعداد ۰ تا ۹ بودند و گذشته از اون، برای این که داده تستی کافی داشته باشیم و مراحل پیادهسازی سریعتر پیش بره، فقط ۷۵ تا عکس رو با کمک labelImg لیبل کردیم.
پیادهسازی پروژه
پس از این که ایده کلی، ابزار و داده برچسبزدهشده رو داشتیم، نوبتی هم باشه نوبت آموزش دادن YOLOv5 برای اینه که کار ما رو به درستی انجام بده. حقیقتا، YOLOv5 و ابزارهای مشابه، خودشون یک دور آموزش دیدند و ما فقط به قولی اونها رو fine-tune میکنیم که کاری که ما بخواهیم رو انجام بدن (در نظر بگیرید که ما در دوران ابتدایی و راهنمایی خیلی چیزا رو یاد گرفتیم، در دبیرستان رفتیم سراغ ریاضی و تجربی و اختصاصی اونها رو یاد گرفتیم و بعد در دانشگاه مثلا مهندسی خوندیم که یک فرم خاصتر از ریاضیه. دقیقا مشابه همین فرایند اینجا برای آموزش YOLOv5 هم داره صورت میگیره) و الان فقط کافیه که دیتا و کدهای مورد نیازمون رو در یک سیستم مناسب پروژههای هوش مصنوعی بارگذاری کنیم و سپس مراحل آموزش رو طی کنیم.
دادههای ما روی Google Colab آپلود شدند چرا که آموزش YOLOv5 نیازمند داشتن GPU است. بعد از اون، آموزش به این صورت شکل گرفت که هفتصد و پنجاه epoch (یا نسل) طول کشید، سایز batch ما ۳۲ بود، اندازه تصویر به ۴۱۶ د ۴۱۶ پیکسل تغییر کرد (اسکریپتی که برای آموزش YOLOv5 توسط تیم Ultralytics ارائه شده خودش امکان تغییر سایز رو فراهم کرده) و مدل پایه مورد استفاده yolov5m بود که با ۲۱.۲ میلیون پارامتر آموزش داده شده. پس از حدود ۳ ساعت و ۴۰ دقیقه، مدل ما آماده بود و نیاز داشتیم که تستش کنیم.
نتایج آزمایش
نتیجه آزمایش روی دیتاست آموزش
همین عکس که در ابتدای مطلب هم ازش استفاده شده، عکسیه که در دیتاست آموزشی موجود بود و درستی کار مدل رو تایید میکرد. جدول زیر هم میزان دقت رو به درستی به ما نشون میده:
نتیجه آزمایش روی دیتاست آزمایشی
در جدول زیر هم به صورت مرتب شده میتونیم میزان دقت این مدل رو هم ببینیم. همچنین با یک تابع ساده، پلاک رو به شکل درستش (مبتنی بر ستون xmin) مرتب کردیم تا با پلاک اصلی تطبیق بدیم:
جمعبندی و نتیجهگیری
در اینجا لازمه که پروسههایی که طی شده رو یک بار دیگه بررسی کنیم تا به یک جمعبندی روی پروژه برسیم:
- ابتدا تصمیم گرفتیم سیستمی طراحی کنیم که حضور و غیاب یا رفت و آمد رو بتونه مبتنی بر پلاک خودروهای حاضر در یک محل خاص، بررسی کنه.
- سپس تصمیم اولیه رو با حذف پروسه دیزاین سختافزاری و همچنین حذف حروف مورد استفاده در پلاک سادهسازی کردیم.
- پس از سادهسازی، ابزارهای متنوعی رو مطالعه کردیم و سپس YOLOv5 رو به عنوان ابزار اصلی خودمون انتخاب کردیم.
- دیتاستی رو تهیه کردیم و برچسب زدیم.
- مدل YOLOv5 رو مطابق نیاز و با دادههای خودمون آموزش دادیم.
در کل، این پروسه گرچه پروسه نسبتا وقتگیر و سختی بود، اما نتیجه به دست آمده واقعا راضیکننده و خوبه. در حال حاضر پروژه ما در حالی قرار داره که میتونه به سادگی با ارتباط با یک سیستم سختافزاری، کاری که براش در نظر گرفته شده رو انجام بده. البته هنوز ضعفهایی متوجه این پروژه هست که در بخش بعدی در موردشون بحث خواهیم کرد.
کارهای آینده
در این قسمت، کارهایی که در آینده میشه برای این پروژه انجام داد رو با هم یک بررسی اجمالی میکنیم:
- توسعه سیستم برای خواندن حروف وسط پلاک (چالشهای خاصی در این زمینه وجود داره، مثلا حرف ژ در پلاک خودرو معمولا به شکل ویلچر چاپ میشه)
- توسعه سیستم برای خواندن پلاکهای غیرشخصی (پلاکهای عمومی و تاکسی عموما زرد، پلاک وزارت دفاع آبی، پلاک سپاه و نیروی انتظامی سبز پررنگ، ارتش سبز خاکی، دیپلماتیک آبی آسمانی و پلاک خودروهای دولتی قرمز هستند)
- توسعه سیستم برای تشخیص و خواندن پلاکهای منطقه آزاد
- توسعه سیستم برای تشخیص و خواندن پلاکهای گذر موقت
- توسعه سیستم سختافزاری و قرار دادن مدلهای هوش مصنوعی در سختافزار مناسب
مجوز نشر
این پست وبلاگ، تحت پروانه مستندات آزاد گنو یا GNU Free Document License منتشر شده و بازنشر و استفاده از محتویاتش کاملا آزاده. فقط توجه لازم داشته باشید که دیتاستی که برای آموزش استفاده شده آزاد نیست و این آزادی در استفاده شامل بخشهایی از این مطلب میشه که مسولیتش با منه (به طور کلی هرچی که شما در این پست خوندید)
سخن آخر
این پست برخلاف پستهای دیگر این وبلاگ به شدت طولانی شد و از بابت این که وقت زیادی برای خوندنش گذاشتید، واقعا از شما متشکرم. در پایان جا داره از شما دعوت کنم که به ویرگول من هم سر بزنید تا اونجا موارد فنی و تجربیات دیگر من رو بخونید. همچنین، اگر این مطلب برای شما مفید بود کافیه که روی تصویر زیر کلیک کنید و من رو به یک فنجان قهوه به انتخاب خودتون مهمان کنید 🙂