我正在开发一个自定义瘦客户端服务器,为其客户端提供呈现的网页。服务器在多核Linux机器上运行,Webkit提供了html渲染引擎。
唯一的问题是客户端显示受限于4位(16色)灰度调色板。我目前正在使用LibGraphicsMagick抖动图像(RGB-> 4bit灰度),这是服务器性能的明显瓶颈。分析表明,超过70%的时间用于运行GraphicsMagick抖动函数。
我已经探索了stackoverflow和Interwebs的高性能解决方案,但似乎没有人在各种图像处理库和抖动解决方案上做过任何基准测试。
我会更乐意发现:
首选C语言库。
答案 0 :(得分:2)
根据所选择的算法,抖动将花费相当多的时间。
实施Bayer (Matrix)和Floyd-Steinberg (Diffusion) dithering非常简单。
使用MMX / SSE进行编码处理并行像素时,可以非常快速地进行拜耳滤波。您也可以使用GPU着色器进行抖动/转换。
FWIW,你已经在使用GraphicsMagick但是有一整套OSS图形库here
答案 1 :(得分:2)
从Adisak提供的列表中,我没有进行任何测试,我打赌AfterImage。 Afterstep人对速度很着迷,并且还描述了一种聪明的算法。
如果您的服务器可以配备具有OpenGL功能的PCI-express显卡,您可以采取其他方法。 Here是Nvidia的一些规格。搜索“索引模式”。您可以做的是选择16或256色显示模式,将图像渲染为平面多边形(如立方体侧面)上的纹理,然后再读回框架。
从OpenGL卡读取帧时,重要的是带宽来自卡,因此需要PCI-express。正如文档所说,你还必须在索引模式中选择你的颜色以获得不错的效果。
答案 2 :(得分:1)
答案 3 :(得分:0)
这是您正在寻找的解决方案。 这是一个 C 函数,它使用颜色参数执行 Ordered Dither (Bayer)。 它足够快,可以用于实时处理。
#ifndef MIN
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef MAX
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef CLAMP
// This produces faster code without jumps
#define CLAMP( x, xmin, xmax ) (x) = MAX( (xmin), (x) ); \
(x) = MIN( (xmax), (x) )
#define CLAMPED( x, xmin, xmax ) MAX( (xmin), MIN( (xmax), (x) ) )
#endif
const int BAYER_PATTERN_16X16[16][16] = { // 16x16 Bayer Dithering Matrix. Color levels: 256
{ 0, 191, 48, 239, 12, 203, 60, 251, 3, 194, 51, 242, 15, 206, 63, 254 },
{ 127, 64, 175, 112, 139, 76, 187, 124, 130, 67, 178, 115, 142, 79, 190, 127 },
{ 32, 223, 16, 207, 44, 235, 28, 219, 35, 226, 19, 210, 47, 238, 31, 222 },
{ 159, 96, 143, 80, 171, 108, 155, 92, 162, 99, 146, 83, 174, 111, 158, 95 },
{ 8, 199, 56, 247, 4, 195, 52, 243, 11, 202, 59, 250, 7, 198, 55, 246 },
{ 135, 72, 183, 120, 131, 68, 179, 116, 138, 75, 186, 123, 134, 71, 182, 119 },
{ 40, 231, 24, 215, 36, 227, 20, 211, 43, 234, 27, 218, 39, 230, 23, 214 },
{ 167, 104, 151, 88, 163, 100, 147, 84, 170, 107, 154, 91, 166, 103, 150, 87 },
{ 2, 193, 50, 241, 14, 205, 62, 253, 1, 192, 49, 240, 13, 204, 61, 252 },
{ 129, 66, 177, 114, 141, 78, 189, 126, 128, 65, 176, 113, 140, 77, 188, 125 },
{ 34, 225, 18, 209, 46, 237, 30, 221, 33, 224, 17, 208, 45, 236, 29, 220 },
{ 161, 98, 145, 82, 173, 110, 157, 94, 160, 97, 144, 81, 172, 109, 156, 93 },
{ 10, 201, 58, 249, 6, 197, 54, 245, 9, 200, 57, 248, 5, 196, 53, 244 },
{ 137, 74, 185, 122, 133, 70, 181, 118, 136, 73, 184, 121, 132, 69, 180, 117 },
{ 42, 233, 26, 217, 38, 229, 22, 213, 41, 232, 25, 216, 37, 228, 21, 212 },
{ 169, 106, 153, 90, 165, 102, 149, 86, 168, 105, 152, 89, 164, 101, 148, 85 }
};
// This is the ultimate method for Bayer Ordered Diher with 16x16 matrix
// ncolors - number of colors diapazons to use. Valid values 0..255, but interesed are 0..40
// 1 - color (1 bit per color plane, 3 bits per pixel)
// 3 - color (2 bit per color plane, 6 bits per pixel)
// 7 - color (3 bit per color plane, 9 bits per pixel)
// 15 - color (4 bit per color plane, 12 bits per pixel)
// 31 - color (5 bit per color plane, 15 bits per pixel)
void makeDitherBayerRgbNbpp( BYTE* pixels, int width, int height, int ncolors ) noexcept
{
int divider = 256 / ncolors;
for( int y = 0; y < height; y++ )
{
const int row = y & 15; // y % 16
for( int x = 0; x < width; x++ )
{
const int col = x & 15; // x % 16
const int t = BAYER_PATTERN_16X16[col][row];
const int corr = (t / ncolors);
const int blue = pixels[x * 3 + 0];
const int green = pixels[x * 3 + 1];
const int red = pixels[x * 3 + 2];
int i1 = (blue + corr) / divider; CLAMP( i1, 0, ncolors );
int i2 = (green + corr) / divider; CLAMP( i2, 0, ncolors );
int i3 = (red + corr) / divider; CLAMP( i3, 0, ncolors );
// If you want to compress the image, use the values of i1,i2,i3
// they have values in the range 0..ncolors
// So if the ncolors is 4 - you have values: 0,1,2,3 which is encoded in 2 bits
// 2 bits for 3 planes == 6 bits per pixel
pixels[x * 3 + 0] = CLAMPED( i1 * divider, 0, 255 ); // blue
pixels[x * 3 + 1] = CLAMPED( i2 * divider, 0, 255 ); // green
pixels[x * 3 + 2] = CLAMPED( i3 * divider, 0, 255 ); // red
}
pixels += width * 3;
}
}
在您的情况下,您需要使用参数 ncolors=4 调用该函数 这意味着每个颜色平面(对于灰度是 1 个平面)将使用每像素 4 位。
所以,你必须调用:
makeDitherBayerRgbNbpp( pixels, width, height, 4 );
输入像素采用 BGR 格式。 出于可视化目的,输出像素也采用 BGR 格式。 要获得这些位,您必须替换此代码:
pixels[x * 3 + 0] = CLAMPED( i1 * divider, 0, 255 ); // blue
pixels[x * 3 + 1] = CLAMPED( i2 * divider, 0, 255 ); // green
pixels[x * 3 + 2] = CLAMPED( i3 * divider, 0, 255 ); // red
像这样:
out.writeBit( i1 ); // blue
out.writeBit( i2 ); // green
out.writeBit( i3 ); // red
有关更多抖动源代码和演示应用程序,您可以查看here