تصویر و ماتریس در OpenCV – پویش با اشاره گر

زمانی که می خواهیم برنامه های OpenCV را به منظور پردازش تصویر و پویش (Scan) پیکسل ها بنویسیم، این سوال پیش می آید که چکونه کدهایی با کارایی بالا (High Performance) بنویسیم که به سرعت تمامی پیکسل های تصویر یا حتی یا ویدیو بلادرنگ مانند دروربین لپ تاپ را پویش کند.

در مطلب تصویر و ماتریس در OpenCV – پویش ماتریس، در مورد تابع <>at و چگونگی دسترسی مستقیم به پیکسل ها صحبت کردیم. اما اگر کارایی و سرعت پویش پیکسل ها بسیار اهمیت دارد، OpenCV راه کار دیگری را پیشنهاد داده که این راه کار استفاده از اشاره گرها (Pointers) است.

استفاده از تابع (ptr<T>(int r

هر شی از کلاس Mat دارای یک متد (تابع) به نام ptr که یک اشاره گر به ابتدای سطر r را بدست می آورد. در OpenCV تمامی پیکسل های درون یک سطر درون یک بلاک پیوسته از حافظه ذخیره می شوند. زمانی که توسط تابع ()imread یک تصویر را می خوانید، چون این تابع از متد ()create از کلاس Mat استفاده می کند، پس تمامی پیکسل های درون یک سطر، در یک بلاک پیوسته از حافظه اصلی (RAM) ذخیره می شوند.

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

با توجه به انواع داده ای که در OpenCV وجود دارند و با توجه به تصویرهای خاکستری خاکستری تک کانالی یا تصویر رنگی سه کانالی، می توانیم توسط متد (ptr<T>(int r اشاره گره هایی از انواع مختلف به هر یک از سطرهای ماتریس ایجاد کنیم.

در متد (ptr<T>(int r، متغیر r به شماره یک سطر از ماتریس اشاره می کند. بناراین با توجه به نوع تصویر و نوع درایه های تصویر (مثلا ۸ بیتی بی علامت یا ۳۲ بیتی ممیز شناور)، می توان از دستورهای زیر برای دسترسی به پیکسل های سطر r استفاده کنیم.

بنابراین در کدهای بالا متغیر (یا شی) ptr اشاره گری به ابتدای سطر r از ماتریس تصویر است. دو خط اول از کد بالا، متغیر ptr اشاره گری از نوع uchar (یا ۸ بیتی بی علامت) به سطری از تصویر تک کانالی هستند. خط سوم متغیر ptr اشاره گری از نوع بردار سه تایی به تصویری سه کانالی است که هر درایه آن به صورت تک بیتی بی علامت است. خط چهارم متغیر ptr اشاره گری از نوع ممیز شناور به تصویر تک کانالی است که درایه های از نوع ۳۲ بیتی ممیز شناور هستند و در نهایت در خط پایانی متغیر ptr اشاره گری از نوع بردار ممیز شناور به تصویر سه کانالی است که درایه های آن از نوع ۳۲ بیتی ممیز شناور هستند.

تعداد سطرهای هر ماتریس توسط خصوصیت rows و تعداد ستون های هر ماتریس توسط خصوصیت cols بدست می اید.

مثال – تبدیل RGB به BGR

به عنوان مثالی از کاربرد متد (ptr<T>(int r در پویش پیکسل ها، در قطعه کد زیر برنامه ای را نوشته ایم که RGB را به BGR تبدیل می کند. در واقع جای کانال قرمز و آبی با یکدیگر عوض می شود. در خط ۹ تابعی به نام RGB2BGR اعلان شده است که پارامتر از نوع کلاس String در OpenCV را دریافت و سپس به ماتریس (تصویر) از نوع کلاس Mat را برگشت می دهد.

در خطوط ۲۵ تا ۴۵ بدنه تابع RGB2BGR تعریف شده است. در خط ۲۶ نام و مسیر تصویر به تابع ()imread ارسال و سپس ماتریسی به نام image ایجاد می شود. سپس در حلقه اول به ازای هر تکرار یک متغیر اشاره گر به نام ptr و از نوع Vec3b ایجاد می شود که به ابتدای سطر فعلی در تکرار حلقه اشاره می کند. در واقع در حلقه تکرار اول، row به سطری از ماتریس اشاره می کند.

در حلقه تکرار دوم به اندازه تعداد ستون ها ادامه پیدا می کند و در هر گام مقدار کانال قرمز با آبی عوض می شود. توجه کنید در مطلب ماتریس تصویر چگونه در حافظه ذخیره می شود توضیح دادیم که هر درایه از تصویر رنگی سه کانالی RGB به صورت یک سه تایی R-G-B است. شکل زیر مطلب را یادآوری می کند.

در واقع توسط کد بالا فضای رنگ RGB را به فضای رنگ BGR تبدیل کرده ایم. در مطلب جداسازی کانال تصویر توسط متد split در OpenCV

بیشتر در مورد فضای رنگ و چگونگی تبدیل یک فضای رنگ (Color Space) به دیگری توسط تابع ()cvtColor صحبت کرده ایم. در مطلب بعدی، مثال و کاربرد دیگری از متد (ptr<T>(int r برای پیمایش پیکسل های مجاور (Neighbor Pixels) گفته شده است.