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

مطابق شکل زیر (شکل ۱)، مشخص است که هر تصویر به صورت یک ماتریس از اعداد ذخیره می شوند که هر کدام از درایه های این ماتریس به یک پیکسل (نقطه) از تصویر اشاره دارد. OpenCV یک کتابخانه نوشته شده به زبان سی پلاس پلاس است که برای اهداف پردازش تصویر (Image Processing) و بینایی ماشین (Computer Vision) استفاده می شود.

به عبارت بهتر OpenCV کتابخانه ای است که از آن برای دست کاری و تغییر همین ماتریس عددی استفاده می شود که این ماتریس عددی در واقع بیانگر یک تصویر از دید رایانه است در صوتی که ما تصویر را به صورت رنگی می بینیم. بنابراین این مهم است که بدانیم OpenCV چگونه تصاویر را می خواند و چگونه تصاویر را اداره می کند.

کلاس Mat ساختاری برای ذخیره سازی تصاویر

Mat (مخفف Matrix) نام یک کلاس در OpenCV است که به عنوان مخزن ذخیره سازی تصویر استفاده می شود. در واقع Mat یک ساختار ماتریسی است که از آن برای ذخیره سازی داده های تصویر و یا برای ایجاد یک ماتریس استفاده می شود.

همانطور که توضیح دادیم در OpenCV، هر تصویر به صورت یک ماتریسی از اعداد ذخیره می شود که هر کدام از درایه های این ماتریس به یک پیکسل از تصویر اشاره دارد. زمانی که می خواهیم یک تصویر را در OpenCV بارگذاری کنیم، باید متغیری (یا نمونه ای – Instance) از کلاس Mat ایجاد کنیم.

درک کد بالا بسیار ساده است. ابتدا یک متغیر (نمونه یا شی) به نام image از کلاس Mat ایجاد کردیم که این کلاس در فضای نام cv قرار دارد. سپس توسط تابع ()imread از فضای نام cv، یک فایل تصویری به فرمت jpg را از دیسک خوانده ایم و در متغیر image ذخیره کرده ایم. اما در واقع image به خود فایل اشاره نمی کند بلکه به ماتریس عددی تصویر اشاره دارد.

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

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

در خطوط ۱ و ۲ دو فایل سرآیند (Header File) به فایل ضمیمه شده اند. سپس توسط کلاس String از فضای نام cv یک متغیر رشته ای ایجاد کرده ایم که به مسیر فایل اشاره دارد. در واقع متغیر imageName مسیر فایل را در خود نگه می دارد ولی متغیر image ماتریس عددی تصویر را در خود نگه می دارد. در خط ۱۱ نیز خود ماتریس عددی تصویر را در خروجی نشان داده ایم.

در قطعه کد زیر چگونگی پیدا کردن اندازه و ابعاد تصویر (عرض و ارتفاع) را نشان داده ایم. هر نمونه از کلاس Mat دارای متدی به نام ()size است که جفت عرض (Width) و ارتفاع (Height) مربوط به تصویر ورودی را برگشت می دهد.

برای پیدا کردن عرض تصویر(پهنا Width) باید از image.size().width و برای دسترسی به ارتفاع تصویر باید از image.size().height استفاده کنید. (خطوط ۱۴ و ۱۵)

ایجاد نمونه هایی از کلاس Mat

در کد بالا با فراخوانی تابع ()imread ذخیره ماتریس عددی تصویر، در متغیر image یک شی یا نمونه از کلاس Mat را ایجاد کرده ایم ولی طبق قطعه کد زیر می توانیم به وضوح و بدون نیاز به فراخوانی تابع ()imread می توانیم یک شی یا نمونه از کلاس Mat را ایجاد کنیم.

در کد بالا یک شی به نام imageMatrix ایجاد کرده ایم که در واقع یک ماتریس دو بعدی است که هر بعد آن یک پیکسل را نشان می دهد. در واقع با استفاده از تابع سازنده کلاس Mat این نمونه را ایجاد کرده ایم.  دو آرگومان اول به ترتیب تعداد سطرها (Rows) و تعداد ستون های (Columns) ماتریس را تعیین می کند. آرگومان سوم نوع داده هایی که هر درایه از ماتریس می تواند نگه دارد را تعیین می کند که در کد بالا از نوع CV_8UC3 استفاده کرده ایمبرای اطلاع بیشتر این لینک را مطالعه کنید.

در OpenCV انواع مختلفی وجود دارند که دو نوع آنها CV_8U و CV_8UC3 است. 8U در واقع به ۸ بیت بی علامت (Unsigned) اشاره دارد و C3 به سه کاناله بودن تصویر اشاره دارد. در مطلب های بعدی در مورد تصویرهای رنگی RGB و تصویر خاکستری (Grayscale) صحبت کرده ایم و مفهوم کانال (Channel) را نیز توضیح داده ایم.

آرگومان چهارم نیز رنگ تصویر را مشخص می کند. همانطور که می دانید رایانه ها از سیستم RGB برای ایجاد و نمایش رنگ ها استفاده می کند، پس اگر ((0,0,255 را استفاده کنیم، پس در واقع رنگ آبی را به تصویر داده ایم

در مطلب تصویر و ماتریس در OpenCV – ایجاد ماتریس ها در مورد چگونگی ایجاد ماتریس ها از طریق کلاس Mat در OpenCV صحبت کرده ایم.

خلاصه و جمع بندی

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

همچنین مطابق با کدهایی که توضیح دادیم، دیدیم که تمامی کلاس های OpenCV درون فضای نام cv قرار دارند و برای همین است که برای دسترسی به کلاس Mat از دستور cv::Mat و یا برای چاپ خروجی توسط دستور cout از دستور std::cout استفاده کرده ایم.

در مطلب های بعدی از دستور using namespace استفاده می کنیم تا یک فضای نام را به درون فایل برنامه معرفی کنیم. در واقع در مفاهیم شی گرایی، از فضای نام (Name Space) برای سازماندهی چندین کلاس مرتبط به هم استفاده می شود. به طور مثال در همین مطلب دو کلاس Mat و String معرفی شدند که هر دو در فضای نام cv قرار دارند، پس برای همین است که در کدهایمان از دستورهای زیر استفاده کرده ایم.

در دستورهای بالا ابتدا یک نمونه از کلاس Mat در فضای نام cv ایجاد کرده ایم و سپس توسط متد ()imread از کلاس Mat تصویر را خوانده و ماتریس عددی آنرا درون متغیر یا شی کلاس Mat بارگذاری کرده ایم. اما بهتر است تا فضای نام را توسط دستور using namespace به درون فایل برنامه معرفی کنیم. برای این منظور باید پس از ضمیمه کردن فایل های سرآیند، فضاهای نام را به برنامه معرفی کنیم.

استفاده از پایتون

در مطلب نصب OpenCV3 با پایتون در تمامی سیستم عامل ها چگونگی نصب OpenCV و پایتون از طریق محیط Anaconda را توضیح دادیم ولی در این دوره تمرکز ما بر روی برنامه نوسی OpenCV با زبان سی پلاس پلاس است.

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

ماژول cv2 مشخص است که مربوط به OpenCV است. اما ماژول numpy چه کاربردی دارد؟ ماژول numpy یکی از ماژول معروف پایتون است که اعمال روی اعداد را تعریف می کند. به طور مثال ما به راحتی می توانیم در سی پلاس پلاس آرایه های (ماتریس های) چند بعدی بسیازیم ولی این کار در پایتون امکان پذیر نیست برای همین نیاز به ماژول numpy داریم.