View Full Version : Median() plugin


ajk
11th February 2014, 14:18
Hi,

I've been capturing old tapes using the median method, ie. capturing the same tape several times to get rid of glitches and noise that do not appear in the same place each time.

There is no Median() function in AviSynth, although there are ways to script it using other plugins. That works fine but I thought I'd take a stab at a bespoke plugin for this purpose. I have no experience whatsoever with AviSynth plugin development but I have managed to get something done over the last week.

If anyone would be so kind as to try this out, I could iron out any bugs and then make a proper readme and stuff for it.

Things to notice:

- the plugin will accept between 3 and 25 clips
- chroma processing can be turned off with "chroma=false", or in the case of RGB32 this will turn off processing for the alpha channel
- there is also a more configurable MedianBlend() function, see examples in the readme or posts further below

Any feedback is appreciated!

# Usage:

Median(clip1,clip2,clip3..., chroma=true/false)


Packages also available for download over here (http://ajk.kapsi.fi/projects/avisynth/median-plugin/).

StainlessS
11th February 2014, 17:18
Would have been nice if source were supplied, I was gonna give it the once over.

ajk
11th February 2014, 17:21
Will do once I've cleaned it up. I also realised that this is probably the debug build, not sure if it will work properly without having Visual Studio or at least some bits of it installed. Will update again later.

StainlessS
11th February 2014, 18:13
Just taken a look, Uses MSVCP120D.dll and MSVCR120D.dll, think the D in 120D signifies debug runtime library.
Above runtimes for Visual Studio 2013, I'm guessing that not too many people have those runtimes installed (I dont, yet).
As VS 2013 will give lots of people problems with missing runtimes, suggest static link with runtime libraries.

EDIT: /MT
http://msdn.microsoft.com/en-us/library/2kzt1wy3.aspx

EDIT: Or, point people to the runtimes here:- http://www.microsoft.com/en-gb/download/details.aspx?id=40784

EDIT: It seems that I do have VS 2013 runtimes installed, but not the debug versions, so must not be included in the runtimes
as linked above, must not release debug versions.

ajk
12th February 2014, 08:10
Yeah sorry about that, I rarely work with Windows desktop programming so I tend to forget these things. I have now uploaded a release version of the plugin linked with /MT, so that should hopefully work without extra effort. There is also a separate archive with the source code.

ajk
13th February 2014, 13:55
I uploaded a new version now which can also handle planar and RGB clips. I didn't really have such raw clips to test with but at least when converted within AviSynth my YUY2 test clips seemd to process correctly. There is also a separate download link for the files now.

TurboPascal7
13th February 2014, 14:05
You should call NewVideoFrame inside GetFrame rather than storing it as a class variable.
Also, current build doesn't seem to work. Access violation writing 0x0000000.

StainlessS
13th February 2014, 14:37
@Ajk, Thanx, I'll take a peek when it clears (those moderators have such an easy time of it here :))

Perhaps you will need a file host service if you are going to be posting zips, I currently use MediaFire but it has been getting a bit annoying of late,

Mediafire lately seems to have been embracing the dark side. I suggest you move your stuff to dropbox.com, much lighter and no popups. I did. :)

I'm currently in process of signing up to DropBox, requires a 36MB download exe (downloading now), presume something like GDrive.

ajk
13th February 2014, 17:19
@TP7

Ok, I could change that. Have to look into that access violation, seemed ok when I posted...

@StainlessS

That's why I also posted the secondary download link :) Maybe I need to make it stand out more...

StainlessS
13th February 2014, 17:40
Ooops, did not see that link, perhaps bright red animated gif for us blind people :)
Taken brief look, only real thing I've seen yet is redefinition of i error in Constructor (VS6 compiler, might as well make it compile everywhere),
and the NewVideoFrame issue posted by TurboPascal7.
Have not as yet tried out the dll, curious what args access Violation occurs with, num clips and colorpspace, or always.
I shall take the text to the pub to peruse in there, ta ta.

Groucho2004
13th February 2014, 17:58
I'm currently in process of signing up to DropBox, requires a 36MB download exe
No, it does not. You don't need that to upload and share your files.

StainlessS
13th February 2014, 18:02
Thank you Grouchy :), had not intended to use any installed app, but takes you straight to download page after
signup, so thiought may be necessary, shall give the exe at least a cursory try though as I've already downloaded it.

ajk, just move the other link adjacent to the attachments (did not re-read the full post, just attachment status).

Gavino
13th February 2014, 18:52
You should call NewVideoFrame inside GetFrame rather than storing it as a class variable.
Also, current build doesn't seem to work. Access violation writing 0x0000000.
The access violation is very likely a result of the first issue.
Since you are using and returning the same PVideoFrame for all frames, it won't be writable after the first frame, so GetWritePtr() returns a null pointer.

StainlessS
13th February 2014, 18:59
v2.5 dll running on v2.6 Avisynth will process v2.6 planar colorspace Chroma incorrect due to IsPlanar() rather than IsYV12().
Can use IsPlanar() if processing Luma only.

EDIT: 2.5 header will eg give GetRowSize as for Yv12.

something I use in constructor


# ifdef AVISYNTH_PLUGIN_25
if(vi.IsPlanar() && vi.pixel_type != 0xA0000008) {
// Here Planar but NOT YV12, If v2.5 Plugin Does NOT support ANY v2.6+ ColorSpaces
env->ThrowError("RT_Stats: show version unsupported for colorSpace in v2.5 plugin");
}
# endif


EDIT: Correction, v2.5 dll, Both IsPlanar and IsYV12 will return true for all planar colorspaces, should perhaps check that it is
actually YV12 you are dealing with when touching chroma.

ajk
13th February 2014, 19:46
Okay, I've fixed the output video frame issue. That actually came over from the "Average" plugin, which I came across while searching for a median function. But Average consists of two classes so there everything gets initialized properly each frame. Interesting that this worked for me during all my testing.

I've updated the attachments again (sorry moderators :)). I made a note of the chroma issue in the readme, but will otherwise leave it for now, since often luma processing is useful enough as it is. I did in fact test with YV16 and YV24 and got only partial results for the chroma planes (half or a quarter, which makes sense now). Have to look into this more later but those formats seem to be kinda uncommon anyway.

ajk
15th February 2014, 08:23
Not too much interest in this I guess? I've now extended the support to 25 clips, and added some extra functionality in the form of MedianBlend(). This will accept any number of clips between 3 and 25, discard some amount of highest and lowest values on a per-pixel basis, and average the rest together.

For example, you can achieve a minimum or maximum function, or combine averaging with median:


# Discard two highest values
MedianBlend(clip1,clip2,clip3, low=0, high=2)

# Discard two lowest values
MedianBlend(clip1,clip2,clip3, low=2, high=0)

# Discard highest and lowest value and average the two remaining ones
MedianBlend(clip1,clip2,clip3,clip4, low=1, high=1)

I'm sure this is pretty familiar with the regulars here, but just as a concrete example of what median does with three captures, here's an image:

http://forum.doom9.org/attachment.php?attachmentid=14044&d=1392448797

We start with three captures, all of which have various black and white streaks. But after sorting the pixel values we end up with three different images, the first one has all the black streaks, last one all the white streaks, and the middle (median) one is quite clean. Depending on how noisy the tape is, five or more captures can help further.

TurboPascal7
15th February 2014, 09:43
I was thinking about writing an optimized temporal-only median some time ago but didn't find any real use for it. Apparently people rarely want to calculate median of more than 5 frames and that can be implemented efficiently with existing tools.

IMHO, your plugin has at least two problems:
1) Most of the times (most of the use cases I've seen) people want to calculate temporal median of a single clip, i.e. "merge" frames 0, 1, 2, 3 and 4 together rather than taking them from completely different clips. With your plugin this is quite cumbersome and requires a few deleteframe/duplicateframe/trim calls to build those multiple clip arguments.

On the other hand if you have a temporal median filter, it's easy to use it with multiple clips by simply calling interleave().median().selectevery(), just like it works with e.g. motion-compensated denoising. This won't work when you need even number of clips but that can be worked around by something like variable forward/backward radii maybe.

I guess people having access to multiple recordings of the exactly same stream is quite uncommon.

2) Your plugin is slow. Optimizing purely temporal median is a trivial task and I don't know why you didn't do this. Probably doesn't matter that much on SD recordings but why pay more when you can pay less?
There are already ways of doing some of the cases more efficiently. Radius 2 is simply mt_average, radius 3 median is Clense(), which is very fast. Radius 5 median is not so trivial, but can be done efficiently with masktools and clense (from here (http://mechaweaponsvidya.wordpress.com/2014/01/31/enter-title-here/)):
function median5(clip a,clip b,clip c,clip d,clip e)
{
abmin = mt_logic(a,b,"min")
abmax = mt_logic(a,b,"max")
cdmin = mt_logic(c,d,"min")
cdmax = mt_logic(c,d,"max")
x = mt_logic(abmin,cdmin,"max")
y = mt_logic(abmax,cdmax,"min")
interleave(x,y,e).clense().selectevery(3,1)
}
You can figure other radii yourself, simply implement the same sorting network with masktools. Yes, it will probably be less memory-efficient but a lot faster in general thanks to very fast SIMD min/max operations.

Now, this won't work with YUY2 and this is where YV16 shines - you simply convert your YUY2 clip to YV16, process it with planar-only (and YV16-aware) filters and convert back if you want to keep YUY2. No additional code for YUY2 required so people can optimize planar to skies to speedup most use cases (no planar RGB though). This also ensures that you're using same processing code for all colorspaces and people won't end up with different results if they happen to pass YV16 and not YUY2 to your plugin. For example your YUY2 chroma output is quite different from YV12 because you calculate median of U and V channels together when processing YUY2 and separately when processing planar formats. This is confusing.

If you want to add some optimizations yourself, feel free to look how it's done in MedianBlur2 (https://github.com/AviSynth/MedianBlur2/blob/7db2c995e72fbc615ee138f748d9c7474de9be2b/MedianBlur2/special.h#L198). Same sorting business, nothing really fancy here. If all frames are 16-byte aligned (almost always in avisynth 2.6, especially avs+), you don't even have to do any border processing and it's trivial in any case.


Anyway, good luck, glad to see people writing avs plugins in 2014. :)

ajk
15th February 2014, 11:47
Thank you for your comments! I agree that the plugin is not particularly optimised at least right now, but I wanted to get all the functionality that I need implemented first. It would be great to have an optimised median function as a core filter, but I guess there hasn't been enough need for one.

There are various reasons for making a plugin rather than using scripting. First, I simply like the convenience of having a single, straightforward function to call for all kinds of different situations and colour spaces. Second, the speed could probably be improved but the whole motivation for this exercise was exactly the case of an analog tape, where you can "easily" make multiple captures, as many as you need to get rid of all the noise. This is a common method, many threads regarding the matter on related forums. Of course, this does not really come up with HD material which is almost always digital. I understand that there may be other use cases for a median function where another approach can be better.

There shouldn't be any difference in the chroma output between interleaved and planar input. The processing for each "stack" of any sort of samples is the same (the ProcessPixel() function, perhaps not the most accurate name). Have you got a sample of where there was a difference?

TurboPascal7
15th February 2014, 12:06
There shouldn't be any difference in the chroma output between interleaved and planar input. The processing for each "stack" of any sort of samples is the same (the ProcessPixel() function, perhaps not the most accurate name). Have you got a sample of where there was a difference?
The difference is how you build the array you pass to that function.
for (unsigned int i = 0; i < depth; i++)
{
luma[i] = srcp[i][x * 2];
chroma[i] = srcp[i][x * 2 + 1];
}
In YUY2, data is stored as YUYVYUYVYUYV, so your chroma array will get UVUVUVUV... instead of UUUUU/VVVVV as it should.

ajk
15th February 2014, 12:12
for (int x = 0; x < width; x++)
{
for (unsigned int i = 0; i < depth; i++)
{
luma[i] = srcp[i][x * 2];
chroma[i] = srcp[i][x * 2 + 1];
}

dstp[x * 2] = ProcessPixel(luma);
dstp[x * 2 + 1] = ProcessPixel(chroma);
}


The processing here essentially advances one sample-pair at a time. In each iteration there is one luma sample, and one chroma sample from some number of clips. The chroma sample type alternates between U and V. To get an array with U and V mingled would mean that the different clips scrp points to are not properly aligned, no?

TurboPascal7
15th February 2014, 12:18
Oh sorry, I'm dumb and keep thinking about spatial processing.
I guess I should have actually checked with YV16 instead of YV12 where difference comes from different chroma subsampling. You can just ignore that part.

ajk
15th February 2014, 17:03
Your plugin is slow

I'll have a closer look at how much space for optimisation there is. But what is a reliable way to gauge the speed of a filter?

I did some testing with VirtualDub's "run video analysis pass". I took a short segment of my five sample clips and converted them to YV12, Interleave()'d them all and ran the analysis, this gave around 100 fps. This was just to establish how fast I can even load five clips simultaneously, without any heavy filtering.

Then I ran the Median5() you posted against my filter, both ran pretty much at the same speed, about 21 fps.

I also took Median1() from here (http://forum.doom9.org/showthread.php?t=159780), and ran that against my filter with three input clips. The result again was quite similar, about 37 fps.

I made sure to close the file in VirtualDub between each test as caching seems to affect the results, running a second pass immediately after the first yields much faster results.

What did you use to see such a big difference in speed? I'm not running AviSynth+ yet so that might be a factor.

Here's the script I used, for reference.

SetMTMode(3,0)

clip1 = AVISource("capture1.avi").ConvertToYV12(interlaced=true)
clip2 = AVISource("capture2.avi").ConvertToYV12(interlaced=true)
clip3 = AVISource("capture3.avi").ConvertToYV12(interlaced=true)
clip4 = AVISource("capture4.avi").ConvertToYV12(interlaced=true)
clip5 = AVISource("capture5.avi").ConvertToYV12(interlaced=true)

SetMTMode(2)

#interleave(clip1,clip2,clip3,clip4,clip5)

#median5(clip1,clip2,clip3,clip4,clip5)
#median(clip1,clip2,clip3,clip4,clip5)

median1(clip1,clip2,clip3)
#median(clip1,clip2,clip3)

Reel.Deel
15th February 2014, 17:50
But what is a reliable way to gauge the speed of a filter?

AVSMeter (http://forum.doom9.org/showthread.php?t=165528) is a very good tool for that purpose.

ajk
15th February 2014, 18:07
@Reel.Deel

Sweet! Nifty tool. I ran the same four scripts again and for median of five I got 20.53 fps (script) vs. 20.31 fps (plugin), and for median of three 37.00 fps (script) vs. 38.20 fps (plugin). Doesn't seem too bad to me. Maybe someone else can verify.

TurboPascal7
15th February 2014, 23:25
You're most likely limited by speed of 5 AviSource calls, while I test only with processing one clip. Or your PC doesn't have SSE2 but that would be kinda strange.

ajk
16th February 2014, 07:35
Ok, well I did one more test with just one clip to simulate a temporal median:

#median5(clip1,clip1.Trim(1,0),clip1.Trim(2,0),clip1.Trim(3,0),clip1.Trim(4,0)) # 163.0 fps
median(clip1,clip1.Trim(1,0),clip1.Trim(2,0),clip1.Trim(3,0),clip1.Trim(4,0)) # 152.4 fps

The masktools version wins by a little bit but I still wouldn't call mine slow with a bold typeface :) This is on an i7-2600K.

Anyway, this was really intended to continue what Average (http://forum.doom9.org/showthread.php?t=100626) was doing. The question of a median function arose in that thread years ago but apparently was never implemented (probably exactly because there were alternatives at least for the most common 3 and 5 clip cases).

ajk
15th March 2014, 13:52
I've updated the plugin to 0.5, chroma=false was not working right with planar clips.

I also added a TemporalMedian() mode in case it is useful to someone. You could use it as a denoiser within one clip if the video doesn't have much movement and you keep the radius small. Otherwise the results can be pretty funky :) But realistically for actual denoising other filters are more appropriate.

The filter accepts a radius between 1 and 12, corresponding to a median of 3 to 25 frames.

TemporalMedian(clip, radius=2) # Median of current, two preceding, and two following frames

althor1138
17th February 2017, 22:01
Hi Ajk. Great idea for a filter and seems to be the only median type of filter that goes in the direction I want it to. I have one question though.

Does the temporalmedian have an option for high and low parameters like the medianblend? This would make it easy to interleave 3 or more separate sources(separate laserdisc releases, for example), motion compensate them, and feed them to your filter while retaining the ability to throw away high or low pixel values. This should allow for removal of dropouts present on the disc and errors during playback.

jmac698
18th February 2017, 09:51
I should point out my summary of this technique and further features you could add.
http://www.digitalfaq.com/forum/video-restore/2734-averaging-multiple-captures-3.html#post45498

You could add this

-With 7 or more captures, eliminating extremes and averaging is better at reducing noise than median.
-...gives more weight to the middle values

So if I could give weights to the sorted values, for example (0,1,1,0) would be the average of the two middle values, excluding the black/white extremes. That syntax would include all previous features as well.

I should add that my magical number 7, refers to median giving 80% the noise reduction as average, or sqr(2/pi), and 7 is the point where avg(5) beats median(7). In my experience though, streaks can still appear in some of the middle values. A much better streak reduction would include some attempt at masking streaks.
You could destreak with median, subtract from original, clean it up, then use that as a mask and average all the pixels that aren't streaked, to get 20% better noise reduction.

ajk
18th February 2017, 13:06
@althor1138

Hi, the temporal version of the filter does not currently have those parameters. But if I understand your idea correctly, you should be able to interleave the clips, motion compensate, and then separate them again with SelectEvery(). After that you can use the other versions of the filter on those clips as normal.

If you've got some sample material, perhaps you could give this a try and see how it turns out?

@jmac698

I implemented that (0,1,1,0) suggestion of yours already three years ago (http://forum.videohelp.com/threads/362361-Median%28%29-plugin-for-Avisynth?p=2302015&viewfull=1#post2302015) when you asked about it over at VideoHelp :) Or do you need the weight values to be floats or something?

Adding masking functionality and such gets a bit complicated within a single plugin, I'd say it's better to go with separate plugins and scripting when venturing there.

Reel.Deel
18th February 2017, 22:58
@ajk

Since the source code for the latest version (v0.6) is not available can you please provide a 64-bit binary? Y8, YV16, and YV24 colorspaces would be great also. :)

ajk
20th February 2017, 14:02
@Reel.Deel

Yeah, the only difference in 0.6 is the added sync stuff, which is still a bit messy and not well commented. But I'll try to make a more modern build when I have some time; adding the colour spaces is trivial.

Aktan
10th February 2018, 03:33
I'm getting an access violation when I try to use a 64-bit dll of version 0.5 that I compiled locally. I'm using AVS+. I'm guessing it's due to using Avisynth interface version 3, or is it something else silly that I've done?

StainlessS
10th February 2018, 13:37
Yep, you will need latest AVS+ headers for 64 bit (#include "avisynth.h"),
and add path to AVS/ additional headers to options (I dont have VS set up at the moment, but need add to both 32bit and 64 options).

in AVS/ folder

alignment.h
avisynth.h
capi.h
config.h
cpuid.h
minmax.h
types.h
win.h


EDIT: I usually copy avisynth.h into current/source folder and is also in avs/ directory as set in options.

EDIT: From FrameStore

#include <windows.h>
#include "avisynth.h" // Avs+26, also needs Options/Projects & Solutions/Include/ directory set to additional avs headers

Make sure set for both 32 and 64 bit options (there is an easily missable 32/64 bit drop down selector in the options).

Aktan
10th February 2018, 13:42
Yep, you will need latest AVS+ headers for 64 bit (#include "avisynth.h"),
and add path to AVS/ additional headers to options (I dont have VS set up at the moment, but need add to both 32bit and 64 options).

in AVS/ folder

alignment.h
avisynth.h
capi.h
config.h
cpuid.h
minmax.h
types.h
win.h


EDIT: I usually copy avisynth.h into current/source folder and is also in avs/ directory as set in options.

:thanks:, I'll try that!

Edit: I did do some debugging, and it's related to how arrays are handle. If I change it to do a constant number of clips that I need (ccc instead of c+), it works fine. This is before I try the AVS+ headers.
Edit 2: So apparently for whatever reason, AVS+ doesn't like the line:

AVSValue array = args[0];

Changing all references of array to args[0] fixed the problem. It's probably pointer related, but I'm not good enough of a C++ programmer to tell, lol.

ajk
11th February 2018, 07:37
Got an email about a thread update :) I had to reinstall my system last year and haven't really got the development stuff set up since then. I should look into an AVS+ version of the plugin at some point but this just hasn't been much of a priority unfortunately :(

But here is the source for v0.6 nevertheless, it's the same as far as the actual median processing goes but it now includes the sync and debug stuff: http://ajk.kapsi.fi/projects/avisynth/median-plugin/Median-0.6-src.zip

@Aktan

I'll be happy to host any versions and changes you come up with, too :)

jpsdr
11th February 2018, 12:30
I've made a VirtualDub median filter a long time ago to remove white dots on VHS, but i've added a parameter : a threshold.
And there is 3 mode : square, line horizontal, line vertical.
You can find it on my github.

FredThompson
11th February 2018, 15:41
Not too much interest in this I guess?
Quite the contrary. There were only 4(?) days between your initial post and this one and there were clearly runtime issues. Your idea and code caught the attention of some of the most active/best coders here. If an idea is good and the time is right, it generally catches on.

To me, this looks fantastic. I've got a few hundred tapes to process and the cleanup time has always been so great that I haven't been motivated to do it...even though I'm aware the longer the tapes sit, the sticker they get and the more magnetic migration happens.

Given the cost of drive space now, setting up a dedicated PC and capturing a complete tape 5 times then calculating median as an interim file is very attractive.

Aktan
11th February 2018, 19:06
Got an email about a thread update :) I had to reinstall my system last year and haven't really got the development stuff set up since then. I should look into an AVS+ version of the plugin at some point but this just hasn't been much of a priority unfortunately :(

But here is the source for v0.6 nevertheless, it's the same as far as the actual median processing goes but it now includes the sync and debug stuff: http://ajk.kapsi.fi/projects/avisynth/median-plugin/Median-0.6-src.zip

@Aktan

I'll be happy to host any versions and changes you come up with, too :)

Thanks for releasing the source code for 0.6! Honestly, with the new VSC2017, setting up the dev takes like 30 mins. Just get the VS
Installer and click some check boxes, and bam! Done!

Sure, I'll compile 0.6 to 64-bit and link you. I don't think I will update it to AVS+ headers though. I'll just fix it to work with the older header like I did with 0.5.

I've made a VirtualDub median filter a long time ago to remove white dots on VHS, but i've added a parameter : a threshold.
And there is 3 mode : square, line horizontal, line vertical.
You can find it on my github.

Cool! Great addition!

Quite the contrary. There were only 4(?) days between your initial post and this one and there were clearly runtime issues. Your idea and code caught the attention of some of the most active/best coders here. If an idea is good and the time is right, it generally catches on.

I think you missed the year the initial post happened...

ajk
11th February 2018, 19:10
@FredThompson

Four days and four years :D But yes, the core concept has worked well for me. It's not always worth it for tapes that play clean anyway, but for some of the more stubborn ones it has worked great.

@Aktan

Yeah, I will get round to it some day :) I'll be happy to host your compilation in the mean time so everything stays in the same place.

Aktan
11th February 2018, 19:39
@Aktan

Yeah, I will get round to it some day :) I'll be happy to host your compilation in the mean time so everything stays in the same place.

Here you go:

<Link Removed>

It contains the changes I did and the compiled 64-bit DLL. I did compile with VSC2017 and Win10SDK so I think it will work fine Vista 64-bit+ but I'm just guessing.

ajk
11th February 2018, 19:56
@Aktan

Thanks - I uploaded it with the others at http://ajk.kapsi.fi/projects/avisynth/median-plugin/Median-0.6-x64.zip

FredThompson
11th February 2018, 21:58
I think you missed the year the initial post happened...Oh, yeah. Guess I should finally admit I'm getting old and vision isn't quite what it used to be....Age is an economical version of beer goggles...

ChaosKing
2nd March 2018, 20:40
Big thx for this filter, it worked very good on a Anime DVD opening/ending. With MedianBlend(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, low=3, high=3) nearly all compression artefacts were gone!

jmac698
6th August 2018, 06:09
Just wanted to mention an O(n) sorting algorithm, which is essential for finding a median.

#Fibonacci Sort
unsorted = [3, 1, 4, 1, 5, 9, 2, 6, 0]
counts = [0] * 10
fib = [0] * (10 + 1)
sortd = [0] * len(unsorted)

#First pass: find the counts
for n in unsorted:
counts[n]+=1

#Second pass: do the Fibonacci magic
i = 0
total = 0
for n in counts:
fib[i] = total
total += n
i+=1

#Third pass: output sorted
for n in unsorted:
sortd[fib[n]] = n
fib[n] += 1

#Results
print(sortd)


I invented this years ago, but now realize it's called the counting sort. It doesn't need comparisons.

I believe @StainlessS asked me about this once, and said he collected sorting algorithms?

TheFluff
6th August 2018, 07:11
You are aware that there is a constant time algorithm for median filters, yes? As in O(1), does not scale with radius at all. tp7 linked his implementation on page 1, four years ago.

StainlessS
6th August 2018, 11:17
I believe @StainlessS asked me about this once, and said he collected sorting algorithms?

Dont recall that, I have some interest in sorting/searching but would not really say that I collect said stuff.
Nice to see you about again JMac :)

EDIT: I'll post at some point a version of PlanetCrop that runs with either avs+ or GScript.
EDIT: Posted PlanetCrop in RT_Stats thread.

jmac698
6th August 2018, 14:24
Not true - the paper says it's O(1) per pixel because they cache some results, but mine is O(1) in that sense also. since I only have 3 operations per pixel which are constant. Also a median is not the same as producing one sorted list of all pixels; in that sense both are O(n). Clearly you can't sort anything in O(1) because you must access the memory in steps, and you can't read a whole screen at once unless it's massively parallel.

Edit: I believe our algs are basically the same, count is the same as histogram

TomArrow
14th January 2019, 14:16
Hey there, I was wondering if it would be at all thinkable to introduce RGB64 support to this plugin. Have never done any plugin coding myself, so not sure if I could handle it, but on the surface it sounds like it shouldn't be too difficult. Could anyone help out or point me in the right direction to do it myself?

Aktan
14th January 2019, 23:32
Hey there, I was wondering if it would be at all thinkable to introduce RGB64 support to this plugin. Have never done any plugin coding myself, so not sure if I could handle it, but on the surface it sounds like it shouldn't be too difficult. Could anyone help out or point me in the right direction to do it myself?

I think it wouldn't be too hard as RGB64 is similar to RGB32 just different bits. I would just look at the source to see how RGB32 was done.

ajk
15th January 2019, 07:26
Hi, should be fairly straightforward, but I haven't been doing much with this recently and haven't got the development environment set up. I may look at this in the future myself, but if anyone can add support in the mean time I'll be happy to include and host the changes.

pinterf
15th January 2019, 08:45
Just a note: instead of RGB64 I recommend a generic planar RGB support.

TomArrow
31st January 2019, 12:23
Okay, so I managed to open the solution of the Median 0.6 src in VS 2017. Retargeted to v141 toolset (because that's the lowest I can use in VS2017 I think) and it compiled just fine.

Now, I have some very basic coding knowledge, but I've never done any AviSynth plugins, not even worked on one. Can someone point me in the right direction on how to add RGB64 support?

Edit: I have now even managed to update the code to the v6 API (hurray me!), so I'm mildly optimistic I will somehow be able to hack this together. :D

Edit 2: I DID IT! Well, it's not perfect I'm sure, but it works. Got some help from some C++ Discord. Well, technically they wrote half of it, but hey, at least it's done.

Source is attached, compiled x86 DLL is here: https://www.mediafire.com/file/qe56dtuz1ntz5m4/Median-0.6-AVS+-withRGB64support.zip/file

Now, if only I knew how to extend the solution to be able to compile a 64 bit version too ... because my avs-file has become so bloated that it only manages to output 2 frames before getting a memory error. :P

But hey, it's AVS+ headers now, so maybe someone can tune in and add 64 bit support? That'd be splendid. Or tell me how to do it and I'll do it.

TomArrow
1st February 2019, 09:42
Damn, I think I found some errors in the code, better don't use the one I posted, it may not be actually doing a real Median. gotta wrap my brain around this...

Edit: Nevermind, false alarm.

TomArrow
1st February 2019, 10:22
Alriiight. Finally, here we are. Wasn't so hard doing the x64 after all.

So in summary, these files:
- Support RGB64 (but not the fast processing mode that's supported in the 8-bit color spaces)
- Implement the new AviSynth+ API (V6)
- Have both 32 bit and 64 bit platforms set up for VS 2017 (not sure if backwards compatible for older VS versions, but maybe?)

The way I did it might not be the most elegant way, so feel free to improve on my work, I'm a newbie after all.

Enjoy, and thanks again for the original work on this plugin. :)

ajk
2nd February 2019, 07:08
Great! I haven't gone through the code in detail but looks fine to me. Should I upload your work in with the other versions so everything is hosted in the same place?

TomArrow
2nd February 2019, 09:20
Great! I haven't gone through the code in detail but looks fine to me. Should I upload your work in with the other versions so everything is hosted in the same place?

Sounds like a good idea. :)

ajk
3rd February 2019, 07:56
Done - I added a very short readme which contains a link to your post above :)

TheGenesis
16th September 2019, 22:34
Wow!!!

Thats an impressive approach.

I have always tried to cleanup my 30 years old Betamax tapes wich I had recorded using a surveillance camera (b/w tube sensor) but couldn't get rid of the noisy line jitter without loosing sharpness.
Yesterday i captured the same sequence 6 times and used MedianBlend() with cutting the lowest and highest outliners. The results are phenomenal. 80% of the noise are gone without any loss on the edges.

Many thanks to ajk and all you guys for making this happen!

ajk
17th September 2019, 09:09
Very nice to hear you have had success with this method! Got any before/after shots you could share?

I finally managed to get all of my own Hi8 tapes captured, it is definitely pretty labor intensive to deal with multiple lossless captures, but worth it in the end for important tapes.

TheGenesis
18th September 2019, 21:04
I'm not done yet. Trying to repair some other issues, such as "replacing only dead parts of a frame" and a watermark wich was burned in the camera sensor.
btw... you have made yourself a hard time lining up multiple captures by hand. I stumbled over a great filter to automate this:

https://forum.doom9.org/showthread.php?p=580999#post580999

That allows you to syncronize multiple peaces and the only thing you have to do is cutting them near the same start and end frame.

LoadPlugin("c:\Program Files\AviSynth\plugins.manual\matchclips.dll")

LoadPlugin("c:\Program Files\AviSynth\plugins.manual\Median.dll")

source1=AviSource("Cap0914_002_topO_RAW.avi" , audio=false).ConvertBackToYUY2()
source2=AviSource("Cap0912_003_mainO_RAW.avi", audio=false).ConvertBackToYUY2()
source3=AviSource("Cap0912_002_main_RAW.avi" , audio=false).ConvertBackToYUY2()
source4=AviSource("Cap0912_001_main_RAW.avi" , audio=false).ConvertBackToYUY2()
source5=AviSource("Cap0914_003_topO_RAW.avi" , audio=false).ConvertBackToYUY2()
source6=AviSource("Cap0914_001_top_RAW.avi" , audio=false).ConvertBackToYUY2()

cntSeekPrev=20
cntSeekNext=80

clip1=source1
clip2=mcshowframe(source1,source2,mcanalyse(source1,source2,cntSeekNext,cntSeekPrev))
clip3=mcshowframe(source1,source3,mcanalyse(source1,source3,cntSeekNext,cntSeekPrev))
clip4=mcshowframe(source1,source4,mcanalyse(source1,source4,cntSeekNext,cntSeekPrev))
clip5=mcshowframe(source1,source5,mcanalyse(source1,source5,cntSeekNext,cntSeekPrev))
clip6=mcshowframe(source1,source6,mcanalyse(source1,source6,cntSeekNext,cntSeekPrev))

# Discard highest and lowest value and average the remaining ones
#return( MedianBlend(clip1,clip2,clip3,clip4,clip5,clip6, low=1, high=1) )

StackVertical(
\ StackHorizontal(
\ StackHorizontal(
\ clip1
\ ,clip2)
\ ,clip3)
\ ,
\ StackHorizontal(
\ StackHorizontal(
\ clip4
\ ,clip5)
\ ,clip6)
\)

The last line is only to visualize the synchronisaton on all clips.

ajk
19th September 2019, 06:45
Looking forward to seeing your results!

The latest version of my plugin actually has an automatic sync feature. It didn't get discussed much here on Doom9 but there are some samples over at VideoHelp: https://forum.videohelp.com/threads/362361-Median()-plugin-for-Avisynth#post2418590

It's still best used with care, as with static scenes the noise can have a larger effect on the calculated difference than the actual content. I use it semi-manually, first with debug output activated and a large search radius to get the clips aligned, then dialed down to just a radius of 1 or 2 to take care of any remaining drops. This approach worked very well with my Hi8 tapes at least.

TheGenesis
25th September 2019, 23:32
Puh! ... that was harder than i thought.

The automatic from MatchClips is not accurate enought ... neither your sync-feature.
But its not your fault ... I have discovered, that the material I'm working with has parity-swaps all over the place ... I had to manually align the hole clip (84min) ... urgs.
Finally I reverted back to Median() because it preserves more details and doesn't fool my deinterlacer to interpolate jumpy fields in between :)

Here the results:

http://genesis-web.de/updown/BEFORE_6444-6823_crf24.mp4

http://genesis-web.de/updown/AFTER_6444-6823_crf14.mp4

each file is about 2MB in size.
I had to squeeze the source material into crf24 ... crf14 produces a 17MB file :)

johnmeyer
25th September 2019, 23:45
I first experimented with multiple VHS captures about the time you joined this forum (2002). It works great, but all the field changes ("parity changes") at scene changes are a killer.

When it works, it is one of the greatest noise reduction techniques around, because there are virtually no residual artifacts, and the result looks really natural.

However, after trying it on a few tapes, I gave up because between the time it took to do three captures and the time it took to align everything, I was spending half a day on just one tape.

Your results look impressively good, but was all of the improvement nothing more than averaging multiple captures? It seems like you got rid of time base errors and also a fair amount of vertical jitter.

TheGenesis
27th September 2019, 00:12
Indeed this is not only cleaned up by averaging. But aligning and averaging was essential to minimize the jitter. Also it increases about 30% of the details for the final filter.
I have done this with multiple steps:

First I made myself a script for the manual alignment that is very fast (if you have a bunch of cores) and aligned my 6 captures.
Then I separately median() the fields (with sync=0) and store the weaved() result lossless to disk.
After that I corrected the lightning errors by tuning the Y-offset, Gamma and Blacklevel,
I manually created a good noise profile of the material to feed into Neat().
I'll tuned QTGMC(), wrote a script to damp the bouncing() even more and finally ran the folowing Script:

#
# EdiusNX-capture.avs
#

SourceFile="SOURCE\Tape1\Tape1_fields.avi"
NeatDeviceNoiseProfile="SecurityCam_SLF30_ES10_EdiusNX.dnp"
NeatNoiseFilterPreset="SecurityCam_SLF30_ES10_EdiusNX.nfp"

# Audio has to be delayed by 120ms when using an ES10 for stabilizing Video (and passing the Audio direct to the capture device)
CompensateForAudioDelay=120

ColorMatrix="Rec601" # Rec709
IsInterlaced=true

NeatTemporalRadius=5

# begin script ...

SetMemoryMax(900) # VD
SetMTMode(3,4)


LoadPlugin("c:\Program Files\AviSynth\plugins.manual\ThreadRequest.dll")

LoadVirtualDubPlugin("C:\Tools\Windows\VirtualDUB\plugins32\NeatVideo4.vdf", "NeatVideo", 5)

LoadPlugin("c:\Program Files\AviSynth\plugins.manual\masktools-v2.2.18\masktools2.dll")

LoadPlugin("c:\Program Files\AviSynth\plugins.manual\depanestimate110\DePanEstimate.dll")
LoadPlugin("c:\Program Files\AviSynth\plugins.manual\depan1131\DePan.dll")

Import("c:\Program Files\AviSynth\plugins.manual\QTGMC.avsi")
Import("c:\Program Files\AviSynth\plugins.manual\SMDegrain.avsi")
LoadPlugin("c:\Program Files\AviSynth\plugins.manual\RemoveGrain-1.0\RemoveGrainSSE3.dll") # ???old???
LoadPlugin("c:\Program Files\AviSynth\plugins.manual\mvtools-2.7.41-with-depans\mvtools2.dll")
LoadPlugin("c:\Program Files\AviSynth\plugins.manual\nnedi3\nnedi3.dll")
LoadPlugin("c:\Program Files\AviSynth\plugins.manual\RgTools-0.98\RgTools.dll")

Import("c:\Program Files\AviSynth\plugins.manual\CaptureTools.avsi")


AviSource(SourceFile, audio=false)
AssumeFrameBased
SetMTMode(2)
VideoFPS=last.FrameRate

last + BlankClip(last, length=(NeatTemporalRadius+1) ) # append blank frames for neat-prefetch

#Trim(3000,0)

AssumeTFF()

# Correct Luma-Errors
ThreadRequest()
ColorYUV(off_y=-14, gamma_y=-40) # Reduce overshooten brightness and enhance contrast (to preserve details in further processing)
Levels(16, 1.0, 255, 0, 235) # compensate for blackness
#return(last)

# Convert to RGB
ThreadRequest()
ConvertToRGB(matrix=ColorMatrix, interlaced=IsInterlaced)
#return(last)

# Denoise and Sharpen
ThreadRequest()
SetMTMode(6)
NeatVideo(NeatDeviceNoiseProfile, NeatNoiseFilterPreset)
SetMTMode(2)
#return(last)

ThreadRequest()
ConvertBackToYUY2()
ConvertToYV12()
#return(last)

# Deinterlace (high quality)
ThreadRequest()
QTGMC( Preset="Slow", EdiThreads=3, TR2=1, EZDenoise=0, NoiseProcess=0, Sharpness=0.4, FPSDivisor=1) # FPSDivisor=1 for double fps # ,Lossless=1 preserves original fields and also their mosquito noise on edges
#return(last)

# Stabilize Frame-Bouncing
ThreadRequest()
StabHomeCorner(dxmax=0, dymax=3)
#return(last)

# Crop off capture defects
ThreadRequest()
Crop(12,6,-12,-6)
#return(last)

# uphold A/V sync
trimFrames = int(last.FrameRate/VideoFPS) * (NeatTemporalRadius+1) # Remove neat-buffer-frames
trimFrames = trimFrames + int(last.FrameRate*CompensateForAudioDelay/1000)
trimFrames > 0 ? last.Trim(trimFrames, 0) : \
trimFrames < 0 ? BlankClip(last, length=(trimFrames*-1) )+last : last

########################################
# force SYNC (if M1 crashed, try M2) #
#SetMTMode(6) # Method1 -> Switch MT #
Distributor() # Method2 -> Insert Task #
return(last) # RETURN #
########################################

johnmeyer
27th September 2019, 01:10
OK, so you've done a huge amount of additional noise filtering. Since you ran both Neat and QTMGC, probably very little of the change between the original and final actually came from the median averaging of the six captures.

TheGenesis
27th September 2019, 08:44
As I said ... about 30% more Details/sharp edges (reduces mosquito noise) and without averaging I also couldn't get rid of the jitter.

I'll tried all sorts of combination ... I'd like to use alternates to Median(), but because of the parity switches (wich are still present in my first stage) this filter is the only one who can deliver frames wich will not end up in jerkiness when running through the deinterlacer.

For reference ... here is the apples to apples comparision without any postprocessing:

http://genesis-web.de/updown/BEFORE_6444-6823_unfolded_crf18.mp4
http://genesis-web.de/updown/AVERAGED_6444-6823_unfolded_crf18.mp4

I could write a script where every single frame from the master will be temporal syncronized in the slave, but this is overkill compared to the expected gains.

What I really would like is getting rid of the burned-in "watermark" from the camera but this is even not a trivial task :)

Spongology
27th September 2019, 10:02
I hardly work using windows desktop programming and is not so familiar about all these.

TheGenesis
27th September 2019, 21:03
In theory this "should" be not as hard.
You have a source and one frame with the watermark.
Then you have to subtract that watermark from the source.

lol ... actually there are a few rules to deal with or else you ruin you source.

One attempt I made was this:

WatermarkRAW = AviSource("Burn-In Watermark.avi").Trim(0,-1)
Black = WatermarkRAW.BlankClip(length=1)
Watermark = WatermarkRAW.Levels(136, 1, 255,0, 255) # mask -> only bright areas of watermark must be used to opage the black frame over the source
Overlay(last, Black, mask=Watermark, mode="multiply")

The problem is, that this is not dynamic enough. The watermark in the source clip only shows up in areas below a certain luminance threshold and only this areas have to be subtracted.
The approach above does this everywhere thus creating invers watermarks where they weren't in the first place :)

pinterf
29th September 2021, 14:02
Hi, could you tell me which license is used for the source? I was kindly asked to make it work under linux but since I'm using github I have to specify a license mode. Should I use the same licencing as Avisynth or MIT or what? Thanks.
(And let me know if all this port is done by someone else, let's not work twice :) )

ChaosKing
29th September 2021, 15:47
See filter.cpp
//////////////////////////////////////////////////////////////////////////////
// Median filter for AviSynth
//
// This filter will take in a number of clips and calculate a pixel-by-pixel
// median out of them. This is useful for reducing noise and glitches in
// analog tape captures, but may have other uses as well.
//
// Author: <email removed>
//
// License: Public domain. Credit would be nice, but do with this what you will.
//
// Forum thread: http://forum.doom9.org/showthread.php?t=170216
//
// History:
// 12-Feb-2014, 0.1: Initial release. YUY2 support only
// 13-Feb-2014, 0.2: Added support for RGB and planar formats
// 13-Feb-2014, 0.3: Fixed output frame buffer issue
// 14-Feb-2014, 0.4: Added MedianBlend functionality
// 15-Mar-2014, 0.5: Added TemporalMedian functionality

Btw there is also a Vapoursynth port https://github.com/dubhater/vapoursynth-median
and another filter written in rust here https://github.com/End-of-Eternity/vs-average

kedautinh12
29th September 2021, 16:06
I seen had a ported but not too much
https://forum.doom9.org/showpost.php?p=1864406&postcount=55

Reel.Deel
29th September 2021, 20:02
(And let me know if all this port is done by someone else, let's not work twice :) )

Aside from the VS ports posted above, TomArrow added RGB48/64 (post #55) but there was another version (also from TomArrow) that had an additional parameter. I just cannot find it at the moment, I believe it was over at Fanres forums.

Maybe TomArrow can chime in.

real.finder
29th September 2021, 20:09
name change also necessary since there are http://www.avisynth.nl/users/vcmohan/manyPlus/Median.html

ajk
6th October 2021, 11:10
@pinterf

Yes, public domain so use as you wish. If it is necessary to apply a license, feel free to choose the same model as Avisynth.

@ChaosKing

Could you please edit your post to remove my email address, I don't want to attract any more spam than already comes in :)

Orikson
18th February 2022, 19:18
First of all, thank you ajk and everyone involved in developing and testing this great plugin! I'm currently capuring my old Video8 tapes to the PC and have great results with it!

I just came over one improvement, that might be great to be done.

I'm capureing my analog signal with 10 Bit color depth so I can deal with any rounding error that might occur during capture and processing. This works fine, but unfortunatelly the median()-plugin only works with 8-bit color depth. I guess so, because the processed video shows a lot of "artefacts". I could explain this due to the 10 bit values stored in a too small variable (e.g. 8 bit) by the median()-plugin which will then cause an overflow. Calling the command ConvertBits(clip, 8) before the median()-command will fix this issue, but of course will get rid of the 10-bit color depth, which might already be handy during the mean calculation done by median().

Am I right with my assumption? I'm not too new to programming and took a look into the source code of your plugin. But I'm more into programming embedded electronics, so it's still hard for me to improve the code. Could you give me a hint about this problem?

ChaosKing
18th February 2022, 21:58
Both VapourSynth median plugins support 10 bit https://forum.doom9.org/showthread.php?p=1953377#post1953377
It is possible to use VS inside avisynth with http://avisynth.nl/index.php/VapourSource

kedautinh12
18th February 2022, 23:29
You can try:
Convertbits(16)
converttorgb64()

Before use this ver
https://forum.doom9.org/showpost.php?p=1864406&postcount=55

Orikson
22nd February 2022, 19:47
Ok thank you, I will try that :thanks:

ajk
23rd February 2022, 07:27
@Orikson

Yeah, indeed no 10-bit support in the original plugin, but please have a look at those options mentioned by others. Report back if you have success, I'm sure others might benefit from the information in the future :)

pinterf
2nd March 2022, 14:56
https://github.com/pinterf/AjkMedian
No windows zip release (didn't have 20 more minutes), just a quick and minimal mod in order to build it under Linux/gcc as well.
The file name of DLL was renamed to AjkMedian and DLL has version info (v0.7)
And a single addition: plugin is able to let through frame properties.

Orikson
3rd April 2022, 17:39
Report back if you have success, I'm sure others might benefit from the information in the future :)

Sure I will, but until now I could not figure out how to get this working :eek:

I gave up on VapourSynth after one day of trying. I guess I could get it working when switching completelly to VS. But now I'm already more into AviSynth and also are afraid of the "documentation" of VS :rolleyes:

So I tried the solution kedautinh12 suggested, even though I do not like the fact that I might need to do two color format conversations (YUV to RGB and back to YUV for output)...
You can try:
Convertbits(16)
converttorgb64()
Before use this ver
https://forum.doom9.org/showpost.php?p=1864406&postcount=55

The first format conversion seem to work and only causes some rounding errors. So I continued to use the median-Plugin on the converted clips but did not get a good result. The debug information was missing and the video was blury, especially during camera movements, see attatched file.

Am I doing something wrong here or is the RGB64 median plugin still buggy somehow? :confused:

clip1 = AVISource("video1.avi")
clip2 = AVISource("video2.avi")
clip3 = AVISource("video3.avi")
clip4 = AVISource("video4.avi")

/*
# - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Include this section to align the frames of all clips
clip1 = ShowFrameNumber(clip1, scroll=true)
clip2 = ShowFrameNumber(clip2, scroll=true)
clip3 = ShowFrameNumber(clip3, scroll=true)
clip4 = ShowFrameNumber(clip4, scroll=true)
*/

# - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Actually set the correct start and end frame of all clips
clip1 = Trim(clip1, 482, 0, pad=true)
clip2 = Trim(clip2, 190, 0, pad=true)
clip3 = Trim(clip3, 459, 0, pad=true)
clip4 = Trim(clip4, 378, 0, pad=true)

# - - - - - - - - - - - - - - - - - - - - - - - - - - - -
clip1_8bit = ConvertBits(clip1, 8)
clip2_8bit = ConvertBits(clip2, 8)
clip3_8bit = ConvertBits(clip3, 8)
clip4_8bit = ConvertBits(clip4, 8)

median_result_8bit = MedianBlend(clip1_8bit,clip2_8bit,clip3_8bit,clip4_8bit, chroma=true, low=1, high=1, sync=5, debug=true)

# - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Converted to RGB for comparison

clip1_RGB64 = ConvertBits(clip1, 16)
clip1_RGB64 = ConvertToRGB64(clip1_RGB64, matrix="Rec601", interlaced=true)

clip2_RGB64 = ConvertBits(clip2, 16)
clip2_RGB64 = ConvertToRGB64(clip2_RGB64, matrix="Rec601", interlaced=true)

clip3_RGB64 = ConvertBits(clip3, 16)
clip3_RGB64 = ConvertToRGB64(clip3_RGB64, matrix="Rec601", interlaced=true)

clip4_RGB64 = ConvertBits(clip4, 16)
clip4_RGB64 = ConvertToRGB64(clip4_RGB64, matrix="Rec601", interlaced=true)

median_result_RGB64 = MedianBlend(clip1_RGB64,clip2_RGB64,clip3_RGB64,clip4_RGB64, chroma=true, low=1, high=1, sync=5, debug=true)

# - - - - - - - - - - - - - - - - - - - - - - - - - - - -
return median_result_8bit # result is ok, debug working, but only 8-bit
return median_result_RGB64 # blury/jumping result, debug not working

Reel.Deel
3rd April 2022, 21:33
There are some inconsistencies in your script:

median_result_8bit = MedianBlend(clip1_8bit,clip2_8bit,clip3_8bit,clip4_8bit, chroma=true, low=1, high=1, sync=5, debug=true)

median_result_RGB64 = Median(clip1_RGB64,clip2_RGB64,clip3_RGB64,clip4_RGB64, chroma=true, low=1, high=1, sync=5, debug=true)

Median does not have the low and high parameters, you should of gotten an error if that is how you're actually using the script.

Also, please host the picture elsewhere, sometimes it takes forever and a day for the attachments to get approved here.

StainlessS
3rd April 2022, 21:53
Also, please host the picture elsewhere, sometimes it takes forever and a day for the attachments to get approved here.

How To post an image that appears in forum post, does not depend upon moderator approval of image (attachments sometimes never get moderator attention).
https://forum.doom9.org/showthread.php?p=1959414&highlight=postimage#post1959414

poisondeathray
3rd April 2022, 22:39
Likely not related to those overflow artifacts , but don't forget interlaced=true when performing ConvertToRGB64

Orikson
4th April 2022, 17:59
Likely not related to those overflow artifacts , but don't forget interlaced=true when performing ConvertToRGB64
Thank you for that reminder, but adding this does not change anything in my case

Median does not have the low and high parameters, you should of gotten an error if that is how you're actually using the script.
You are totally right, the Median (without Blend) happened while I was playing around and of course causes an error. I updated the code in my post above. Also I uploaded the image here:

https://i.postimg.cc/06KWtzCW/RGB64-median-blur.png (https://postimg.cc/06KWtzCW)

Reel.Deel
5th April 2022, 13:37
@Orikson

I'm not sure why it's not working for you but I made a synthetic test and the output is correct:

LSMASHVideoSource("YUV420P8.mp4")

a = AddGrainC(var=1.0, seed=1).Trim(1,0).ConvertToRGB64(matrix="PC.601")
b = AddGrainC(var=7.5, seed=2).Trim(2,0).ConvertToRGB64(matrix="PC.601")
c = AddGrainC(var=15.0, seed=3).Trim(3,0).ConvertToRGB64(matrix="PC.601")
d = AddGrainC(var=30.0, seed=4).Trim(4,0).ConvertToRGB64(matrix="PC.601")

MedianBlend(a,b,c,d, chroma=false, low=1, high=1, sync=5, debug=true)

Don't mind matrix="PC.601", I only used it because it's probably a good idea not to do a range conversion since the output is probably going back to YUV and can avoid multiple limited to full range conversions.
Oh and I set chroma parameter to false because when it's true it also processes the alpha channel which is not needed in this case.

poisondeathray
5th April 2022, 15:51
I can reproduce the issue on a 10bit422 prores source with motion , and trimmed like RD's example above. Native 10bit has overflow errors. The 8 bit down conversion has no blended/ghosted images and works well. The 16bit RGB upconversion has an issue with alignment and sync that the 8bit422 down version does not - motion is "jerky" in 16bit RGB with the plugin and different from the 8bit version, with some ghosted/blended frames. Unlikely to be source filter/seek issues, as Prores is I-frame. I think there is some issue with "sync" parameter in that "Median-0.6-RGB64-32+64bit" version .

EDIT: it had something to do with AddGrainC - If I remove that, it becomes aligned in RGB64 and works ok (but still without debug overlay)

Reel.Deel
5th April 2022, 16:10
EDIT: it had something to do with AddGrainC - If I remove that, it becomes aligned in RGB64 and works ok (but still without debug overlay)

That's odd. I have not tried with anything other than 8-bit YUV sources that I have. I'll try to find a 10-bit 422 prores sample somewhere and see if I can reproduce it. I looked at the source code and from what I can tell, debug is not implemented for RGB64.

Edit: ok I found a 4k 10bit prores sample, little bit of motion but I was able to see the that the video is jerky and has blended frames. I used the same script from earlier. I'm with you PDR, something might be off with the align parameter. It should not matter what the format was before converting to RGB64.

poisondeathray
5th April 2022, 16:32
That's odd. I have not tried with anything other than 8-bit YUV sources that I have. I'll try to find a 10-bit 422 prores sample somewhere and see if I can reproduce it. I looked at the source code and from what I can tell, debug is not implemented for RGB64.

I used this (and ConvertToRGB64(matrix="Rec709"), because it was "HD", but it shouldn't matter)
https://drive.google.com/file/d/1ObKwhduXJnyFVIipeouS_VI6NIF7Q9Ai/view?usp=sharing

Basically I cannot reproduce either; the issue was inserting AddGrain for me . His script had ShowFrameNumber inserted, but that doesn't cause the blending for me (works ok too)

I used LSmashVideoSource , so not indexed. LWLibavVideoSource (indexed) does not change the problem with AddGrainC for me

Orikson
6th April 2022, 16:04
Thank you for your replys! :thanks:

I uploaded a sample onto my google drive. You should be able to download it
https://drive.google.com/drive/folders/1Ao3wxKPeIpYlPFp8EOvSbgPUjrikIW5p?usp=sharing

One strange thing I recognized is, that my source files seem to be a bit missread by VirtualDub or AviSynth?! :confused: I don't think it has anything to do with the faulty median()-result, has it?

The video file has been captured with "Blackmagic Media Express" and a "Blackmagic DeckLink Studio 4K"
I can open and play the original captured video file with Media Player Classic BE (MPC-BE). It is recognized as Codec "AJA Video Systems Xena v210" and YUV 4:2:2 with 10-Bits
When I open this file in VirtualDub and export it again without any processing, it will use the setting "Pixel format P210".
I cannot view this exported file anymore with MPC-BE, but still with VirtualDub


Basically I cannot reproduce either; the issue was inserting AddGrain for me . His script had ShowFrameNumber inserted, but that doesn't cause the blending for me (works ok too)
In the post with your script, you did not convert the bitrate to 16-bit before converting to RGB64. I tested it but also with direct convertion to RGB64 without 16-bit conversion I had the same effect. The ShowFrameNumber() should be commented out most of the time. I use it only one in the very beginning to align the video clips so that the Median-Sync is good

I'm with you PDR, something might be off with the align parameter. It should not matter what the format was before converting to RGB64.
This reads like there is an actual issue with the median() function using RGB64 and not about my usage, right? I also tried to convert to RGB32 instead of RGB64, and with this the median()-function works as intended.

poisondeathray
6th April 2022, 19:47
One strange thing I recognized is, that my source files seem to be a bit missread by VirtualDub or AviSynth?! :confused: I don't think it has anything to do with the faulty median()-result, has it?

The video file has been captured with "Blackmagic Media Express" and a "Blackmagic DeckLink Studio 4K"
I can open and play the original captured video file with Media Player Classic BE (MPC-BE). It is recognized as Codec "AJA Video Systems Xena v210" and YUV 4:2:2 with 10-Bits
When I open this file in VirtualDub and export it again without any processing, it will use the setting "Pixel format P210".
I cannot view this exported file anymore with MPC-BE, but still with VirtualDub



The difference is "v210" is packed 10bit422 , "p210" is planar 10bit422 .

You can export v210 out of vdub2 (vdub2, not vdub classic) by selected video=>compression=>uncompressed=> (pixel format button)=> 4:2:2 YCbCr v210 . There is also MOV container export support



In the post with your script, you did not convert the bitrate to 16-bit before converting to RGB64. I tested it but also with direct convertion to RGB64 without 16-bit conversion I had the same effect. The ShowFrameNumber() should be commented out most of the time. I use it only one in the very beginning to align the video clips so that the Median-Sync is good


It did not make much of a difference. The 1st 2 frames were bad, but the rest ok (but 8bit down conversion also had problems with 1st 2 frames) . Compared to AddGrain result, where almost every frame was bad and it was jerky