edge detection با استفاده از OpenCv
از سری مقالات آموزش OpenCv اندروید, مبحث edge detection را بر میگزینیم.
در مقالات قبل با استفاده از انواع filter های OpenCv, پردازش هایی را بر روی تصاویر اعمال کردیم. حذف noise و تغییر Contrast تصاویر مثال هایی از کاربر filter ها در OpenCv است. در این مقاله نیز با استفاده از filter های موجود, میخواهیم پردازش های مرتبط با edge detection را انجام دهیم. بدیهی است که برای پیدا کردن مرز ها,باید از اختلاف شدت رنگ pixel در مقایسه با pixel های مجاور آن استفاده شود. در تصاویر, شدت و یا نوع رنگ pixel ها با نرخ کم تغییر میکند. این تعریف به این معناست که هر pixel مقداری نزدیک به pixel های مجاور خود دارد. بنابراین اگر تغییر شدت و یانوع رنگ pixel ها در یک محدوده مشخص دارای نرخ بالایی باشد, میتواند دلیل بر وجود مرز (edge) در آن محدوده باشد.
برای محاسبه اختلاف مقدار pixel ها, از چنین فرمولی استفاده میکنیم:
این فرمول اختلاف دو pixel چپ و راست
و در این فرمول اختلاف دو pixel بالا و پایین pixel مد نظر را محاسبه میکنیم. فرمول اول محاسبه اختلاف x و فرمول دوم محاسبه اختلاف y است. نتیجه این محاسبات یک vector برای هر pixel است که عنصر اول vector, اختلاف x و عنصر دوم اختلاف y را نگهداری میکند. بررسی این vector دو نتیجه حائز اهمیت را مشخص میکند:
- با استفاده از این اختلاف میتوان وجود مرز را مشخص کرد
- با استفاده از این اختلاف میتوان مسیر مرز را مشخص کرد
اکنون با استفاده از این محاسبات, میتوان اولین روش edge detection را بررسی کنیم. در ابتدا نویز تصویر را حذف میکنیم. با استفاده از فرمول های ذکر شده, اختلاف ها را محاسبه میکنیم. یک مقدار را به عنوان حداقل مقدار وجود مرز تعیین میکنیم. این مقدار را threshold مینامیم. اگر اختلاف از این مقدار کمتر باشد, آن محدوده به عنوان مرز در نظر گرفته نمیشود.
در OpenCv از الگوریتم های زیادی برای edge detection استفاده میشود. اما در اینجا از این دو الگوریتم استفاده میکنیم:
اکنون به پیاده سازی این دو الگوریتم میپردازیم. پروژه ای که از ابتدای سری آموزش ها ایجاد کردهایم را ادمه میدهیم. برای پیاده سازی الگوریتم Sobel Edge Detection به این صورت عمل میکنیم:
private void sobelEdgeDetector(Mat src) { Size sz = new Size(5, 5); Imgproc.GaussianBlur(src, src, sz, 0, 0); }
بر اساس روش های تعریف شده در مقاله قبل, noise تصویر را کاهش میدهیم.
Imgproc.cvtColor(src, src, Imgproc.COLOR_RGB2GRAY);
تصویر را به حالت grayscale تبدیل میکنیم. علت این تبدیل را در مقاله تصاویر در OpenCv بررسی کردیم.
Mat fx = new Mat(); Mat fy = new Mat(); Imgproc.Sobel(src, fx, CvType.CV_16S, 1, 0); Imgproc.Sobel(src, fy, CvType.CV_16S, 0, 1);
متد Sobel با استفاده از فرمول های ذکر شده اختلاف ها را بررسی میکند. متغیر اول Mat اصلی تصویر است که تا به اینجا مورد پردازش قرار گرفته است. متغیر دوم Mat خروجی را مشخص میکند. متغیر سوم طول بیت های Mat را مشخص میکند. اختلاف بین دو pixel, حداقل صفر و حداکثر ۲۵۵ است. اگر این اختلاف را در یک فضای ۸ بیتی ذخیره کنیم, overflow رخ میدهد و باعث میشود تا مقادیری را از دست بدهیم. بنابراین فضای ذخیره سازی را ۱۶ بیتی در نظر میگیریم. متغیر چهارم و پنجم, به ترتیب مشخص کننده اختلاف نسبت به x و یا y هستند.
Mat absX = new Mat(); Mat absY = new Mat(); Core.convertScaleAbs(fx, absX); Core.convertScaleAbs(fy, absY);
تا به اینجا ما اختلاف pixel ها را بررسی کردیم. اما برای نمایش تصویر به مقدار pixel نیاز داریم. بنابراین باید مقادیر اختلاف, با مقادیر اصلی جمع شوند و در نهایت در خانه های ۸ بیتی ذخیره شوند. متد convert scale Abs این پردازش ها را برای ما انجام میدهد.
Core.addWeighted(absX, 0.5, absY, 0.5, 0, src);
اختلاف های بدست آمده از دو فرمول, دو تصویر مجزا را برای ما تولید میکند. در یک فرمول مرز های عمودی و در یک فرمول مرز های افقی مشخص شده است. بنابراین نیاز است تا این دو تصویر با یکدیگر ادغام شوند و یک تصویر واحد را تشکیل دهند. متغیر اول تصویر اول را مشخص میکند. متغیر دوم برابر وزن تصویر اول است. با استفاده از وزن دهی به هریک از تصاویر میتوان سهم آن تصویر در تصاویر نهایی را تعیین کرد. به همین ترتیب متغیر سوم, تصویر دوم و متغیر چهارم, وزن تصویر دوم را مشخص میکند. اگر بخواهیم مقداری را به مجموع این دو تصویر اضافه کنیم, این مقدار را به عنوان متغیر پنجم به متد ارسال میکنیم. متغیر ششم Mat خروجی را مشخص میکند.
کد کامل Sobel Edge Detector به این صورت است:
private void sobelEdgeDetector(Mat src) { Size sz = new Size(5, 5); Imgproc.GaussianBlur(src, src, sz, 0, 0); Imgproc.cvtColor(src, src, Imgproc.COLOR_RGB2GRAY); Mat fx = new Mat(); Mat fy = new Mat(); Imgproc.Sobel(src, fx, CvType.CV_16S, 1, 0); Imgproc.Sobel(src, fy, CvType.CV_16S, 0, 1); Mat absX = new Mat(); Mat absY = new Mat(); Core.convertScaleAbs(fx, absX); Core.convertScaleAbs(fy, absY); Core.addWeighted(absX, 1, absY, 0.5, 0, src); }
اکنون الگوریتم Canny Edge Detection را پیاده سازی میکنیم. پیاده سازی این الگوریتم بسیار آسان تر است, زیرا تنها با استفاده از یک متد میتوان edge detection را انجام داد. ابتدا نیاز است تا این کد را به متد onCreate اضافه کنید:
if (!OpenCVLoader.initDebug()) { // Handle initialization error }
این کد برای این است که متد canny به درستی پیدا شود.
private void cannyEdgeDetector(Mat src) { Imgproc.cvtColor(src, src, Imgproc.COLOR_RGB2GRAY); Imgproc.Canny(src, src, 200, 300); }
در متد canny متغیر اول Mat ورودی و متغیر دوم Mat خروجی است. با استفاده از متغیر سوم و چهارم دامنه threshold را تعیین میکنیم. سومین متغیر حداقل مقدار مجاز threshold و متغیر چهارم حداکثر مقدار مجاز threshold است.
در این مقاله سعی بر این شد تا مفهوم edge detection را مورد بررسی قرار دهیم و دو الگوریتم edge detection را پیاده سازی کنیم.
سری مقالات اموزش OpenCv اندروید ادامه دارد.
با ما همراه باشید.
دیدگاهتان را بنویسید
برای نوشتن دیدگاه باید وارد بشوید.