تغییر Contrast تصاویر در OpenCv
در سری مقالات آموزش OpenCv اندروید, میخواهیم Contrast یک تصویر را تغییر دهیم.
در مقاله قبل شیوه محاسبه Histogram تصاویر مورد بررسی قرار گرفت. در این مقاله نیز با استفاده از این مفهوم میخواهیم کیفیت تصاویر را افزایش دهیم و با تغییر Contrast تصاویر Effect هایی را ایجاد کنیم. در حقیقت با افزایش Contrast یک رنگ که افزونگی آن را با استفاده از Histogram بدست میآوریم, میتوان کیفیت تصویر را افزایش داد و یا ویژگی تصویری خاصی را اعمال کرد.
Histogram Equalization یک تابعی است که ورودی آن Histogram تصویر اصلی و خروجی آن یک Histogram گسترش یافته است که توزیع یکنواخت شدت مقدار مورد نظر را مشخص میکند. این تابع با گسترش و افزایش شدت رنگ مورد نظر, باعث بهبود کیفیت تصویر میشود. در حقیقت این تابع فعالیت چندانی بر روی Histogram تصویر انجام نمیدهد. تمرکز اصلی بر روی افزایش شدت رنگ است و به ندرت بر روی range تاثیر میگذارد و در نتیجه باعث میشود تا حد قابل قبولی کیفیت تصویر بهبود یابد. در سری مقالات آموزش OpenCv تا به اینجا از الگوریتم هایی استفاده کردیم که در حالت Grayscale و Full Color تفاوت چندانی نداشتند. اما در اینجا از حالت Grayscale استفاده میکنیم. علت این امر این است که وقتی از حالت Grayscale استفاده میکنیم, تنها دو رنگ سیاه و سفید وجود دارند و تمایز رنگ ها بر اساس شدت آنها است. به این ترتیب درک تغییرات Histogram ساده تر میشود.
برای تغییر Contrast پروژه ای که از ابتدا ایجاد کرده ایم را ادامه میدهیم. متد loadImage را به این صورت تغییر میدهیم:
boolean b = false; private void loadImage(String imagePath) { ..... Mat histogramEq = new Mat(); Imgproc.cvtColor(image, histogramEq, Imgproc.COLOR_RGB2GRAY); if (b) { Imgproc.equalizeHist(histogramEq, histogramEq); } // display Bitmap bitmap = Bitmap.createBitmap(histogramEq.cols(), histogramEq.rows(), Bitmap.Config.RGB_565); Utils.matToBitmap(histogramEq, bitmap); imageView.setImageBitmap(bitmap); b = !b; }
یک متغیر از نوع boolean ایجاد میکنیم و با هر بار کلیک بر روی button مقدار آن را تغییر میدهیم تا بتوان تصویر اصلی را با Contrast آن مقایسه کرد. ابتدا تصویر را به grayscale تبدیل میکنیم و آن را در histogramEq قرار میدهیم. در کلیک بعدی متد equlizeHist فراخوانی میشود و Contrast تصویر را تغییر میدهد. توجه داشته باشید که اگر تصویر در حالت grayscale نباشد, این الگوریتم به درستی کار نمیکند و دچار خطا میشوید.
اگر بخواهیم Contrast یک تصویر رنگی را تغییر دهیم, ابتدا نیاز است تا تصویر را از حالت RGB به HSV تبدیل کنیم و سپس تغییر Contrast را بر روی دو channel آن که شامل Saturation و Value میشود, اعمال کنیم. برای توضیحات پیرامون RGB و HSV میتوانید به اینجا مراجعه کنید.
private void colorHistEq(Mat mat) { Mat v = new Mat(mat.rows(), mat.cols(), CvType.CV_8UC1); Mat s = new Mat(mat.rows(), mat.cols(), CvType.CV_8UC1); Mat hsvMat = new Mat(); Imgproc.cvtColor(mat, hsvMat, Imgproc.COLOR_RGB2HSV); byte[] valueSaturation = new byte[3]; byte[] vb = new byte[1]; byte[] sb = new byte[1]; for (int i = 0; i < hsvMat.rows(); i++) { for (int j = 0; j < hsvMat.cols(); j++) { hsvMat.get(i, j, valueSaturation); v.put(i, j, new byte[]{valueSaturation[2]}); s.put(i, j, new byte[]{valueSaturation[1]}); } } Imgproc.equalizeHist(v, v); Imgproc.equalizeHist(s, s); for (int i = 0; i < hsvMat.rows(); i++) { for (int j = 0; j < hsvMat.cols(); j++) { v.get(i, j, vb); s.get(i, j, sb); hsvMat.get(i, j, valueSaturation); valueSaturation[2] = vb[0]; valueSaturation[1] = sb[0]; hsvMat.put(i, j, valueSaturation); } } Imgproc.cvtColor(hsvMat, mat, Imgproc.COLOR_HSV2RGB); }
در متد بالا و در دو حلقه تکرار اول, ابتدا تک تک مقدایر S و V برای pixel ها را نگهداری میکنیم. سپس متد equalizeHist را بر روی هر دو Channel اجرا میکنیم و سپس مقادیر را مجددا در مکان قبلی خود قرار میدهیم. به این ترتیب Contrast بر روی تک تک pixel های آن اعمال میشود. در نهایت تصویر را از حالت HSV به RGB تبدیل میکنیم. متد loadImage را به این صورت تغییر میدهیم
boolean b = false; private void loadImage(String imagePath) { ..... Mat histogramEq = new Mat(); Imgproc.cvtColor(image, histogramEq, Imgproc.COLOR_RGB2GRAY); if (b) { colorHistEq(image); } // display Bitmap bitmap = Bitmap.createBitmap(histogramEq.cols(), histogramEq.rows(), Bitmap.Config.RGB_565); Utils.matToBitmap(histogramEq, bitmap); imageView.setImageBitmap(bitmap); b = !b; }
اگر بخواهیم با استفاده از تغییر Contrast رنگ خاصی, جلوه های تصویری ایجاد کنیم نیاز است تا از ماسک ها استفاده کنیم. ماسک ها object هایی از کلاس Mat هستند که تمام مقادیر تصویر را دارند اما تنها یک Channel رنگ را برای آنها تعیین میکنیم. برای مثال میخواهیم با استفاده از ماسک قرمز جلوه تصویری ایجاد کنیم. ابتدا نیاز داریم تا بوسیله یک متد این تغییر را اعمال کنیم
private void colorHistWithMask(Mat mat,Mat result, Mat mask) { Mat channel = new Mat(mat.rows(), mat.cols(), CvType.CV_8UC1); mat.copyTo(channel, mask); Imgproc.cvtColor(channel, channel, Imgproc.COLOR_RGB2GRAY, 1); Imgproc.equalizeHist(channel, channel); Imgproc.cvtColor(channel, channel, Imgproc.COLOR_GRAY2RGB, 3); channel.copyTo(result,mask); }
در این متد با استفاده از دستور copyto مقدار mat را با تعیین ماسک مورد نظر, درون یک mat دیگر قرار میدهد. سپس تصویر را به حالت grayscale تبدیل میکند و equalizeHist را روی آن اعمال میکند. چهارمین پارامتر در cvtColor مشخص کننده تعداد channel است. سپس با استفاده از cvtColor تصویر را از حالت grayscale به حالت RGB تبدیل میکند و نتیجه را با ماسک در result قرار میدهد. برای فراخوانی این متد و نیز ایجاد ماسک نیز به این صورت عمل میکنیم
Mat red = new Mat(image.rows(), image.cols(), image.type(), new Scalar(1, 0, 0, 0)); colorHistWithMask(image, image, red);
در اینجا یک mat ایجاد کرده ایم و تنها یک channel از آن را فعال کرده ایم.
در این مقاله سعی شد تا با مفهوم Contrast آشنا شویم و همچنین با استفاده از آن بتوانیم کیفیت تصاویر را تغییر دهیم و جلوه های تصویری ایجاد کنیم. در مقاله بعد به مبحث حذف نویز تصاویر میپردازیم.
سری مقالات آموزش OpenCv اندروید ادامه دارد.
با ما همراه باشید.
دیدگاهتان را بنویسید
برای نوشتن دیدگاه باید وارد بشوید.