مبحث پردازش تصویر در هدوپ بحث جذابی است که نمیتوان مثالها و ابزارهای بسیاری برای آن پیدا کرد. زیرا که نه تنها پیچیدگی های راه اندازی و استفاده از OpenCV را می بایست متحمل شد، بلکه مدل پردازشی پیشفرض هدوپ یعنی MapReduce نیز اصول و قواعد پیچیدهای دارد که میتواند کار را چندبرابر سخت کند. ما در این مقاله قصد داریم مثالی در پردازش تصویر(تشخیص چهره) را به کمک هدوپ تحلیل و پیادهسازی کنیم.
برای کار با الگوریتم های پردازش تصویر در هدوپ ۳ کتابخانه مشهور زیر وجود دارند:
- HIPI ( Hadoop Image Processing Interface )
- MIPr ( MapReduce Image Processing Framework for Hadoop )
- OpenIMAJ ( Open Intelligent Multimedia Analysis for Java )
دو کتابخانه HIPI و MIPr از کتابخانه استاندارد پردازش تصویر OpenCV استفاده میکنند و درواقع واسطی بین OpenCV و جاوا و در نهایت هدوپ هستند. اما کتابخانه OpenIMAJ به تنهایی، خود کتابخانه ای جهت پردازش تصویر در جاوا میباشد و از OpenCV استفاده نمی کند. نکتهای که در کتابخانههای HIPI و MIPr وجود دارد این است که HIPI مبتنی بر نسخه ۱ هدوپ پیادهسازی شده است در صورتی که MIPr از نسخه ۲ هدوپ استفاده می کند. به همین علت ما نیز در این مثال از کتابخانه MIPr استفاده خواهیم کرد. همچنین دیتاست مورد استفاده ما در این مثال LFW است که مجموعهای با حجم های متفاوت از چهرههای افراد می باشد. ما در این مثال از مجموعه ۱۰۰۰ تایی این دیتاست استفاده می کنیم.
در ابتدای این مثال، ابتدا بدون استفاده از هدوپ الگوریتم تشخیص چهره را با زبان جاوا و کتابخانه OpenCV به صورت زیر می نویسیم:
long startTime = System.currentTimeMillis(); System.loadLibrary(Core.NATIVE_LIBRARY_NAME); System.out.println("\nRunning FaceDetector"); String[] files = {"multiface.png","multiface2.png","multiface3.png", "multiface4.png"}; CascadeClassifier faceDetector = new CascadeClassifier("haarcascade_frontalface_alt.xml"); for (int i =0;i<files.length;i++){ Mat image = Highgui.imread(files[i]); MatOfRect faceDetections = new MatOfRect(); faceDetector.detectMultiScale(image, faceDetections); System.out.println(String.format("Detected %s faces", faceDetections.toArray().length)); for (Rect rect : faceDetections.toArray()) { Core.rectangle(image, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height), new Scalar(0, 255, 0)); } String filename = "ouput"+i+".png"; System.out.println(String.format("Writing %s", filename)); Highgui.imwrite(filename, image); } long endTime = System.currentTimeMillis(); long totalTime = (endTime - startTime); System.out.println("Totaltime(ms) : "+totalTime);
در کد بالا ۴ عکس به برنامه داده میشود تا تعداد چهرههای موجود در عکس شناسایی شود. ابتدا ۴ عکس در آرایه files قرار میگیرد که بیانگر عکس هایی است که در مسیر پروژه قرار دادیم. برای تشخیص چهره می بایست کلاس CascadeClassifier که یکی از کلاس های OpenCV است را به همراه فایل xml مربوط به آموزش الگوریتم تعریف کنیم. در مورد چیستی این فایل xml میتوانید به مستندات مربوط به OpenCV مراجعه کنید. در این کد به ازای هر عکسی که در آرایه وجود دارد عملیات تشخیص تکرار می شود. درواقع نتایج عملیات Classification در ماتریسی به نام FaceDetection ذخیره میشود. تعداد آرایه های موجود در این ماتریس بیانگر تعداد چهرههایی است که در یک تصویر شناسایی شده است. در مرحله بعد از طریق مقادیر موجود در ماتریس به دور چهره ای که در تصویر شناسایی شده است مستطیلی کشیده میشود که حاکی از تشخیص چهره موردنظر است. در نهایت تصویر جدیدی که برروی آن مستطیل رسم کردهایم با نام جدید ذخیره می شود. دقت شناسایی چهره، ارتباط مستقیم به فایل xml آموزش و دفعات اجرای برنامه دارد. قبل از اجرای برنامه ابتدا قصد داریم برنامه را با یک عکس تست کنیم. نتیجه را در جدول شماره ۱ مشاهده کنید.
پس از انجام تست اول حالا قصد داریم دو اجرای بالا را در هدوپ پیادهسازی و تست کنیم. برای اینکار ابتدا هدوپ را در حالت Pseudo-Distributed در VirtualBox راه اندازی کنیم و در این حالت اجرای برنامه را تست کنیم. همانطور که توضیح داده شد در این برنامه از موتور پردازشی MapReduce استفاده شده است. برای اجرای عملیات تشخیص چهره به صورت موازی و توزیع شده تابع map مربوط را به صورت زیر می نویسیم:
protected void map(NullWritable key, MatImageWritable value, Context context) throws IOException, InterruptedException { Mat image = value.getImage(); if (image != null) { CascadeClassifier faceDetector = null; faceDetector = new CascadeClassifier("/data/haarcascades/haarcascade_frontalface_alt.xml"); MatOfRect faceDetections = new MatOfRect(); faceDetector.detectMultiScale(image, faceDetections); for (Rect rect : faceDetections.toArray()) { Core.rectangle(image, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height), new Scalar(0, 0, 255), 3); } MatImageWritable matiw = new MatImageWritable(image); matiw.setFormat("jpg"); matiw.setFileName(value.getFileName() + "_result"); context.write(NullWritable.get(), matiw); } }
در کد بالا الگوریتم تشخیص چهره به همان صورت است که در مثال قبلی توضیح داده شد ولی نکاتی وجود دارد که آنرا در ادامه شرح خواهیم داد.
در نوع اجرای موازی این الگوریتم، پوشه تصاویر به برنامه داده میشود تا هر تابع Map تعدادی از این تصاویر را برروی ماشینهای کلاستر هدوپ پردازش کند. هر تصویر از طریق متغیر سریالی شده MatImageWritable در کد برنامه قابل دسترس است و درواقع به جای آرایه ای که در اجرای اول بود اینکار ورودی با مدیریت هدوپ از طریق این متغیر به کدبرنامه ارسال می شود. به دلیل اینکه این برنامه فاقد فاز Reduce است نتیجه تابع Map هر ماشین که تصویر جدید میباشد به هدوپ ارسال می شود و هدوپ تصاویر را در خروجی ذخیره می کند. این الگوریتم را ابتدا با یک عکس و سپس با ۴ عکس اجرا میکنیم تا شرایط یکسان با اجرای معمولی الگوریتم وجود داشته باشد.
نکتهای که در اینجا می بایست دقت کنید این است که هدوپ در حالت Pseudo-Distributed در VirtualBox راه اندازی و این برنامه برروی آن اجرا شده است. لذا انتظار نداشته باشید نتیجهای که این اجرا در مقایسه با حالت عادی الگوریتم دارد نه تنها برابر باشد بلکه بهتر باشد. نتیجه را در جدول شماره ۱ مشاهده کنید.
در نهایت میخواهیم این الگوریتم را در حالت Fully-Distributed هدوپ اجرا کنیم. برای اینکار ۲ سرور را با مشخصات ۴ گیگابایت رم، ۸ هسته سی پی یو ۲.۱ گیگاهرتز،۱ ترابایت دیسک سخت و ۱۰۰ مگابیت سرعت شبکه، پیکربندی و هدوپ را برروی آن راه اندازی می کنیم. اگر نمیدانید چطور هدوپ را در حالت چند گره راه اندازی کنید این مقاله را مطالعه کنید. برنامهای که در اجرای دوم نوشته بودیم را اینبار برروی کلاستر ۲ گره ای که پیکربندی کرده ایم، اجرا می کنیم. تعداد عکسهای ورودی ما این بار در ابتدا ۱۰۰ عکس و سپس ۱۰۰۰ عکس خواهد بود. نتیجه اجرای سوم را در جدول شماره ۱ مشاهده کنید.
مسئله | زبان برنامه نویسی | نوع اجرا | تعداد تصاویر | زمان اجرا(میلی ثانیه) |
تشخیص چهره | جاوا | غیرموازی | 1 | 847 |
تشخیص چهره | جاوا | غیرموازی | 4 | 1776 |
تشخیص چهره | جاوا | شبه موازی | 1 | 1160 |
تشخیص چهره | جاوا | شبه موازی | 4 | 15900 |
تشخیص چهره | جاوا | موازی | 100 | 562 |
تشخیص چهره | جاوا | موازی | 1000 | 486 |
از موردکاوی بالا میتوان این نتیجه را گرفت که:
۱. هدوپ به خوبی و با سرعت بالاتر میتواند فرآیند پردازش تصویر را به صورت موازی و توزیع شده در وسعت کلان انجام دهد.
۲. هدوپ برای کار بر روی یک سیستم چه به صورت واقعی و چه به صورت شبیه سازی شده ساخته نشده است و ماهیت اجرای موازی را زیرسوال و نتیجه مسأله را اشتباه و گاهی اوقات غیرقابل اعتماد می سازد.
۳. هدوپ در مسائلی که معیارهای کلان داده برقرار نیستند نتیجه عکس خواهد داشت. به این صورت که دادههایی که نمیتوان به آنها کلان داده گفت اگر از طریق هدوپ مورد تحلیل و پردازش قرار گیرند، هدوپ نمی تواند کارایی چندان مناسبی داشته باشد. به دلیل اینکه هدوپ برای تحلیل و پردازش دادههای ساده و غیرکلان ساخته نشده است و ابزارهای بهتری برای اینکار وجود دارند.
نکته ۱ : کتابخانه MIPr وظیفه معرفی و انتقال تنظیمات برنامه، انواع متغیر، قالب های دادهای کار با تصاویرو عملیات خواندن و نوشتن تصویر را دارد و هسته اصلی کار یعنی تشخیص تصویر(چهره) بر عهده OpenCV می باشد.
نکته ۲ : دقت کنید که کتابخانههای OpenCV نظیر فایلهای .so و فایلهای موردنیاز دیگر به دلیل اجرا شدن در حالت موازی و توزیع شده در هدوپ می بایست ابتدا در HDFS ذخیره شوند و به صورت فایلهای کش توسط متد AddCacheFile به تنظیمات Job معرفی شوند تا برنامه بتواند در هر ماشین از این کتابخانهها استفاده کند.
نکته ۳ : این الگوریتم فقط برروی فرمت های استاندارد تصاویر مانند Jpeg و PNG تست شده است.
نکته ۴ : برای پردازش نقاط دیگر از صورت مثل بینی،چشم،گوش و لبخند فقط کافی است فایل آموزش xml در کلاس CascadeClassifier را تغییر دهید.
نکته ۵ : نتایج ممکن است در پیکربندی ها و تغییرات گوناگون متفاوت باشند.
سايت خوبي داريد ، موفق باشيد.
تشکر
کيفيت سايت عالي….
بسيار عالي
سلامخيلي خوب بود
بسيااار خوب
کارتون حرف نداره
درود بر شما
دمتون گرم مرسي
پست بسيار خوب
ممنون
وقتتون بخير بسيار عالي بود
مرسي…
بسيارعالي
مرسي و موفق باشيد
بسيااار خوب
عالي…
تمام مطالبتون خوب هستند
جالب بود موفق باشيد و خدافظ
خوب بود ممنون
سلام ممنون
مرسي از سايت مفيدتون
خوب بود ممنون
ممنون
درود بر شما
عاليدستتون درد نکنه
ممنون بابت اين مطلب مفيد
ممنون بابت اين مطلب مفيد
خيلي دنبالش بودم-تشکر
تشکر ويژه از مديريت سايت
بسيار سپاسگذارم
عالييييي
تشکر بسيار
خوب بودممنونم ازتون
سلام ، ضمن تشکر از سایت بسیار عالیتون
ایا امکانش وجود دارد سورس کد مربوط به این قسمت (پردازش تصویر در هدوپ) را نیز قرار دهید.
با سپاس فراوان
با سلام اگر امکانش هست سورس کدش را قرار بدید . ممنون