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;
}
結論: 我這一個禮拜以來到底在做什麼...
沒有留言:
張貼留言