真彩色:是指图像中的每个像素值都分成R、G、B三个基色分量,每个基色分量直接决定其基色的强度,这样产生的色彩称为真彩色。
256色图:仅表示256种颜色,在bmp文件格式种采用调色板(Palette)来保存图片的色彩信息,图片在进行色彩表达式需要进行索引。
介绍将真彩图转化为256色图的方法:八叉树颜色量化(octree color quantization)。
使用C以及opencv实现。
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <opencv.hpp>
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
using namespace std;
using namespace cv;
static unsigned char mask[8] =
{ 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
unsigned int maxcolor = 16;
unsigned int currentcolor = 0;
bool pri = false;
typedef struct NODE
{
bool IsLeaf; //是否为叶子节点
bool Reduce; //是否可归并
unsigned int count; //此节点记录了多少种像素颜色
unsigned int level; //层级,当 level = 7就是叶子节点
unsigned int redsum; //红色分量总和
unsigned int greensum; //绿色分量总和
unsigned int bluesum; //蓝色分量总和
unsigned int mapto; //映射到容器中,肯根据索引查找
unsigned int childnum; //不为空的子节点数量
NODE* ptrChild[8]; //子节点初始化为空
NODE(unsigned int lev)
{
level = lev;
redsum = greensum = bluesum = count = childnum = 0;
mapto = -1;
for (int i = 0; i < 8; i++)
{
ptrChild[i] = NULL;
}
IsLeaf = false;
Reduce = true;
}
}*PNODE;
std::vector<PNODE> LeafNodes;
std::vector<int> HeadNodes[8];
void RecursiveReduce(int idx)
{
if (LeafNodes[idx]->Reduce == false)
{
return;
}
LeafNodes[idx]->Reduce = false;
for (int i = 0; i < 8; i++)
{
if (LeafNodes[idx]->ptrChild[i] != NULL)
RecursiveReduce(LeafNodes[idx]->ptrChild[i]->mapto);
}
}
//减少节点
void ReduceColor()
{
int minidx = -1;
for (int i = 7; i >= 0; i--)
{
int mincount = 0x7f7f7f;
for (int j = 0; j < HeadNodes[i].size(); j++)
{
int idx = HeadNodes[i][j];
if (LeafNodes[idx]->Reduce && LeafNodes[idx]->childnum >= 2 && mincount > LeafNodes[idx]->childnum)
{
mincount = LeafNodes[idx]->childnum;
minidx = idx;
}
}
if (minidx != -1)
break;
}
RecursiveReduce(minidx);
LeafNodes[minidx]->IsLeaf = true;
currentcolor -= (LeafNodes[minidx]->childnum - 1);
if (pri)
cout << "得到索引" << minidx << "\t目前的颜色数量" << currentcolor << endl;
}
void addColor(PNODE &anode, unsigned int red, unsigned int green, unsigned int blue, bool newnode)
{
if (anode->level < 8 && newnode) //将该节点的索引放进所在层中,方便之后搜索
{
HeadNodes[anode->level].push_back(anode->mapto);
}
anode->redsum += red;
anode->greensum += green;
anode->bluesum += blue;
anode->count += 1; //即上图中的数量,即节点代表的像素数量
if (anode->IsLeaf)
return;
if (anode->level == 8) //如果是第8层
{
anode->IsLeaf = true;
anode->Reduce = false;
if (newnode) //新颜色,需要新建一个叶子节点
{
currentcolor += 1;
anode->IsLeaf = true;
if (currentcolor > maxcolor)
{
if (pri)
cout << "需要减去颜色" << endl;
ReduceColor();
}
}
}
else
{
unsigned int shift = 7 - anode->level; //用于计算7颜色的7位二进制
unsigned int Idx = (((red & mask[anode->level]) >> shift) << 2) |
(((green & mask[anode->level]) >> shift) << 1) |
((blue & mask[anode->level]) >> shift);
if (anode->ptrChild[Idx] == nullptr) //子节点不存在,需要新建一个
{
anode->ptrChild[Idx] = new NODE(anode->level + 1);
LeafNodes.push_back(anode->ptrChild[Idx]);
anode->ptrChild[Idx]->mapto = LeafNodes.size() - 1;
anode->childnum += 1;
addColor(anode->ptrChild[Idx], red, green, blue, true);
}
else
{
addColor(anode->ptrChild[Idx], red, green, blue, false);
}
}
}
//建立调色盘
int QueryColor(PNODE& anode, unsigned int red, unsigned int green, unsigned int blue)
{
if (anode->IsLeaf)
{
return anode->mapto;
}
else
{
unsigned int shift = 7 - anode->level;
unsigned int Idx = (((red & mask[anode->level]) >> shift) << 2) |
(((green & mask[anode->level]) >> shift) << 1) |
((blue & mask[anode->level]) >> shift);
if (pri)
cout << "shift=" << shift << "\tidx=" << Idx << "下一层数是" << anode->level + 1 << endl;
return QueryColor(anode->ptrChild[Idx], red, green, blue);
}
}
int main()
{
Mat srcImg = imread("bread.png");
imshow("原图", srcImg);
PNODE RootNode = new NODE(0);
LeafNodes.push_back(RootNode);
RootNode->mapto = 0;
HeadNodes[0].push_back(0);
for (int i = 0; i < srcImg.rows; i++)
{
for (int j = 0; j < srcImg.cols; j++)
{
addColor(RootNode, srcImg.at<Vec3b>(i, j)[2], srcImg.at<Vec3b>(i, j)[1], srcImg.at<Vec3b>(i, j)[0], false);
}
}
for (int i = 0; i < srcImg.rows; i++)
{
for (int j = 0; j < srcImg.cols; j++)
{
int vectoridx = QueryColor(RootNode, srcImg.at<Vec3b>(i, j)[2], srcImg.at<Vec3b>(i, j)[1], srcImg.at<Vec3b>(i, j)[0]);
if (pri)
cout << "vectoridx =" << vectoridx << endl;
srcImg.at<Vec3b>(i, j)[2] = LeafNodes[vectoridx]->redsum / LeafNodes[vectoridx]->count;
srcImg.at<Vec3b>(i, j)[1] = LeafNodes[vectoridx]->greensum / LeafNodes[vectoridx]->count;
srcImg.at<Vec3b>(i, j)[0] = LeafNodes[vectoridx]->bluesum / LeafNodes[vectoridx]->count;
}
}
imshow("处理后的图", srcImg);
imwrite("out.bmp", srcImg);
waitKey(0);
}