ImageSharp icon indicating copy to clipboard operation
ImageSharp copied to clipboard

Feature request: Add Median filter

Open dejanberic opened this issue 6 years ago • 5 comments

This is a simple filter which can be used to filter out noise.

Here is one paper on fast Median and Bilateral filtering: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.93.1608&rep=rep1&type=pdf

dejanberic avatar Jan 21 '19 12:01 dejanberic

Referring to gitter talk witn @antonfirsov i take that issue. I will start implementing it in february

michasacuer avatar Jan 26 '19 14:01 michasacuer

@michasacuer great news! Thanks! 👍

antonfirsov avatar Jan 26 '19 14:01 antonfirsov

Just in case it helps (probably not, but I don't think it can hurt to mention it) I was recently working on basic median filtering, i.e. simply taking the median of a square window. You can see the most up-to-date version of the fastest program I came up with here - feel free to look at everything else in the repo, but I think that'll be by far the most useful part of it. It is written in F# though, so might not be of as much use to you. Moreover, I have undoubtedly done something silly, or somehow not used ImageSharp effectively. I also didn't get around to implementing more interesting types of median filters.

Based on some quick profiling of my program, it appears to spend about 60% of its time in the Array.sort function. I tried implementing some alternatives like Insertion Sort and Shell Sort (I did think about Radix sort, but I can't remember actually testing it), but nothing came close to being as fast as the built-in .NET sort once the arrays got bigger than about 10 elements. Someone suggested that I move from sorting the array to using a selection algorithm like QuickSelect, but I never got around to implementing it/trying it out.

I hope that this helps 😃

EDIT: Just remembered something else that might be of interest: I created a Golang version of the F# program to have a quick comparison (hidden away elsewhere in that repo). When running them both sequentially, the Golang version runs about 1.75x faster, though I never could determine exactly why that should be the case. .NET provides a much easier way to parallelise array operations however (I literally just need to change Array.map to Array.Parallel.map on one line), and when I use that, the F# version runs about twice as fast on my quad-core machine.

Jarak-Jakar avatar Feb 04 '19 01:02 Jarak-Jakar

Thanks for help! I will start to implementing this after my exams (i think it will be int the next one, two weeks)

michasacuer avatar Feb 04 '19 16:02 michasacuer

Isn't this a 9 tap tent filter, as described by Smith? https://pdfs.semanticscholar.org/cdf7/1f6ea2178cfa210a30c5870c235f3acdc42a.pdf

In HLSL:

	void PS_TentFilter(float4 vpos : SV_Position, float2 texcoord : TEXCOORD, out float4 fragment : SV_Target0)
	{
		float4 coord = BUFFER_PIXEL_SIZE.xyxy * float4(1, 1, -1, 0);
		float4 average;
		average = tex2D(SamplerCDBuffer2, texcoord - coord.xy);
		average += tex2D(SamplerCDBuffer2, texcoord - coord.wy) * 2;
		average += tex2D(SamplerCDBuffer2, texcoord - coord.zy);
		average += tex2D(SamplerCDBuffer2, texcoord + coord.zw) * 2;
		average += tex2D(SamplerCDBuffer2, texcoord) * 4;
		average += tex2D(SamplerCDBuffer2, texcoord + coord.xw) * 2;
		average += tex2D(SamplerCDBuffer2, texcoord + coord.zy);
		average += tex2D(SamplerCDBuffer2, texcoord + coord.wy) * 2;
		average += tex2D(SamplerCDBuffer2, texcoord + coord.xy);
		fragment = average / 16;
	}

not sure how fast this is in CPU space however.

FransBouma avatar Jun 16 '20 14:06 FransBouma

Fixed via #2219 !

JimBobSquarePants avatar Sep 12 '22 02:09 JimBobSquarePants