نویسه‌خوانی به عملیات تشخیص متن در عکس و تبدیل آن می‌باشد. در این پروژه از شما انتظار می‌رود تا متن انگلیسی را در تصاویر حاوی متون تایپ شده انگلیسی تشخیص دهید.

۱. مقدمه

مدتی پیش در ادارات و سازمان‌های اداری، تجاری مثل بانک‌ها تمام اسناد و مدارک بصورت دست‌نویس بود وبه صورت کاغذ بایگانی می‌شد، برای بایگانی آن اسناد و هم‌چنین نگه داری آن‌ها مکانی بزرگ مورد نیاز بود، حتی دستیابی به سند مورد نظر زمانبر بود. با پیشرفت تکنولوژی پس از مدتی تصمیم گرفته شد تا تمام آن اسناد بصورت متن‌های قابل ویرایش و قابل جستجو در رایانه‌ها ذخیره شوند، اما با این حجم عظیم اسناد، چگونه؟
نابینایان نیاز به کتاب‌هایی داشتند که یا صوتی باشد و یا به خط مخصوصشان نوشته شده باشد، اما با این تعداد زیاد کتاب‌ها، چگونه ؟
این‌گونه نیازها باعث شد تا مفهومی به نام OCR1 معرفی شود، OCR به فرایند تبدیل اسناد تایپ شده، متون داخل تصاویر، دست‌نوشته‌ها و ... به متن قابل ویرایش و جستجو برای دستگاه می‌باشد.
امروزه مثال‌هایی این چنین که از OCR استفاده می‌شود را در اطرافمان زیاد می‌بینیم، از بارکد‌ خوان‌های فروشگاه، اسکنرهای بانک برای اسکن قبوض و چک‌ها، ... تا اپلیکیشن‌هایی چون QRCode خوان‌ها که در تلفن‌های هوشمند خود و اطرافیان به کرات مشاهده کرده‌ایم.

۱.۱. پیش پردازش

تصاویرمورد نظر ممکن است دارای مشکلاتی باشد که فرایند تشخیص متن را به خطا بیاندازد، برخی مشکلات و راه حل آن‌ها و پیش پردازش‌های دیگر عبارتند از:

  • اصلاح زاویه‌ی تصاویر2 : ممکن است تصویر ورودی زاویه مناسبی نداشته باشه،باید با روش‌هایی تصویر را چرخاند تا زاویه‌اش با خط افق صفر شود!

  • حذف نویز موجود در تصاویر: ممکن است به دلیل قدیمی بودن، کیفیت پایین دوربین و دلایلی دیگر تصویر ورودی دارای مقداری نویز (نقاط سیاه یا رنگی اضافی در تصویر) باشد که باید در از بین بردن یا حداقل کاهش آن‌ها کوشید تا تشخیص اشتباهی نداشته باشیم.[1,2]

  • سیاه و سفید کردن تصاویر: البته این مورد جزء مشکلات نمی‌باشد ولی اگر تصاویر رنگی بود، نیاز است که به دلیل تشخیص راحت تر و جدا کردن متن از پس زمینه‌ی تصویر از این کار استفاده شود(به عبارتی دیگر تضاد رنگی بین نوشته و پس‌زمینه به وجود بیاید). برای این کار، روش‌های گوناگونی از قبیل otsu، markov، global fixed و ... وجود دارد که بعداً برخی از روش‌هایش را توضیح خواهم داد.[1,2,3]

  • حذف خطوط اضافی: برخی از نوشته‌ها دارای خطوط (بردارهایی) در اطرافشان یا زیر‌خط3 و ... هستند که جزء خود متن نیستند.[2]

  • چسبیدگی یا جداشدن حروف: در برخی تصاویر ممکن است قسمتی از یک حرف جدا شده باشد و یا ممکن است چند حرف به‌هم چسبیده باشند، مانند تصویر زیر[2]

    تصویر شماره 1 - برخی از مشکلات پیش رو و رفع آن

۱.۱.۱. روش‌های سیاه و سفید کردن تصاویر4

در این‌ قسمت چند مورد از روش‌های سیاه و سفید کردن تصاویر با هدف جدا کردن متن از پس‌زمینه اشاره می‌کنیم.
* در این‌جا هر رنگ پیکسل -براساس مقدار سیاه یا سفید بودن5- تصویر ورودی را x و هر پیکسل تصویر نهایی را b می‌نامیم.

  • روش Global Fixed Threshold : در این روش که از ساده‌ترین روش‌هاست اگر x_i\ge 0.5 باشد b_i را یک می‌گذاریم، در غیر این صورت صفر می‌گذاریم(فرض بر این است که x_i بین صفر تا یک و b_i فقط یک یا صفر می‌توانند باشند).[3]

  • روش Otsu Threshold : تقریبا همانند روش قبلی می‌باشد با این تفاوت که به جای مقدار 0.5 مقدار t را در‌نظر می‌گیریم، این مقدار باید به گونه‌ای
    انتخاب شود که به بهترین نتیجه منجر شود. اگر رنگ پیکسل‌ها را بر اساس مقدار سیاه یا سفید بودنشان مقدار‌دهی کنیم مقادیر این‌گونه می‌باشد که کلاس مورد نظر {G={0,1,…,L-1 می باشد و بر اساس t این به دو کلاس {0,1,…,t} و {t+1,t+2,…,L-1} تقسیم می‌شود که باید مقدار واریانس داخل کلاسی به حداقل و واریانس بین کلاسی به حداکثر برسد، یعنی اگر واریانس داخلی را به صورت زیر تعریف کنیم، باید t به گونه ای باشد که این واریانس به حداقل برسد .

    {\sigma_W}^2(t) = W_1(t){\sigma_1}^2(t) + W_2(t){\sigma_2}^2(t)

    که در این جا Wها احتمال دو کلاس مجزا شده توسط t می باشد و اگر واریانس بین کلاسی را به صورت زیر تعریف کنیم، باید مقدارش به حداکثر برسد.
    {\sigma_B}^2(t) = {\sigma}^2 - {\sigma_W}^2(t) = W_1(t)W_2(t) [\mu_1(t) - \mu_2(t) ]^2

    و داریم[4]
    W_1(t) = {\Sigma}_0^t p_i(t)

    \mu_1(t) = {\Sigma}_0^t p_i(t) x_i(t)

  • روش Markov Model : در این روش علاوه بر پیکسل فعلی، پیکسل‌های قبلی هم مورد بررسی قرار میگیرد، در این‌جا بطور مثال پیکسل قبلی یعنی پیکسل‌های بالا و سمت چپ پیکسل مورد نظر هستند که تصمیم برای این که پیکسل کنونی سیاه است یا سفید به پیکسل‌های قبلی وابسته است، علاوه بر برتری این روش نسبت به روش‌های دیگر به خاطر تشخیص بهتر انحنا و زواید حروف، معایبی هم دارد بطور مثال در تصویر شماره 3 در نمونه شماره 2 می‌بینید که پیکسل اضافه‌تری هم سیاه شده است.[3]

    تصویر شماره 2 - بررسی پیکسل های قبلی در روش Markov

    تصویر شماره 3 - مقایسه روش Markov و روش General fixed threshold

۱.۲. پردازش

در این مرحله باید به هدف اصلی که تشخیص حروف و تبدیل آن‌ها به متن قابل ویرایش و جستجو برای دستگاه می‌باشد برسیم. الگوریتم‌ها و روش‌های گوناگونی وجود دارند که در قسمت‌های بعدی مفصل‌تر به آن‌ها خواهم پرداخت.

۱.۳. پس پردازش

پس از این که متن را تشخیص دادیم، ممکن است برخی از حروف به درستی تشخیص داده نشده باشند یا حتی ممکن است خود دست‌نوشته غلط املایی داشته باشد، پس برای بالا بردن دقت نتیجه‌ی کار می‌توان از واژه‌نامه‌ها6 استفاده کرد که برای زبان‌های برنامه نویسی مختلف ارائه شده اند. واژه‌نامه‌ها می‌توانند عمومی یا تخصصی برای زمینه خاصی مثلا ورزشی، مهندسی، ... باشند.[1,7]

۲. کارهای مرتبط

مواردی که در مقدمه ذکر شد، کارهایی است که برای بهبود نتایج انجام داده می‌شود. برای تشخیص و تبدیل متن از تصاویر، روش های متفاوتی وجود دارد که برخی از آن‌ها شامل چند مورد زیر می‌باشد:

۲.۱. الگوریتم‌ها

  • تطبیق الگو7 به روش شیار-قطاع : در این روش به تولید ماتریس مخصوص هر حرف می‌پردازیم و سپس ماتریس را با ماتریس‌های نمونه‌هایی که از قبل داشته‌ایم و مقدار آن را می‌دانیم مقایسه می‌کنیم و سپس تصمیم می‌گیریم. پس از طی نمودن مراحل پیش پردازش‌ها برای نرمال‌سازی تصویر مورد نظر، باید ابتدا متن را به صورت سطر به سطر جدا کرده و در هر سطر هر یک از حروف را مورد پردازش قرار دهیم و پس از اتمام پردازش بر روی یک حرف، سراغ حروف بعدی رفته و در انتها از در کنار هم گذاشتن اطلاعات بدست آمده، متن را تشکیل می‌دهیم. پس از این که تصویر را محدود به حروف مورد نظر کردیم، تصویر حرف کنونی را به صورت صفر و یک درون یک ماتریس n \times n ذخیره می‌کنیم(به‌طور مثال ماتریس 15 \times 15)، بدین صورت که به‌جای قسمت‌های سیاه رنگ 1 گذاشته و قسمت‌های سفید رنگ را صفر می‌گذاریم.
    در ادامه ماتریس به دست آمده را به 5 شیار8 و 8 قطاع9 تقسیم می‌کنیم، برای این کار ابتدا درایه‌ی مرکزی ماتریس را یافته و سپس دورترین درایه از نظر فاصله نسبت به درایه‌ی مرکزی می‌یابیم، با تقسیم مقدار به دست آمده-شعاع-به تعداد شیارها می‌توان شیارهای مختلف ماتریس را به دست آورد.

    تصویر شماره 4 - تبدیل تصویر به ماتریس متناظر و تقسیم ماتریس به شیار و قطاع

    با در نظر گرفتن شیار و قطاع مرتبط با آن می‌توان تعداد درایه‌های با مقدار یک را به دست آورد، سپس ماتریسی جدیدی تشکیل داده، موسوم به ماتریس شیار-قطاع که هر درایه‌ی آن نشان‌دهنده‌ی تعداد یک در شیار و قطاع مورد نظر می‌باشد. حال برای تشخیص حرف، آن را با نمونه‌هایی که از قبل داشته‌ایم مقایسه کرده و آن را به دست می‌آوریم.[6]

  • تطبیق الگو به روش نزدیک‌ترین همسایگی10 : در این روش هم اساس کار بر تقسیم‌بندی تصویر و تبدیل آن به ماتریس متناظر می‌باشد با این تفاوت که یک مرحله‌ی پیش پردازش اضافی دارد و روش تقسیم‌بندی و دسته‌بندی کردن11 از روش قبل متفاوت است.
    ابتدا به توضیح مختصری در ارتباط با الگوریتم نزدیک‌ترین همسایگی(K-NN) می‌پردازم. هدف این الگوریتم دسته‌بندی ورودی‌ها بر اساس دسته‌بندی‌های داده‌هایی از قبل دسته‌بندی شده‌اند، می‌باشد. اگر D را مجموعه داده هایی در نظر بگیریم که قبلا دسته‌بندی شده و x را داده‌ای که قصد دسته‌بندی کردنشان را داریم، که x = ( x\prime , y\prime ) که در اینجا x\prime داده‌ی مورد بررسی می‌باشد و y\prime هم نام دسته‌اش. ابتدا به محاسبه‌ی فاصله‌ی بین داده‌ی مورد بررسی و کل داده‌های پیشین می‌پردازیم که به تشکیل آرایه‌ی k عضوی از نزدیک‌ترین دسته‌ها به نام D_Z منجر می‌شود. حال، با در نظر گرفتن رأی اکثریت12 اقدام به انتخاب دسته‌ی مورد نظر می‌کنیم، که رأی اکثریت را می‌توان از روش زیر به دست آورد.

    y' = _v^{argmax} \Sigma _{(x_i,y_i) \in D_z} I( v = x_i )

    *در این‌جا i ، منظور i امین نزدیک‌ترین همسایه می‌باشد و v هم نام دسته‌ می‌باشد و هم‌چنین تابع I هم تابعی است که در صورت درستی عبارت داخلش 1 برمی‌گرداند و در غیر این‌صورت صفر برمی‌گرداند.
    تصویر زیر مثالی از این الگوریتم می‌باشد، بدین صورت که اگر دو دسته‌ی مربع‌های آبی و دسته‌ی دایره‌های سبز در نظر بگیریم در صورتی که K=3 باشد، سه تا از نزدیک‌ترین‌ها دارای دو مربع آبی و یک دایره‌ی سبز می‌باشد که دسته‌ی مربع‌های آبی را برمی‌گزیند.
    تصویر شماره 5 - مثالی از روش نزدیک ترین همسایگی

    در ادامه پس ازاین که توسط روش خاص خود به نازک سازی13 حروف (پیش پردازش) -که در [5] توضیح بیشتری داده شده- پرداخت، نوبت به توضیح چگونگی تقسیم‌بندی و تشکیل ماتریس متناظر می‌رسد. اگر تصویر ورودی را X بگیریم و پیکسل‌های پس‌زمینه را یک بگذاریم و پیکسل‌های پیش زمینه را صفر بگذاریم، ابتدا x و y بیشینه و کمینه را به‌دست آورده تا تصویر را محدود به حرف مورد نظر کنیم. سپس از تصویر به دست آمده به تشکیل ماتریس X_E می‌پردازیم.
    سپس به تقسیم‌بندی ماتریس بدست آمده به خانه‌های هم اندازه می‌پردازیم که خانه‌های به دست آمده C_i نام‌گذاری می‌کنیم، اگر در هر کدام از این خانه‌ها نسبت مقادیر یک به مقادیر صفر را بدست بیاوریم، به ازای هر خانه داریم، P_i .
    P_i = \frac {n_w}{n_B}

    اگر نسبت‌های بدست آمده را در یک آرایه به نام R_X بگذاریم، حال آرایه‌ای داریم که مشخصه‌ی هر حرف می‌باشد، که هر کدام را می‌توان به نام حروف مورد نظر نام گذاری کرد مثلا آرایه‌ی A،B،C، ... .
    از این پس، پس از دریافت ورودی به ساخت ماتریس آن مطابق آن‌چه در بالا ذکر شد، پرداخته و سپس با استفاده از الگوریتم نزدیک‌ترین همسایگی اقدام به دسته‌بندی آن می‌کنیم.البته فاصله را بر اساس فرمول اقلیدس می‌توان به دست آورد، به طوری که X_S ماتریس داده مورد بررسی و X_T داده‌هایی که قبلا دسته‌بندی شده‌اند و Q همان مقدار P برای داده‌ی مورد بررسی می‌باشد.
    Distance_{Euclidean}(X_{T1} , X_{S1}) = D_1 = \sqrt{\Sigma_{j=1}^N (P_{1,j} - Q_{1,j})^2}

    در پیاده‌سازی این روش از نرم‌افزار متلب استفاده شده و مقدار K=5 در نظر گرفته شده که در آزمایش‌های مختلف مطابق تصویر شماره 7 به تقریبا 95 درصد تشخیص درست دست یافته‌اند.[5]
    تصویر شماره 6 - نمونه ای از داده های مورد بررسی و ساخت ماتریس آن

    تصویر شماره 7 - میانگین درصد تشخیص درست

۲.۲. ابزارهای موجود

  • موتور Tesseract : این موتور تشخیص متن، ابتدا سطر‌ها را شناسایی می‌کند (سطرهای زاویه‌دار را هم شناسایی می‌کند و تغییر زاویه‌ای در آن‌ها به وجود نمی‌آورد که باعث می‌شود از کیفیت تصویر کاسته نشود). پس از شناسایی سطر‌ها و ایجاد خطوط و مسیر در اطراف حروف نوبت به جداسازی حروف می‌رسد، بدین ترتیب که نقاطی که تشخیص داده می‌شود محل جدا شدن هستند را انتخاب می‌کند مثلا نقاطی که در قسمت‌های مقعر هستند، تصویر زیر کلمه‌ای را می‌بینیم که بر روی آن نقاط انتخابی با پیکان نشان داده شده‌اند.

    تصویر شماره 8 - پیکان ها نشان دهنده ی نقاط انتخابی برای برش هستند

    سپس از نقاط مختلف برش را انجام می‌دهد تا به بهترین حالت دست یابد. بعد از این، نوبت دسته‌بندی می‌باشد، در Tesseract دسته‌بندی‌ها بر اساس شکل چندضلعی‌ها و خطوط ایجاده شده‌ی اطراف حروف می‌باشد و پس از مقایسه با داده‌هایی که قبلا دسته‌بندی شده‌اند با روشی مشابه K-NN دسته‌ی متناسب را برمی‌گزیند. تفاوت Tesseract با ابزار و روش‌های دیگر نحوه‌ی دسته‌بندی آن می‌باشد که فونت های مختلف را می‌تواند شناسایی کند و ویژگی‌های دیگر آن، به استفاده از واژه‌نامه‌ها به عنوان پس پردازش می‌توان اشاره کرد.[7]

  • کتابخانه OpenCV : این کتابخانه علاوه بر تشخیص متن، کارهایی چون تشخیص چهره، تشخیص حرکت در دوربین و فیلم، خواندن پلاک خودرو و کارهای زیادی که مربوط به پردازش تصویر می‌شود را انجام می‌دهد و ادعا شده که دارای 2500 الگوریتم بهینه برای کارهای مختلفش می‌باشد. این کتابخانه برای تشخیص متن از الگوریتم‌هایی چون K-NN و SVM14 استفاده می‌کند و برای زبان‌های برنامه نویسی سی، سی پلاس پلاس، پایتون، جاوا و متلب نوشته شده است.

  • ابزارهای آنلاین : وبسایت‌های مختلفی وجود دارند که هر کدام از آن‌ها با الگوریتم خودشان می‌توانند تصاویری را که ما بارگذاری می‌کنیم به متن تبدیل کنند، وبسایت‌هایی چون onlineocr ، free-ocr ، newocr و ... ، البته خیلی از آن‌ها از الگوریتم‌های پیچیده‌ای استفاده نکرده‌اند که به همین دلیل گاهی اوقات جواب نادرست می‌دهند. تصویر زیر نمونه‌ی تست شده می‌باشد که هر سه وبسایت جواب متفاوتی داده‌اند و فقط یکی از آن‌ها کاملا درست بوده است.

    تصویر شماره 9 - مقایسه وبسایت های مختلف در تشخیص متن

۳. آزمایش‌ها

در این قسمت با انجام آزمایشاتی به میزان تشخیص درست و مقایسه‌ی روش‌های مختلف می‌پردازیم. دو روشی که مورد مقایسه قرار می‌گیرد، استفاده از دو کتابخانه‌ی pytesser و OpenCV می‌باشد، که در دو مرحله‌ی تشخیص حروف و تشخیص کلمات مورد بررسی قرار می‌گیرند.
مجموع دادگان15 مورد استفاده برای تشخیص حروف که از اینجا قابل دانلود می‌باشد، به صورت تصاویری می‌باشد که برای هر حرف 200 تصویر وجود دارد که ما از 100 تای اول آن به عنوان داده‌ی آموزش16 و از 100 تای بقیه به عنوان داده‌ی مورد آزمایش17 استفاده می‌کنیم ( از این 100 داده‌ی آموزشی برای آموزش مرحله‌ی تشخیص کلمات هم استفاده می‌شود).
مجموع دادگان مورد آزمایش برای تشخیص کلمات که از اینجا قابل دانلود می‌باشد، به صورت تصاویری از کلمات در حالات مختلف است که مقدار آن‌ها در فایل xml18 ضمیمه شده در آن درون تگ image با مشخصه‌ی tag نمایش داده می‌شود.

۳.۱. تشخیص حروف

  • استفاده از pytesser: ماژول19 pytesser که پروژه‌ی منبع باز20 گوگل می‌باشد، از موتور تشخیص حروف Tesseract استفاده می‌کند. استفاده از آن بدین صورت است که با دادن آدرس تصاویر، دستوری تصاویر را می‌خواند و دستوری دیگر آن را به صورت رشته‌ی تشخیص داده شده برمی‌گرداند.

from pytesser import *
image = Image.open('directory of image')
response = image_to_string(image)

در این ماژول با هر بار فراخوانی تابع image_to_string موتور Tesseract فراخوانی می‌شود که با استفاده از آن می‌توان حروف را تشخیص داد( روش کار موتور Tesseract در قسمت قبل توضیح داده شد).
در آزمایش صورت گرفته در بین حروف بزرگ انگلیسی، برای هر حرف از100 تا به عنوان داده‌ی مورد آزمایش استفاده کردیم، یعنی 2600 داده مورد آزمایش که قرار گرفت. در این آزمایش از 2600 داده‌ی مورد بررسی 1741 مورد به درستی تشخیص داده شد.

  • استفاده از OpenCV: به دلیل این که دادگان ما با استفاده از نام فولدرشان باید دسته بندی شوند، ابتدا با استفاده از دو حلقه تمامی داده‌ها رو در درون یک آرایه‌ی دو بعدی ذخیره می‌کنیم. آرایه 26 درایه دارد که هر کدام از این درایه‌ها 200 درایه‌ی دیگر که 200 داده از 26 حرف انگلیسی می‌باشد را دارند. بصورت زیر ابتدا به ساخت آرایه‌ی کلی می‌پردازیم.

 for char in alphabet:
    for i in range(0,200):
         j = alphabet.index(char)
         img[j].append(cv2.imread('./training/training/upper/'+char+'/'+str(i)+'.jpg'))
         gray[j].append(cv2.cvtColor(img[j][-1],cv2.COLOR_BGR2GRAY))

در این روش ما باید تعدادی داده را به عنوان داده‌های آموزشی یا یادگیری معرفی کنیم و تعدادی داده‌ی دیگر را به عنوان داده‌ی مورد آزمایش. در اینجا 100 تصویر اول هر حرف را داده‌ی آموزشی و 100 تصویر دوم را داده‌ی آزمایشی معرفی می‌کنیم. سپس به هر کدام از داده‌ها باید مقداری به عنوان پاسخش بدهیم، بدین منظور که به طور مثال، 100 داده‌ی اول فولدر اول و 100 داده‌ی دوم فولدر اول هر دو از یک جنس هستند.

train = x[:,:100].reshape(-1,400).astype(np.float32)
test = x[:,100:200].reshape(-1,400).astype(np.float32)
k = np.arange(26)
train_labels = np.repeat(k,100)[:,np.newaxis]
test_labels = train_labels.copy()

حال، با استفاده از الگوریتم نزدیک ترین همسایگی به دسته‌بندی داده‌های آزمایشی بر اساس داده‌هایی که قبلا از آن‌ها یاد گرفته، می‌پردازیم. پس از آن با بررسی مقدار به دست آمده با مقدار متنظر با آن در آرایه‌ی از پیش تعیین شده، می‌توان درصد درستی را به دست آورد.

knn = cv2.ml.KNearest_create()
knn.train(train,cv2.ml.ROW_SAMPLE,train_labels)
ret,result,neighbours,dist = knn.findNearest(test,k=1)
matches = result==test_labels
correct = np.count_nonzero(matches)
accuracy = correct*100.0/result.size

در این روش از 2600 داده ی مورد آزمایش 2493 مورد به جواب درست رسید.

روش تعداد داده‌های مورد آزمایش تعداد تشخیص درست درصد درستی
pytesser 2600 1741 66.96%
OpenCV 2600 2498 95.88%

۳.۲. تشخیص کلمات

  • استفاده از pytesser:همان‌طور که ذکر شد دادگان مورد استفاده برای تشخیص کلمات، تصاویری هستند که مقدار هر تصویر در فایلی xml ذخیره شده است. در ابتدا باید مقدار هر تصویر را در آرایه‌ای ذخیره نماییم.

    تصویر شماره 10 - قسمتی از فایل xml حاوی اطلاعات تصاویر

    ابتدا توسط ماژول xml.dom که برای استفاده از فایل‌های xml می‌باشد، سعی در خواندن فایل word.xml داریم. همان‌گونه که ذکر شد، هر تصویر داخل تگ image می‌باشد و مقدار آن‌ها در مشخصه‌ی tag نوشته شده است. با استفاده از کد زیر می‌توان مقدار هر تصویر را در آرایه‌ای که شماره هر خانه‌ی آن متناسب با نام تصویر آن می‌باشد، ذخیره نمود.

      from xml.dom import minidom
      response = []
      doc = minidom.parse("word.xml")
      images = doc.getElementsByTagName("image")
      for image in images:
          word = image.getAttribute("tag")
          response.append(word)
    

    در این آزمایش صورت گرفته از بین 1100 داده‌ی مورد آزمایش، 522 کلمه درست تشخیص داده شد.

  • استفاده از OpenCV: در این روش ابتدا همانند تشخیص حروف، به تولید محتوای مربوط به داده‌ی مورد آموزشی می‌پردازیم. سپس برای پاسخ بهتر لازم است مراحل پیش پردازش را طی کنیم، این مراحل شامل سیاه و سفید کردن تصاویر، تار کردن21 تصویر ( به منظور پر کردن برخی از فضاهای خالی نامناسب )، ... و در نهایت جداسازی22 حروف کلمات می‌باشد. بزرگترین مانع این قسمت، جداسازی حروف می‌باشد که در اکثر موارد به جواب نادرست منتهی می‌شود و طبق مراحل قبل می‌دانیم که پس از جداسازی صحیح حروف می‌توان به نتایج مطلوبی رسید.

img = cv2.imread('Directory of image')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
gray = cv2.medianBlur(gray,5)
ret3,thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
thresh_color = cv2.cvtColor(thresh,cv2.COLOR_GRAY2BGR)
thresh = cv2.erode(thresh,None,iterations = 1)
thresh,contours,hierarchy = cv2.findContours(thresh,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)

تصویر شماره 11 - نمونه جداسازی درست

تصویر شماره 12 - نمونه جداسازی نادرست

حال با جداسازی و به دست آوردن حدفاصل‌ها، دسته‌بندی آن قسمت با استفاده از روش نزدیک ترین همسایگی را انجام می‌دهیم. سپس مقادیر بدست آمده را در یک رشته ذخیره کرده و با درایه‌ی متناظر آن چک می‌شود تا درصد درستی محاسبه شود. البته در این قسمت به دلیل مشکل جداسازی حروف در اکثر قریب به اتفاق تصاویر، نبود داده‌ی مناسب برای یادگیری ( داده‌های یادگیری فقط حاوی حروف بزرگ انگلیسی بود و اعداد و کاراکترهای خاص را نداشت) و ... تنها از بین 1100 داده‌ی مورد آزمایش به 11 جواب درست رسید!

roi = cv2.resize(roi,(20,20))
roi = roi.reshape((1,400))
roi = np.float32(roi)
retval, results, neigh_resp, dists = knn.findNearest(roi, k = 1)
word += chr(results)

تصویر شماره 13 - یکی از داده‌هایی که به جواب درست منجر شده

روش تعداد داده‌های مورد آزمایش تعداد تشخیص درست درصد درستی
pytesser 1100 522 47.45%
OpenCV 1100 11 1%

کدهای پروژه در سایت گیت‌هاب در دسترس می‌باشد. در مرحله‌ی بعد برای بهبود نتایج، باید مرحله جداسازی را بهبود بخشیم و دادگان آموزشی بیشتری را جمع آوری کنیم تا به جواب درست‌تری دست یابیم.

۴. کارهای آینده

در این فاز به رفع مشکلاتی که باعث درصد تشخیص درستی پایینی شده بودند، می‌پردازیم. همان طور که قبلا هم گفته شده بود با مشکلاتی چون استفاده نکردن از داده‌های یادگیری مناسب و مشکل عمده در جداسازی حروف مواجه بودیم.

  • افزودن داده‌های بیشتر به داده‌های یادگیری: با استفاده از کدی که قبلا برای یادگیری داده‌ها استفاده می‌کردیم، داده‌های جدیدی را اضافه کردیم ولی در نتایج تغییر چندانی مشاهده نشد.

  • رفع مشکل جداسازی: در قسمت تشخیص حروف، روش ما به درستی جواب داده بود و به درصد درستی بسیار خوبی رسیده بودیم، اما در تشخیص کلمات یکی از بزرگترین اشکالات جداسازی نادرست حروف در کلمات بود. با بررسی و مقایسه‌ی چند مورد از داده‌هایی که تشخیص درست داده بود و داده‌هایی که تشخیص نادرست داده بود، متوجه شدیم که تصاویری که پس زمینه‌ی آن‌ها رنگی تیره و رنگ متن روشن بود، به درستی جداسازی می‌شود. مشکل ما با تصاویری بود که پس زمینه‌ی آن‌ها رنگی روشن و رنگ متن آن تیره می باشد. برای رفع این مشکل، به جای این که با استفاده از کد زیر تصاویر را سیاه و سفید کنیم:

 tret3,thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

کد برعکس سیاه و سفید کردن را هم در هر مرحله تست کردیم، بدین صورت که در هر مرحله علاوه بر انجام فرایند برای تصویر سیاه و سفید، برای تصویر سیاه و سفیدی که رنگ ها معکوس شده بودند هم انجام می‌شد. پس از بررسی هر دو آزمایش، هر کدام که به نتیجه‌ی درستی منجر می‌شود را اعلام می‌کند. در تصویر زیر چند نمونه از تصاویری که در روش قبل به اشتباه جداسازی شده بودند و در این روش به درستی جداسازی شده‌اند را مشاهده میکنید:

tret3,thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

تصویر شماره 14 - نمونه ای از محدوده بندی ها پس از رفع مشکل

  • رفع مشکلات محدوده‌ها23 : حتی با رفع این مشکل گفته شده باز هم نتیجه‌ی کار، چندان تغییری نکرد. با بررسی بیشتر متوجه شدیم که برخی از محدوده‌های جداسازی داخل یکدیگر قرار میگیرند که باعث ایجاد مشکل در تشخیص و جداسازی می‌شود. مانند تصویر زیر:

    تصویر شماره 15 - نمونه ای از مشکل محدوده ها

    برای رفع این مشکل، مد مکان‌یابی محدوده‌ها را از حالت معمولی به حالت EXTERNAL تغییر دادیم. این حالت باعث می‌شود که اگر محدوده‌هایی درون یکدیگر قرار گرفته‌اند، محدوده‌ی بیرونی انتخاب شود.

      thresh,contours,hierarchy=cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
    

با انجام این تقریبا مشکلات جداسازی حل شد ولی باز هم نتایج تغییر چندانی نکرد. با دقت و جستجوی بیشتر پی بردیم که این کتابخانه برای انتخاب محدوده‌ها ترتیب خاصی قائل نیست، پس برای رفع این مشکل هم مستطیل‌های بدست آمده از انتخاب محدوده‌ها را بر اساس محور xها مرتب کردیم، طبق کد زیر:

rects = []
for cnt in contours:
            x,y,w,h = cv2.boundingRect(cnt)
            rects.append([x,y,w,h])
rects.sort(key = lambda rects:rects[0])

با انجام این کار تغییرات خیلی بیشتری در نتایج حاصل شد که در جدول زیر گزارش شده است:

روش تعداد داده‌های مورد آزمایش تعداد تشخیص درست درصد درستی
OpenCV 1100 148 13.45%

حال اگر به عنوان نتیجه گیری بخواهیم خلاصه‌ای از روند کار را ذکر کنیم، بدین صورت است که در ابتدا با انجام پیش پردازش‌ها بر روی تصاویر، تعدادی از داده‌ها را به عنوان داده‌های یادگیری به الگوریتم داده، سپس الگوریتم با جداسازی حروف در کلمات هرکدام از آن‌ها را با دسته‌های مختلف داده‌های یادگیری مقایسه و دسته‌بندی می‌کند و نتیجه را گزارش میدهد. در نهایت به عنوان پس پردازش هم میتوان کلمات به دست آمده را با مجموع کلمات موجود در پایگاه داده مقایسه کرد و نزدیک‌ترین کلمه را به کلمه‌ی تشخیص داده شده انتخاب کرد.

۵. مراجع

[1] http://en.wikipedia.org/wiki/Optical_character_recognition
[2] http://www.nicomsoft.com/optical-character-recognition-ocr-how-it-works
[3] Maya R. Gupta, Nathaniel P. Jacobson, Eric K. Garcia "OCR binarization and image pre-processing for searching
historical documents" [2006]
[4] EUGEN-DUMITRU TĂUTU and FLORIN LEON "OPTICAL CHARACTER RECOGNITION SYSTEM
USING SUPPORT VECTOR MACHINES" [2012]
[5] Mohammad Imrul Jubair, Prianka Banik "A Simplified Method for Handwritten Character Recognition from Document Image"
[6] Faisal Mohammad, Jyoti Anarase, Milan Shingote, Pratik Ghanwat "Optical Character Recognition Implementation
Using Pattern Matching" [2014]
[7] Ray Smith "An Overview of the Tesseract OCR Engine" [2007]

۶. لینک‌های مفید


  1. Optical Character Recognition

  2. De-Skew

  3. Underline

  4. Binarization

  5. GrayScale

  6. Lexicon

  7. Pattern Matching

  8. Track

  9. Sector

  10. K-Nearest Neighbour

  11. Classification

  12. Majority Voting

  13. Thinning

  14. Support Vector Machine

  15. Data Set

  16. Training

  17. Test

  18. Extensible Markup Language

  19. Module

  20. Open source

  21. Blurring

  22. Segmentation

  23. Contours

تایید شده

با سلام ، پروژه به خوبی پیاده سازی شده ،روش های مختلف ازمایش شده اند،مقایسه و نتیجه گیری به درستی صورت گرفته است ، عملکرد شما در تمامی مراحل مطلوب میباشد.اوردن بخش هایی از کد و توضیحات ان غیر ضروری است.بهتر بودید نتایج را در یک جدول می اوردید ک مقایسه روش ها راحت تر صورت بگیرد . خسته نباشید .

تایید شده

سلام
متن شما به طرز خوب و قابل فهمی نوشته شده است و از نکات مثبت کار شما کامنت گذاری کدها و توضیح مناسب و کافی برای هر روش است.
بهتر بود به عنوان داده های train از اعداد هم استفاده کنید و فقط به حروف بزرگ و کوچک بسنده نکنید. همچنین پیشرفت خوبی در بهبود نتایج داشتید و برای مشخص شدن ارزش کارتان میتوانستید کار خود را با دیگران مقایسه کنید.
موفق باشید.

رد شده

سلام
پروژه ای که انجام دادید، اطلاعات کامل و مفیدی در اختیار خواننده قرار می دهد و مطالب به صورت واضح بیان شده اند.تصاویری که در قسمت های مختلف پروژه قرار داده شده بود، به فهم مطالب کمک می کرد. ارجاع به مقالات انجام شده بود اما بهتر بود از تعداد مقالاتی بیشتری برای این پروژه استفاده می کردید.
موفق باشید

تایید شده

سلام، پروژه خوبی انجام داده‌اید و با مثال‌ها و عکس‌هایی که آورده‌اید خواننده کاملا متوجه موضوع می‌شود. علاوه بر آن توضیحات روان و گویاست. چند نکته به ذهنم رسید که ذکر می‌کنم.

  • در بخش پیش‌پردازش مشکلاتی را ذکر کرده‌اید اما به جز مشکل سیاه سفید بودن تصاویر راهکاری برای رفع مشکلات دیگر بیان نشده است.

  • نتایج فاز بهبود نتایج بهتر بود در همان بخش آزمایشات ذکر می‌شد. همچنین بهتر بود مقایسه‌ای بین نتایج پس از بهبود نتایج و قبل از آن صورت می‌گرفت. در بخش کار‌های آینده بهتر بود مواردی را ذکر می‌کردید که فرصت انجام آنها وجود نداشت.

  • نکته آخر اینکه با وجود اینکه در دستاست تصویر عدد وجود داشت اما شما در داده‌های train از آنها استفاده نکردید.

موفق باشید.

تایید شده

ضمن عرض خسته نباشید و تشکر بابت پروژه مفید شما، نکاتی به نظرم آمد که برای شما عرض می‌کنم:
1- پروژه شما دارای انسجام بسیار خوبی می‌باشد که مطالعه کننده‌ی ان به خوبی می‌تواند از مطالب پروژه‌ی شما استفاده کند.
2- همچنین در پروژه‌شما تصاویر بسیار گویا و واضحی وجود دارد که به فهم بهتر موضوع پروژه کمک می‌کند.
3- کدهای شما در گیت هاب هم دارای توضیحات و کامنت ‌های مختصر و مفیدی می‌باشد که نقطه قوت قسمت پیاده‌سازی پروژه‌ی شما محسوب ‌می‌شود.
4- بهتر بود در قسمت یادگیری ماشین برای داده‌های training ، از پایگاه داده ای برای اعداد نیز استفاده می‌کردید و فقط از حروف کوچک و بزرگ استفاده نمی‌کردید.
5- نکته آخر این است که در فاز بهبود نتایج، تشخیص درست نویسه‌خوان پیشرفت کرده است که جزء نکات مثبت پروژه‌ی شما می‌باشد.

تایید شده

سلام

  • بخش بهبود نمی بایست تحت عنوان "کارهای آینده" بیان می شد. به نظر می رسدعنوان می بایست اصلاح می شد.

  • ایده های در نظر گرفته شده برای بهبود نتایج منطقی و معقول می باشد.

  • دقت نهایی که با بهبود بدست آمده نیز به نظر قابل قبول نیست و دقت های بدست آمده رضایت بخش نیستند. بهتر بود برای انتخاب روش پایه که قصد بهبود آنرا داشتید دقت بیشتری بیشتری به خرج می دادید.