Welcome to Doom9's Forum, THE in-place to be for everyone interested in DVD conversion. Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules. |
21st June 2016, 10:41 | #1 | Link |
Soul Architect
Join Date: Apr 2014
Posts: 2,559
|
Implementing Ordered Dither
I'm trying to implement Ordered Dithering into AviSynthShader.
I wrote the code to create the Bayer Matrix, trimming the 32x32 matrix from MPC-HC's source code at 16x16 and copying each value into the B and G fields of a BGRA texture (does the order between both byte fields matter?) Code:
#include "Dither.h" // Dither matrix in 16-bit floating point format const unsigned short DITHER_MATRIX[DITHER_MATRIX_SIZE][DITHER_MATRIX_SIZE] = { 0x2c90, 0x38f4, 0x3bba, 0x29e0, 0x35f4, 0x3230, 0x3bbc, 0x3924, 0x3a46, 0x3644, 0x39e2, 0x370c, 0x3444, 0x3b1a, 0x3140, 0x39d2, 0x385a, 0x3b24, 0x2c10, 0x38c6, 0x3808, 0x2780, 0x3bbe, 0x37f8, 0x350c, 0x3a6c, 0x3368, 0x3bc0, 0x3000, 0x3886, 0x31b0, 0x3554, 0x3a94, 0x3618, 0x3430, 0x3a34, 0x3834, 0x39fe, 0x2740, 0x3758, 0x3494, 0x3b7a, 0x2700, 0x3958, 0x3858, 0x3a24, 0x364c, 0x3bc2, 0x3278, 0x3a22, 0x353c, 0x39de, 0x3268, 0x3a98, 0x36fc, 0x2ed0, 0x39e0, 0x30f0, 0x381a, 0x3996, 0x35ac, 0x3af2, 0x39b8, 0x37bc, 0x3250, 0x39dc, 0x3800, 0x30e8, 0x3b42, 0x34d4, 0x3970, 0x3afe, 0x3020, 0x3898, 0x33e8, 0x3b34, 0x2e10, 0x3320, 0x391a, 0x26c0, 0x3784, 0x38de, 0x3060, 0x3b5c, 0x3600, 0x38e6, 0x3490, 0x3b2a, 0x387a, 0x365c, 0x3b3c, 0x2be0, 0x37ac, 0x33d8, 0x2680, 0x3b98, 0x38d6, 0x2a60, 0x3b7e, 0x391e, 0x36d0, 0x2fe0, 0x3812, 0x32a0, 0x3a84, 0x36b0, 0x3a50, 0x357c, 0x37dc, 0x3b68, 0x3594, 0x3aca, 0x344c, 0x3a7c, 0x3674, 0x3884, 0x2d30, 0x3a48, 0x3170, 0x398e, 0x2900, 0x3a30, 0x34bc, 0x38ea, 0x3b70, 0x3a3c, 0x3852, 0x3460, 0x3b04, 0x37a0, 0x351c, 0x2d40, 0x3a80, 0x394e, 0x3b84, 0x3614, 0x3900, 0x2b20, 0x396c, 0x31b8, 0x38ca, 0x3a0c, 0x3038, 0x385c, 0x39a2, 0x2c70, 0x3ba2, 0x3464, 0x3992, 0x36dc, 0x3bc4, 0x3580, 0x3824, 0x32d0, 0x3abc, 0x2ec0, 0x3560, 0x30f8, 0x3974, 0x3610, 0x3a12, 0x3110, 0x3aaa, 0x38a2, 0x35e4, 0x341c, 0x28c0, 0x3a02, 0x34a8, 0x3b60, 0x3790, 0x3aa2, 0x2c40, 0x346c, 0x373c, 0x3bc6, 0x32f0, 0x37e8, 0x391c, 0x3100, 0x3af6, 0x2640, 0x3868, 0x3098, 0x3b3e, 0x3944, 0x3620, 0x3870, 0x39da, 0x374c, 0x3bc8, 0x2e20, 0x3804, 0x3932, 0x3660, 0x3260, 0x3bca, 0x38ce, 0x3ade, 0x382e, 0x30a0, 0x389e, 0x33a0, 0x363c, 0x3b86, 0x3910, 0x3a58, 0x2820, 0x36a0, 0x3b28, 0x34e0, 0x3a40, 0x3768, 0x3510, 0x3a54, 0x390e, 0x36e8, 0x2ae0, 0x3bcc, 0x31a0, 0x3aa4, 0x2600, 0x38cc, 0x3400, 0x3ac4, 0x2800, 0x3b4a, 0x39ee, 0x2cc0, 0x3764, 0x31c8, 0x35cc, 0x3bb6, 0x39a8, 0x2f30, 0x3a1e, 0x3816, 0x3160, 0x35b0, 0x389a, 0x3a86, 0x3070, 0x3848, 0x2d70, 0x38ba, 0x3baa, 0x2e60, 0x3414, 0x3ae4, 0x3544, 0x3a06, 0x37fc, 0x347c, 0x36d8, 0x3b12, 0x35a4}; HRESULT __stdcall CopyDitherMatrixToSurface(InputTexture* dst, IScriptEnvironment* env) { // Copy into BG values of BGRA texture int TempMatrix[DITHER_MATRIX_SIZE][DITHER_MATRIX_SIZE]{ }; short* pOut; for (int i = 0; i < DITHER_MATRIX_SIZE; ++i) { for (int j = 0; j < DITHER_MATRIX_SIZE; ++j) { *(short*)&TempMatrix[i][j] = DITHER_MATRIX[i][j]; } } HR(CopyAviSynthToBuffer((byte*)&TempMatrix, 4 * DITHER_MATRIX_SIZE, 1, DITHER_MATRIX_SIZE, DITHER_MATRIX_SIZE, dst, env)); return S_OK; } HRESULT __stdcall CopyAviSynthToBuffer(const byte* src, int srcPitch, int clipPrecision, int width, int height, InputTexture* dst, IScriptEnvironment* env) { // Copies source frame into main surface buffer, or into additional input textures RECT SrcRect; SrcRect.top = 0; SrcRect.left = 0; SrcRect.right = width; SrcRect.bottom = height; HR(D3DXLoadSurfaceFromMemory(dst->Surface, nullptr, nullptr, src, GetD3DFormat(clipPrecision, false), srcPitch, nullptr, &SrcRect, D3DX_FILTER_NONE, 0)); return S_OK; } Code:
sampler s0 : register(s0); uniform sampler s1 : register(s1); // the Bayer Matrix texture float4 p0 : register(c0); float2 p1 : register(c1); uniform float4 MatrixSize : register(c2); // width, height, 1/width, 1/height #define width (p0[0]) #define height (p0[1]) #define px (p1[0]) #define py (p1[1]) float Bayer(float2 uv) { uv = uv * MatrixSize.zw; float2 val = dot(tex2D(s1, uv).bg, float2(256.0 * 255.0, 255.0)); val = val * MatrixSize.z * MatrixSize.w; return val; } // -- Main code -- float4 main(float2 tex : TEXCOORD0) : COLOR { float4 c0 = tex2D(s0, tex); c0.x = c0.x + 1 / Bayer(tex); c0.y = c0.y + 1 / Bayer(tex); c0.z = c0.z + 1 / Bayer(tex); return c0; } Thanks
__________________
FrameRateConverter | AvisynthShader | AvsFilterNet | Natural Grounding Player with Yin Media Encoder, 432hz Player, Powerliminals Player and Audio Video Muxer Last edited by MysteryX; 21st June 2016 at 13:11. |
21st June 2016, 14:22 | #2 | Link |
Soul Architect
Join Date: Apr 2014
Posts: 2,559
|
OK, after taking a good break, I went through it again trying to understand each line. I came to the conclusion that the "dot" line was designed to rebuild a number between 0 and 65535 and the function returned a number between 0 and 65535 from the Bayer Matrix based on the pixel position.
This appears to work. When I compare with and without in Photoshop and generate a difference map, Magic Wand sees difference with sensitivity 3 and selects everything with sensitivity 4. How can I test whether it's doing what it's supposed to do? Code review would be a good start. If I invert b and g, it doesn't look right. I just want to be sure I'm mapping the values properly. Code:
sampler s0 : register(s0); uniform sampler s1 : register(s1); // the Bayer Matrix texture float4 p0 : register(c0); float2 p1 : register(c1); uniform float4 MatrixSize : register(c2); // width, height, 1/width, 1/height #define width (p0[0]) #define height (p0[1]) #define px (p1[0]) #define py (p1[1]) float Bayer(float2 uv) { uv = uv * MatrixSize.zw; float val = dot(tex2D(s1, uv).bg, float2(256.0 * 255.0, 255.0)); val = val * MatrixSize.z * MatrixSize.w; return val; } // -- Main code -- float4 main(float2 tex : TEXCOORD0) : COLOR { float4 c0 = tex2D(s0, tex); c0.xyz += (Bayer(tex) - 128.0) / 256.0 / 255.0; return c0; }
__________________
FrameRateConverter | AvisynthShader | AvsFilterNet | Natural Grounding Player with Yin Media Encoder, 432hz Player, Powerliminals Player and Audio Video Muxer Last edited by MysteryX; 21st June 2016 at 14:25. |
Thread Tools | Search this Thread |
Display Modes | |
|
|