بهبود تصاویر با افزایش کنتراست
افزایش کنتراست با یکنواخت سازی هیستوگرام
امروزه روشهای بهبود تصویر بسیاری در حال استفاده هستند. یکی از ایده ها بهبود کنتراست تصویر است. یکی از روش های افزایش کنتراست تصویر با کیفیت پایین، تکنیک یکنواخت سازی هیستوگرام است. بطوریکه مقادیر سطوح خاکستری تصویر را بنحوی تغییر میدهد تا کل بازه ممکن را تسخیر کند و ایده اساسی آن نگاشت مقادیر شدت سطوح روشنایی از طریق یک تابع توزیع انتقال است.
یکنواخت سازی هیستوگرام موجب میشود کنتراست تصویر نسبت به حالت اولیه آن بیشتر شود که این به معنای بهبود کیفیت تصویر و افزایش دقت پردازش های بعدی است. اگرچه این روش قادر به افزایش کنتراست تصویر است اما تصویر حاصل معمولا دارای بهبود غیر طبیعی و اشباع شدت میباشد، همچنین در مشخص نمودن مرزها و لبه های بین اشیا مختلف قدرتمند است ولی ممکن است باعث کاهش جزئیات محلی شود.
فرض کنید یک تصویر خاکستری با مقادیر سطوح روشنایی r در بازه [0,1] وجود داشته باشد، یک تابع تبدیل مانند T بر روی این تصویر بصورت (s=T(r قابل تعریف است.
به منظور یکنواخت سازی هیستوگرام، تبدیلی مانند T باید دارای دو خاصیت باشد:
- این تابع تبدیل بصورت یکنوا صعودی باشد
- بازای r در بازه [0,1] مقادیر T(r) نیز در بازه [0,1] قرار گیرند.
این شروط تضمین میکنند که دامنه خروجی با ورودی یکی باشد، و همچنین نگاشتی یک به یک باشد و مانع ایجاد ابهام شود.
یک ایده برای تابع تبدیل (s=T(r با فرض پیوسته در نظر گرفتن تابع توزیع احتمال که خروجی یکنواخت تولید کند استفاده از رابطه زیر است.
با توجه به تابع یکنواخت ساز فوق و در نظر گرفتن هیستوگرام نرمال شده تصویر در حالت گسسته میتوان تابع تبدیلی که هیستوگرام را یکنواخت کند به شکل زیر بیان کرد:
که در آن MN تعداد کل پیکسلها در تصویر، nk تعداد پیکسلهایی که شدت روشنایی rk دارند و L تعداد سطوح ممکن شدت روشنایی در تصویر است. در واقع ابتدا باید هیستوگرام نرمال شده و سپس هیستوگرام تجمعی تصویر ورودی را محاسبه نمود و نهایتا اعداد را به بازه [0,L-1] انتقال داد و با نگاشت هر پیکسل در تصویر ورودی با شدت روشنایی rk به یک پیکسل متناظر با شدت روشنایی sk تصویر خروجی که دارای هیستوگرامی متعادلتر شده است را بدست آورد.
بعنوان نمونه نتیجه این عملیات را در تصویر زیر میبینید که تصویر ورودی اولیه دارای هیستوگرامی با مقادیری در محدوده خاص و بصورت نا یکنواخت است در حالی که هیستوگرام تصویر حاصل نسبتا یکنواخت تر است و نتیجه کار بهبود کنتراست و بهبود جلوه بصری در تصویر خروجی است
نکته ای که در انتها قابل ذکر است اینکه هیستوگرام تصویر یکنواخت شده مستقل از هیستوگرام اولیه آن است، بدین معنی که اگر یک تصویر با روشنایی های مختلف داشته باشیم (روشن تر یا تیره تر) پس از اعمال الگوریتم یکنواخت سازی، هیستوگرام آن ها یکسان خواهند بود.
منبع
برخی از کاربردهای تصاویر ماهواره ای به شناسایی عوارض معطوف میشوند و در آنها نیازی به دانستن ارزش واقعی هر پیکسل نمیباشد. برای مثال هنگامی که میخواهید عوارضی را که بر روی یک تصویر ماهواره ای رقومی دیده میشود ترسیم نمایید، ارزش مقدار هر پیکسل کمک چندانی به شما نمیکند و مهم این است که بتوانید عوارض را از یکدیگر متمایز سازید. در اینحالت بهبود کنتراست تصاویر بسیار حائز اهمیت میگردد.
اما در برخی موارد ارزش مقدار ذخیره شده برای هر پیکسل از اهمیت بالایی برخوردار است. برای مثال هنگامی که میخواهید شاخص NDVI را برای یک تصویر ماهواره ای چند بانده محاسبه کنید، مقادیر ذخیره شده در تک تک پیکسلها اهمیت پیدا میکنند.
در مواردی که ارزش اولیه پیکسلها برای شما ارزش چندانی ندارد، میتوانید با تغییر کنتراست تصاویر، قدرت تفکیک بالاتری را ایجاد کنید. این قدرت تفکیک بالاتر به شما کمک میکند تا بتوانید حدود هر عارضه بر روی تصویر را تشخیص داده و عوارض را از یکدیگر متمایز نمایید. اما این کار چگونه امکان پذیر است؟
همانطور که میدانید ارزش ثبت شده برای هر پیکسل در یک باند از تصویر ماهواره ای، بین اعداد صفر و 255 متغیر است. هرچه به سمت صفر میرویم تصویر تیره تر شده و هر چه به سمت 255 حرکت میکنیم پیکسل ما روشن تر دیده میشود. در تصاویری که کنتراست پایین تری دارند، بیشتر پیکسلها دارای مقادیری از ارزش هستند که محدوده کوچکی را به خود اختصاص داده است. مثلاً اکثر پیکسلها مقادیری بین 50 تا 100 دارند. در اینحالت بخشهایی از محدوده 250 واحدی ما خالی میماند و عوارض اختلاف رنگ کمتری خواهند داشت.
همانطور که در تصویر بالا مشاهده میکنید، کنتراست پایین تصویر در سه باند RGB باعث شده است تا بخشهای موجود در تصویر به سختی از یکدیگر متمایز شوند. همچنین اگر به نمودار هیستوگرام هر باند دقت کنیم متوجه خواهیم شد که در هر باند، بخش کوچکی از فضای موجود برای نمایش هر رنگ استفاده شده است.
برای بهبود کنتراست تصاویر به روشهای مختلفی میتوانیم فضای موجود بین ارزش صفر تا 255 را بین پیکسلها تقسیم نماییم. مثلاً فرض میکنیم در یکی از باندهای تصویر ما مینیمم و ماکزیمم ارزشها 50 و 100 باشد. اگر بخواهیم مینیمم را بر روی صفر قرار داده و ماکزیمم بر روی 250 قرار گیرد، درواقع تصویری ایجاد کرده ایم که در آن فاصله بین ارزش پیکسلها 5 برابر شده است. در اینحالت اگر بین دو پیکسل یک واحد اختلاف ارزش وجود داشته باشد، این یک واحد اختلاف به 5 واحد افزایش خواهد یافت. مسلماً تمایز بین دو پیکسل با ارزشهای متوالی بسیار سخت تر از تمایز بین دو پیکسلی خواهد بود که 5 واحد با یکدیگر اختلاف دارند. این اختلاف در کل تصویر تسری پیدا نموده و درنهایت باعث افزایش قدرت تمایز عوارض خواهد شد.
تصویری که در بالا مشاهده میکنید همان تصویر قبل است که با استفاده از روشی که خدمتتان عرض شد افزایش کنتراست پیدا کرده است. به دامنه ارزش پیکسلها در هر باند دقت کنید. به کار گیری دامنه وسیعتر برای نشان دادن ارزش پیکسلها باعث افزایش وضوح تصویر شده است.
درحقیقت نوعی کلاسه بندی یا همان Classification برای مقادیر ارزش پیکسلها در نظر گرفته شده است و کلیه مقادیر در کلاسهایی که از صفر شروع شده و به 255 ختم میشوند افراز شده اند. روشهای مختلفی برای نحوه کلاسه بندی ارزشها وجود دارد که برخی از آنها مبتنی بر محاسبه پارامترهای آماری هستند. روشهای مختلفی چون Minimum-Maximum ، Standard Deviations ، Histogram Specification ، Histogram Equalize و Percent Clip نمونه هایی از روشهای کلاسه بندی هستند که در نرم افزار ArcGIS برای بهبود کنتراست تصاویر در نظر گرفته شده اند.
کافیست تا یک نمونه از فایل رستری را در نرم افزار ArcGIS باز کرده و در پنجره Layer Properties و در سربرگ Symbology ، حالت نمایش را در حالت Stretched قرار دهید و سپس در بخش Stretch گزینه Type را تغییر دهید تا اثر تغییر روش کلاسه بندی را در نمایش فایل رستری خود مشاهده نمایید.
منبع
افزایش کنتراست یک تصویر با دستور histeq در متلب
دستور histeq در متلب، برای افزایش کنتراست یک تصویر به کار می رود. چنانچه مقادیر مربوط به رنگ های به کار رفته در یک تصویر را مشاهده کنیم (این کار با دستور imhist در متلب، امکان پذیر می باشد)، آنگاه ممکن است که بخشی از رنگ ها، به مقدار زیاد، در تصویر به کار رفته باشند و بخشی دیگر، کمتر در تصویر باشند. افزایش کنتراست، باعث می شود که میزان به کار رفتن رنگ های مختلف، به هم نزدیکتر شود و دیگر تفاوت زیادی که ذکر شد، وجود نداشته باشد. به مثال زیر توجه کنید :
مثال
clear all close all clc img=imread(‘image.jpg’); img=rgb2gray(img); imshow(img); figure histeq(img);
نتیجه
تصویر اصلی :
تصویر پس از افزایش کنتراست :
افزایش کنتراست با Contrast stretching
همانطوری که می بینید پراکندگی پیکسل ها در بازه مشخصی هستش و شما در تصویر نه سیاه و نه سفید مطلق دارید با نرمالیز کردن می تونید طوری توزیع را مقدار پیکسل ها را تغییر بدید که کل بازه ۰ تا ۲۵۵ را پوشش بده که هیستوگرام و تصویر بعد از نرمالیزمیشه به صورت زیر:
یک نکته ای را که باید متذکر بشم تفاوت Normalize با histogram equalization هستش عملیات نرمالیز به صورت خطی داده ها را تغییر مقیاس میده ولی عملیات histogram equalization به صورت غیر خطی هستش.
فرمول برای نرمالیز کردن
تصویر فعلی که قرار نرمالیز بشه دارای یک Max و Min هستش و شما قصد دارید تصویر را به بازه جدید تغییر مقیاس دهید یعنی یک بازه با حد پایین NewMin و حد بالای NewMax که ما توی تصویر معمولاً از بازه 0 و 255 استفاده می کنیم. حال باید dynamic range تصویر اصلی و تصویر نهایی را به صورت زیر محاسبه کنید.
dr_src = Max – Min
dr_dst = NewMax – NewMin
پس از آن مقدار scale را محاسبه می کنیم.
scale = dr_dst/dr_src
I_n = (I – Min) * scale + NewMin
یکی دیگه از کاربردهای آماری دیگه ای که داره گاهی اوقات شما آرایه ای از مقادیر دارید و بازه اعداد ممکنه متفاوت باشند در این شرایط شما می تونید از نرمالیز استفاده کرده و داده را به بازه دلخواه تغییر مقیاس بدید مثال خیلی کاربردیش زمانیکه شما قصد دارید یک شبکه عصبی MLP را آموزش بدید و در شرایطی که active function شما از نوع سیگموید باشه برای همگرایی سریع شبکه باید داده های ورودی شبکه در بازه منفی یک و یک باشه که شما به راحتی می تونید با نرمالیز کردن داده های ورودی به شکل مطلوب تغییرشون بدید.
منبع
افزایش کنتراست با تعدیل هیستوگرام
برای تعدیل هیستوگرام :
مرحله۱ – PMF ( تابع جرم احتمال ) رو حساب می کنیم .
وقتی هیستوگرام را محاسبه می کنیم میزان فراوانی یا فرکانس هر سطح خاکستری نمایش داده میشود مانند شکل زیر:
PMF در ابتدا مجموع فراوانی ها را محاسبه می کند و سپس مقدار هر فراوانی را بر کل فراوانی ها تقسیم می کنیم.
pmf تابعی است که احتمال وقوع متغیر تصادفی x=k را نشان میدهد.( دقت داشته باشید که در pmf مقادیر k گسسته هستند) و به این دلیل که این تابع احتمال را نشان می دهدبنانبراین می بایست دو شرط زیر هم برای این تابع برقرار باشند :
1_ (p(x باید بزرگتر مساوی 0 باشد .
2_ به ازای همه k ها مجموع تمام (p(x=k ها باید 1 شود .
برای هیستوگرام عکس هم میشه تابعی با شرایط بالا پیدا کرد :
اگر x را به صورت یک متغیر تصادفی داخل فضای نمونه شامل همه رنگ ها در نظر بگیریم و k هم مجموعه اعداد 0 تا 255 باشد، pmf را می توان با تقسیم تعداد پیکسل ها با رنگ مورد نظر بر تعداد کل پیکسل ها محاسبه کرد :
p(x=k)=number of pixels with color k / total number of pixels
کد ++C این کار به صورت زیر است :
#include "stdafx.h" #include < vector > #include < string > #include < iostream > #include < algorithm > #include < numeric > using namespace std; void computePMF(const vector < int > &src,vector < float > &dst){ float sum = (float)std::accumulate(src.begin(), src.end(), 0); dst.resize(src.size()); for (size_t i=0; i < src.size();i++) dst[i] = src[i] / sum; } int _tmain(int argc, _TCHAR* argv[]) { vector < int > hist(10); for (auto &item : hist) item = rand()%5; vector < float > pmf; computePMF(hist,pmf); for (auto item :pmf) cout < < item < < endl; return 0; }
مرحله ۲ – با استفاده از PMF مقادیر CDF ( تابع توزیع تجمعی) را حساب می کنیم .
توزیع تجمعی یعنی وقتی PMF را محاسبه کردید بعد از آن مقدار هر اندیس در CDF برابر است با مقدار مجموع همه PMF های کوچکتر و مساوی با آن اندیس می باشد.
اگر PMF به صورت زیر باشد:
CDF به صورت زیر خواهد شد.
کد ++C محاسبه CDF به صورت زیر می باشد:
#include "stdafx.h" #include < vector > #include < string > #include < iostream > #include < algorithm > #include < numeric > using namespace std; void computePMF(const vector < int > &src,vector < float > &dst){ float sum = (float)std::accumulate(src.begin(), src.end(), 0); dst.resize(src.size()); for (size_t i=0; i < src.size();i++) dst[i] = src[i] / sum; } void computeCDF(const vector < float > pmf,vector<float> &cdf){ cdf.resize(pmf.size()); float sum=0; for (size_t i=0; i < pmf.size();i++){ cdf[i] = sum + pmf[i]; sum += pmf[i]; } } int _tmain(int argc, _TCHAR* argv[]) { vector < int > hist(10); for (auto &item : hist) item = rand()%5; vector < float > pmf; computePMF(hist,pmf); vector < float > cdf; computeCDF(pmf,cdf); for (auto item :cdf) cout < < item < < endl; return 0; }
مرحله ۳ – نهایتا مقادیر CDF بدست آمده رو normalize می کنیم
که مقادیر ScaledCDF رنگ خروجی ما هستن
برای equalize کردن Histogram عکس رنگی بوسیله opencv
اول عکس رو به فضای رنگی YCrCb میبریم
بعد بر روی کانال مربوط به شدت نور بوسیله تابع equalizeHist عملیات مربوطه رو انجام میدیم
کد :
#include < opencv2/highgui/highgui.hpp > #include < opencv2/imgproc/imgproc.hpp > #include < iostream > using namespace cv; int main( ) { const char* original_window="Source"; const char* equalized_window="Equalized image"; Mat image = imread("F:\\image1.jpg"); Mat equalized_image; std::vector < Mat > channels; cvtColor(image, equalized_image, CV_BGR2YCrCb); split(equalized_image,channels); equalizeHist(channels[0], channels[0]); merge(channels,equalized_image); cvtColor(equalized_image, equalized_image, CV_YCrCb2BGR); namedWindow(original_window,WINDOW_NORMAL); namedWindow(equalized_window,WINDOW_NORMAL); imshow(original_window,image); imshow(equalized_window,equalized_image); waitKey(0); }
این کد هم به زبان ++C است که به راحتی قابل تبدیل به #C می باشد:
#include < iostream > #include < opencv2/highgui/highgui.hpp > #include < opencv2/imgproc/imgproc.hpp > using std::cout; using std::cin; using std::endl; using namespace cv; void imhist(Mat image, int histogram[]) { // initialize all intensity values to 0 for(int i = 0; i < 256; i++) { histogram[i] = 0; } // calculate the no of pixels for each intensity values for(int y = 0; y < image.rows; y++) for(int x = 0; x < image.cols; x++) histogram[(int)image.at < uchar > (y,x)]++; } void cumhist(int histogram[], int cumhistogram[]) { cumhistogram[0] = histogram[0]; for(int i = 1; i < 256; i++) { cumhistogram[i] = histogram[i] + cumhistogram[i-1]; } } void histDisplay(int histogram[], const char* name) { int hist[256]; for(int i = 0; i < 256; i++) { hist[i]=histogram[i]; } // draw the histograms int hist_w = 512; int hist_h = 400; int bin_w = cvRound((double) hist_w/256); Mat histImage(hist_h, hist_w, CV_8UC1, Scalar(255, 255, 255)); // find the maximum intensity element from histogram int max = hist[0]; for(int i = 1; i < 256; i++){ if(max < hist[i]){ max = hist[i]; } } // normalize the histogram between 0 and histImage.rows for(int i = 0; i < 256; i++){ hist[i] = ((double)hist[i]/max)*histImage.rows; } // draw the intensity line for histogram for(int i = 0; i < 256; i++) { line(histImage, Point(bin_w*(i), hist_h), Point(bin_w*(i), hist_h - hist[i]), Scalar(0,0,0), 1, 8, 0); } // display histogram namedWindow(name, CV_WINDOW_AUTOSIZE); imshow(name, histImage); } int main() { // Load the image Mat image = imread("scene.jpg", CV_LOAD_IMAGE_GRAYSCALE); // Generate the histogram int histogram[256]; imhist(image, histogram); // Caluculate the size of image int size = image.rows * image.cols; float alpha = 255.0/size; // Calculate the probability of each intensity float PrRk[256]; for(int i = 0; i < 256; i++) { PrRk[i] = (double)histogram[i] / size; } // Generate cumulative frequency histogram int cumhistogram[256]; cumhist(histogram,cumhistogram ); // Scale the histogram int Sk[256]; for(int i = 0; i < 256; i++) { Sk[i] = cvRound((double)cumhistogram[i] * alpha); } // Generate the equlized histogram float PsSk[256]; for(int i = 0; i < 256; i++) { PsSk[i] = 0; } for(int i = 0; i < 256; i++) { PsSk[Sk[i]] += PrRk[i]; } int final[256]; for(int i = 0; i < 256; i++) final[i] = cvRound(PsSk[i]*255); // Generate the equlized image Mat new_image = image.clone(); for(int y = 0; y < image.rows; y++) for(int x = 0; x < image.cols; x++) new_image.at < uchar > (y,x) = saturate_cast < uchar > (Sk[image.at < uchar > (y,x)]); // Display the original Image namedWindow("Original Image"); imshow("Original Image", image); // Display the original Histogram histDisplay(histogram, "Original Histogram"); // Display equilized image namedWindow("Equilized Image"); imshow("Equilized Image",new_image); // Display the equilzed histogram histDisplay(final, "Equilized Histogram"); waitKey(); return 0; }
منبع
دیدگاه خود را ثبت کنید
تمایل دارید در گفتگوها شرکت کنید؟در گفتگو ها شرکت کنید.