تصاویر در OpenCV
در سری مقالات آموزش OpenCv در اندروید, میخواهیم ساختار تصاویر را در OpenCV بررسی کنیم.
در ابتدا نیاز است تا مفاهیمی را مورد بررسی قرار دهیم. برای نوشتن این پروژه نیاز است تا درک کافی نسبت به ساختار تصاویر و روش اجتماع رنگ ها در تصاویر ایجاد شود. تصاویر از مجموعهای از رنگ ها (Color Mapping) ایجاد و برای ذخیره یک صحنه در دنیای واقعی استفاده میشوند. مختصات D(i,j) مشخص میکند که یک pixel در موقعیت iام در سطر و در موقعیت jام در ستون چه مقداری را دارد. i و j از نقطه بالا سمت چپ تصویر شروع میشوند. (i = j =0)
برای نگهداری رنگ ها از یک یا چند channel استفاده میشود. در اکثر موارد (برای پردازش) از یک channel که grayscale است استفاده میشود. در grayscale رنگ ها بر اساس شدت برحسب رنگ خاکستری دسته بندی میشوند. به این ترتیب رنگ ها با شدت بیشتر به رنگ سفید و رنگ ها با شدت کمتر به رنگ مشکی میل میکنند. هر pixel میتواند حجمی معادل یک byte داشته باشد و مقادیر آن از ۰ (رنگ مشکی) تا ۲۵۵ (رنگ سفید) متغیر است. همچنین یکی از موارد پر کاربرد، استفاده از سه channel رنگی برای نگهداری pixel ها است که شامل رنگ قرمز, سبز و آبی میشود و مقادیر pixel از ترکیب این سه رنگ بدست میآید. گاهی صحبت از channel چهارمی به نام alpha به میان میآید. این channel برای مشخص کردن میزان محوی (transparency) استفاده میشود.
چشم انسان دارای دو نوع یاخته برای تشخیص رنگ ها میباشد. یاخته های مخروطی که برای تشخیص نوع رنگ ها و یاخته های استوانه ای که برای تشخیص شدت رنگ ها استفاده میشوند. ساختار چشم نیز به گونه ای است که تعداد یاخته های استوانه ای در آن بیشتر است. بنابراین اهمیت شدت رنگ ها با توجه به ساختار چشم بیشتر از شدت رنگ است. برای تشخیص بهتر تصاویر توسط چشم انسان از یک روش به نام Hue (رنگ), Saturation (اشباع) و Value (مقدار) و یا به اختصار HSV استفاده میشود:
- Hue : مشخص کننده رنگ ها مانند قرمز, سبز و آبی است
- Saturation : میزان خلوص رنگ را مشخص میکند. برای مثال قرمز کدر یا روشن
- Value : مشخص کننده شفافیت رنگ است و به آن luminance گویند
و روش بعدی استفاده از روش binary است که آرایه pixel ها مقادیر را به صورت ۰ یا ۱ نگهداری میکنند. این روش برای شناسایی لبه ها در تصاویر بسیار پرکاربرد است. وقتی از openCv استفاده میکنیم باید بدانیم که از چه روشی برای نگهداری تصاویر استفاده میکند. در پردازش بوسیله OpenCv عمدتا از کلاس Mat استفاده میکنیم. تصاویر با تمام روش های گفته شده را میتوان در این کلاس قرار داد. برای مثال اگر از grayscale بخواهیم استفاده کنیم, در این کلاس، یک آرایه ای از pixel ها با یک channel ذخیره میشود. این کلاس نیز مانند تمام کلاس های جاوا Constructor دارد. یک Constructor پیش فرض و بدون ورودی برای آن تعریف شده است. اما گاهی نیاز است تا این کلاس را با استفاده از ویژگی هایی برای تصویر ایجاد کنیم:
Mat zeroToHeroMat=new Mat(row,column,type)
در این Constructor سطر (row) و ستون (Col) از نوع integer هستند. نکته مهم مشخص کردن type است. ساختار type به این صورت است:
CV_[SIZE][DATA_TYPE][NUMBER_OF_CHANNEL]
- Size: حجم داده را مشخص میکند : ۸ , ۱۶ , ۳۲ , ۶۴
- Data_type: نوع داده را مشخص میکند: اعداد علامت دار S , اعداد بی علامت U, اعداد شناورF
- Number_of_Channel: تعداد channel را مشخص میکند: C4 , C3 , C2 , C1
برای مثال CV_16UC4 یک object از کلاس Mat ایجاد میکند که داده هارا به صورت ۱۶ بیتی, در سیستم اعداد بی علامت و با چهار Channel در خود نگهداری میکند.
یک پروژه جدید ایجاد میکنیم و OpenCv Module را به آن اضافه میکنیم. در مقاله قبل شیوه افزودن Module را بررسی کرده ایم. برای دریافت تصاویر از دوربین نیاز است تا به فایل layout پروژه چنین کدی را اضافه کنیم:
<org.opencv.android.JavaCameraView android:layout_width="match_parent" android:id="@+id/zeroToHeroCamera" android:layout_height="match_parent" />
سپس با استفاده از butter knife قابلیت دسترسی به آن را در کد ها فراهم میکنیم. توجه داشته باشید که نیاز است تا Permission استفاده از دوربین را به برنامه اضافه کنید.
در بدنه کلاس یک CallBack ایجاد میکنیم که برای تعیین صحت اتصال OpenCv استفاده میشود:
@BindView(R.id.zeroToHeroCamera) public CameraBridgeViewBase cameraView; public BaseLoaderCallback loaderCallback=new BaseLoaderCallback(this) { @Override public void onManagerConnected(int status) { if (status == LoaderCallbackInterface.SUCCESS) { Log.i("Zero To Hero", "onManagerConnected: " + " OpenCv Loaded"); cameraView.enableView(); super.onManagerConnected(status); } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); cameraView.setCameraIndex(0); cameraView.setCvCameraViewListener(this); }
و object ایجاد شده را در زمان اتصال OpenCV به پروژه، به آن ارجاع میدهیم:
@Override protected void onResume() { super.onResume(); OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_0_0, this, loaderCallback); }
ما در اینجا از نسخه ۳.۰.۰ OpenCv استفاده کرده ایم. سه متد از Interface که آن را در ابتدا مشخص کردهایم وجود دارد :
@Override public void onCameraViewStarted(int width, int height) { } @Override public void onCameraViewStopped() { } @Override public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) { Mat frame = inputFrame.rgba(); Log.i("Zero To Hero", "Red : " + frame.get(10, 10)[0]); Log.i("Zero To Hero", "Green : " + frame.get(10, 10)[1]); Log.i("Zero To Hero", "Blue : " + frame.get(10, 10)[2]); return frame; }
همانطور که از نام متد ها مشخص است, متد onCameraViewStart به هنگام شروع دوربین و متد onCameraViewStoped به هنگام پایان کار با دوربین فراخوانی میشود. متد onCameraFrame هر frame دریافتی از دوربین را گرفته و آن را پردازش میکند. در اینجا یک Object از کلاس Mat ایجاد کرده ایم که یک frame با روش سه Channel از دوربین دریافت میکند. و در مختصات i = 10 و j = 10 مقدار رنگ های pixel را مشخص میکند. چون از سه Channel استفاده شده است پس به صورت یک آرایه مقادیر رنگی را به ترتیب دریافت میکنیم.
در این مقاله سعی شد تا مفهوم تصاویر در OpenCv را مورد بررسی قرار دهیم. در مقاله بعدی یک تصویر ذخیره شده در حافظه داخلی را با استفاده از OpenCV بارگذاری میکنیم.
سری مقالات آموزش OpenCv همچنان ادامه دارد.
با ما همراه باشید.
دیدگاهتان را بنویسید
برای نوشتن دیدگاه باید وارد بشوید.