HQX and Median Filters

  • tybalitea
  • Topic Author
More
8 years 10 months ago #1 by tybalitea HQX and Median Filters was created by tybalitea
Hi i was wondering if it was possible to add these kind of filters
i think it would be useful and interesting for image treatment...

good examples there :

hqx : www.shadertoy.com/view/MslGRS
median fiter : www.shadertoy.com/view/XsXGDX

Please Log in or Create an account to join the conversation.

  • Martigen
More
8 years 10 months ago #2 by Martigen Replied by Martigen on topic HQX and Median Filters

tybalitea wrote: Hi i was wondering if it was possible to add these kind of filters
i think it would be useful and interesting for image treatment...

good examples there :

hqx : www.shadertoy.com/view/MslGRS
median fiter : www.shadertoy.com/view/XsXGDX

That HQ4X is pretty awesome. I was playing Endless Dungeon recently and trying to find ways with the Framework to improve the pixel art (they went total hardcore and it's as pixelated as that Nyan cat, too much for the wonderful design imho) -- and this would be the perfect shader for it!

How hard is it to add a shader like this? I'd happily test it and post screenies of Endless Dungeon with it!

Please Log in or Create an account to join the conversation.

  • crosire
More
8 years 10 months ago #3 by crosire Replied by crosire on topic HQX and Median Filters
Totally untested, but should work. It's ready to be pluged into the framework like usual (copy into "ReShade\CustomFX\HQ4X.h" and add "#include EFFECT(CustomFX, HQ4X)" to ReShade.fx):
// hq4x filter
// Ripped from https://github.com/libretro/common-shaders/blob/master/hqx/hq4x.cg

float4 PS_HQ4X(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
	float mx = 1.0; // start smoothing wt.
	const float k = -1.10; // wt. decrease factor
	const float max_w = 0.75; // max filter weigth
	const float min_w = 0.03; // min filter weigth
	const float lum_add = 0.33; // effects smoothing

	float4 color = tex2D(RFX_backbufferColor, uv);
	float3 c = color.xyz;

	float x = 0.5 * (1.0 / 256.0);
	float y = 0.5 * (1.0 / 32.0);

	const float3 dt = 1.0*float3(1.0, 1.0, 1.0);

	float2 dg1 = float2( x, y);
	float2 dg2 = float2(-x, y);

	float2 sd1 = dg1*0.5;
	float2 sd2 = dg2*0.5;

	float2 ddx = float2(x,0.0);
	float2 ddy = float2(0.0,y);

	float4 t1 = float4(uv-sd1,uv-ddy);
	float4 t2 = float4(uv-sd2,uv+ddx);
	float4 t3 = float4(uv+sd1,uv+ddy);
	float4 t4 = float4(uv+sd2,uv-ddx);
	float4 t5 = float4(uv-dg1,uv-dg2);
	float4 t6 = float4(uv+dg1,uv+dg2);

	float3 i1 = tex2D(RFX_backbufferColor, t1.xy).xyz;
	float3 i2 = tex2D(RFX_backbufferColor, t2.xy).xyz;
	float3 i3 = tex2D(RFX_backbufferColor, t3.xy).xyz;
	float3 i4 = tex2D(RFX_backbufferColor, t4.xy).xyz;

	float3 o1 = tex2D(RFX_backbufferColor, t5.xy).xyz;
	float3 o3 = tex2D(RFX_backbufferColor, t6.xy).xyz;
	float3 o2 = tex2D(RFX_backbufferColor, t5.zw).xyz;
	float3 o4 = tex2D(RFX_backbufferColor, t6.zw).xyz;

	float3 s1 = tex2D(RFX_backbufferColor, t1.zw).xyz;
	float3 s2 = tex2D(RFX_backbufferColor, t2.zw).xyz;
	float3 s3 = tex2D(RFX_backbufferColor, t3.zw).xyz;
	float3 s4 = tex2D(RFX_backbufferColor, t4.zw).xyz;

	float ko1 = dot(abs(o1-c),dt);
	float ko2 = dot(abs(o2-c),dt);
	float ko3 = dot(abs(o3-c),dt);
	float ko4 = dot(abs(o4-c),dt);

	float k1=min(dot(abs(i1-i3),dt),max(ko1,ko3));
	float k2=min(dot(abs(i2-i4),dt),max(ko2,ko4));

	float w1 = k2; if(ko3<ko1) w1*=ko3/ko1;
	float w2 = k1; if(ko4<ko2) w2*=ko4/ko2;
	float w3 = k2; if(ko1<ko3) w3*=ko1/ko3;
	float w4 = k1; if(ko2<ko4) w4*=ko2/ko4;

	c=(w1*o1+w2*o2+w3*o3+w4*o4+0.001*c)/(w1+w2+w3+w4+0.001);
	w1 = k*dot(abs(i1-c)+abs(i3-c),dt)/(0.125*dot(i1+i3,dt)+lum_add);
	w2 = k*dot(abs(i2-c)+abs(i4-c),dt)/(0.125*dot(i2+i4,dt)+lum_add);
	w3 = k*dot(abs(s1-c)+abs(s3-c),dt)/(0.125*dot(s1+s3,dt)+lum_add);
	w4 = k*dot(abs(s2-c)+abs(s4-c),dt)/(0.125*dot(s2+s4,dt)+lum_add);

	w1 = clamp(w1+mx,min_w,max_w);
	w2 = clamp(w2+mx,min_w,max_w);
	w3 = clamp(w3+mx,min_w,max_w);
	w4 = clamp(w4+mx,min_w,max_w);

	return float4((w1*(i1+i3)+w2*(i2+i4)+w3*(s1+s3)+w4*(s2+s4)+c)/(2.0*(w1+w2+w3+w4)+1.0), 1.0);
}

technique HQ4X_Tech < enabled = RFX_Start_Enabled; >
{
	pass
	{
		VertexShader = RFX_VS_PostProcess;
		PixelShader = PS_HQ4X;
	}
}
The following user(s) said Thank You: tybalitea, jas01

Please Log in or Create an account to join the conversation.

  • Martigen
More
8 years 10 months ago #4 by Martigen Replied by Martigen on topic HQX and Median Filters

crosire wrote: Totally untested, but should work. It's ready to be pluged into the framework like usual (copy into "ReShade\CustomFX\HQ4X.h" and add "#include EFFECT(CustomFX, HQ4X)" to ReShade.fx):

Omigosh awsome! Heading off to bed so will try this out tomorrow :) Thankyou!

Please Log in or Create an account to join the conversation.

  • Martigen
More
8 years 10 months ago - 8 years 10 months ago #5 by Martigen Replied by Martigen on topic HQX and Median Filters
Finally got around to trying this, thanks Crosire.

It's... almost working? :) The effect looks like french window blinds horizontally across the screen. Something is working, but not quite right yet. I don't want to distract you from Reshade though so don't stress. I also realised, looking at the window-blinded interface result, that of course the interface will be affected unless using a mask, and it's one of those games in which the interface is always changing, so it might not be practical to use (for this game, at least) in the long run. Still a cool effect though.
Last edit: 8 years 10 months ago by Martigen.

Please Log in or Create an account to join the conversation.

  • kingeric1992
More
8 years 10 months ago - 8 years 10 months ago #6 by kingeric1992 Replied by kingeric1992 on topic HQX and Median Filters
HQ4X
edit the x y to output res in corsair's conversion.
	float x = 0.5 * (1.0 / Width);
	float y = 0.5 * (1.0 / Hight);
Last edit: 8 years 10 months ago by kingeric1992.
The following user(s) said Thank You: tybalitea

Please Log in or Create an account to join the conversation.

  • tybalitea
  • Topic Author
More
8 years 10 months ago #7 by tybalitea Replied by tybalitea on topic HQX and Median Filters
seems to work quite well, here are some tests (my screen res is 1920*1080):

vanilla :
[img


float x = 0.5 * (1.0 / 640.0);
float y = 0.5 * (1.0 / 360.0);


[img



float x = 0.5 * (1.0 / 1024.0);
float y = 0.5 * (1.0 / 576.0);


[img


float x = 1.5 * (1.0 / 1920.0);
float y = 1.5 * (1.0 / 1080.0);


[img

Please Log in or Create an account to join the conversation.

  • crosire
More
8 years 10 months ago - 8 years 10 months ago #8 by crosire Replied by crosire on topic HQX and Median Filters
I suggest to just replace it with:
float x = 0.5 * BUFFER_RCP_WIDTH;
float y = 0.5 * BUFFER_RCP_HEIGHT;
That'll work with every resolution =).
Last edit: 8 years 10 months ago by crosire.

Please Log in or Create an account to join the conversation.

  • tybalitea
  • Topic Author
More
8 years 10 months ago #9 by tybalitea Replied by tybalitea on topic HQX and Median Filters
yes much better indeed, changing the multiplier should be enough to define the strength

Please Log in or Create an account to join the conversation.

  • Marty McFly
More
8 years 10 months ago #10 by Marty McFly Replied by Marty McFly on topic HQX and Median Filters
I actually ported a more complex median filter version as experiment for blurring of noisy raw SSAO, might as well port it as standalone shader.
The following user(s) said Thank You: tybalitea, jas01

Please Log in or Create an account to join the conversation.

  • Martigen
More
8 years 10 months ago - 8 years 10 months ago #11 by Martigen Replied by Martigen on topic HQX and Median Filters
As promised, pics from Dungeon of the Endless! (open full-screen in separate tabs to compare)

HQ4X off (2560x1600):


HQ4X on y = 0.5 * (1.0 / 2560); float y = 0.5 * (1.0 / 1600);


HQ4X on y = 0.5 * (1.0 / 1000); float y = 0.5 * (1.0 / 500);


The pipe and the green sludge in the middle top... almost no pixelation! Impressive. Of course, it's also blurring the interface for now.

Edited for Crosire's change and playing around with scales. Interesting way to soften an image (besides FXAA blurring) for higher-res sources I imagine.
Last edit: 8 years 10 months ago by Martigen.
The following user(s) said Thank You: tybalitea

Please Log in or Create an account to join the conversation.

  • acknowledge
More
8 years 8 months ago - 8 years 8 months ago #12 by acknowledge Replied by acknowledge on topic HQX and Median Filters
Can you guys port xBRZ filter to reshade please? It's something similar to hqx,but is a more advanced one.
Link below:
sourceforge.net/projects/xbrz/?source=navbar
Last edit: 8 years 8 months ago by acknowledge.

Please Log in or Create an account to join the conversation.

  • Martigen
More
8 years 7 months ago #13 by Martigen Replied by Martigen on topic HQX and Median Filters
Just a bump -- can we get this added officially to the Framework? @luciferhawk

Please Log in or Create an account to join the conversation.

  • Ganossa
More
8 years 6 months ago #14 by Ganossa Replied by Ganossa on topic HQX and Median Filters
Done :P

The following user(s) said Thank You: SunBroDave, acknowledge

Please Log in or Create an account to join the conversation.

  • ninjafada
More
8 years 6 months ago #15 by ninjafada Replied by ninjafada on topic HQX and Median Filters
will you add this to the next framework package update ?

Please Log in or Create an account to join the conversation.

  • Violins77
More
8 years 6 months ago #16 by Violins77 Replied by Violins77 on topic HQX and Median Filters

LuciferHawk wrote: Done :P


Guys! I am DYING to tet this effect! I've been trying for hours to get it to work, but I just see that it should be added to the framework! Is it gonna be released soon?

Please Log in or Create an account to join the conversation.

  • ninjafada
More
8 years 6 months ago - 8 years 6 months ago #17 by ninjafada Replied by ninjafada on topic HQX and Median Filters
i made a zip with the file ninjafada.com/sweetfx/HQ4X.zip , extract in reshade folder, edit CustomFX.cfg (end of the file ) to change the strength

Last edit: 8 years 6 months ago by ninjafada.

Please Log in or Create an account to join the conversation.

  • JPulowski
More
8 years 2 months ago #18 by JPulowski Replied by JPulowski on topic HQX and Median Filters
This is not the true HQ4X filter. The shader has been ported from Shadertoy and it is dated as 2013-07-12. It was based on an older version of HQ4X from RetroArch. On June 3, 2014 it has been replaced with Armada's true HQX shaders. This is the reason why the code on GitHub and Shadertoy looks different. You can find more about it here: filthypants.blogspot.com/2014/06/true-hq2x-shader-comparison-with-xbr.html

Currently I am trying to port "true" version, but since scaling is involved in the process it is quite complex for me to port everything at first try. But eventually it will be done, I guess.
The following user(s) said Thank You: Quentin-Tarantino, Genrix, mcabel

Please Log in or Create an account to join the conversation.

  • mcabel
More
8 years 2 months ago - 8 years 2 months ago #19 by mcabel Replied by mcabel on topic HQX and Median Filters
Hi, is there a configuration I can Use to make HQ4x look like typically expected?



I'm using it on final fantasy tactics -remotejoy on my pc, and instead of looking smooth and sharp, the image looks blur-ier like if it had gaussian blur instead:

http://ibin.co/2VDcm8OvxGbY
above-unfiltered / below "hq4x" .

Also +1 to xBR ....it's like hq4x but the image output tend to be more accurate and nicer looking.
Last edit: 8 years 2 months ago by mcabel. Reason: typo

Please Log in or Create an account to join the conversation.

  • kingeric1992
More
8 years 2 months ago - 8 years 2 months ago #20 by kingeric1992 Replied by kingeric1992 on topic HQX and Median Filters
@JPulowski
Untested, consider it pseudo code.
I've comb though Armada651's port to the C version, looks quite legit so it's pretty much a direct port.
Didn't check the LUT texture though, (would be a pain in the ass) but you can still procedurally generate the LUT tex on Reshade initialization if you don't want to use Armada651's pregenerated luttex.
/**************************************************************************
 * Copyright (C) 2003 Maxim Stepin ( maxst@hiend3d.com )    // HQnX
 * Copyright (C) 2010 Cameron Zemek ( grom@zeminvaders.net) // HQnX
 * Copyright (C) 2011 Francois Gannaz <mytskine@gmail.com>  // HQnX
 * Copyright (C) 2014 Jules Blok ( jules@aerix.nl )         // Armada651
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 **************************************************************************
 *
 * HQnX Initinal port on ReShade by kingeric1992 .Feb/1/16
 *
 * check 
 *      https://code.google.com/archive/p/hqx/                      for original C implementation
 *      https://github.com/libretro/common-shaders/tree/master/hqx  for Cg/HLSL implementation by Armada651
 *
 **************************************************************************/
 
//settings
#define HQnX_ToggleKey (unbound)    //HQnX toggle key
#define HQnX_Scale 4                //set scale 2|3|4
#define HQnX_InputTex InputTexture  //set input texture
#define HQnX_SrcScaleX  640         //source scale X
#define HQnX_SrcScaleY  480         //source scale Y
float3  HQnX_YUVoffset    = {0, 0.5, 0.5};            //or use define
float3  HQnX_YUVthreshold = {0.1882, 0.0275, 0.0235}; //or use define

//textures & samplers.
//lut tex: .rgba == {center weight, diagonal weight, horizontal weight, vertical weight}
texture HQ4xTex < source = "ReShade/HQ4xLut.png"; > { Width = 256; Height = 256; Format = RGBA8F; };
texture HQ3xTex < source = "ReShade/HQ3xLut.png"; > { Width = 256; Height = 144; Format = RGBA8F; };
texture HQ2xTex < source = "ReShade/HQ2xLut.png"; > { Width = 256; Height = 64;  Format = RGBA8F; };

sampler HQ4xLutColor { Texture = HQ4xTex;       MinFilter = POINT; MagFilter = POINT;};
sampler HQ3xLutColor { Texture = HQ3xTex;       MinFilter = POINT; MagFilter = POINT;};
sampler HQ2xLutColor { Texture = HQ2xTex;       MinFilter = POINT; MagFilter = POINT;};
sampler HQnXSrcColor { Texture = HQnX_InputTex; MinFilter = POINT; MagFilter = POINT;};

#define HQnXLutColor(a) HQ##a##xLutColor

float3x3 yuv =
{
    0.299,  0.587,  0.114,
   -0.169, -0.331,  0.5,
      0.5, -0.419, -0.081
};

bool Diff(float3 yuv1, float3 yuv2) {
    bool3 res = abs((yuv1 + HQnX_YUVoffset) - (yuv2 + HQnX_YUVoffset)) > HQnX_YUVthreshold;
    return res.x || res.y || res.z;
}

struct VS_OUTPUT {
    float4 position  : POSITION;
    float4 texCoord0 : TEXCOORD0;
    float4 texCoord1 : TEXCOORD1;
    float4 texCoord2 : TEXCOORD2;
};

VS_OUTPUT VS_HQnX(in uint id : SV_VertexID)
{
    VS_OUTPUT OUT;

    float2 coord = 0;
    coord.x = (id == 2) ? 2.0 : 0.0;
    coord.y = (id == 1) ? 2.0 : 0.0;

    float4 offset = {- 1 / HQnX_SrcScaleX, 0, 1 / HQnX_SrcScaleX, 1 / HQnX_SrcScaleY}; //  Src Pixel Size
    OUT.position  = float4(coord * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
    OUT.texCoord0 = coord.xxxy + offset.xyzw;
    OUT.texCoord1 = coord.xxxy + offset.xyzy;
    OUT.texCoord2 = coord.xxxy - offset.zyxw;
    return OUT;
}

//*  use point sampler
//** only support upscale x2, x3, x4.
float4 PS_HQnX(in VS_OUTPUT IN) : COLOR
{
    float4   offset = {- 1 / HQnX_SrcScaleX, 0, 1 / HQnX_SrcScaleX, 1 / HQnX_SrcScaleY}; //  Src Pixel Size
    float2   index  = frac(IN.texCoord / offset.zw);
    float2   dir    = sign(index - 0.5);
    float4x3 pixels = //4 rows, 3 column
    {
        tex2D(HQnXSrcColor, IN.texCoord1.yw                  ).rgb, //center
        tex2D(HQnXSrcColor, IN.texCoord1.yw + dir * offset.zw).rgb, //diagonal
        tex2D(HQnXSrcColor, IN.texCoord1.yw + dir * offset.zy).rgb, //horizontal
        tex2D(HQnXSrcColor, IN.texCoord1.yw + dir * offset.yw).rgb  //vertical
    };

    float3 w[9];                                               //   +------+------+------+
    w[1] = mul(yuv, tex2D(HQnXSrcColor, IN.texCoord0.xw).rgb); //   |      |      |      |
    w[2] = mul(yuv, tex2D(HQnXSrcColor, IN.texCoord0.yw).rgb); //   | w[1] | w[2] | w[3] |
    w[3] = mul(yuv, tex2D(HQnXSrcColor, IN.texCoord0.zw).rgb); //   +------+------+------+
    w[4] = mul(yuv, tex2D(HQnXSrcColor, IN.texCoord1.xw).rgb); //   |      |      |      |
    w[0] = mul(yuv, pixels[0]);                                //   | w[4] | w[0] | w[5] |
    w[5] = mul(yuv, tex2D(HQnXSrcColor, IN.texCoord1.zw).rgb); //   +------+------+------+
    w[6] = mul(yuv, tex2D(HQnXSrcColor, IN.texCoord2.xw).rgb); //   |      |      |      |
    w[7] = mul(yuv, tex2D(HQnXSrcColor, IN.texCoord2.yw).rgb); //   | w[6] | w[7] | w[8] |
    w[8] = mul(yuv, tex2D(HQnXSrcColor, IN.texCoord2.zw).rgb); //   +------+------+------+

    //use LUT 256 cases * (16 if else * (n * n) bias) to replace switch table, index to get lut offset
    //check https://code.google.com/archive/p/hqx/ cpu source on switch table.
    index    = floor(index * HQnX_Scale);
    index.y  = index.x + index.y * HQnX_Scale;
    index.y += (Diff(w[4], w[2]) + (Diff(w[2], w[5]) << 1) + (Diff(w[7], w[4]) << 2) + (Diff(w[5], w[7]) << 3)) * (HQnX_Scale * HQnX_Scale);
    index.x  = Diff(w[0], w[1]);

    for(int i=1; i<8; i++)
        index.x += Diff(w[0], w[i+1]) << i;

    index   = (index + 0.5) / float2(256.0, 16.0 * (HQnX_Scale * HQnX_Scale));

//or use linear sampling to colapse sample quad (bypass float4x3 pixels) similar to optimized bicubic filter
/*
    float4 weight = tex2D(HQnXLutColor(HQnX_Scale), index);
    index.y = (weight.y + weight.w ) / dot(weight, 1);
    index.x = lerp( weight.z / (weight.x + weight.z), weight.w / (weight.y + weight.w), index.y);
    return tex2D(decal, (floor(IN.texCoord / offset.zw) + 0.5 + index * dir) * offset.zw));
*/
    float4 weight = tex2D(HQnXLutColor(HQnX_Scale), index);
    return float4(mul(weight / dot(weight, 1), pixels), 1.0);
}

technique HQnX < enabled = RFX_Start_Enabled; toggle = HQnX_ToggleKey; >
{
	pass 	{
		VertexShader = VS_HQnX;
		PixelShader  = PS_HQnX;
	}
}
Last edit: 8 years 2 months ago by kingeric1992. Reason: typo
The following user(s) said Thank You: JPulowski

Please Log in or Create an account to join the conversation.

We use cookies
We use cookies on our website. Some of them are essential for the operation of the forum. You can decide for yourself whether you want to allow cookies or not. Please note that if you reject them, you may not be able to use all the functionalities of the site.