clear all close all clc RGB = imread('RainbowLace.bmp') [X, mapA] = rgb2ind(RGB, 256); image(X); colormap(mapA); colorbar; imwrite(X, mapA,'Result_1.bmp'); RGB = imread('today-1.bmp') [X, mapB] = rgb2ind(RGB, 256); imwrite(X, mapB,'Result_2.bmp'); !start Result_2.bmp
而以下是用Visual C++實作Median Cut的程式碼
(注意: 這份code只是將圖片轉成256色,非真正8位元圖像)
/*************************************************** Theme: Transform 24bit Image to 256 colors image Environment: Visual Studio 2012 (Visual C++) Date: 102/03/24 Author: Lee Jhe-Wei ***************************************************/ #include <cv.h> #include <highgui.h> #include <iostream> using namespace cv; using namespace std; struct Pixel { uchar R; uchar G; uchar B; }; //顏色查詢表Look-Up-Table及索引 vector<pixel> table(256); int index = 0; //記錄所有中位數的R值、G值及B值 uchar medianR[3][128], medianG[3][128], medianB[2][128]; void MedianCut(vector<pixel> colorSpace, int cube, int pos) //pos紀錄該cube所在的位置 { int R[256] = {0}, G[256] = {0}, B[256] = {0}; //紀錄R值、G值及B值的色階分佈 for (int i = 0; i < (int)colorSpace.size(); ++i) { ++R[colorSpace[i].R]; ++G[colorSpace[i].G]; ++B[colorSpace[i].B]; } //取得該cube的中位數 int median = (colorSpace.size() + 1) / 2, count = 0, left = 0, right = 0; vector<pixel> leftSpace(median); vector<pixel> rightSpace(colorSpace.size() - median); //根據cube的數目判斷切第幾次,選擇切R、G或B switch (cube) { case 1: for (int i = 0; i < 256; ++i) { count += R[i]; if (count >= median) { medianR[0][pos] = i; break; } } //將R值小於中位數R值放置於leftSpace、大於則放置於rightSpace for (int i = 0; i < (int)colorSpace.size(); ++i) { if (colorSpace[i].R < medianR[0][pos]) { leftSpace[left] = colorSpace[i]; ++left; } else if (colorSpace[i].R > medianR[0][pos]) { rightSpace[right] = colorSpace[i]; ++right; } } //等於中位數R值則先放leftSpace,填滿後再放rightSpace for (int i = 0; i < (int)colorSpace.size(); ++i) { if (colorSpace[i].R != medianR[0][pos]) continue; if (left < (int)leftSpace.size()) { leftSpace[left] = colorSpace[i]; ++left; } else { rightSpace[right] = colorSpace[i]; ++right; } } break; case 2: for (int i = 0; i < 256; ++i) { count += G[i]; if (count >= median) { medianG[0][pos] = i; break; } } for (int i = 0; i < (int)colorSpace.size(); ++i) { if (colorSpace[i].G < medianG[0][pos]) { leftSpace[left] = colorSpace[i]; ++left; } else if (colorSpace[i].G > medianG[0][pos]) { rightSpace[right] = colorSpace[i]; ++right; } } for (int i = 0; i < (int)colorSpace.size(); ++i) { if (colorSpace[i].G != medianG[0][pos]) continue; if (left < (int)leftSpace.size()) { leftSpace[left] = colorSpace[i]; ++left; } else { rightSpace[right] = colorSpace[i]; ++right; } } break; case 4: for (int i = 0; i < 256; ++i) { count += B[i]; if (count >= median) { medianB[0][pos] = i; break; } } for (int i = 0; i < (int)colorSpace.size(); ++i) { if (colorSpace[i].B < medianB[0][pos]) { leftSpace[left] = colorSpace[i]; ++left; } else if (colorSpace[i].B > medianB[0][pos]) { rightSpace[right] = colorSpace[i]; ++right; } } for (int i = 0; i < (int)colorSpace.size(); ++i) { if (colorSpace[i].B != medianB[0][pos]) continue; if (left < (int)leftSpace.size()) { leftSpace[left] = colorSpace[i]; ++left; } else { rightSpace[right] = colorSpace[i]; ++right; } } break; case 8: for (int i = 0; i < 256; ++i) { count += R[i]; if (count >= median) { medianR[1][pos] = i; break; } } for (int i = 0; i < (int)colorSpace.size(); ++i) { if (colorSpace[i].R < medianR[1][pos]) { leftSpace[left] = colorSpace[i]; ++left; } else if (colorSpace[i].R > medianR[1][pos]) { rightSpace[right] = colorSpace[i]; ++right; } } for (int i = 0; i < (int)colorSpace.size(); ++i) { if (colorSpace[i].R != medianR[1][pos]) continue; if (left < (int)leftSpace.size()) { leftSpace[left] = colorSpace[i]; ++left; } else { rightSpace[right] = colorSpace[i]; ++right; } } break; case 16: for (int i = 0; i < 256; ++i) { count += G[i]; if (count >= median) { medianG[1][pos] = i; break; } } for (int i = 0; i < (int)colorSpace.size(); ++i) { if (colorSpace[i].G < medianG[1][pos]) { leftSpace[left] = colorSpace[i]; ++left; } else if (colorSpace[i].G > medianG[1][pos]) { rightSpace[right] = colorSpace[i]; ++right; } } for (int i = 0; i < (int)colorSpace.size(); ++i) { if (colorSpace[i].G != medianG[1][pos]) continue; if (left < (int)leftSpace.size()) { leftSpace[left] = colorSpace[i]; ++left; } else { rightSpace[right] = colorSpace[i]; ++right; } } break; case 32: for (int i = 0; i < 256; ++i) { count += B[i]; if (count >= median) { medianB[1][pos] = i; break; } } for (int i = 0; i < (int)colorSpace.size(); ++i) { if (colorSpace[i].B < medianB[1][pos]) { leftSpace[left] = colorSpace[i]; ++left; } else if (colorSpace[i].B > medianB[1][pos]) { rightSpace[right] = colorSpace[i]; ++right; } } for (int i = 0; i < (int)colorSpace.size(); ++i) { if (colorSpace[i].B != medianB[1][pos]) continue; if (left < (int)leftSpace.size()) { leftSpace[left] = colorSpace[i]; ++left; } else { rightSpace[right] = colorSpace[i]; ++right; } } break; case 64: for (int i = 0; i < 256; ++i) { count += R[i]; if (count >= median) { medianR[2][pos] = i; break; } } for (int i = 0; i < (int)colorSpace.size(); ++i) { if (colorSpace[i].R < medianR[2][pos]) { leftSpace[left] = colorSpace[i]; ++left; } else if (colorSpace[i].R > medianR[2][pos]) { rightSpace[right] = colorSpace[i]; ++right; } } for (int i = 0; i < (int)colorSpace.size(); ++i) { if (colorSpace[i].R != medianR[2][pos]) continue; if (left < (int)leftSpace.size()) { leftSpace[left] = colorSpace[i]; ++left; } else { rightSpace[right] = colorSpace[i]; ++right; } } break; case 128: for (int i = 0; i < 256; ++i) { count += G[i]; if (count >= median) { medianG[2][pos] = i; break; } } for (int i = 0; i < (int)colorSpace.size(); ++i) { if (colorSpace[i].G < medianG[2][pos]) { leftSpace[left] = colorSpace[i]; ++left; } else if (colorSpace[i].G > medianG[2][pos]) { rightSpace[right] = colorSpace[i]; ++right; } } for (int i = 0; i < (int)colorSpace.size(); ++i) { if (colorSpace[i].G != medianG[2][pos]) continue; if (left < (int)leftSpace.size()) { leftSpace[left] = colorSpace[i]; ++left; } else { rightSpace[right] = colorSpace[i]; ++right; } } break; default: //切成256個cube後計算cube內RGB的平均值,為該cube的代表值 int meanR = 0, meanG = 0, meanB = 0; for (int i = 0; i < 256; ++i) { meanR += i * R[i]; meanG += i * G[i]; meanB += i * B[i]; } meanR /= (int)colorSpace.size(); meanG /= (int)colorSpace.size(); meanB /= (int)colorSpace.size(); //將代表值存入Look-Up Table table[index].R = meanR; table[index].G = meanG; table[index].B = meanB; ++index; return; } //Divide and Conquer cube*= 2; MedianCut(leftSpace, cube, pos * 2); MedianCut(rightSpace, cube, pos * 2 + 1); } //設定原圖的新顏色 void SetNewColor(Mat &image) { for (int i = 0; i < image.rows; ++i) { for (int j = 0; j < image.cols; ++j) { index = 0; //若大於中位數的RGB值則進入right child,否則進入left child for (int n = 0; n < 3; ++n) { if (image.at<vec3b>(i, j).val[2] > medianR[n][index]) { index = index * 2 + 1; } else index = index * 2; if (image.at<vec3b>(i, j).val[1] > medianG[n][index]) { index = index * 2 + 1; } else index = index * 2; if (n == 2) break; if (image.at<vec3b>(i, j).val[0] >= medianB[n][index]) { index = index * 2 + 1; } else index = index * 2; } //設定該pixel的新顏色 image.at<vec3b>(i, j).val[0] = table[index].B; image.at<vec3b>(i, j).val[1] = table[index].G; image.at<vec3b>(i, j).val[2] = table[index].R; } } } int main(int argc, char *argv[]) { Mat image; cout << "Usage: Convert a 24bit image into a 8bit image." << endl; image = imread(argv[1], CV_LOAD_IMAGE_COLOR); // Read the file if(!image.data ) // Check for invalid input { cout << "Could not open or find the image" << endl; system("pause"); return -1; } cout << "Constructing image data..." << endl; //建立圖片大小的RGB陣列 vector<vector ixel=""> > RGB(image.rows, vector<pixel>(image.cols)); //建立色階分佈圖 vector<pixel> colorSpace(image.rows * image.cols); for( int i = 0; i < image.rows; ++i) { for ( int j = 0; j < image.cols; ++j) { RGB[i][j].B = image.at<vec3b>(i, j).val[0]; RGB[i][j].G = image.at<vec3b>(i, j).val[1]; RGB[i][j].R = image.at<vec3b>(i, j).val[2]; colorSpace[i * image.cols + j].R = RGB[i][j].R; colorSpace[i * image.cols + j].G = RGB[i][j].G; colorSpace[i * image.cols + j].B = RGB[i][j].B; } } cout << "Finished!" << endl; // Create a window for display. namedWindow("24bit", CV_WINDOW_AUTOSIZE); // Show the image inside it. imshow("24bit", image); // Create a window for display. cout << "Median cuting..." << endl; MedianCut(colorSpace, 1, 0); cout << "Finished!\nSetting colors..." << endl; SetNewColor(image); cout << "Finished!" << endl; namedWindow("8bit", CV_WINDOW_AUTOSIZE); imshow("8bit", image); // Save the image. imwrite("saved.bmp", image); waitKey(0); // Wait for a keystroke in the window return 0; }
結論: 我這一個禮拜以來到底在做什麼...
沒有留言:
張貼留言