Google Code Prettify

2013年4月3日 星期三

多媒體:24bit image 轉 8bit image

以下是MATLAB的實作程式碼:


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 &lt; (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 &lt; 256; ++i) {
    count += R[i];
    if (count &gt;= median) {
     medianR[0][pos] = i;
     break;
    }
   }
   //將R值小於中位數R值放置於leftSpace、大於則放置於rightSpace
   for (int i = 0; i &lt; (int)colorSpace.size(); ++i) {
    if (colorSpace[i].R &lt; medianR[0][pos]) {
     leftSpace[left] = colorSpace[i];
     ++left;
    }
    else if (colorSpace[i].R &gt; medianR[0][pos]) {
     rightSpace[right] = colorSpace[i];
     ++right;
    }
   }
   //等於中位數R值則先放leftSpace,填滿後再放rightSpace
   for (int i = 0; i &lt; (int)colorSpace.size(); ++i) {
    if (colorSpace[i].R != medianR[0][pos])
     continue;
    if (left &lt; (int)leftSpace.size()) {
     leftSpace[left] = colorSpace[i];
     ++left;
    }
    else {
     rightSpace[right] = colorSpace[i];
     ++right;
    }
   }
   break;
  case 2:
   for (int i = 0; i &lt; 256; ++i) {
    count += G[i];
    if (count &gt;= median) {
     medianG[0][pos] = i;
     break;
    }
   }
   for (int i = 0; i &lt; (int)colorSpace.size(); ++i) {
    if (colorSpace[i].G &lt; medianG[0][pos]) {
     leftSpace[left] = colorSpace[i];
     ++left;
    }
    else if (colorSpace[i].G &gt; medianG[0][pos]) {
     rightSpace[right] = colorSpace[i];
     ++right;
    }
   }
   for (int i = 0; i &lt; (int)colorSpace.size(); ++i) {
    if (colorSpace[i].G != medianG[0][pos])
     continue;
    if (left &lt; (int)leftSpace.size()) {
     leftSpace[left] = colorSpace[i];
     ++left;
    }
    else {
     rightSpace[right] = colorSpace[i];
     ++right;
    }
   }
   break;
  case 4:
   for (int i = 0; i &lt; 256; ++i) {
    count += B[i];
    if (count &gt;= median) {
     medianB[0][pos] = i;
     break;
    }
   }
   for (int i = 0; i &lt; (int)colorSpace.size(); ++i) {
    if (colorSpace[i].B &lt; medianB[0][pos]) {
     leftSpace[left] = colorSpace[i];
     ++left;
    }
    else if (colorSpace[i].B &gt; medianB[0][pos]) {
     rightSpace[right] = colorSpace[i];
     ++right;
    }
   }
   for (int i = 0; i &lt; (int)colorSpace.size(); ++i) {
    if (colorSpace[i].B != medianB[0][pos])
     continue;
    if (left &lt; (int)leftSpace.size()) {
     leftSpace[left] = colorSpace[i];
     ++left;
    }
    else {
     rightSpace[right] = colorSpace[i];
     ++right;
    }
   }
   break;
  case 8:
   for (int i = 0; i &lt; 256; ++i) {
    count += R[i];
    if (count &gt;= median) {
     medianR[1][pos] = i;
     break;
    }
   }
   for (int i = 0; i &lt; (int)colorSpace.size(); ++i) {
    if (colorSpace[i].R &lt; medianR[1][pos]) {
     leftSpace[left] = colorSpace[i];
     ++left;
    }
    else if (colorSpace[i].R &gt; medianR[1][pos]) {
     rightSpace[right] = colorSpace[i];
     ++right;
    }
   }
   for (int i = 0; i &lt; (int)colorSpace.size(); ++i) {
    if (colorSpace[i].R != medianR[1][pos])
     continue;
    if (left &lt; (int)leftSpace.size()) {
     leftSpace[left] = colorSpace[i];
     ++left;
    }
    else {
     rightSpace[right] = colorSpace[i];
     ++right;
    }
   }
   break;
  case 16:
   for (int i = 0; i &lt; 256; ++i) {
    count += G[i];
    if (count &gt;= median) {
     medianG[1][pos] = i;
     break;
    }
   }
   for (int i = 0; i &lt; (int)colorSpace.size(); ++i) {
    if (colorSpace[i].G &lt; medianG[1][pos]) {
     leftSpace[left] = colorSpace[i];
     ++left;
    }
    else if (colorSpace[i].G &gt; medianG[1][pos]) {
     rightSpace[right] = colorSpace[i];
     ++right;
    }
   }
   for (int i = 0; i &lt; (int)colorSpace.size(); ++i) {
    if (colorSpace[i].G != medianG[1][pos])
     continue;
    if (left &lt; (int)leftSpace.size()) {
     leftSpace[left] = colorSpace[i];
     ++left;
    }
    else {
     rightSpace[right] = colorSpace[i];
     ++right;
    }
   }
   break;
  case 32:
   for (int i = 0; i &lt; 256; ++i) {
    count += B[i];
    if (count &gt;= median) {
     medianB[1][pos] = i;
     break;
    }
   }
   for (int i = 0; i &lt; (int)colorSpace.size(); ++i) {
    if (colorSpace[i].B &lt; medianB[1][pos]) {
     leftSpace[left] = colorSpace[i];
     ++left;
    }
    else if (colorSpace[i].B &gt; medianB[1][pos]) {
     rightSpace[right] = colorSpace[i];
     ++right;
    }
   }
   for (int i = 0; i &lt; (int)colorSpace.size(); ++i) {
    if (colorSpace[i].B != medianB[1][pos])
     continue;
    if (left &lt; (int)leftSpace.size()) {
     leftSpace[left] = colorSpace[i];
     ++left;
    }
    else {
     rightSpace[right] = colorSpace[i];
     ++right;
    }
   }
   break;
  case 64:
   for (int i = 0; i &lt; 256; ++i) {
    count += R[i];
    if (count &gt;= median) {
     medianR[2][pos] = i;
     break;
    }
   }
   for (int i = 0; i &lt; (int)colorSpace.size(); ++i) {
    if (colorSpace[i].R &lt; medianR[2][pos]) {
     leftSpace[left] = colorSpace[i];
     ++left;
    }
    else if (colorSpace[i].R &gt; medianR[2][pos]) {
     rightSpace[right] = colorSpace[i];
     ++right;
    }
   }
   for (int i = 0; i &lt; (int)colorSpace.size(); ++i) {
    if (colorSpace[i].R != medianR[2][pos])
     continue;
    if (left &lt; (int)leftSpace.size()) {
     leftSpace[left] = colorSpace[i];
     ++left;
    }
    else {
     rightSpace[right] = colorSpace[i];
     ++right;
    }
   }
   break;
  case 128:
   for (int i = 0; i &lt; 256; ++i) {
    count += G[i];
    if (count &gt;= median) {
     medianG[2][pos] = i;
     break;
    }
   }
   for (int i = 0; i &lt; (int)colorSpace.size(); ++i) {
    if (colorSpace[i].G &lt; medianG[2][pos]) {
     leftSpace[left] = colorSpace[i];
     ++left;
    }
    else if (colorSpace[i].G &gt; medianG[2][pos]) {
     rightSpace[right] = colorSpace[i];
     ++right;
    }
   }
   for (int i = 0; i &lt; (int)colorSpace.size(); ++i) {
    if (colorSpace[i].G != medianG[2][pos])
     continue;
    if (left &lt; (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 &lt; 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 &amp;image)
{
 for (int i = 0; i &lt; image.rows; ++i) {
  for (int j = 0; j &lt; image.cols; ++j) {
   index = 0;

   //若大於中位數的RGB值則進入right child,否則進入left child
   for (int n = 0; n &lt; 3; ++n) {
    if (image.at<vec3b>(i, j).val[2] &gt; medianR[n][index]) {
     index = index * 2 + 1;
    }
    else
     index = index * 2;
    if (image.at<vec3b>(i, j).val[1] &gt; medianG[n][index]) {
     index = index * 2 + 1;
    }
    else
     index = index * 2;
    if (n == 2)
     break;
    if (image.at<vec3b>(i, j).val[0] &gt;= 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 &lt;&lt; "Usage: Convert a 24bit image into a 8bit image." &lt;&lt; endl;

 image = imread(argv[1], CV_LOAD_IMAGE_COLOR); // Read the file
    if(!image.data )                              // Check for invalid input
    {
        cout &lt;&lt; "Could not open or find the image" &lt;&lt; endl;
  system("pause");
        return -1;
    }

 cout &lt;&lt; "Constructing image data..." &lt;&lt; endl;
 //建立圖片大小的RGB陣列
 vector<vector ixel=""> &gt; RGB(image.rows, vector<pixel>(image.cols));
 //建立色階分佈圖
 vector<pixel> colorSpace(image.rows * image.cols);
 for( int i = 0; i &lt; image.rows; ++i)
    {
  for ( int j = 0; j &lt; 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 &lt;&lt; "Finished!" &lt;&lt; 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 &lt;&lt; "Median cuting..." &lt;&lt; endl;
 MedianCut(colorSpace, 1, 0);
 cout &lt;&lt; "Finished!\nSetting colors..." &lt;&lt; endl;
 SetNewColor(image);
 cout &lt;&lt; "Finished!" &lt;&lt; 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;
}

結論: 我這一個禮拜以來到底在做什麼...

沒有留言:

張貼留言