PDA

View Full Version : کاهش رنگ



pswin.pooya
شنبه 13 خرداد 1391, 09:39 صبح
سلام

دوستان چه شکلی می تونم تعداد رنگهای داخل تصویر رو کم کنم. مثلا یک تصویر 32 بیت رو 16 بیتی کنم و یا اینکه بعضی از رنگهایی رو که کم استفاده شدن رو حذف کنم و یکی دیگه معادل اونها رو بذارم. مثلا من احتیاج دارم که کل تصویرم 30 رنگ داشته باشه. اگر امکان داره چند تا الگوریتم مناسب رو معرفی کنید.پ

من کلی سرچ زدم منتها نتیجه نگرفتم.

مصطفی ساتکی
شنبه 13 خرداد 1391, 20:51 عصر
سلام
الگوریتم هایی که این دست کارهارو انجام میدن به نام های color quantization و image segmentation معروف هستند
یکی از روش های خیلی ساده برای انجام اینکار vector quantization بوسیله kmean clustring هستش به طور مثال شما تصویری دارید که در اون n رنگ استفاده شده حالا میخاید تعداد رنگ های مورد استفاده در pallete خودتونو به m رنگ کاهش بدید مسلماً شما بایستی m رنگ (r g b) پیشنهاد بدید و مشخص کنید که کدام نواحی از تصویر بایستی با هر کدام از این رنگ ها ترسیم شه.
رنگ رو تو فضای 3 بعدی رو 3 محور تصویر کنید و هر رنگی که تو تصویرتون دارید تو این فضا نگاشت کنید حالا تو این نگاشت بایستی عمل کلاسترینگ انجام بدید که نواحی مختلف رو تو فضا با صفحاتی به صورت غیر خطی جدا کنید یکی از روش های کلاسترینگ که در اون تعداد کلاستر مشخصه باشه همین روش kmean هستش که k تعداد کلاستر رو مشخص می کنه این روش همین می تونه به صورت iterative انجام شه و همین می تونه به روش های کاهش خطا(optimization ) انجام بگیره که یا الگوریتم تعداد دفعات خاصی تکرار شه یا اگر خطا از آستانه موردنظر کمتر باشه به عمل کلاسترینگ خاتمه بدیم.
به این ترتیب پس از پایان عمل کلاسترینگ مرکز کلاسترهای همون رنگ های پالت شما رو تشکیل می دن و کل رنگ های موچود در اون کلاستر در تصویر حاصله بایستی به رنگ مرکز کلاستر ترسیم شوند.
موفق باشید

pswin.pooya
یک شنبه 14 خرداد 1391, 19:48 عصر
سلام
من سعي كردم از kmean دز OpenCV استفاده كنم. منتها برنامه من كرش ميكنه. ميتونيد من رو راهنمايي كنيد. اين هم كد برنامه هست:


cv::Mat img = cv::imread("c:/test.jpg");

if ( !img.data )
{
cout << "Error: Can't load image file." << endl;
}
else
{
cv::Mat samples(img.rows * img.cols, 3, CV_32F);
for( int y = 0; y < img.rows; y++ )
for( int x = 0; x < img.cols; x++ )
for( int z = 0; z < 3; z++)
samples.at<float>(y + x*img.rows, z) = img.at<cv::Vec3b>(y,x)[z];
cv::Mat labels;
cv::Mat centers;
cv::kmeans(samples,15,samples,cv::TermCriteria(CV_ TERMCRIT_ITER|CV_TERMCRIT_EPS, 0.0001, 10000),5,cv::KMEANS_PP_CENTERS,centers);


cv::Mat new_image( img.size(), img.type() );
for( int y = 0; y < img.rows; y++ )
for( int x = 0; x < img.cols; x++ )
{
int cluster_idx = labels.at<int>(y + x*img.rows,0);
new_image.at<cv::Vec3b>(y,x)[0] = centers.at<float>(cluster_idx, 0);
new_image.at<cv::Vec3b>(y,x)[1] = centers.at<float>(cluster_idx, 1);
new_image.at<cv::Vec3b>(y,x)[2] = centers.at<float>(cluster_idx, 2);
}
cv::imshow( "clustered image", new_image );

cv::imshow("test",img);
}

cv::waitKey(0);

براس سورس بالا از وب استفاده كردم و هنوز توي OpenCV مبتدي حساب ميشم. دارم به سرعت كتابش رو ميخونم تا ببينيم چه ميشه.

kmean براي يكي از كاربردهاي من كه يه قالب رنگ دارم مناسب هست. اما يه جاي ديگه لازم دارم كه دقيقا تعداد رنگ رو مشخص كنم (يا حداقل محدوده - مثلا بين 250 تا 300 رنگ). و برنامه بايد توي تصوير داده شده بهترين تركيب رنگ رو بهم بده. چيزي كه به ذهنم خودم ميرسه شمارش رنگ و انتخاب بالاترين رينجها هست. منتها نمي دونم براي پيكسلهايي كه توي اون رينج نيستن بايد چي كار كنم. يعني چطوري ميتونم ميزان نزديكي اون پيكسلها رو به يكي از رنگهاي الگوي خودم بدست بيارم.( شايد بشه از HSV استفاده كرد. اما مطمئن نيستم.)

شايد سوالهام ابتدايي باشه اما الان فقط چند روزه كه زدم توي خط پردازش تصوير و رنگها و ... . من بايد تا كمتر از يك ماه ديگه يه برنامه كاهش رنگ خوب به همراه يك قالب تصويري جديد lost-less فوقالعاده فشرده ( يه چيزي در حد png) ايجاد كنم :لبخند: