احتمالا در جریان باشید که مدت نسبتا زیادیه که وارد حوزه پردازش تصویر و بینایی ماشین شدم (برای مثال نقشه راه بینایی ماشین رو میتونید از اینجا بخونید) و حتی یک کانال تلگرامی کوچک برای انتقال دانش و تجربه در این زمینه راه انداختم که اسمش رو جامعه بینایی ماشین گذاشتم (که میتونید اینجا در موردش بخونید). چند ماه پیش، یکی از دوستانم ایدهای مطرح کرد. این ایده، در مورد خوندن پلاک ماشین و ثبتش در یک پایگاه داده با کمک هوش مصنوعی بود (که این پروژه هم انجام شد و اینجا در مورد این پروژه هم توضیح دادم).
پروژه پلاکخوان یا Automated Number Plate Recognition که بهش ANPR هم میگن، من رو تشویق و تحریک کرد که یک پروژه نویسهخوان نوری یا همون OCR فارسی هم پیش ببرم. اما پیشبرد پروژه OCR تا حد زیادی به تعویق افتاد چرا که درگیر توسعه محصول در استارتاپی بودم. اما از عید نوروز ۱۴۰۱ خیلی جدیتر به پیادهسازی یک OCR فارسی درست و حسابی فکر کردم. گرچه این پروژه رو تا حد زیادی به عبارتی Hold کردم، اما خب نتایج جالبی تا الان ازش به دست آمده که حیف بود در این مطلب وبلاگ در موردش ننویسم.
شروع پروژه: درک کارکرد OCR
قبل از این که بخواهیم یک سیستم OCR برای زبان فارسی پیاده کنیم؛ باید درک کنیم که OCR چیه و چه کار میکنه و چرا مهمه که برای زبانهای مختلف داشته باشیمش. پروسه OCR یا تشخیص نویسه نوری که البته بهش نویسهخوان نوری هم گفته میشه، پروسهایه که طی اون، متنی از داخل یک عکس استخراج میشه و میتونیم بعدتر با ابزارهای واژهپرداز یا پردازش متن، با اون متن کار کنیم. برای این که این مثال رو بهتر درک کنیم، فرض کنیم که یک قوطی دارو داریم و حالا میخواهیم ببینیم که ترکیبات دارو چطوریه. چه کار میکنیم؟
اولین کاری که میتونیم بکنیم اینه که برچسب روی بسته دارو رو بخونیم. اما گاهی پیش میاد که ما دقیقا نمیتونیم درست از این چیزا سر در بیاریم (به هرحال هرطور بررسی کنیم، من مثلا برنامهنویسم و نه شیمیدان یا داروساز و خب طبیعیه که نتونم اون دیتا رو بفهمم). حالا فرض کنید یک اپلیکیشن روی گوشی همراهمون نصب داریم که فقط کافیه یک عکس از جعبه دارو بهش بدیم. اون تمام این دیتا رو به ما میده. حالا چطوری؟ اول میاد نوشته روی دارو رو به متن تبدیل میکنه و متن رو در دیتابیس خاصی جستجو میکنه.
خب، الان فهمیدیم OCR چیه و چی کار میکنه. حالا وقتشه که بریم سراغ پروژه من. این که پروژه چی شد و به کجا رسید. یک مسیر جذاب طی شد اما خب این مسیر جذاب یه جاهایی هم تو دستانداز افتاده. چون پروژه هنوز تمام نشده و خیلی مونده تا به نتیجه خوبی برسه، ترجیح دادم «هرچی که تا الان انجام شده» رو در این مطلب باهاتون به اشتراک بذارم.
پروسه انجام پروژه OCR فارسی
فاز اول: تصمیمگیری
اولین قدم در انجام هر پروژهای، نوشتن یک نقشه راه برای اون پروژهست. اولین کاری که من کردم این بود که بیام بررسی کنم که سوادم در چه حده و چه ابزارهایی در اختیار دارم. گذشته از اون، اصلا پروژه OCR فارسی چقدر میتونه برای جامعه فارسیزبان موثر واقع بشه.
خب در این مساله، من از آخر به اول رفتم. اولین سوال این بود که چرا به یک OCR فارسی نیاز داریم؟ موضوع اینجاست که حفظ زبان، در گرو چه چیزهاییه. شاید چند قرن پیش، شعر فارسی چیزی بود که زبان فارسی رو حفظ کرد (دیگه فکر نکنم کسی باشه که ماجرای شاهنامه رو ندونه 😁). بعد از اون، نوشتن سفرنامه و حکایات روشی بود که در کنار شعر، به حفظ زبان کمک کرد. سالها بعد مطبوعات و جراید و همچنین رمان و … باعث حفظ زبان فارسی شدند. در دنیای امروز هم کارهایی مثل توسعه فونت، توسعه مدلهای هوش مصنوعی و همچنین پردازش زبان فارسی و …؛ روشی برای حفظ زبانه.
حالا که میدونم یکی از دلایلی که OCR فارسی رو توسعه میدم، اینه که از زبان فارسی حفاظت و صیانت کنم (و قطعا وقتی از حروف فارسی استفاده کنم برای زبانهای دیگری مثل کُردی، عربی و … هم قابل استفاده خواهد بود) نیاز بود بررسی کنم که چه ابزارهایی در اختیار دارم. اولین ابزاری که به نظرم رسید، بهترین زبان برنامهنویسی دنیا بود (😁) یعنی پایتون! خب بررسی پایتون رو در یک بخش جداگانه توضیح میدم ولی فعلا پایتون رو در نظر داشته باشید. در پایتون PyTorch و OpenCV هم داریم که خب یعنی هر آنچه برای کارهام نیاز بود در یک پکیج داشتم.
و اما مهمترین بحثی که پیش میاد اینه. سوادم در چه حده؟ این بخش چالشبرانگیز کاره. چرا که ممکنه تحت تاثیر اثر دانینگ کروگر باشیم و خودمون رو بسیار بیشتر از چیزی که هستیم بدونیم. خوشبختانه در حوزه پردازش تصویر و بینایی ماشین مدتهاست که این اثر رو رد کردم و میدونم که سوادم دقیقا کجاست و بیش از سوادم اگر بخوام کاری کنم، لازمه که مطالعاتم رو بیشتر کنم. حالا واقعا سوادم در چه حده؟ بعد از یک بررسی دیدم که آشنایی خوبی با پایتون و لایبرری OpenCV دارم. بعد از اون، کمی هم از الگوریتمهای یادگیری ماشین و یادگیری عمیق سردرمیارم. با الگوریتمهای شناس مثل YOLO هم که آشنایی دارم و همه اینها کافیه که برم سراغ پیادهسازی.
فاز دوم: ابزارهای مورد استفاده برای پیادهسازی پروژه OCR فارسی
در این بخش با هم بررسی خواهیم کرد که چه ابزارهایی برای پیادهسازی OCR نیاز بود. در واقع، این پلنی بود که من چیدم برای استفاده از ابزارها.
- پایتون: همونطور که گفتم پایتون، بهترین زبان برنامهنویسی دنیا؛ حداقل در این قسمت ماجرا بود. پایتون زبان راحتیه و رسیدن به نتیجه درست و حسابی بهش نسبتا آسون. به همین خاطر پایتون رو انتخاب کردم. گذشته از این بسیاری از ابزارهای هوش مصنوعی و یادگیری ماشین هم در پایتون قابل استفاده هستند.
- OpenCV: ابزار OpenCV یا Open Computer Vision که معرف حضور همه هست. این ابزار، کلی تابع و کلاس و … برای پردازش تصویر با متدهای کلاسیک یادگیری ماشین رو در خودش جای داده و گذشته از اون، پایه بسیاری از کتابخانههای مدیریت و ویرایش تصاویر دیگر مانند Pillow هم هست.
- زرنویس: ابزار زرنویس (لینک) ابزاری بود که چند وقت پیش برای نوشتن متن فارسی روی تصاویر به کمک Pillow نوشتم.
- PyTorch: کتابخانه PyTorch هم که باز معرف حضور هست. یکی از بهترین ابزارها برای پیادهسازی پروژههای یادگیری عمیق.
- الگوریتم YOLOv5: الگوریتم YOLOv5 (لینک) هم یکی از بهترین الگوریتمهای تشخیص اشیا یا Object Detection محسوب میشه و خب با کارهای Ultralytics کار باهاش شدیدا راحت هم شده.
- ابزار LabelImg: ابزار LabelImg (لینک) هم یک ابزار مناسب برای برچسب زدن به تصاویر برای YOLOv5 (و در کل الگوریتم یولو) به حساب میاد.
فاز سوم: جمعآوری دادههای مناسب برای پروژه و آموزش مدل
من همیشه در پروژههای هوش مصنوعی، علم داده، یادگیری ماشین و … یک حرف ثابت رو تکرار میکنم. اون حرف چیه؟ این که جمعآوری و پیشپردازش داده مورد استفاده در پروژه، سختترین بخش کاره. در این پروژه هم همینطور بود. اولین گامی که داشتم این بود که بیام و خود پروژه رو فازبندی کنم. چطوری؟ اینطوری که بیام کار رو بخش به بخش ببرم جلو و برای هربخش، جدا پلن بچینم. به همین خاطر به چند بخش ریز تقسیمش کردم که دقیقا بنبستم در یکی از این بخشها بود.
- بخش اول – تشخیص اعداد فارسی: در این بخش تا حد زیادی تنبلی کردم و به جای استخراج اعداد از متون، با استفاده از زرنویس و چند فونت فارسی آزاد، حدود صدتا تصویر که در هر کدوم اعداد ۴-۵ رقمی بودند تولید کردم. بعد از اون، اعداد رو لیبل کردم و بعد از لیبل کردن اونها، رفتم سراغ ترین کردن مدل YOLOv5 با استفاده از دادهای که از اعداد به دست آورده بودم. این مدل خوب کار کرد، گرچه روی چندین فونت خاص خیلی خوب کار میکرد و روی چندین فونت اصلا کار نمیکرد. این موارد رو بعدتر در قسمت های آتی توضیح خواهم داد.
- بخش دوم – تشخیص حروف فارسی: این بخش، یکم چالشیتر شد. چطور؟ از اونجا که رندم تولید کردن کلمات فارسی که تمامی حالات حروف درشون باشه (مثلا هم ک توش باشه هم کـ هم ـکـ) کار آسونی نبود. به همین خاطر کاری که کردم چه بود؟ این بود که از دیتاست شتر (لینک) استفاده کردم و حدود ۱۰۰ تا تصویر رو جدا کردم و شروع کردم لیبل زدن و ترین کردن مدل. اینجا نتیجه بهتر بود و میتونست فونتهای بیشتری رو تشخیص بده. گرچه در این مورد خاص، یک سری حروف مثل ث و ژ با دقت کمتری شناخته میشدند.
- بخش سوم – تشخیص بلاکهای کلمات: دقیقا جایی که چالش داشتم، اینجا بود. لیبل زدن متون طولانی یکم دردسرش زیاد بود. به همین خاطر ابتدا اومدم متون رو «خط به خط» لیبل زدم و خطها رو جدا کردم. بعد از اون با استفاده از Contour های موجود در عکس کلمات رو جدا کنم و به مدل تشخیص حروف بدم که خب اون هم خودش یکم داستانهای خاص خودش رو داشت. به هرحال، تا اینجای کار، مدل تشخیص اعداد و حروف به خوبی کار میکرد و نیاز بود این اتفاق هم بیفته. اما خب متاسفانه این اتفاقه افتادنش یکم سخت بود. نمیگم ناممکن اما خب سخته. به همین خاطر، فعلا پروژه در همین مرحله hold شده.
جمعبندی و نتایج پروژه
در نهایت ببینیم چه چیزهایی الان داریم و چه چیزهایی نداریم؟ تا نتایج پروژه رو بتونیم بهتر و بهتر و بهتر بررسی کنیم 😁 اول از همه ببینیم چیا رو داریم؟ خب در حال حاضر دو مدل خوب برای تشخیص اعداد و حروف فارسی داریم. این مدلها دارن با دقتهای خوبی کار میکنن اما نیاز دارند که یکم بهتر بشن (یعنی در اینجا نیاز داریم که کمی Fine Tuning روی مدلهای فعلی یا مدلهای YOLOv5 و … انجام بدیم) و مدلی برای تشخیص خط و کلمه داریم که درست کار نمیکنه. در واقع بخواهیم بهتر ببینیم: چیزی که داریم تشخیص نسبتا با دقت حروف و اعداده و چیزی که نداریم تشخیص کلمات به صورت بلاکه.
کارهای آینده
در این بخش بهتره به این فکر کنیم که چه کارهایی در آینده میشه برای بهبود این پروژه انجام داد. در لیست زیر به این مسائل میپردازیم که دقیقا چه کارهایی لازمه انجام بشه.
- تغییر مدل: یا نوشتن مدل از بتدا با روشهای Probabilistic یا استفاده از متدهای Instance segmentation
- تشخیص بهتر بلاکهای کلمات و شماره (یا با استفاده از Object Detection یا استفاده از سایر متدها)
- اضافه کردن هسته این کار به یکی از OCR های مشابه مانند EasyOCR یا PaddleOCR
سخن نهایی
در پایان باید از شما بابت زمانی که گذاشتید و این متن نسبتا بلند بالا رو خوندید، متشکرم. در حال حاضر، شما میتونید کدهایی که برای این پروژه نوشتم رو اینجا بخونید و اگر لازم بود، کمکی به پروژه کنید. اگر هم نه که میتونید از مدلها و دفترچههای ژوپیتری که قرار دادم استفاده کنید. همچنین، اگر دوست دارید مطالبی مشابه این وبلاگ بخونید میتونید به ویرگول من (لینک) مراجعه کنید.