我一直在寻找一个优化(即,快速)算法,24位RGB位图转换为使用抖动16位(RGB565)位图。 我在寻找的东西在C / C ++在那里我居然可以控制抖动是如何应用的。 GDI +似乎提供了一些方法,但如果他们抖动与否我不能告诉。 而且,如果他们不抖动,他们使用什么样的机制(弗洛伊德 - 斯坦伯格?)
有没有人有位色彩深度转换与抖动一个很好的例子?
我一直在寻找一个优化(即,快速)算法,24位RGB位图转换为使用抖动16位(RGB565)位图。 我在寻找的东西在C / C ++在那里我居然可以控制抖动是如何应用的。 GDI +似乎提供了一些方法,但如果他们抖动与否我不能告诉。 而且,如果他们不抖动,他们使用什么样的机制(弗洛伊德 - 斯坦伯格?)
有没有人有位色彩深度转换与抖动一个很好的例子?
正如你提到的,弗洛伊德 - 斯坦伯格抖动方法很受欢迎,因为它的简单和快捷。 对于24位和16位颜色之间的细微差别的结果将是接近最佳视觉。
有人建议我用的样品图片莉娜 ,但我决定反对; 尽管其悠久的历史作为测试图像,我认为它太性别歧视的现代情感。 相反,我提出我自己的照片。 首先是原始的,随后转化为抖动RGB565(和转换回24位用于显示)。
和代码,在C ++:
inline BYTE Clamp(int n)
{
n = n>255 ? 255 : n;
return n<0 ? 0 : n;
}
struct RGBTriplet
{
int r;
int g;
int b;
RGBTriplet(int _r = 0, int _g = 0, int _b = 0) : r(_r), g(_g), b(_b) {};
};
void RGB565Dithered(const BYTE * pIn, int width, int height, int strideIn, BYTE * pOut, int strideOut)
{
std::vector<RGBTriplet> oldErrors(width + 2);
for (int y = 0; y < height; ++y)
{
std::vector<RGBTriplet> newErrors(width + 2);
RGBTriplet errorAhead;
for (int x = 0; x < width; ++x)
{
int b = (int)(unsigned int)pIn[3*x] + (errorAhead.b + oldErrors[x+1].b) / 16;
int g = (int)(unsigned int)pIn[3*x + 1] + (errorAhead.g + oldErrors[x+1].g) / 16;
int r = (int)(unsigned int)pIn[3*x + 2] + (errorAhead.r + oldErrors[x+1].r) / 16;
int bAfter = Clamp(b) >> 3;
int gAfter = Clamp(g) >> 2;
int rAfter = Clamp(r) >> 3;
int pixel16 = (rAfter << 11) | (gAfter << 5) | bAfter;
pOut[2*x] = (BYTE) pixel16;
pOut[2*x + 1] = (BYTE) (pixel16 >> 8);
int error = r - ((rAfter * 255) / 31);
errorAhead.r = error * 7;
newErrors[x].r += error * 3;
newErrors[x+1].r += error * 5;
newErrors[x+2].r = error * 1;
error = g - ((gAfter * 255) / 63);
errorAhead.g = error * 7;
newErrors[x].g += error * 3;
newErrors[x+1].g += error * 5;
newErrors[x+2].g = error * 1;
error = b - ((bAfter * 255) / 31);
errorAhead.b = error * 7;
newErrors[x].b += error * 3;
newErrors[x+1].b += error * 5;
newErrors[x+2].b = error * 1;
}
pIn += strideIn;
pOut += strideOut;
oldErrors.swap(newErrors);
}
}
我不能保证这个代码是完美的,我已经解决,我在另一评论提到那些细微的错误之一。 但是它确实产生上述结果。 它采用24位像素BGR顺序由Windows,并在小尾数顺序产生R5G6B5 16位像素。
我建议所用有序抖动 ( http://en.wikipedia.org/wiki/Ordered_dithering ),由于弗洛伊德斯坦伯格 需要更多的处理和计算并且仅适用于静态图像/不适用于动画或恒定变化上显示效果很好。
我创造了我自己的优化下令从24位/ 32位RGB色彩抖动,以16bit的RGB565色彩,即单独tresshold成子像素(在我使用AROMA项目 )。 这是更快的方式,然后弗洛伊德-斯坦伯格,因为没有昂贵的计算(特别是无繁殖和申报单计算 ),并能够在动画,因为它使用的固定tresshold使用。
它的质量也好得多比有序抖动,关于维基定义的算法。
这里抖动结果的一个例子:
这里的来源。 请享用!
/* Dither Tresshold for Red Channel */
static const BYTE dither_tresshold_r[64] = {
1, 7, 3, 5, 0, 8, 2, 6,
7, 1, 5, 3, 8, 0, 6, 2,
3, 5, 0, 8, 2, 6, 1, 7,
5, 3, 8, 0, 6, 2, 7, 1,
0, 8, 2, 6, 1, 7, 3, 5,
8, 0, 6, 2, 7, 1, 5, 3,
2, 6, 1, 7, 3, 5, 0, 8,
6, 2, 7, 1, 5, 3, 8, 0
};
/* Dither Tresshold for Green Channel */
static const BYTE dither_tresshold_g[64] = {
1, 3, 2, 2, 3, 1, 2, 2,
2, 2, 0, 4, 2, 2, 4, 0,
3, 1, 2, 2, 1, 3, 2, 2,
2, 2, 4, 0, 2, 2, 0, 4,
1, 3, 2, 2, 3, 1, 2, 2,
2, 2, 0, 4, 2, 2, 4, 0,
3, 1, 2, 2, 1, 3, 2, 2,
2, 2, 4, 0, 2, 2, 0, 4
};
/* Dither Tresshold for Blue Channel */
static const BYTE dither_tresshold_b[64] = {
5, 3, 8, 0, 6, 2, 7, 1,
3, 5, 0, 8, 2, 6, 1, 7,
8, 0, 6, 2, 7, 1, 5, 3,
0, 8, 2, 6, 1, 7, 3, 5,
6, 2, 7, 1, 5, 3, 8, 0,
2, 6, 1, 7, 3, 5, 0, 8,
7, 1, 5, 3, 8, 0, 6, 2,
1, 7, 3, 5, 0, 8, 2, 6
};
/* Get 16bit closest color */
BYTE closest_rb(BYTE c) {
return (c >> 3 << 3); /* red & blue */
}
BYTE closest_g(BYTE c) {
return (c >> 2 << 2); /* green */
}
/* RGB565 */
WORD RGB16BIT(BYTE r, BYTE g, BYTE b) {
return ((WORD)((r>>3)<<11)|((g>>2)<<5)|(b>>3));
}
/* Dithering by individual subpixel */
WORD dither_xy(
int x,
int y,
BYTE r,
BYTE g,
BYTE b
){
/* Get Tresshold Index */
BYTE tresshold_id = ((y & 7) << 3) + (x & 7);
r = closest_rb(
MIN(r + dither_tresshold_r[tresshold_id], 0xff)
);
g = closest_g(
MIN(g + dither_tresshold_g[tresshold_id], 0xff)
);
b = closest_rb(
MIN(b + dither_tresshold_b[tresshold_id], 0xff)
);
return RGB16BIT(r, g, b);
}
/* Dithering Pixel from 32/24bit RGB
*
* GetR, GetG, GetB -> Function to get individual color in pixel
*
*/
WORD dither_color_xy(int x, int y, DWORD col) {
return dither_xy(x, y, GetR(col), GetG(col), GetB(col));
}
/* EXAMPLES */
void ExampleDither1(WORD * dest, DWORD * src, int width, int height){
int x, y;
for (y=0; y<height; y++){
for (x=0; x<width; x++){
int pos = y * width + x;
dest[pos] = dither_color_xy(x,y,src[pos]);
}
}
}
void ExampleDither2(WORD * dest, BYTE * src, int width, int height){
int x, y;
for (y=0; y<height; y++){
for (x=0; x<width; x++){
int pos = y * width + x;
dest[pos] = dither_xy(x,y,src[pos*3],src[pos*3+1],src[pos*3+2]);
}
}
}
另一个结果(24位顶 - 底有序RGB565-16bit): 查看全分辨率图像
弗洛伊德-斯坦伯格抖动
for each y from top to bottom
for each x from left to right
oldpixel := pixel[x][y]
newpixel := find_closest_palette_color(oldpixel)
pixel[x][y] := newpixel
quant_error := oldpixel - newpixel
pixel[x+1][y] := pixel[x+1][y] + 7/16 * quant_error
pixel[x-1][y+1] := pixel[x-1][y+1] + 3/16 * quant_error
pixel[x][y+1] := pixel[x][y+1] + 5/16 * quant_error
pixel[x+1][y+1] := pixel[x+1][y+1] + 1/16 * quant_error
我敢打赌,你可以很容易地实现这种降压!