View Full Version : Gamma-aware, dithered colorspace conversion and resizing


PhrostByte
12th March 2011, 20:06
Hello all, I've made a new filter that performs gamma-corrected colorspace conversion and Spline36 resizing in a single function.

Download version 8 for 32-bit:
http://sourceforge.net/projects/int64/files/ResampleHQ/ResampleHQ-v8.zip/download

Full Documentation:
http://svn.int64.org/viewvc/int64/resamplehq/doc/index.html?revision=341

Kernel visualization:
http://svn.int64.org/viewvc/int64/resamplehq/doc/kernels.html

Usage:
ResampleHQ(clip
[, int width]
[, int height]
[, string dstcolorspace]
[, string srcmatrix]
[, string dstmatrix]
[, bool dither]
[, float src_left]
[, float src_top]
[, float src_width]
[, float src_height]
[, string kernel]
[, float karg1]
[, float karg2]
[, float kblur_x]
[, float kblur_y]
[, string chroma_kernel]
[, float chroma_karg1]
[, float chroma_karg2])

Too many settings to list here, see documentation above for what they all do.

Note: Dithering YV12 and YUY2 output is not currently supported and will come at a later version. Interlaced formats are also not supported.

Here's an example from Avisynth's gamma-ignorant Spline36Resize:

http://svn.int64.org/viewvc/int64/resamplehq/doc/earthlights_small1.png

And now here's the gamma-aware ResampleHQ version:

http://svn.int64.org/viewvc/int64/resamplehq/doc/earthlights_small2.png

Note how the ResampleHQ image is much brighter overall, and shows faint light in completely new places around Canada, Alaska, western United States, and along coastlines.

This image was cherry-picked to show how off Avisynth's resizers can be with sharp contrast. Most video will show far less improvement.

Dogway
12th March 2011, 20:18
music to my ears! will test it soon.

jmac698
12th March 2011, 21:20
http://avisynth.org/mediawiki/External_filters#Resizers
Updated.

Dogway
12th March 2011, 21:49
Just tested.
I can see dither still is not optimal.
Also I wanted to ask if the chroma around some edges is normal, notice the reddish outline:
http://i212.photobucket.com/albums/cc35/Dogway/Misc/raw.png
http://i212.photobucket.com/albums/cc35/Dogway/Misc/spline64-1.png
http://i212.photobucket.com/albums/cc35/Dogway/Misc/ResampleHQ.png

PhrostByte
12th March 2011, 22:06
Thanks for trying it out. I see the red edges you're talking about, I'll check it out.

Dithering isn't even there yet. The code is finished but not yet integrated. Next build will have it.

Archimedes
14th March 2011, 14:12
What a lucky break. In the last view days I was thinking about the same issue (making a plugin for gamma corrected resizing). And now I see, somebody has already done the job. :)

Regarding the picture above, I can't reproduce red edges with ResampleHQ.

Spline36Resize >> (http://img833.imageshack.us/i/rawspline36resize.png/)
ResampleHQ >> (http://img692.imageshack.us/i/rawresamplehq.png/)

Dogway
14th March 2011, 15:25
I imagine it has to do with yuv content, and chroma subsampling. But maybe that is the expected behaviour, I was just wondering from my ignorance.
Talking about kernels any options for automttap3? Its a function so maybe it implies kernels from bilinear and lanczosresize.

PhrostByte
14th March 2011, 16:19
The red edges were due to a chroma conversion bug with Y'CbCr formats. I've fixed it already, am finishing up dithering before next release though. Some time today probably.

pbristow
14th March 2011, 17:15
This is good to see! :)

Once all the bugs are out of the colourspace/gamma correction & dither code, will you then be adding other options for the resize algorithm (e.g. Lanczos, or even good old Bilinear & Bicubic? :) )?

Is it modular enough that you could just add an option such as ' "resizer" = string ', and use it to call any existing AVIsynth resizer in between the input and output stages? That would open to door to things such as gamma-aware EDI, etc.

Archimedes
14th March 2011, 17:19
There is also a bug with the alpha channel (RGB32 input).

PhrostByte
14th March 2011, 18:21
This is good to see! :)

Once all the bugs are out of the colourspace/gamma correction & dither code, will you then be adding other options for the resize algorithm (e.g. Lanczos, or even good old Bilinear & Bicubic? :) )?

Is it modular enough that you could just add an option such as ' "resizer" = string ', and use it to call any existing AVIsynth resizer in between the input and output stages? That would open to door to things such as gamma-aware EDI, etc.

Other sinc kernels (Lanczos, Spline, etc.) will be added soon. Non-sinc algorithms will come later.

Unfortunately it's not possible to reuse other filters.

There is also a bug with the alpha channel (RGB32 input).

Actually didn't realize the alpha channel was used by anything. Easy to fix, at least. I'll add it to the list.

PhrostByte
16th March 2011, 16:26
v2 is up, download here (http://sourceforge.net/projects/int64/files/ResampleHQ/ResampleHQ-v2.zip/download).

I'll be busy the next couple days so I decided to put out what I've finished. All the bugs identified are fixed (please test to make sure!), and dithering works for RGB output. I unfortunately wasn't able to finish YV12 and YUY2 dithering in time, so that'll come later.

Dogway
16th March 2011, 17:48
Thanks for all the effort!
I will wait until you release the dither version for a current project.
And hopefully make this one my default resizer.

leeperry
16th March 2011, 20:43
music to my ears!
to mine as well :D

I'm currently forced to use this for upscaled SD through madVR:
ColorMatrix(mode="Rec.601->Rec.709",clamp=0,opt=0)

I already use SmoothLevels() for a proper TV>PC conversion, it does add dithering...and so does madVR, so I'm not sure that I've got any headroom for more dithering.

How is your plugin supposed to be different/better than the aforementioned command? I strictly want 601>709, and especially not something that messes w/ saturations :o

PhrostByte
16th March 2011, 21:29
How is your plugin supposed to be different/better than the aforementioned command? I strictly want 601>709, and especially not something that messes w/ saturations :o

TV.601->PC.709 doesn't require any linear blending, so my filter won't be able to do much for you. Two possible improvements which would be negligible:

If you're using both ColorMatrix and SmoothLevels together, then ResampleHQ will give you less rounding error.
Proper dithering does require linear blending, so ResampleHQ will give more correct results than anything that does non-linear dithering. I'd be (pleasantly) surprised if whatever dithering SmoothLevels does is performed linearly.


The brightness difference you see in those pictures is actually what correct resizing is supposed to look like. ResampleHQ doesn't mess with brightness, saturation, or anything like that at all -- everything else just does it wrong :)

IanB
16th March 2011, 23:46
Neat filter.

For those interested in the source code, it appears to be here (http://svn.int64.org/viewvc/int64/resamplehq/resamplehq/).

The dither seems to be error diffusion with a twist. r1 and l1 flip sign on each line. This is fine for l1 because it applies to the rerr2[] pointers of the next line, but r1 applies to the rerr1[] pointers of the current line, so the accumulating error is added to an already processed pixel :confused:

PhrostByte
17th March 2011, 00:08
the accumulating error is added to an already processed pixel :confused:

if you scan left->right, then l1 is an offset to the left pixel, and r1 is an offset to the right pixel.

it alternates between scanning left->right and right->left (see the calculation of x). I flip the sign on l1/r1 each line too, so r1 is always an offset to the pixel next in line.

it's called "serpentine scanning" and helps avoid some rare bad looking patterns.

Mug Funky
17th March 2011, 01:37
a lil' feature request?

could you possibly implement cropping routines similar to avisynth's resizers? these allow precise (subpixel) cropping of the image which is necessary in all manner of video resizing applications (ie field alignment, correct 702 width scaling from and to HD, etc).

thanks!

btw, very nice work :)

IanB
17th March 2011, 22:37
if you scan left->right, then l1 is an offset to the left pixel, and r1 is an offset to the right pixel.

it alternates between scanning left->right and right->left (see the calculation of x). I flip the sign on l1/r1 each line too, so r1 is always an offset to the pixel next in line.

it's called "serpentine scanning" and helps avoid some rare bad looking patterns.

Ah, yes I missed this code color::dimension_type x = (y & 1) ? (width - xx - 1) : xx;

You have obviously thought about this a lot. So on the Even lines you diffuse error with this kernel 1 [ - # 7 ]
16 [ 4 5 0 ]and on the Odd line with this kernel 1 [ 7 # - ]
16 [ 0 5 4 ]

What other advantages have you found instead of using the default Floyd and Steinberg kernel? 1 [ - # 7 ]
16 [ 3 5 1 ]

PhrostByte
17th March 2011, 22:59
a lil' feature request?

could you possibly implement cropping routines similar to avisynth's resizers? these allow precise (subpixel) cropping of the image which is necessary in all manner of video resizing applications (ie field alignment, correct 702 width scaling from and to HD, etc).

Definitely planned.

What other advantages have you found instead of using the default Floyd and Steinberg kernel? 1 [ - # 7 ]
16 [ 3 5 1 ]

A while ago I read a study that did an automated comparison of various dithering techniques, including all common error diffusion patterns and even randomized ones. It concluded that while the Floyd-Steinberg pattern was near perfect for regular scanning, it was actually sub-optimal for serpentine scanning. The pattern I'm using tested best in its class, outmatched only by a slow and complicated edge-directed binary search algorithm.

I tried it out myself on a few handfuls of images and found that it did help avoid certain bad patterns, so I stuck with it.

madshi
18th March 2011, 08:57
FWIW, most of these dithering algorithms are optimized for halftoning (8bit -> 1bit). I believe that for our use (high bitdepth -> 8bit) we have different needs. I would suggest to use the method proposed in the paper "Optimized Error Diffusion for Image Display" (PDF download available via google). This dithering method whitens the quantization error which should produce best results for our needs, IMHO.

But of course the optimal solution would be if AviSynth would be able to handle a full high bitdepth processing chain (16bit int or even 32bit float). This way dithering could be avoided altogether, or at least delayed to the very last step. E.g. dithering could be done to 10bit, with the final result fed to the new x264 10bit encoder. The current limitation of AviSynth to 8bit means that basically every processing step that internally produces higher bitdepth (resampling, color conversion, and many more) must do an internal dithering step for optimal results. If this is not done, rounding errors will add up. But even if it's done, dithering noise adds up. Having higher bitdepth support would be better in any case.

PhrostByte
18th March 2011, 17:29
FWIW, most of these dithering algorithms are optimized for halftoning (8bit -> 1bit). I believe that for our use (high bitdepth -> 8bit) we have different needs. I would suggest to use the method proposed in the paper "Optimized Error Diffusion for Image Display" (PDF download available via google). This dithering method whitens the quantization error which should produce best results for our needs, IMHO.

But of course the optimal solution would be if AviSynth would be able to handle a full high bitdepth processing chain (16bit int or even 32bit float). This way dithering could be avoided altogether, or at least delayed to the very last step. E.g. dithering could be done to 10bit, with the final result fed to the new x264 10bit encoder. The current limitation of AviSynth to 8bit means that basically every processing step that internally produces higher bitdepth (resampling, color conversion, and many more) must do an internal dithering step for optimal results. If this is not done, rounding errors will add up. But even if it's done, dithering noise adds up. Having higher bitdepth support would be better in any case.

I've also wondered if the classic error diffusion algorithms were optimal for high bit depths. From my tests it seems to perform acceptably, but if there's something better I definitely want to know. Interesting paper, I'll read it. Thanks.

I've been considering making a backwards-compatible extension to IClip -- it would have GetFrame16 and GetFrame32F member functions, and transparently down-convert if GetFrame was called by a legacy filter. All anyone would need to do is call dynamic_cast<IClipEx*>(clip) to test if a clip offers the extended formats. It'd be a fair amount of work, but I think rewarding in the end. Would people use this?

jmac698
19th March 2011, 20:35
Yes, I would use it. For now I'm using a script-compatible system where the extra low bits are in a separate clip. There's other filters that use deep color processing as well. Could you make it compatible to my tools for now? It would be the easiest approach.
http://forum.doom9.org/showthread.php?p=1467907#post1467907

PhrostByte
20th March 2011, 05:22
v3 is out. sub-pixel cropping, selectable resize kernels, and some small optimizations. big overhaul to support SSE touched a lot of code, so be on the lookout for bugs.

Download for 32-bit and 64-bit:
http://sourceforge.net/projects/int64/files/ResampleHQ/ResampleHQ-v3.zip/download

Full documentation:
http://svn.int64.org/viewvc/int64/resamplehq/doc/index.html?revision=255

PhrostByte
20th March 2011, 05:26
Yes, I would use it. For now I'm using a script-compatible system where the extra low bits are in a separate clip. There's other filters that use deep color processing as well. Could you make it compatible to my tools for now? It would be the easiest approach.
http://forum.doom9.org/showthread.php?p=1467907#post1467907

Unfortunately transparent compatibility is basically impossible -- all the filters you're depending on would have to explicitly support it. Until they did, the video they see would just appear like any other clip (low bit depth and non-linear colorspace), so you wouldn't be able to get much out of it.

Given the amount of filters we have that haven't been updated in ages and have had their authors disappear, I don't really know how big of an impact it would be able to make. But I guess we have to start somewhere?

Dogway
20th March 2011, 07:25
Perceived bugs:
-Omitting or setting dither=false, causes a crash.
-looks like dither only works when changing colorspace from yv12 to rgb (not on resizing etc)
-Strange black artifacts around contrasty edges when DSTCOLORSPACE is RGB (independent of input)
-Overall there's strong ringing, black outline plus bright ringing.

Tell me if you want me to upload my tests.

PhrostByte
20th March 2011, 18:08
Perceived bugs:
-Omitting or setting dither=false, causes a crash.
-looks like dither only works when changing colorspace from yv12 to rgb (not on resizing etc)
-Strange black artifacts around contrasty edges when DSTCOLORSPACE is RGB (independent of input)
-Overall there's strong ringing, black outline plus bright ringing.

Tell me if you want me to upload my tests.

Please do, I've tested all the possible colorspace conversions and can't replicate any of that.

Dogway
20th March 2011, 19:10
Dither=false crashes no matter what. I even emptied the plugin folder.
Here are my tests:
http://www.mediafire.com/?l6t0pf2mfto32xg

PhrostByte
20th March 2011, 20:23
Dither=false crashes no matter what. I even emptied the plugin folder.
Here are my tests:
http://www.mediafire.com/?l6t0pf2mfto32xg

Thanks! v4 is up with everything fixed.

The crashes were a bug from my SSE preparations, and the dithering artifacts were due to resizing creating out-of-range values (which is normal, I just didn't clamp them properly).

I believe the extra ringing is merely a result of linear blending. Regular Spline36 has it too, just not as intense -- just like with other images, the sharp contrast is brought out more with linear blending.

Download for 32-bit and 64-bit:
http://sourceforge.net/projects/int64/files/ResampleHQ/ResampleHQ-v4.zip/download

Full documentation:
http://svn.int64.org/viewvc/int64/resamplehq/doc/index.html?revision=257

tritical
20th March 2011, 21:50
I believe the extra ringing is merely a result of linear blending. Regular Spline36 has it too, just not as intense -- just like with other images, the sharp contrast is brought out more with linear blending.

If you are enlarging an image, working with linear values will absolutely create more ringing around edges simply because you are enlarging the difference between dark/bright pixels... so the overshoot of resampling functions with negative coefficients will be greater than if you work with gamma corrected values. Really, for enlarging there is no reason to believe that working with the linear values will give a better result (with standard fir interpolation functions).. because the resampling functions do not approximate the true image better when fit to the linear values than when fit to the gamma corrected values. At least I have never seen any evidence of this, and my tests show that it isn't true.

Shrinking or downsizing an image is different because you have to low-pass filter the image before decimation (or interpolation) in order to avoid aliasing. It is the low-pass filtering step that requires working in linear space if you want to approximate an optical blur. Avisynth's resizing functions don't separate those two steps. The low-pass filtering is accomplished by increasing the support width of the resampling function by a factor of old_width/target_width. Obviously, the larger the downsizing ratio the stronger the low-pass filtering, and therefore the larger the difference between working with gamma-corrected versus linear values.

Random thought: I don't know how flexible Avisynth's resampling code is, but it would be really nice if you could manually control the support width - maybe by supplying a user specified scaling factor >= 1.0 - instead of having it always scaled by a factor of max(old_width/target_width,1.0).

*.mp4 guy
20th March 2011, 22:56
Increasing support width will blur things to all hell. The algorithm avisynth uses should be able to do this easily, iirc, if the code itself is this capable, I have no idea.

cretindesalpes
21st March 2011, 00:22
Nice! It would be great if you could also add support for 16-bit data as output and/or input (for example, with the MSB part stacked onto the LSB), so the dithering could be done later.

Dogway
21st March 2011, 03:50
@PhrostByte: Yes, everything looks right now : D
Just a question, still images should be treated as... Rec.601?

Also I made a funny experiment, ported resampleHQ to automttap3:
http://i212.photobucket.com/albums/cc35/Dogway/Misc/th_automttap3HQ.png (http://i212.photobucket.com/albums/cc35/Dogway/Misc/automttap3HQ.png)

PhrostByte
21st March 2011, 04:35
Just a question, still images should be treated as... Rec.601?

The matrix is only used for YV12/YUY2 (it defines the mix of R,G,B that goes into Y, and the integer range for Y'CbCr). For everything else it is ignored. I'd assume still images would be RGB.

Dogway
21st March 2011, 04:37
ay! yes, what I had been thinking...

tritical
21st March 2011, 06:51
Increasing support width will blur things to all hell. The algorithm avisynth uses should be able to do this easily, iirc, if the code itself is this capable, I have no idea.

What I'm saying is that Avisynth's current method of scaling the support by max(old_width/target_width,1.0) is just a rule of thumb. There is no reason to believe that that value is optimal for every image, and it would be interesting if you could supply the scaling factor yourself (after looking at the code I think this would be very easy to do). However, what I'm really thinking about is if you were to perform low-pass filtering yourself before calling one of the built in resizers. In that case, you wouldn't want the filter support increased because you don't need low-pass filtering just interpolation. Anyways, getting off topic now.

*.mp4 guy
21st March 2011, 07:52
What I'm saying is that Avisynth's current method of scaling the support by max(old_width/target_width,1.0) is just a rule of thumb.

Avisynths current method is naively theoretically correct for purposes of keeping the frequency response of the output as close to the input as can be done using the current resizing kernel. The only way to do better is to break out the non-linearity. Though, as you mentioned, there are other reasons to make it adjustable. I just don't want people to think that the avisynth interpolators are arbitrary.

PhrostByte
21st March 2011, 17:12
What I'm saying is that Avisynth's current method of scaling the support by max(old_width/target_width,1.0) is just a rule of thumb. There is no reason to believe that that value is optimal for every image, and it would be interesting if you could supply the scaling factor yourself (after looking at the code I think this would be very easy to do). However, what I'm really thinking about is if you were to perform low-pass filtering yourself before calling one of the built in resizers. In that case, you wouldn't want the filter support increased because you don't need low-pass filtering just interpolation. Anyways, getting off topic now.

I guess you mean min(target_width/old_width, 1.0). I'll add an option to let you override it.

tritical
21st March 2011, 17:13
Avisynths current method is naively theoretically correct for purposes of keeping the frequency response of the output as close to the input as can be done using the current resizing kernel.
Under what [arbitrary] definition of close? Certainly it does not completely capture the only thing that really matters for image processing - the perceived quality of the person doing the resizing.

SilaSurfer
21st March 2011, 17:54
PhrostByte nice work!;) Just tried it.

@Dogway

How did you port resampleHQ to automttap3, and was that image resampled with it? Looks awasome.

*.mp4 guy
21st March 2011, 22:46
Under what [arbitrary] definition of close? If the avisynth linear interpolators could use an infinite sinc kernel, and and the input to the interpolator is a perfectly bandlimited signal capable of being properly sampled at the destination resolution, then the support width calculations used by avisynth guarantee perfect reconstruction at the destination resolution, and any other arbitrary resolution that does not cause sub-critical sampling to occur.

Certainly it does not completely capture the only thing that really matters for image processing - the perceived quality of the person doing the resizing.
In my opinion, it is overall the best compromise. Avisynth resizers certainly look much better then the abysmal interpolators used on most dvds; said dvds either being blurred to hell, with accompanying gibbs artifacts or have aliasing everywhere.

Sapo84
23rd March 2011, 13:30
I think that YV12 output is a bit broken at the moment, and there are visible artefacts, in particular they are pretty obvious near reds border.
But, well, let's make screenshots speak.

ResampleHQ(1280,720,"YV12","TV.709","TV.709",false,198,22,-48,-164)
http://www.cbland.net/images4/ResampleHQYV12.png
around the red circle there are obvious problems with the resampler output

Spline36Resize(1280,720,198,22,-48,-164)
http://www.cbland.net/images4/SplineYV12.png
on the other hand Spline36's output is perfect

and if we convert to RGB32
ResampleHQ(1280,720,"RGB32","TV.709","TV.709",false,198,22,-48,-164)
http://www.cbland.net/images4/ResampleHQRGB32.png
there are no more artefacts

Spline36Resize(1280,720,198,22,-48,-164).ConverttoRGB32(matrix="Rec709")
http://www.cbland.net/images4/SplineRGB32.png
Spline is good as well.

Using different matrix/crop/dither did not change the outcome at all.

PhrostByte
23rd March 2011, 18:13
I think that YV12 output is a bit broken at the moment, and there are visible artefacts, in particular they are pretty obvious near reds border.

Confirmed. I'll look for a solution. Chroma sub-sampling is evil.

henryho_hk
24th March 2011, 03:37
Sapo84, can we have the original picture for comparsion? And what program do you use to extract the PNG file from a YV12 AVS?

Dogway
24th March 2011, 10:22
Yes, I can confirm it, YV12 is totally broken. Even the next line outputs wrong results:
# converting from RGB to YV12
ResampleHQ(DSTCOLORSPACE="YV12",dither=false)

Sapo84
24th March 2011, 10:35
Sapo84, can we have the original picture for comparsion?
Sure.
http://www.cbland.net/images4/notresampled.png

And what program do you use to extract the PNG file from a YV12 AVS?
AvsPmod.
Now that you can even specify the matrix used to convert from YV12 to RGB32 during playback is basically the swiss knife of avisynth ^^

PhrostByte
25th March 2011, 01:07
This is turning out to be a tricky problem to solve. It occurs whenever sub-sampled YUV is converted between gamma-compressed and linear.

You can't go directly from YUV -> linear YUV. You need to do YUV -> RGB -> linear RGB -> linear YUV.

When it is sub-sampled, you run into the same problem run-of-the-mill renderers do: when converting to RGB the chroma isn't rescaled nicely, but simply point sampled.

I wanted to avoid rescaling gamma-compressed chroma, but I'm not sure if that's possible now. Any clever ideas?

Mug Funky
25th March 2011, 02:47
could the gamma resize be just done on the luma only? chroma exists in chroma-land where gamma makes no sense...

or perhaps the gamma can happen on the chroma channels using a correspondingly subsampled luma channel to convert them to intermediate chroma channels. that might work.

PhrostByte
25th March 2011, 04:16
could the gamma resize be just done on the luma only? chroma exists in chroma-land where gamma makes no sense...

or perhaps the gamma can happen on the chroma channels using a correspondingly subsampled luma channel to convert them to intermediate chroma channels. that might work.

Chromaticity is independent from luminance. Chroma is dependent on luma. Not the same thing :(

I thought of sub-sampling luma too, but I haven't tried it yet. Will report back in a bit :)

madshi
25th March 2011, 07:54
Resampling luma will change the luma and chroma value of every pixel. So if you want resampling to be done with proper quality, I don't think you have any chance of avoiding doing proper chroma upsampling as a first step. Of course that means that the output of your filter should probably be either RGB or YCbCr 4:4:4 because otherwise chroma will lose quality. For chroma upsampling I'd suggest a soft filter to avoid aliasing artifacts.

Gavino
25th March 2011, 14:25
If the final output is to be YV12, the chroma accuracy could potentially be improved by having a separate chroma conversion path using resampled luma. Instead of effectively doing this:
YV12->YV24->sRGB->linear RGB->resample->sRGB->YV24->YV12
which involves chroma resampling as both the first and last steps, do this:

YV12->YV24->sRGB->linear RGB->resample->sRGB->luma
and
YV12->resample luma to chroma grid->sRGB->linear RGB->resample to destn chroma grid->sRGB->chroma

Whether this would make a visible difference, I don't know.

kolak
26th March 2011, 19:03
and if we convert to RGB32
ResampleHQ(1280,720,"RGB32","TV.709","TV.709",false,198,22,-48,-164)
http://www.cbland.net/images4/ResampleHQRGB32.png
there are no more artefacts




This has also chroma problems- not as visible as direct YV12, but visible enough.


Andrew

PhrostByte
30th March 2011, 02:07
Got caught up in Crysis 2 for most of this past week -- it's like a frakkin' Michael Bay movie in all the right ways.

I'm going full-speed on ResampleHQ now. Should have something new up in the next couple days.

PhrostByte
5th April 2011, 19:02
For chroma upsampling I'd suggest a soft filter to avoid aliasing artifacts.

I'm going to default it to bilinear like Avisynth does, but let it be customized. Can you post code for the SoftCubic kernel you use? I'd like to add support for it.

madshi
5th April 2011, 19:09
Ok, here goes:

float Cubic(float distance, float param1, float param2)
// return cubic weight coefficients
{
float P0, P1, P2, P3;
float result = 0;

if (distance <= 2.0f)
{
if (distance < 1.0f)
{
P0 = (+ 1.0f - 1.0f/3.0f * param1 - 0.0f * param2);
P1 = 0;
P2 = (- 3.0f + 2.0f * param1 + 1.0f * param2);
P3 = (+ 2.0f - 3.0f/2.0f * param1 - 1.0f * param2);
} else {
P0 = (- 0.0f + 4.0f/3.0f * param1 + 4.0f * param2);
P1 = (+ 0.0f - 2.0f * param1 - 8.0f * param2);
P2 = (- 0.0f + 1.0f * param1 + 5.0f * param2);
P3 = (+ 0.0f - 1.0f/6.0f * param1 - 1.0f * param2);
}
result = P0 + P1 * distance + P2 * distance * distance + P3 * distance * distance * distance;
}
return result;
}

float GetFilterCoeffs(float distance, RESAMPLING_FILTER filter)
// return coeffecients for the specified resampling filter
{
float result = 0;

switch (filter)
{
case rfCatmullRom :
case rfBicubic50 : result = Cubic(distance, 0.00f, 0.50f); break;
case rfBicubic60 : result = Cubic(distance, 0.00f, 0.60f); break;
case rfBicubic75 : result = Cubic(distance, 0.00f, 0.75f); break;
case rfSoftCubic100 : result = Cubic(distance, 1.00f, 0.00f); break;
case rfSoftCubic80 : result = Cubic(distance, 0.80f, 0.20f); break;
case rfSoftCubic70 : result = Cubic(distance, 0.70f, 0.30f); break;
case rfSoftCubic60 : result = Cubic(distance, 0.60f, 0.40f); break;
case rfSoftCubic50 : result = Cubic(distance, 0.50f, 0.50f); break;
case rfMitchell : result = Cubic(distance, 1.0f/3.0f, 1.0f/3.0f); break;
[...]

Gavino
5th April 2011, 19:37
float Cubic(float distance, float param1, float param2)
Looks like that is just the same as Avisynth's BicubicResize, where param1 and param2 represent the b and c arguments.
Then, in the 'soft' settings, used with 0.5<= b <=1 and c = 1-b.
case rfSoftCubic100 : result = Cubic(distance, 1.00f, 0.00f); break;
case rfSoftCubic80 : result = Cubic(distance, 0.80f, 0.20f); break;
case rfSoftCubic70 : result = Cubic(distance, 0.70f, 0.30f); break;
case rfSoftCubic60 : result = Cubic(distance, 0.60f, 0.40f); break;
case rfSoftCubic50 : result = Cubic(distance, 0.50f, 0.50f); break;

madshi
5th April 2011, 20:44
Looks like that is just the same as Avisynth's BicubicResize
Is it? Well, there's only one way to do the math correctly, I guess... ;)

Gavino
5th April 2011, 21:50
Is it? Well, there's only one way to do the math correctly, I guess... ;)
Actually, there is more than one way of doing it. In the Avisynth implementation, your line:
result = P0 + P1 * distance + P2 * distance * distance + P3 * distance * distance * distance;
is effectively replaced by:
result = P0 + distance * (P1 + distance * (P2 + distance * P3));
which is marginally faster (fewer multiplies). ;)

PhrostByte
6th April 2011, 05:24
Ok, here goes:
Thanks!

Looks like that is just the same as Avisynth's BicubicResize, where param1 and param2 represent the b and c arguments.
Then, in the 'soft' settings, used with 0.5<= b <=1 and c = 1-b.
So it does.

henryho_hk
7th April 2011, 03:18
Found an interesting diagram about cubic resizers: http://www.imagemagick.org/Usage/resize/#mitchell

madshi
7th April 2011, 07:15
Actually, there is more than one way of doing it. In the Avisynth implementation, your line [...] is effectively replaced by [...] which is marginally faster (fewer multiplies). ;)
Haha - you're right... :p

That said, the weights are usually only calculated once and then stored in some array. So it's not a few saved multiplies per pixel, not even per frame.

PhrostByte
7th April 2011, 09:10
Here's version 5. Hopefully the last of the chroma bugs. Been hitting F2 so much in Virtualdub that I've started hitting F2 instead of F5 in browsers, lol.

Download for 32-bit and 64-bit:
http://sourceforge.net/projects/int64/files/ResampleHQ/ResampleHQ-v5.zip/download

Full documentation:
http://svn.int64.org/viewvc/int64/resamplehq/doc/index.html?revision=268

Changelog:

Catmull–Rom, Gaussian, Hermite, Mitchell–Netraveli, Robidoux, Sinc, and SoftCubic kernels.
SMPTE 240M and FCC matrices.
Customization of kernel support scale.
Customization of chroma kernel.
Support for SetMTMode(2).
More SSE versions of colorspace conversions.
Bug fix: make SSE paths work with unaligned sources.
Bug fix: scale chroma correctly.

SubJunk
7th April 2011, 09:12
Thanks a lot :)

Dogway
7th April 2011, 10:09
Thank you!
I can't make RGB work, either input or ouput. I get a crash (my fault?):
crashinfo.txt (http://www.mediafire.com/?bj7furs34bh7ff2)

edit: that was in avs 2.57 MT winXP SP3
edit2: It worked if dither=false, so its a dither thing in RGB.

PhrostByte
7th April 2011, 13:00
Thank you!
I can't make RGB work, either input or ouput. I get a crash (my fault?):
crashinfo.txt (http://www.mediafire.com/?bj7furs34bh7ff2)

i can't download that file, for some reason mediafire gives me an invalid url. do you have a script that reproduces it?

edit: nevermind, i got it through another browser.

Yellow_
7th April 2011, 13:28
Is there anything to gain from implementing yesgrey's high precision 3D LUT (yCMS) for colourspace conversions used in conjunction with the necessary bits of Triticals t3dlut plugin?

http://forum.doom9.org/showthread.php?t=154719

PhrostByte
7th April 2011, 14:22
Is there anything to gain from implementing yesgrey's high precision 3D LUT (yCMS) for colourspace conversions used in conjunction with the necessary bits of Triticals t3dlut plugin?

http://forum.doom9.org/showthread.php?t=154719

Not sure, I'll check it out.

Actual colorspace conversion is the cheapest part of ResampleHQ right now -- resampling takes up a huge amount of time compared to it.

I'm currently experimenting with OpenCL which should give a pretty nice speedup as is, though it can also use 3D LUTs so it could also help assuming you've got enough vram.

Archimedes
7th April 2011, 14:39
Thanks for the update. Hermite and Robidoux do not working (unsupported kernels).

LoRd_MuldeR
7th April 2011, 14:45
Also "Spline32" (mentioned in the docs) does not work, but "Spline36" (undocumented) does ;)

PhrostByte
7th April 2011, 15:15
Thanks for the update. Hermite and Robidoux do not working (unsupported kernels).

Fixed. You can use Bicubic with b/c set manually until I get a new version out.

Also "Spline32" (mentioned in the docs) does not work, but "Spline36" (undocumented) does ;)

Doh!

Thank you!
I can't make RGB work, either input or ouput. I get a crash (my fault?):
crashinfo.txt (http://www.mediafire.com/?bj7furs34bh7ff2)

edit: that was in avs 2.57 MT winXP SP3

Still trying to reproduce this. Strange crashdump, it includes instructions that don't exist in my filter, like movups.

ganymede
7th April 2011, 23:04
Mitchell–NetraveliIt's a typo, the name of the filter should be Mitchell–Netravali (from the name of Don P. Mitchell and Arun N. Netravali).

PhrostByte
9th April 2011, 00:11
Version 6. Fixes Dogway's crash and some other things.

Download for 32-bit and 64-bit:
http://sourceforge.net/projects/int64/files/ResampleHQ/ResampleHQ-v6.zip/download

Full documentation:
http://svn.int64.org/viewvc/int64/resamplehq/doc/index.html?revision=272

Changelog:

SSE Y'CbCr output conversions. All conversions now have SSE implementations.
Bug fix: correct rounding in SSE output conversions.
Bug fix: allocate dithering error buffers.
Bug fix: Hermite and Robidoux kernels are now enabled.
Bug fix: correct spelling of Spline36 and Mitchell–Netravali.

SubJunk
9th April 2011, 00:36
Nice one, thanks

PhrostByte
10th April 2011, 18:43
Anyone have a shiny new Sandy Bridge CPU willing to run a lengthy benchmark? I wrote a bunch of AVX stuff but have no way of testing if it is actually any faster.

Yellow_
13th April 2011, 08:07
Enjoying using your plugin and have a query, not a bug to report but I notice when converting to RGB that I see faint red/blue rectangular blocks along the edges of content in any chosen image frame. The source is h264AVC from a Canon DSLR. I can put up a sample but guess the description is enough. Assume this is result of chroma subsampling / moire / line skipping. They also appear to be non square even though its square pixel source

So query is, is there anything that can be done in the interpolation of chroma, assume its going 4:2:0 to 4:2:2 to RGB that could subdue the alternate red blue blocks its like chequreboard

I notice this with other conversion methods to RGB including yCMS 3DLUT + Triticals t3dlut plugin

ChaosKing
13th April 2011, 12:26
Anyone have a shiny new Sandy Bridge CPU willing to run a lengthy benchmark? I wrote a bunch of AVX stuff but have no way of testing if it is actually any faster.
I can test it. Have a SB 2500 CPU

PhrostByte
13th April 2011, 15:39
Enjoying using your plugin and have a query, not a bug to report but I notice when converting to RGB that I see faint red/blue rectangular blocks along the edges of content in any chosen image frame. The source is h264AVC from a Canon DSLR. I can put up a sample but guess the description is enough. Assume this is result of chroma subsampling / moire / line skipping. They also appear to be non square even though its square pixel source

So query is, is there anything that can be done in the interpolation of chroma, assume its going 4:2:0 to 4:2:2 to RGB that could subdue the alternate red blue blocks its like chequreboard

I notice this with other conversion methods to RGB including yCMS 3DLUT + Triticals t3dlut plugin

I suspect it's caused by chroma bleeding into luma because of subsampling. Some colors right next to each other can react particularly bad. If you post an example image I can take a look.

I can test it. Have a SB 2500 CPU

Here it is. It'll create a "benchmark results.txt" once it's done, you can just paste the results here.

http://sourceforge.net/projects/int64/files/ResampleHQ/resamplehq-v7pre-avxbench.zip/download

Dogway
13th April 2011, 16:01
I made some tests. I use an image I used once before because it has good features to test on like small details, big details, and some well defined letters.
From what I observed most of the scaling kernels show the ringing I described a few weeks back. So this is how I classify the different algorithms:

blurry: principally because of this (http://forum.doom9.org/showthread.php?)p=1474853#post1474853)
bilinear
rubidoux

ringing:
lanczos4
spline64
spline36

good balance of both of them:
lanczos (best in my opinion)
blackman (2nd best)
spline16
catmull

I also included automttap3 for comparison, it was the one who retained most detail in my last test, but I wouldnt use it for graphics or cartoons because it also creates some ugly ringing repetition. Also added spline64.
If I tell you the truth I was a bit dissappointed concerning the ringing thing, even if that was what it was supposed to do :/

Pack with the tests, .psd file and separated .png files
35Mb rar:
http://www.mediafire.com/?16a31o7v0im652o

ChaosKing
13th April 2011, 16:24
Benchmark results
------------------

The AVX version seems to be very slow :/

RGB24 -> linear RGB C: (fastest/slowest/average) wall time speed is 6.59281/6.10231/6.51858 runs/second.
RGB24 -> linear RGB C relative speed: 1.0x
RGB24 -> linear RGB SSSE3: (fastest/slowest/average) wall time speed is 37.5498/33.94/36.5475 runs/second.
RGB24 -> linear RGB SSSE3 relative speed: 5.69557x
RGB24 -> linear RGB AVX: (fastest/slowest/average) wall time speed is 3.00409/2.71127/2.94455 runs/second.
RGB24 -> linear RGB AVX relative speed: 0.455661x
RGB32 -> linear RGB C: (fastest/slowest/average) wall time speed is 4.67475/3.83495/4.55645 runs/second.
RGB32 -> linear RGB C relative speed: 1.0x
RGB32 -> linear RGB SSE2: (fastest/slowest/average) wall time speed is 37.7303/35.7484/37.0366 runs/second.
RGB32 -> linear RGB SSE2 relative speed: 8.07107x
RGB32 -> linear RGB AVX: (fastest/slowest/average) wall time speed is 2.76705/2.44912/2.72385 runs/second.
RGB32 -> linear RGB AVX relative speed: 0.591913x
RGB32 -> linear RGBA C: (fastest/slowest/average) wall time speed is 4.55221/4.31145/4.49747 runs/second.
RGB32 -> linear RGBA C relative speed: 1.0x
RGB32 -> linear RGBA SSE2: (fastest/slowest/average) wall time speed is 36.1119/33.9868/35.8453 runs/second.
RGB32 -> linear RGBA SSE2 relative speed: 7.93283x
RGB32 -> linear RGBA AVX: (fastest/slowest/average) wall time speed is 2.85771/2.20617/2.79098 runs/second.
RGB32 -> linear RGBA AVX relative speed: 0.627764x
YV12 -> YUV C: (fastest/slowest/average) wall time speed is 165.108/157.79/163.724 runs/second.
YV12 -> YUV C relative speed: 1.0x
YV12 -> YUV SSE2: (fastest/slowest/average) wall time speed is 300.263/286.618/295.344 runs/second.
YV12 -> YUV SSE2 relative speed: 1.81859x
YV12 -> YUV AVX: (fastest/slowest/average) wall time speed is 19.5201/18.1788/19.3726 runs/second.
YV12 -> YUV AVX relative speed: 0.118226x
YUY2 -> YUV C: (fastest/slowest/average) wall time speed is 204.879/178.597/199.624 runs/second.
YUY2 -> YUV C relative speed: 1.0x
YUY2 -> YUV SSE2: (fastest/slowest/average) wall time speed is 424.132/361.432/417.757 runs/second.
YUY2 -> YUV SSE2 relative speed: 2.07016x
YUY2 -> YUV AVX: (fastest/slowest/average) wall time speed is 32.1951/28.7248/31.7467 runs/second.
YUY2 -> YUV AVX relative speed: 0.157142x
YUV -> linear RGB C: (fastest/slowest/average) wall time speed is 16.9974/12.2325/16.4998 runs/second.
YUV -> linear RGB C relative speed: 1.0x
YUV -> linear RGB SSE2: (fastest/slowest/average) wall time speed is 37.3566/35.0877/36.9554 runs/second.
YUV -> linear RGB SSE2 relative speed: 2.19778x
YUV -> linear RGB AVX: (fastest/slowest/average) wall time speed is 3.72789/3.47262/3.68511 runs/second.
YUV -> linear RGB AVX relative speed: 0.219321x
linear RGB -> RGB24 C: (fastest/slowest/average) wall time speed is 6.25605/5.79279/6.17731 runs/second.
linear RGB -> RGB24 C relative speed: 1.0x
linear RGB -> RGB24 SSSE3: (fastest/slowest/average) wall time speed is 40.4334/33.1002/39.0018 runs/second.
linear RGB -> RGB24 SSSE3 relative speed: 6.46308x
linear RGB -> RGB24 AVX: (fastest/slowest/average) wall time speed is 3.30754/2.9804/3.24551 runs/second.
linear RGB -> RGB24 AVX relative speed: 0.528695x
linear RGB -> RGB32 C: (fastest/slowest/average) wall time speed is 4.37648/4.11399/4.33744 runs/second.
linear RGB -> RGB32 C relative speed: 1.0x
linear RGB -> RGB32 SSE2: (fastest/slowest/average) wall time speed is 41.4194/40.0089/41.09 runs/second.
linear RGB -> RGB32 SSE2 relative speed: 9.46409x
linear RGB -> RGB32 AVX: (fastest/slowest/average) wall time speed is 3.57475/3.04053/3.43611 runs/second.
linear RGB -> RGB32 AVX relative speed: 0.816809x
linear RGBA -> RGB32 C: (fastest/slowest/average) wall time speed is 4.44825/4.36037/4.42751 runs/second.
linear RGBA -> RGB32 C relative speed: 1.0x
linear RGBA -> RGB32 SSE2: (fastest/slowest/average) wall time speed is 39.6152/36.8389/39.01 runs/second.
linear RGBA -> RGB32 SSE2 relative speed: 8.90578x
linear RGBA -> RGB32 AVX: (fastest/slowest/average) wall time speed is 3.31775/2.84886/3.2405 runs/second.
linear RGBA -> RGB32 AVX relative speed: 0.745854x
YUV -> YV12 C: (fastest/slowest/average) wall time speed is 155.964/138.181/153.442 runs/second.
YUV -> YV12 C relative speed: 1.0x
YUV -> YV12 SSE2: (fastest/slowest/average) wall time speed is 450.69/430.569/445.116 runs/second.
YUV -> YV12 SSE2 relative speed: 2.88972x
YUV -> YV12 AVX: (fastest/slowest/average) wall time speed is 15.0684/14.3686/14.9177 runs/second.
YUV -> YV12 AVX relative speed: 0.0966147x
YUV -> YUY2 C: (fastest/slowest/average) wall time speed is 201.52/167.831/199.426 runs/second.
YUV -> YUY2 C relative speed: 1.0x
YUV -> YUY2 SSE2: (fastest/slowest/average) wall time speed is 659.215/645.618/654.092 runs/second.
YUV -> YUY2 SSE2 relative speed: 3.2712x
YUV -> YUY2 AVX: (fastest/slowest/average) wall time speed is 21.4287/20.0173/21.215 runs/second.
YUV -> YUY2 AVX relative speed: 0.106335x
linear RGB -> YUV C: (fastest/slowest/average) wall time speed is 8.66521/8.32953/8.50003 runs/second.
linear RGB -> YUV C relative speed: 1.0x
linear RGB -> YUV SSE2: (fastest/slowest/average) wall time speed is 38.0747/33.7847/37.6462 runs/second.
linear RGB -> YUV SSE2 relative speed: 4.39398x
linear RGB -> YUV AVX: (fastest/slowest/average) wall time speed is 3.74787/3.71133/3.74012 runs/second.
linear RGB -> YUV AVX relative speed: 0.432519x

PhrostByte
13th April 2011, 17:39
I made some tests. I use an image I used once before because it has good features to test on like small details, big details, and some well defined letters.
From what I observed most of the scaling kernels show the ringing I described a few weeks back. So this is how I classify the different algorithms:

Thanks for the analysis. My own eyeballed tests tend to agree, I've seen the best downsizing results with Lanczos2/3 and Spline16.

Benchmark results
------------------

The AVX version seems to be very slow :/

Very bizarre results indeed. I'll have to look things over closely, because those can't be correct.

markanini
13th April 2011, 19:00
It does accent ringing, sometimes beneficial, sometimes detrimental depending on the source. A question I want to ask is when dealing with a difficult source what's a good kernel to use when spline16 and lanczos2 has too much ringing and you want to retain decent sharpness still.

Yellow_
14th April 2011, 00:21
I suspect it's caused by chroma bleeding into luma because of subsampling. Some colors right next to each other can react particularly bad. If you post an example image I can take a look.

Thanks, here's the link. It's a 400x zoom of a 1920x1088 frame h264AVC.

http://www.yellowspace.webspace.virginmedia.com/1920x1088_DSLR_400xZoom.png

PhrostByte
14th April 2011, 04:03
It does accent ringing, sometimes beneficial, sometimes detrimental depending on the source. A question I want to ask is when dealing with a difficult source what's a good kernel to use when spline16 and lanczos2 has too much ringing and you want to retain decent sharpness still.

Try Blackman2. I made this nifty little webpage to help people choose a kernel:
http://svn.int64.org/viewvc/int64/resamplehq/doc/kernels.html

You'll need a browser that supports HTML5 canvas.

Thanks, here's the link. It's a 400x zoom of a 1920x1088 frame h264AVC.

http://www.yellowspace.webspace.virginmedia.com/1920x1088_DSLR_400xZoom.png

Yea, that's chroma bleeding. It's more noticeable when color meets white/black/gray/etc., because grays don't actually have chroma. When chroma gets subsampled, it gives the gray some of the surrounding colors' chroma and results in weird colors.

There actually is something I can do to help combat this, though I haven't started any work on it as it's a little complex.

Archimedes
14th April 2011, 14:34
Spline36Resize >> (http://img232.imageshack.us/i/sn850652spline36resize.png/)
ResampleHQ, Spline36 >> (http://img641.imageshack.us/i/sn850652spline36.png/)

Depending on the source and the used kernel, gamma aware resizing produces dark lines around bright areas where the same 8 bit resizer in AviSynth did not fail (see example above). Tested also with Image Analyzer (which is also capable of gamma aware resizing).

The effect decrease with Lanczos (2 lobes), but not completely. Same with Spline16. With Blackman (2 lobes) and Bicubic (b=0.33, c=0.33) the effect is gone.

ResampleHQ, Lanczos (2 lobes) >> (http://img810.imageshack.us/i/sn850652lanczos.png/)
ResampleHQ, Blackman (2 lobes) >> (http://img28.imageshack.us/i/sn850652blackman.png/)
ResampleHQ, Bicubic (b=0.33, c=0.33) >> (http://img191.imageshack.us/i/sn850652bicubic.png/)

Yellow_
14th April 2011, 18:29
Yea, that's chroma bleeding. It's more noticeable when color meets white/black/gray/etc., because grays don't actually have chroma. When chroma gets subsampled, it gives the gray some of the surrounding colors' chroma and results in weird colors.

Ok, thanks for the explanation.

There actually is something I can do to help combat this, though I haven't started any work on it as it's a little complex.

Good news, look forward to that all in good time.

Archimedes
15th April 2011, 09:47
good balance of both of them:
lanczos (best in my opinion)
blackman (2nd best)
spline16
catmull

Did some further tests and came to similar results. A good compromise between blurring, sharpening and ringing seems to be: Lanczos (2 lobes) and CatmullRom (which is practically the same as Lanczos with 2 lobes).

Bicubic >> (http://img691.imageshack.us/i/pditargetbicubic.png/)
Blackman (2 lobes) >> (http://img585.imageshack.us/i/pditargetblackman.png/)
CatmullRom >> (http://img864.imageshack.us/i/pditargetcatmullrom.png/)
Lanczos (2 lobes) >> (http://img834.imageshack.us/i/pditargetlanczos.png/)
Spline16 >> (http://img853.imageshack.us/i/pditargetspline16.png/)

TinTime
15th April 2011, 11:25
All looks very interesting - thanks for this!

Anyway, I've just found a small bug. If you set src_width or src_height to -0 then it produces some peculiar (although not unattractive :)) results. Presumably it should use default values if either of these are set to 0, like AVISynth's resizers.

PhrostByte
19th April 2011, 22:10
Benchmark results
------------------

The AVX version seems to be very slow :/

If you don't mind trying a new version, I think I figured out what was going on.

http://sourceforge.net/projects/int64/files/ResampleHQ/ResampleHQ-v7pre2-avxbench.zip/download

ChaosKing
20th April 2011, 21:52
Looks good now or should I say: an amazing speedup :P

It could be that since "linear RGB -> x ", the values ​​are slightly distorted, because my brother started to play Portal 2 on that PC. ^^"

RGB24 -> linear RGB C: (fastest/slowest/average) wall time speed is 4.64519/4.6013/4.63308 runs/second.
RGB24 -> linear RGB C relative speed: 1.0x
RGB24 -> linear RGB SSSE3: (fastest/slowest/average) wall time speed is 36.5916/36.1973/36.4791 runs/second.
RGB24 -> linear RGB SSSE3 relative speed: 7.8773x
RGB24 -> linear RGB AVX: (fastest/slowest/average) wall time speed is 63.7797/63.3852/63.5543 runs/second.
RGB24 -> linear RGB AVX relative speed: 13.7303x
RGB32 -> linear RGB C: (fastest/slowest/average) wall time speed is 1.96892/1.95244/1.96175 runs/second.
RGB32 -> linear RGB C relative speed: 1.0x
RGB32 -> linear RGB SSE2: (fastest/slowest/average) wall time speed is 38.7904/38.4984/38.6492 runs/second.
RGB32 -> linear RGB SSE2 relative speed: 19.7014x
RGB32 -> linear RGB AVX: (fastest/slowest/average) wall time speed is 61.5876/60.6015/61.2052 runs/second.
RGB32 -> linear RGB AVX relative speed: 31.2799x
RGB32 -> linear RGBA C: (fastest/slowest/average) wall time speed is 1.89056/1.88258/1.8879 runs/second.
RGB32 -> linear RGBA C relative speed: 1.0x
RGB32 -> linear RGBA SSE2: (fastest/slowest/average) wall time speed is 37.478/37.2069/37.377 runs/second.
RGB32 -> linear RGBA SSE2 relative speed: 19.8238x
RGB32 -> linear RGBA AVX: (fastest/slowest/average) wall time speed is 58.1383/57.8567/58.0005 runs/second.
RGB32 -> linear RGBA AVX relative speed: 30.7519x
YV12 -> YUV C: (fastest/slowest/average) wall time speed is 49.1157/48.8132/48.9772 runs/second.
YV12 -> YUV C relative speed: 1.0x
YV12 -> YUV SSE2: (fastest/slowest/average) wall time speed is 293.662/276.124/290.44 runs/second.
YV12 -> YUV SSE2 relative speed: 5.97899x
YV12 -> YUV AVX: (fastest/slowest/average) wall time speed is 291.98/290.154/291.136 runs/second.
YV12 -> YUV AVX relative speed: 5.94473x
YUY2 -> YUV C: (fastest/slowest/average) wall time speed is 73.0191/72.4696/72.8227 runs/second.
YUY2 -> YUV C relative speed: 1.0x
YUY2 -> YUV SSE2: (fastest/slowest/average) wall time speed is 418.173/407.67/416.318 runs/second.
YUY2 -> YUV SSE2 relative speed: 5.7269x
YUY2 -> YUV AVX: (fastest/slowest/average) wall time speed is 441.182/376.143/405.183 runs/second.
YUY2 -> YUV AVX relative speed: 6.04201x
YUV -> linear RGB C: (fastest/slowest/average) wall time speed is 6.26964/5.08769/6.1638 runs/second.
YUV -> linear RGB C relative speed: 1.0x
YUV -> linear RGB SSE2: (fastest/slowest/average) wall time speed is 38.2352/37.4367/37.9741 runs/second.
YUV -> linear RGB SSE2 relative speed: 6.09846x
YUV -> linear RGB AVX: (fastest/slowest/average) wall time speed is 59.4667/59.0774/59.3507 runs/second.
YUV -> linear RGB AVX relative speed: 9.48486x
linear RGB -> RGB24 C: (fastest/slowest/average) wall time speed is 1.91731/1.89385/1.90992 runs/second.
linear RGB -> RGB24 C relative speed: 1.0x
linear RGB -> RGB24 SSSE3: (fastest/slowest/average) wall time speed is 39.3451/38.7191/39.0217 runs/second.
linear RGB -> RGB24 SSSE3 relative speed: 20.521x
linear RGB -> RGB24 AVX: (fastest/slowest/average) wall time speed is 53.6576/51.0381/52.9992 runs/second.
linear RGB -> RGB24 AVX relative speed: 27.9859x
linear RGB -> RGB32 C: (fastest/slowest/average) wall time speed is 1.82714/1.79387/1.81084 runs/second.
linear RGB -> RGB32 C relative speed: 1.0x
linear RGB -> RGB32 SSE2: (fastest/slowest/average) wall time speed is 44.3867/44.0377/44.1762 runs/second.
linear RGB -> RGB32 SSE2 relative speed: 24.293x
linear RGB -> RGB32 AVX: (fastest/slowest/average) wall time speed is 53.4973/45.477/51.7734 runs/second.
linear RGB -> RGB32 AVX relative speed: 29.2792x
linear RGBA -> RGB32 C: (fastest/slowest/average) wall time speed is 1.72983/1.65757/1.71013 runs/second.
linear RGBA -> RGB32 C relative speed: 1.0x
linear RGBA -> RGB32 SSE2: (fastest/slowest/average) wall time speed is 42.1848/39.7659/41.8548 runs/second.
linear RGBA -> RGB32 SSE2 relative speed: 24.3867x
linear RGBA -> RGB32 AVX: (fastest/slowest/average) wall time speed is 48.3195/46.7094/47.833 runs/second.
linear RGBA -> RGB32 AVX relative speed: 27.9332x
YUV -> YV12 C: (fastest/slowest/average) wall time speed is 146.967/143.542/145.766 runs/second.
YUV -> YV12 C relative speed: 1.0x
YUV -> YV12 SSE2: (fastest/slowest/average) wall time speed is 390.946/370.838/383.787 runs/second.
YUV -> YV12 SSE2 relative speed: 2.66009x
YUV -> YV12 AVX: (fastest/slowest/average) wall time speed is 392.435/299.917/359.429 runs/second.
YUV -> YV12 AVX relative speed: 2.67022x
YUV -> YUY2 C: (fastest/slowest/average) wall time speed is 187.74/182.522/186.619 runs/second.
YUV -> YUY2 C relative speed: 1.0x
YUV -> YUY2 SSE2: (fastest/slowest/average) wall time speed is 521.429/455.525/489.856 runs/second.
YUV -> YUY2 SSE2 relative speed: 2.77739x
YUV -> YUY2 AVX: (fastest/slowest/average) wall time speed is 492.264/432.675/468.23 runs/second.
YUV -> YUY2 AVX relative speed: 2.62205x
linear RGB -> YUV C: (fastest/slowest/average) wall time speed is 2.94834/2.44282/2.75141 runs/second.
linear RGB -> YUV C relative speed: 1.0x
linear RGB -> YUV SSE2: (fastest/slowest/average) wall time speed is 38.0381/36.8236/37.6511 runs/second.
linear RGB -> YUV SSE2 relative speed: 12.9016x
linear RGB -> YUV AVX: (fastest/slowest/average) wall time speed is 56.6484/54.8323/56.095 runs/second.
linear RGB -> YUV AVX relative speed: 19.2137x

PhrostByte
22nd April 2011, 02:35
Looks good now or should I say: an amazing speedup :P

Sweet, glad it worked. Those results were about what I expected.

henryho_hk
13th May 2011, 02:59
V6 x64 is giving me a blank screen in occasions. I am trying to prepare for a simple and reproducible scenario.....

markanini
18th May 2011, 00:35
http://svn.int64.org/viewvc/int64/resamplehq/doc/kernels.html
I take it from studying your graph that Blackman3, Catmull-Rom, Lanczos2, Spline16 would all make good general purpose resizing kernels and some quick visual test I made seem to confirm this, atleast to the extent that I can't tell them apart and they all look perfectly fine.

PhrostByte
18th May 2011, 01:05
V6 x64 is giving me a blank screen in occasions. I am trying to prepare for a simple and reproducible scenario.....

Let me know!

I take it from studying your graph that Blackman3, Catmull-Rom, Lanczos2, Spline16 would all make good general purpose resizing kernels and some quick visual test I made seem to confirm this, atleast to the extent that I can't tell them apart and they all look perfectly fine.

Yes. Start from one of those and if it doesn't look good, try something that improves in the areas you need.

Lyle_JP
20th May 2011, 07:26
V6 x64 is giving me a blank screen in occasions. I am trying to prepare for a simple and reproducible scenario.....

Unfortunately, I have nothing but reproducible scenarios. I am trying to run the x64 version on sET's 64-bit Avisynth 2.5.8, and every video I feed to ResampleHQ comes out as nothing but a properly resized black screen. It doesn't matter what arguments I use, even all defaults. Source doesn't matter, either. I wish I could be more help narrowing down the issue, but for now this plug-in simply doesn't work at all in my environment.

PhrostByte
25th May 2011, 01:09
V6 x64 is giving me a blank screen in occasions. I am trying to prepare for a simple and reproducible scenario.....

Unfortunately, I have nothing but reproducible scenarios. I am trying to run the x64 version on sET's 64-bit Avisynth 2.5.8, and every video I feed to ResampleHQ comes out as nothing but a properly resized black screen. It doesn't matter what arguments I use, even all defaults. Source doesn't matter, either. I wish I could be more help narrowing down the issue, but for now this plug-in simply doesn't work at all in my environment.

found the problem. will put a fix out shortly.

NicolasRobidoux
3rd June 2011, 21:37
...

blurry: principally because of this (http://forum.doom9.org/showthread.php?)p=1474853#post1474853)
bilinear
rubidoux
...

Warning:

The robidoux cubic filter is meant to be used with Clamped EWA (Elliptical Weighted Averaging) resampling, which is different from the way the other cubic filters are generally used.

It is meant to be used with a technique originating from the field of texture mapping, adapted to perform resizing and resampling.
See ImageMagick Examples (http://www.imagemagick.org/Usage/distorts/#area_resample), the Better and faster image resizing and resampling Libre Graphics Meeting 2011 presentation video (http://river-valley.tv/better-and-faster-image-resizing-and-resampling/) as well as http://www.imagemagick.org/Usage/resize/#distort_resize and http://www.imagemagick.org/Usage/resize/#robidoux for details.

This being said, the best Clamped EWA method is the filter known in recent ImageMagick as lanczossharp (IMHO).
That is, "convert -filter lanczossharp -distort resize..." with a very recent version of ImageMagick.

IMHO Clamped EWA lanczossharp is actually a fantastic resizing and resampling filter. Better than anything on your list.

This does not mean that the robidoux filter will "break things" if used like the other bicubic filters. It is just that, the way you are using it, it is not supposed to be very good. Indeed, it is quite blurry.

madshi
3rd June 2011, 22:22
Hi Nicolas,

nice to see you here, welcome to the forum!

One thing I don't understand is how "Elliptical" has anything to do with simple image up-/downscaling. I mean if there's no perspective transformation, how can there be ellipses? How can it matter whether you use EWA or conventional distance weighting if all ellipses are actually circles?

BTW, how do you like this idea:

http://forum.doom9.org/showthread.php?t=145358

NicolasRobidoux
4th June 2011, 00:49
Thanks for the update. Hermite and Robidoux do not working (unsupported kernels).

Note: Robidoux is a recent addition to ImageMagick.

NicolasRobidoux
4th June 2011, 01:04
Hi Nicolas,

nice to see you here, welcome to the forum!


Hello Madshi.

(I won't be too good of a poster for a bit: I'm reading the threads a bit too fast to make sure all my comments are on target.)

I actually joined Doom9 in March to push some my goods unto unsuspecting passerbys. And lo and behold, some relevant threads just sprouted!

One thing I don't understand is how "Elliptical" has anything to do with simple image up-/downscaling. I mean if there's no perspective transformation, how can there be ellipses? How can it matter whether you use EWA or conventional distance weighting if all ellipses are actually circles?...
I could go into a longwinded explanation, but won't.

Let me just say that if you are preserving aspect ratios exactly, then you won't have ellipses: only disks.

If you don't reduce in any of the two directions (for example, if you are enlarging in both directions, or keeping one dimension the same and enlarging in the other), you will get disks, not ellipses.

But if your resize ratio is slightly different horizontally and vertically, and you are downsampling in at least one direction, then you'll get ellipses aligned with the axes instead of disks.

More wishy washy: Your image may have sampled the world on a uniform grid, but the world is not laid out on a uniform grid. Some of the artifacts one gets with common samplers are a consequence of being enslaved to Descartes. Using rotationally invariant samplers takes off these shackles.

But really, the proof is in the pudding:

Install a recent version of ImageMagick and try any resizing task (up/down/mix and match) with "convert -filter lanczossharp -distort resize".

Documentation: http://www.imagemagick.org/Usage/distorts/#resize and http://www.imagemagick.org/Usage/resize/#distort_resize.

If you find something that works, overall, better with natural images, let me know.

(Warning: The Jinc EWA code is going to see some major optimizations this Summer. So will the (regular) tensor Lanczos code.)

Mini-Me
4th June 2011, 04:58
Hello Madshi.

(I won't be too good of a poster for a bit: I'm reading the threads a bit too fast to make sure all my comments are on target.)

I actually joined Doom9 in March to push some my goods unto unsuspecting passerbys. And lo and behold, some relevant threads just sprouted!

I could go into a longwinded explanation, but won't.

Let me just say that if you are preserving aspect ratios exactly, then you won't have ellipses: only disks.

If you don't reduce in any of the two directions (for example, if you are enlarging in both directions, or keeping one dimension the same and enlarging in the other), you will get disks, not ellipses.

But if your resize ratio is slightly different horizontally and vertically, and you are downsampling in at least one direction, then you'll get ellipses aligned with the axes instead of disks.

More wishy washy: Your image may have sampled the world on a uniform grid, but the world is not laid out on a uniform grid. Some of the artifacts one gets with common samplers are a consequence of being enslaved to Descartes. Using rotationally invariant samplers takes off these shackles.

But really, the proof is in the pudding:

Install a recent version of ImageMagick and try any resizing task (up/down/mix and match) with "convert -filter lanczossharp -distort resize".

Documentation: http://www.imagemagick.org/Usage/distorts/#resize and http://www.imagemagick.org/Usage/resize/#distort_resize.

If you find something that works, overall, better with natural images, let me know.

(Warning: The Jinc EWA code is going to see some major optimizations this Summer. So will the (regular) tensor Lanczos code.)

Whoa...
A few years ago I was thinking about texture magnification for 3D graphics, and I idly wondered if using the radial distance from source samples might be better for rotational invariance than using traditional resizing kernels...but trying to figure out things like zero crossings made my brain hurt. I'm sooooo happy that someone else actually went forward with the legwork! It's probably still a long way from being put into GPU's, and it isn't used in Avisynth yet either, but it's really cool to see that it exists. :)

madshi
4th June 2011, 08:10
Let me just say that if you are preserving aspect ratios exactly, then you won't have ellipses: only disks.

If you don't reduce in any of the two directions (for example, if you are enlarging in both directions, or keeping one dimension the same and enlarging in the other), you will get disks, not ellipses.

But if your resize ratio is slightly different horizontally and vertically, and you are downsampling in at least one direction, then you'll get ellipses aligned with the axes instead of disks.

More wishy washy: Your image may have sampled the world on a uniform grid, but the world is not laid out on a uniform grid. Some of the artifacts one gets with common samplers are a consequence of being enslaved to Descartes. Using rotationally invariant samplers takes off these shackles.
Ok, makes sense.

Personally, I'm not much of a math/science guy. I usually understand things best by looking at code. Do you happen to have a Jinc EWA implementation which is as simple and short as possible? Ideally only targetted at up/downscaling (not for rotations or anything else), optimized for easy understanding instead of speed? That would go a long way helping me understand the basic principle of how Jinc EWA differs from convential linear resamplers.

If you find something that works, overall, better with natural images, let me know.
I've found that ICBI (which I've modded to not ring) produces better results than simple linear Lanczos. But NNEDI3 seems to be even better. See here:

original: http://img69.imageshack.us/img69/6127/z3hs1n8ns1t.png
spline36: http://bengal.missouri.edu/~kes25c/castle_spline36.png
NNEDI3: http://bengal.missouri.edu/~kes25c/castle_abs.png

PhrostByte
4th June 2011, 10:32
Personally, I'm not much of a math/science guy. I usually understand things best by looking at code. Do you happen to have a Jinc EWA implementation which is as simple and short as possible? Ideally only targetted at up/downscaling (not for rotations or anything else), optimized for easy understanding instead of speed? That would go a long way helping me understand the basic principle of how Jinc EWA differs from convential linear resamplers.

I'm the same way! I'd love to see some simple code for it so I can try it out here.

I did notice some of this stuff while digging through ImageMagick's code, but didn't understand what it was doing so I left it alone. Overall ImageMagick has a far more interesting resampling system.

NicolasRobidoux
4th June 2011, 12:39
...
I've found that ICBI (which I've modded to not ring) produces better results than simple linear Lanczos. But NNEDI3 seems to be even better.
...

The *NEDI* people have done great work, and I consider their methods my only "real" competition in the quality department (if you forgive the boast contained in this statement).

(I still need to do a more careful comparison. Waiting for sabbatical or unemployment so I can get some work done.)

madshi
4th June 2011, 12:48
I'm the same way!
Yeah, we programmers are weird. We prefer code over plain English explanations... :)

The *NEDI* people have done great work, and I consider their methods my only "real" competition in the quality department (if you forgive the boast contained in this statement).
FWIW, NNEDI3 is not related to NEDI in any way. I don't like most of the NEDI variations much, personally, because they have loads of weird directional artifacts. NNEDI3 is a completely different solution, based on a trained neural network. As far as I can see: NEDI < ICBI < NNEDI3. But I guess this is OT here.

NicolasRobidoux
4th June 2011, 13:11
...
Do you happen to have a Jinc EWA implementation which is as simple and short as possible? Ideally only targetted at up/downscaling (not for rotations or anything else), optimized for easy understanding instead of speed? That would go a long way helping me understand the basic principle of how Jinc EWA differs from convential linear resamplers.
...

Unfortunately this is not something I will be able to put time into for a few months. At this point, your best bet is the (not yet fully optimized) ImageMagick code found here:

http://trac.imagemagick.org/browser/ImageMagick/trunk/magick/distort.c

http://trac.imagemagick.org/browser/ImageMagick/trunk/magick/resample.c

http://trac.imagemagick.org/browser/ImageMagick/trunk/magick/resize.c

NicolasRobidoux
4th June 2011, 13:14
...
FWIW, NNEDI3 is not related to NEDI in any way. I don't like most of the NEDI variations much, personally, because they have loads of weird directional artifacts.
...

Thank you anyway for the info.

I had not done a careful comparison, but iNEDI seemed to work pretty well with my limited testing.

madshi
4th June 2011, 14:22
Unfortunately this is not something I will be able to put time into for a few months. At this point, your best bet is the (not yet fully optimized) ImageMagick code
Thanks, will have a look when I find some time.

I had not done a careful comparison, but iNEDI seemed to work pretty well with my limited testing.
ICBI was created by the same guys who created iNEDI. ICBI is newer than iNEDI and as far as I can see, it's faster and has better image quality. But NNEDI3 seems to be even better than ICBI, judging from a quick comparison.

NicolasRobidoux
4th June 2011, 15:12
...
ICBI was created by the same guys who created iNEDI.
...

Oops! I indeed meant ICBI, not iNEDI.

markanini
4th June 2011, 19:36
Install a recent version of ImageMagick and try any resizing task (up/down/mix and match) with "convert -filter lanczossharp -distort resize".
Just tried this on a half dozen photographic images. Smooth yet detailed, very nice. On one problematic image with combined aliasing/ringing/moire I modified the command line to use the filter with your name and got a result that got me a (subjectively) better detail-to-artifacts ratio than anything I could get out of Avisynth.

madshi
4th June 2011, 19:41
@markanini, can you upload your "problematic image" and the result you got with ImageMagick?

NicolasRobidoux
4th June 2011, 19:46
...
On one problematic image with combined aliasing/ringing/moire
...
When moire is a concern, it should surprise no-one that "convert -filter lanczos -distort resize" is a safer
bet than "convert -filter lanczossharp -distort resize". (The results are generally almost the same, however, so this substitution may not make much difference.)

And yes, "convert -filter robidoux -distort resize" or "convert -distort resize" (since robidoux is the default---not my decision) is an OK scheme. Robidoux is kind of the Mitchell-Netravali of the Clamped EWA world. I don't particularly like it, but many people find it to be "balanced." Also: Robidoux is just about as cheap a Clamped EWA scheme can be.

I'm not being falsely modest here: I strongly believe that "distort lanczossharp" and "distort lanczos" are better all around schemes.

(Oh! And Robidoux would make Don Munsil happy: 2-lobe filter (like Catmull-Rom, Mitchell-Netravali and Lanczos 2) constructed with no direct consideration of frequency response (although there is a surprising connection to Jinc Lanczos 2: see http://www.imagemagick.org/Usage/resize/#robidoux).)

markanini
4th June 2011, 20:36
@markanini, can you upload your "problematic image" and the result you got with ImageMagick?

Sure:http://imgur.com/a/javFH
Originally a cameraphone image, cropped, NNEDI3 x4 upsized, de-convolution sharpened luminance.

NicolasRobidoux
4th June 2011, 20:42
...
NNEDI3 x4 upsized, de-convolution sharpened luminance.
All bets are off with "originals" which actually are sharpened enlargements.

markanini
4th June 2011, 20:47
Fair enough, the real original:
http://imgur.com/jE0US

EDIT: Actually it may have been resized and re-compressed. It's from the photographers blog. He didn't keep the original so I can't tell what's been done to it. I played bass guitar in this band while it lasted. Sorry about any confusion.

NicolasRobidoux
4th June 2011, 20:55
Mark: Thank you for the precisions.

This would appear to explain the "amazing" performance of the Robidoux filter in this particular instance. (Phew! My bad name is saved.)

madshi
4th June 2011, 20:56
Eeeeuw, the "original" looks totally awful. Not a good candidate for comparison, IMHO. Also I'm more interested in upscaling than in downscaling. Thanks, anyway, though!

@PhrostByte, hope you don't mind the off-topic chat.

markanini
4th June 2011, 21:42
I just want to add that the image host's layout lets you compare the Clamped EWA Robidoux to your browsers resizing algo. In Chrome I see close to equal amounts of texture in the brickwork and left hand side of the tent yet markedly less artifacting in the Robidoux version when looking at the checkerboard tiles and any hard edges like the speaker stands.

*.mp4 guy
5th June 2011, 01:14
Browser interpolation is notoriously terrible. Anything anyone would normally consider using would be better.

henryho_hk
5th June 2011, 02:09
Since EWA distort involves much more pixels than normal resizers, may I presume that there is a greater need to "linearize" the image beforehand?

NicolasRobidoux
5th June 2011, 02:19
Since EWA distort involves much more pixels than normal resizers, may I presume that there is a greater need to "linearize" the image beforehand?

It should not make much difference.

Also:

EWA Robidoux only requires about 4pi/16 of the input values required by orthogonal bicubic or Lanczos 2 filtering (or interpolation if you are enlarging). Note that 4pi/16 < 1.

EWA Jinc Lanczos 3 and EWA Jinc Lanczos 3 "sharp" require a little more than 9pi/36 of the input values required by orthogonal Lanczos 3 filtering. Again, 9pi/36 < 1.

That is: Generally, EWA resizing methods use less input data than comparable orthogonal resize methods.

(The above estimates are for reducing. They are pretty rough for enlarging. When I have more time, I'll compute the exact ratios when enlarging. But the gist is correct.)

markanini
5th June 2011, 04:10
Browser interpolation is notoriously terrible. Anything anyone would normally consider using would be better.

I neglected to mention my browser induced artifacts we're similar to what I got using anything else inside or outside of Avisynth that didn't cause significant blurring. So in this case I found a exception to your resoning, which I agree with in general, in favor of EWA Robidoux. For the first time I can at least view this image at arms length from my screen and not be too annoyed. Not to kiss mr. Robidoux ass, I'd be glad to hear about anything else that might benfit this image, which AFAIK is unlikely unless a better NNEDI3 or better deconvolution sharpening becomes available which is nothing I'll hold my breath for. I'll leave it at that.

*.mp4 guy
5th June 2011, 04:11
I should not make much difference.

Also:

EWA Robidoux only requires about 4pi/16 of the input values required by orthogonal bicubic or Lanczos 2 filtering (or interpolation if you are enlarging). Note that 4pi/16 < 1.

EWA Jinc Lanczos 3 and EWA Jinc Lanczos 3 "sharp" require a little more than 9pi/36 of the input values required by orthogonal Lanczos 3 filtering. Again, 9pi/36 < 1.

That is: Generally, EWA resizing methods use less input data than comparable orthogonal resize methods.

(The above estimates are for reducing. They are pretty rough for enlarging. When I have more time, I'll compute the exact ratios when enlarging. But the gist is correct.)
Presumably you are talking about orthogonal linear interpolation as if it was carried out on a two dimensional area, This is not the case, As I believe was mentioned in reference to the superiority of ewa filters.

A 2 lobe orthogonal linear interpolator would typically require 7.5 total input pixel operations per input pixel (IPOPIP's) for a 2:1 downscale, as implemented by a separable filter, whereas it would take 25 IPOPIP's if implemented as a 2 dimensional filter. I cannot see how a viable 2 lobed interpolation kernel could be implemented with less then 7.5 IPOPIP's, though 25 IPOPIP's is an easily bested number.

Its possible I have misunderstood you due to differing conventions, but that's how it hashes out after everything is broken down into convolution operations.

[edit}
I neglected to mention my browser induced artifacts we're similar to what I got using anything else inside or outside of Avisynth that didn't cause significant blurring. For the first time I can at least view this image at arms length from my screen and not be too annoyed. Not to kiss mr. Robidoux ass, I'd be glad to hear about anything else that might benfit this image, which AFAIK is unlikely unless a better NNEDI3 or better deconvolution sharpening becomes available which is nothing I'll hold my breath for. I'll leave it at that. What exactly is your desired use case for this image? are you trying to make it as large as the nnedi3/deconvolution image, or trying to make it as large as the Robidoux downscale? the whole thing doesn't make much sense to me.

NicolasRobidoux
5th June 2011, 14:10
There indeed seems to be some misunderstanding going on here.

First, my "I(t) should not make much difference" (yes, there was a typo, a missing "t") was an answer to henryho_hk 's question "Since EWA distort involves much more pixels than normal resizers, may I presume that there is a greater need to "linearize" the image beforehand?", which I understood as concerning the use of linear light.

In this context, I was not counting flops---flop-wise, an EWA method is definitely more expensive than a comparable separable method implemented accordingly---I was counting the raw number of values that are combined to get a single output value.

Let's compare, say, the typical number of pixels "averaged" to get an orthogonal Lanczos 2-lobes or Bicubic (Keys filtering or cubic B-Spline smoothing, say) filtered output value when downsampling by a factor of 2 in both directions, to the number required by Clampled EWA Robidoux of Jinc Lanczos 2.

Note also that I am filtering, not interpolating. If you are doing a 2:1 downscale by interpolating, you are begging for moire and jaggies. Not as much if you filter. So, generally, I don't recommend using interpolation in and by itself when downsampling. (Of course, you could low pass the original with, for example, box filtering, and then interpolate, but this is not what I'm comparing. I'm looking at using exactly one filter to do the downsampling. Please clarify if I am missing something.)

For simplicity, I'll consider an output pixel value located at the average of four nearby input pixel locations ("interlaced," kind of). I could also consider other locations, to get a typical value.

With the orthogonal versions, you are grabbing everything that falls strictly within a (2*4)x(2*4)=8x8 square centered at the output location. This is 64 pixel values.

With the EWA versions, you are grabbing everything that falls within a disk of radius 2*2=4 (actually, EWA Jinc Lanczos 2 extends slightly past radius 2; I'll ignore this for now; I like Robidoux more anyway). A little programming establishes that there are 52 such pixel locations.

Compare this to my earlier estimate:

52/64 = .81

4pi/16 = .79

Pretty close.

(Yes, I understand that I should consider other possible locations for the output pixel and average the counts. I need coffee.)

-----

P.S. It finally dawned on me what IPOPIP count is. I'll do THAT count in a future post.

Presumably you are talking about orthogonal linear interpolation as if it was carried out on a two dimensional area, This is not the case, As I believe was mentioned in reference to the superiority of ewa filters.

A 2 lobe orthogonal linear interpolator would typically require 7.5 total input pixel operations per input pixel (IPOPIP's) for a 2:1 downscale, as implemented by a separable filter, whereas it would take 25 IPOPIP's if implemented as a 2 dimensional filter. I cannot see how a viable 2 lobed interpolation kernel could be implemented with less then 7.5 IPOPIP's, though 25 IPOPIP's is an easily bested number.

Its possible I have misunderstood you due to differing conventions, but that's how it hashes out after everything is broken down into convolution operations.
...

NicolasRobidoux
5th June 2011, 14:18
If the question is: "Will an EWA method run as fast for resizing as a comparable separable method?", the answer is "No."

As far as the method I'm promoting (Clamped EWA Jinc lanczossharp, which is not the same as Clamped EWA Robidoux) goes, the filter kernel's support is a disk with radius slightly larger than 3. We are certainly not talking about greased lightning.

*.mp4 guy
5th June 2011, 16:14
Note also that I am filtering, not interpolating. If you are doing a 2:1 downscale by interpolating, you are begging for moire and jaggies. Not as much if you filter. So, generally, I don't recommend using interpolation in and by itself when downsampling. (Of course, you could low pass the original with, for example, box filtering, and then interpolate, but this is not what I'm comparing. I'm looking at using exactly one filter to do the downsampling. Please clarify if I am missing something.)(lowpass) Filtering and interpolation are functionally the same in this case, they both are carried with the same operation.

NicolasRobidoux
6th June 2011, 04:25
Assuming I understand correctly what IPOPIP is, with the geometry I described in my earlier post, an orthogonal two-lobe filter will require 4 IPOPIP to downsample by a factor of 2 in a data driven implementation exploiting separability, and an EWA two-lobe filter will require 13 in the same context. (A bit shaky on the computation but I think I got the drift.)

henryho_hk
6th June 2011, 05:27
I love EWA when processing still photos.... though it may be too luxurious for video processing.

PhrostByte
23rd June 2011, 02:03
Here's version 7. Mostly optimizations -- significantly faster on my Core 2 Quad, I'm curious to see how it performs versus v6 on a >4 core CPU, and ones with AVX capability. Also includes kernel visualizations (http://svn.int64.org/viewvc/int64/resamplehq/doc/kernels.html).

http://sourceforge.net/projects/int64/files/ResampleHQ/ResampleHQ-v7.zip/download

Changelog:

Multi-core optimizations.
SSE/AVX vertical resampler.
AVX implementations of all conversions.
Optimizations to SSE RGB conversions.
Significant memory use reduction and minor optimizations to dithered RGB output.
Better compatibility with Avisynth built-in resizers.
Add kernel visualization docs.
Remove 64-bit version temporarily.


Going to look at EWA for next version, as well as figure out why 64-bit is crashing Avisynth.

henryho_hk
23rd June 2011, 17:12
Gamma-aware EWA? Woh!

NicolasRobidoux
23rd June 2011, 17:22
...
Going to look at EWA for next version, as well as figure out why 64-bit is crashing Avisynth.

FYI

1) The ImageMagick code implementing the best (IMHO) upsampling EWA filter, namely lanczossharp, uses a somewhat slow method of computing the weights. My student Chantal Racette and I will be putting together a faster way of doing this this Summer.

2) There is a very simple EWA implementation (using the teepee, that is, cone filter, which is not very good for upsampling) currently being built into a GEGL method. Its code is sufficiently advanced to be poached. The source code is found here: http://git.gnome.org/browse/gegl/tree/gegl/buffer/gegl-sampler-lohalo.c

Further developments are found in the samplers branch.

You may also contact me directly (or post here) if you have questions.

henryho_hk
24th June 2011, 01:02
PhrostByte, I have a suggestion on the kernel visualiization html.

The kernel names are now taking too much vertical space. Can they be arranged in columns like a table?

NicolasRobidoux
24th June 2011, 11:56
PhrostByte:

Suggestion if you are going to implement EWA in a "scanline friendly" environment for resizing:

Resize to a nearby or larger resolution which is a power of two (so that the EWA coefficients can be recycled every so many scanlines) and finish with an other scheme (bilinear, even).

PhrostByte
24th June 2011, 19:31
FYI

1) The ImageMagick code implementing the best (IMHO) upsampling EWA filter, namely lanczossharp, uses a somewhat slow method of computing the weights. My student Chantal Racette and I will be putting together a faster way of doing this this Summer.

2) There is a very simple EWA implementation (using the teepee, that is, cone filter, which is not very good for upsampling) currently being built into a GEGL method. Its code is sufficiently advanced to be poached. The source code is found here: http://git.gnome.org/browse/gegl/tree/gegl/buffer/gegl-sampler-lohalo.c

Further developments are found in the samplers branch.

You may also contact me directly (or post here) if you have questions.

EWA looks pretty much how I imagined it, just using the basic distance formula to find the sample distance passed to the kernel.

All the Jinc function stuff is completely greek to me, though :)

PhrostByte:

Suggestion if you are going to implement EWA in a "scanline friendly" environment for resizing:

Resize to a nearby or larger resolution which is a power of two (so that the EWA coefficients can be recycled every so many scanlines) and finish with an other scheme (bilinear, even).

I think a significant portion of EWA can be implemented with SIMD, so I should be able to get it pretty fast without sacrificing any quality.

PhrostByte, I have a suggestion on the kernel visualiization html.

The kernel names are now taking too much vertical space. Can they be arranged in columns like a table?

I've been trying to find a better place to put them for a while, to no avail. They should arrange into columns already on Firefox/WebKit.

NicolasRobidoux
24th June 2011, 19:37
Clarification RE: something I wrote earlier: ImageMagick does use efficient formulas for the computation of the jinc 1 function. However, current research will lead to even faster approximations of the best radial kernels, most likely within two months or so.

NicolasRobidoux
24th June 2011, 19:40
Clarification RE: something I wrote earlier: ImageMagick does use efficient formulas for the computation of the jinc 1 function. However, current research will lead to even faster approximations of the best radial kernels, most likely within two months or so.
... in particular, there will be no need for square roots of the distances: short polynomial expansions will use x^2+y^2 (x is horizontal distance between data point and sampling point, y is vertical distance) directly, and there will be no need to compute jinc1 twice (once for the filter, once for the windowing function).

PhrostByte
25th August 2011, 05:08
Version 8. Again, mostly optimizations—overall 2–3x as fast as v7, and in particular resizing RGB is actually slightly faster than Avisynth's gamma-ignorant resizers.

http://sourceforge.net/projects/int64/files/ResampleHQ/ResampleHQ-v8.zip/download

Changelog:

RGB8-specialized gamma corrections—15% faster color conversions.
New gamma correction approximations—200% faster color conversions.
SSE horizontal resampler—25% faster resizing.
Cache optimizations to vertical resampler—10% faster resizing.
Experimental (untested) FMA4 color conversions for AMD Bulldozer.
Reduced memory usage.
Remove automatic multithreading in favor of SetMtMode.
Bug fix: handle very tiny row widths.


64-bit is still not working. I am very puzzled by this—the error "Evaluate: Unrecognized exception!" is happening outside of my code: after AvisynthPluginInit2 finishes successfully and before GetFrame is called. Any devs with 64-bit plugins have some advice?

henryho_hk
25th August 2011, 05:59
New version! Woh!

SubJunk
27th August 2011, 01:17
Thanks a lot for the update

henryho_hk
13th September 2011, 07:12
V8 is giving black screen my computer upsizing 720x480 YV12 source to 1280x720. XP 64bit + Avisynth x86 DLL 2.6.0.2, dated 2011/05/25.

Now I am trying to isolate the test case.

Edit: No more problems with SEt's 2.6 MT 2011.09.13

killazys
2nd November 2011, 22:55
Question... is resizing/colorspace correction related to the bit depth? As in, Hi10P vs. 8bit? And.. if I'm going to be resizing from 1080p to 720p with no colorspace changes, what's the purpose of "gamma-awareness?" Am I missing something?

PhrostByte
3rd November 2011, 03:14
Question... is resizing/colorspace correction related to the bit depth? As in, Hi10P vs. 8bit? And.. if I'm going to be resizing from 1080p to 720p with no colorspace changes, what's the purpose of "gamma-awareness?" Am I missing something?

Bit-depth is unrelated to color-space, resizing, or gamma-aware processing. A higher bit depth will allow you to process and store color more accurately -- nothing more. In practice it lets you represent gradients with less banding.

You can think of gamma-aware processing as treating your image as if it were actual light rather than the typical computerized representation of color. It gives you a more visually correct resize. It's not related to color-space, and doesn't matter if you're converting or not. Simply resizing from 1080p->720p is enough to warrant gamma-aware processing.

I'm moving houses so I won't have enough time for a couple days, but if you want a more detailed explanation I can give one then.

Happy scripting!

jmac698
3rd November 2011, 13:20
One visible effect is that small points of light will look brighter, which is how they should be.

jmac698
3rd November 2011, 13:23
Oh Phrost,
What is the best resizer to get back the original image again? For example blur(1).resize(width*1.3,height).resize(width/1.3,height) where the first step is to ensure it's low bandwith, the last two steps should have virtually no effect.

NicolasRobidoux
3rd November 2011, 14:58
REL=: ... if I'm going to be resizing from 1080p to 720p with no colorspace changes, what's the purpose of "gamma-awareness?" Am I missing something?

Many colour spaces do not measure light/colour intensity with units which are "physically relevant." Instead, they use a "ruler" to represent light/colour intensity which has tickmarks at irregular "physical units."

For example, 0 to 5 in sRGB correspond to light intensities which are much closer to each other in "physical terms" than 200-205, in part to make up for the fact that our eyes are more discriminating of slight shade differences between dark colours than slight shade differences between bright ones. So, if you are only going to store 256^3 shades, you should pack more dark shades than light shades, hence the ruler with denser tick marks near zero than elsewhere.

Many people argue that image resampling should be done in so-called "linear light", meaning light in units that are physically, as opposed to perceptually, relevant (or even matched to hardware specs), because the process of resampling then matches more closely what happens in the real world when, roughly, you have a digital camera with much denser, or less dense, sensors.

Gamma-aware resampling converts the image, measured in "nonlinear" units, to one measured in linear ("physical") units, does the resampling using these units, and then converts back to "perceptual" units. This is the most reasonable way of doing things if you believe that resampling should mimic what happens in the "real world".

Clearly, there is less gain in using a skewed ruler when you store images in floating point (say) because there are enough shades everywhere to please even the most discriminating eyes. But the units you use to store light (or other) measurements are, at least in principle, independent of how many bits you use to store them (even though in practice one choice influences the other: you wouldn't use nanometers to measure your child's height).

jmac698
3rd November 2011, 15:20
The argument is a bit stronger than that, the original viral page I think is this one:
http://www.4p8.com/eric.brasseur/gamma.html

madshi
3rd November 2011, 15:41
The argument is a bit stronger than that, the original viral page I think is this one:
http://www.4p8.com/eric.brasseur/gamma.html
Yeah, that page does a good job showing the benefits of linear light processing. But you have to be aware that most of the images used on that page include very high pixel-to-pixel contrast patterns (e.g. dithering patterns, or alternating lines etc), which you don't ever see in movie content. With typical movie content the biggest difference between gamma scaling and linear light scaling is that you get more halos when using a resampler with a negative lobe (e.g. Lanczos).

SEt
3rd November 2011, 17:06
Real world photos definitely scale more correctly with linear light scaling. Difference is not everywhere and often not noticeable on first look, but also it doesn't suffer from severely wrong results from time to time as non-gamma-aware resize does.
On video it's the sharper and more detailed video - the more the difference.

madshi
3rd November 2011, 17:09
The latest madVR version offers an option to do scaling in linear light. FWIW, so far the majority of users seem to prefer to leave the option off - and that's not due to performance issues.

SEt
3rd November 2011, 17:16
Implementing linear light scaling is a bit tricky. With dumb reverse_gamma -> usual_scaling -> apply_gamma results often won't be nice.

madshi
3rd November 2011, 17:21
So what do you suggest instead? Using a non-linear scaling algorithm?

SEt
3rd November 2011, 17:50
Non-linear scaling allows a lot of freedom that should be able to correct the problems, though mathematics should be pretty intimidating. The best real world non-linear solution so far seems to be nnedi, but it's empirical one.

madshi
3rd November 2011, 18:24
So is non-linear scaling the solution to the "Implementing linear light scaling is a bit tricky" problem you mentioned? Or are you applying special tweaks to linear resamplers to make linear light scaling work better?

I'm not sure if NNEDI3 would work with linear light? I mean it was trained with gamma corrected light images, AFAIK.

SEt
3rd November 2011, 18:48
Personally I tweak linear resamplers now. Results are not perfect though. NNEDI needs to work in the same light it was trained (current in corrected), but being non-linear it doesn't really matter.

madshi
3rd November 2011, 19:03
What kind of tweaks are you doing? Something like this?

http://forum.doom9.org/showthread.php?t=145358

SEt
4th November 2011, 18:26
No, won't help as it's unrelated to main problem (and non-linear too). I'm playing with 2D non-separable resampling. Something similar to EWA but worse.

madshi
4th November 2011, 18:58
Ah ok. I think I'll try my luck with non-linear methods.

tritical
4th November 2011, 19:56
IMO, working in linear light is only important for downscaling (shrinking) images. Specifically, the larger the ratio of original_size/new_size the more important it is. The reason is because the larger the ratio, the stronger the low-pass filtering you need to do before interpolation in order to avoid aliasing, and if you don't work in linear light when doing the low-pass filtering then you wont approximate an optical blur.

For enlargement, where you're not performing low-pass filtering, but are simply trying to predict values at intermediate locations I don't believe that there is any evidence that fir interpolation in linear light is more accurate than in gamma corrected. I have done tests myself that show this. The typical FIR filters don't fit a vast majority of image content any better in linear light than they do in gamma corrected except for cases where the difference between the two would be too small to notice. Working in linear light will definitely cause more ringing (increase overshoot) when using FIR filters with negative taps though.

killazys
6th November 2011, 07:34
Thanks for the responses! One more thing, why did you pick Bilinear for chroma subsampling? It makes everything.. softer..

PhrostByte
9th November 2011, 13:32
Thanks for the responses! One more thing, why did you pick Bilinear for chroma subsampling? It makes everything.. softer..

It's Avisynth's default, that's the only reason.

NicolasRobidoux
16th November 2011, 20:30
http://imagemagick.org/discourse-server/viewtopic.php?f=22&t=19636&p=78285#p78285

Stereodude
17th November 2011, 03:57
Any chance for a x64 version of the latest build or does it still not work?

Stereodude
24th November 2011, 06:05
So, I noticed that my x264 encodes were smaller when using ResampleHQ instead of plain Spline36Resize. Has anyone else noticed this? I would have expected the opposite to be true.

Using ResampleHQ(1280,720, "YV12", "TV.709", "TV.709", false, 0, 0, 0, 0 ,"Spline36"):
encoded 4746 frames, 1.43 fps, 3114.31 kb/s
x264 [info]: frame I:210 Avg QP:14.09 size: 89541
x264 [info]: frame P:1078 Avg QP:19.45 size: 29109
x264 [info]: frame B:3458 Avg QP:23.31 size: 7772

Using Spline36Resize(1280,720):
encoded 4746 frames, 1.36 fps, 3322.29 kb/s
x264 [info]: frame I:211 Avg QP:14.64 size:106961
x264 [info]: frame P:1073 Avg QP:19.67 size: 30165
x264 [info]: frame B:3462 Avg QP:23.33 size: 7877

My x264 command line:
--crf 18 --preset placebo --tune film --vbv-maxrate 40000 --vbv-bufsize 30000 --level 4.1 --keyint 24 --open-gop --ref 9 --b-adapt 2 --colorprim "bt709" --transfer "bt709" --colormatrix "bt709" --sar 1:1

PhrostByte
24th November 2011, 16:58
So, I noticed that my x264 encodes were smaller when using ResampleHQ instead of plain Spline36Resize.

Just a coincidence, probably.

Stereodude
24th November 2011, 17:25
Just a coincidence, probably.Well FWIW I've seen it on all three of my test encodes so far. I've got another few tests clips I'll be doing and will report back.

markanini
24th November 2011, 19:59
Wild guess, it (over-?)accentuates contours over vanilla Spline36 so maybe the encoder has an easier time distinguishing between that and noise and what not....

Stereodude
25th November 2011, 00:13
My original tests were OTA broadcast 1080i HDTV (MPEG-2) that was IVTC'd or QTGMC deinterlaced, debanded, and finally resized. I ran a 5000 frame test this afternoon from a pretty high bitrage Blu-Ray (AVC/H.264) with only resizing and got the same sort of results.

markanini
27th November 2011, 13:07
http://imagemagick.org/discourse-server/viewtopic.php?f=22&t=19636&p=78285#p78285

An updated Lanczossharp?

NicolasRobidoux
27th November 2011, 15:06
An updated Lanczossharp?
Exactly. From a spectral viewpoint (which never tells the whole story in image processing), the theory suggests that the previous one was too soft, which some on this forum stated as well. So, I went on the hunt for a sharper one.

The thread documents the hunt.

NicolasRobidoux
27th November 2011, 18:09
...
Random thought: I don't know how flexible Avisynth's resampling code is, but it would be really nice if you could manually control the support width - maybe by supplying a user specified scaling factor >= 1.0 - instead of having it always scaled by a factor of max(old_width/target_width,1.0).
This last scaling (or its reciprocal, depending on whether you do the lookup "forward" or "backward") is what the ImageMagick implementation of Clamped EWA (Elliptical Weighted Averaging) resampling uses when resizing.

In addition, depending on the filter, there are situations when using a scaling factor < 1.0 gives good results.

NicolasRobidoux
27th November 2011, 18:13
Actually, there is more than one way of doing it. In the Avisynth implementation, your line:

is effectively replaced by:
result = P0 + distance * (P1 + distance * (P2 + distance * P3));
which is marginally faster (fewer multiplies). ;)
This is a standard trick usually taught in Numerical Analysis 1: the Horner Scheme (http://en.wikipedia.org/wiki/Horner_scheme)

NicolasRobidoux
27th November 2011, 18:46
In case someone wants to try the new sharper EWA ImageMagick filters without sorting through the ImageMagick Forum threads I mentioned earlier, here is what you can run if you have a reasonably recent IM install.

The first one is the new four lobe "optimally sharp" Jinc-windowed Jinc EWA (replace INPUT_IMAGE and PERCENT by the desired values):
convert INPUT_IMAGE -define filter:filter=Jinc -define filter:window=Jinc -define filter:blur=0.88451002338585141 -define filter:lobes=4 -distort Resize PERCENT% JincJinc4blur0p88451002338585141.png

It even works fairly well (IMHO) with "Super Mario"-type old skool CG, even though it has noticeable haloing.

The second is the BC-cubic EWA which is a sharper version of the Robidoux filter (using the same optimization method that produced the above 4-lobe Jinc-windowed Jinc):
convert INPUT_IMAGE -define filter:c=.3689927438004929 -filter Cubic -distort Resize PERCENT% RobidouxSharp.png This would be quite a cheap scheme to implement (even though it is a cylindrical scheme).

These methods are documented in the following threads:
http://imagemagick.org/discourse-server/viewtopic.php?f=22&t=19636 and http://imagemagick.org/discourse-server/viewtopic.php?f=22&t=19823&sid=f3054401194ad62e9b9cbe42116ad860

You may see the above as improvements (or at least sharper versions) of convert INPUT_IMAGE -filter LanczosSharp -distort Resize PERCENT% LanczosSharp.png

and convert INPUT_IMAGE -distort Resize PERCENT% Robidoux.png
(the Robidoux EWA filter is the current ImageMagick default).

P.S. If you don't like the idea of using 4 lobes, here is the 3-lobe version:
convert INPUT_IMAGE -define filter:filter=Jinc -define filter:window=Jinc -define filter:blur=0.88549061701764 -define filter:lobes=3 -distort Resize PERCENT% JincJinc3blur0p88549061701764.png
IMHO, the mild "third halo band" of the 4-lobe version is worth the antialiasing.

P.S. Actually, when haloing is glaringly obvious, the "third halo band" may be offensive, and the 3-lobe version is better. This is seen in some of the results linked in http://forum.doom9.org/showthread.php?p=1541800#post1541800. See, for example, the "bullseye" enlargements.

markanini
28th November 2011, 12:07
the new four lobe "optimally sharp" Jinc-windowed Jinc EWA

Tried A/B-ing the new LaczosSharp and lanczos3 in Irfanview on a 10Mpixel photo resized to to 13%. Wasn't sure if I could see a difference at all though the original was neither very detailed or a problem image. I wonder if there's a DBT program for images out there.

EDIT: Is it possible to use a softer kernel for chroma?

NicolasRobidoux
28th November 2011, 15:30
Tried A/B-ing the new LaczosSharp and lanczos3 in Irfanview on a 10Mpixel photo resized to to 13%. Wasn't sure if I could see a difference at all though the original was neither very detailed or a problem image...
What I forgot to say is that it is when you upsample that the differences jump at you, esp. if you have sharp non-vertical/horizontal lines and interfaces.

What you are seeing is that if the image is reasonably smooth ("sub-critical", meaning, not too far from being band-limited away from the Nyquist threshold) both filters are decent low-pass filters, and consequently give somewhat similar results when downsampling because Lanczos 3 and "sharpened" Jinc-windowed Jinc 4 have similar footprints (Lanczos 3 has the usual square of half-width equal to 3, "sharpened" Jinc-windowed Jinc 4 is a disk of radius 3.75126261283712774 with an area just a little over 44, compared to an area of 36 for the Lanczos 3 square).

I expect more of a difference downsampling text, old skool CG or other images with very crisp pieces.

EDIT: Is it possible to use a softer kernel for chroma?I could go on a hunt for a good match, but I think you'd get better results by post-processing the chroma channel with a reasonable anti-aliasing filter. I really like convolving with the five-point cross filter

0 t 0
t 1-4t t
0 t 0
where t is in (0,1/5], with favorite value t=1/8 (1/16 also works well).

infoeater
28th November 2011, 16:26
Following Avisynth script is causing ResampleHQ-v8 to report "Unknown ResampleHQ internal error" at frame 5941:
Note: I used Avisynth "AVS 2.6.0 Alpha 3 [110525]" installed in old directory.

LoadPlugin("C:\Program Files\AviSynth 2.5\plugins\ffms\ffms2.dll")
FFVideoSource("C:\Video\00106org.mp4")
ResampleHQ(width=768, height=432, dstcolorspace="YV12", srcmatrix="TV.709", dstmatrix="TV.601", dither=true, kernel="Spline36", chroma_kernel="Spline36")


EDIT:
Setting dither to false doesn't help.
Setting kernel and chroma_kernel to Bilinear doesn't help.
Setting dstmatrix to TV.709 doesn't help.
Removing all parameters except width and height doesn't help.
Remuxing source file from MTS without audio does help (?!).
Remuxing source file from MTS with same parameters does help (?!).
Removing ResampleHQ from actions on original file doesn't help(?!). Avisynth reported different error: "FFVideoSource: Insanity detected: decoder returned an empty frame"
Out of date. Original muxed file was corrupted in not reproduceable way probably because of temporal lack of disk space while muxing. However Avisynth reported error was not very usable, as it pointed to ResampleHQ, but problem was somewhere else.

NicolasRobidoux
30th November 2011, 13:13
@markanini: I would also consider prefiltering the chroma (before resampling).
... I really like convolving with the five-point cross filter

0 t 0
t 1-4t t
0 t 0
where t is in (0,1/5], with favorite value t=1/8 (1/16 also works well).

markanini
30th November 2011, 14:10
@markanini: I would also consider prefiltering the chroma (before resampling).

I'll give it a try. :)

NicolasRobidoux
30th November 2011, 15:43
Note: The cross filter can be done using a sum of separable filters (actually 1D box). It is equal to

t *
(
[ 1 1 1 ]
+
[ 1 ]
[ 1 ]
[ 1 ]
)
+
(1-6*t) *
[1]

titlis
10th December 2011, 02:53
Bug report (at least I thought)

http://forum.doom9.org/showthread.php?t=163349

ResampleHQ produces a small amount of chroma shifting
as mentioned in thread above.
Probably horizontal resize issue according to Gavino

NicolasRobidoux
10th December 2011, 03:47
@markanini: Mark, I tried to reply with a private message but I'm not sure it went through.

In any case:

I have not tested my attempts at maximally sharpening Jinc-windowed Jinc for downsampling.

Actually, I have tested methods ("mine" and others') for downsampling less than for upsampling.

However, here are some quick pointers regarding downsampling, hopefully correct:

1) Nohalo-LBB, LBB, VSQBS and the like are NOT meant for downsampling.

2) Jinc-windowed Jinc filters are low-pass filters. They should work well. Better than (orthogonal) Lanczos? Don't know.

I am guessing that the maximally sharpened ones (which are not currently "named schemes" in ImageMagick) will not be better than (orthogonal) Lanczos. On the other hand, pre-existing halos and/or moire have less impact when downsampling.

I am also guessing that the current EWA LanczosSharp ("sharpened" Jinc-windowed Jinc 3) will be competitive, maybe better than (orthogonal) Lanczos 3. However, it is nearly identical to EWA Lanczos ("straight" Jinc-windowed Jinc 3), which is why I suggested to Anthony Thyssen of ImageMagick that he just get rid of it to simplify things.

I believe that EWA Robidoux will be slightly better than EWA Lanczos2Sharp ("sharpened" Jinc-windowed Jinc 2), which is why I suggested it be taken out of ImageMagick as well. A large commercial client of mine actually chose EWA Robidoux as default downsampling scheme. It interacts well with strong jpeg compression.

EWA Mitchell and EWA RobidouxSharp (which is not yet in ImageMagick but is defined in its forums) should also work pretty well for downsampling. Mitchell is sharper than Robidoux, and RobidouxSharp is sharper than Mitchell.

EWA Robidoux, Mitchell and RobidouxSharp only have one halo, unlike EWA LanczosSharp and EWA Lanczos (or orthogonal Lanczos which, in ImageMagick, is Lanczos 3).

Although I have no strong reason to think so besides the large number of lobes and consequently halos, I doubt that using 4 lobes or more is worth it. But I may be wrong. In any case, it is not hard to program ImageMagick to use "straight" or "sharpened" EWA to use Jinc-windowed Jinc 4.

3) I have not taken the time to think about what one should expect in terms of spectrum when one is resampling a RAW image (or a "gently" demosaiced RAW image), as opposed to the usual "sharpened" jpegs than come out of many digital cameras. This may have an impact on what will work well, or not. It could be that this is just what the maximally sharpened EWA Jinc-windowed Jinc are for.

killazys
14th December 2011, 04:19
So.. was 16 bit input/output support ever added in to this?

Also, if I have dark halos as evidenced in the mouse-over picture here: http://screenshotcomparison.com/comparison/98651
What downsampling filter would be recommended?

Sapo84
14th December 2011, 17:39
So.. was 16 bit input/output support ever added in to this?
That would be nice, ResampleHQ is by far the best resizer out there (you can really see the differenze when there is overlayed text, ResampleHQ looks much brighter and more natural), 16 bit input and output would mean having a pretty big part of the filtering process with higher precision, which really would help a lot when encoding with the Hi10P profile.

Also, if I have dark halos as evidenced in the mouse-over picture here: http://screenshotcomparison.com/comparison/98651
What downsampling filter would be recommended?
If you are bothered by the dark halos (they don't seems too bad to me) why not giving dehalo_alpha a try?
Setting brightstr to 0.0 and darkstr to 0.0...1.0 should reduce dark halos quite effectively.

Stephen R. Savage
14th December 2011, 21:28
For those interested, the results of ResampleHQ can be recreated using DitherTools (http://forum.doom9.org/showthread.php?t=153589).


ImageSource("earthlights_big.jpg")
x = 1200
y = 600

Dither_convert_8_to_16()
Dither_y_gamma_to_linear()
Dither_resize16(x, y)
Dither_y_linear_to_gamma()
DitherPost()

This produces slightly incorrect colors as it skips a YUV->RGB->YUV, which is theoretically wrong as chroma is not independent of luma. However, the differences are marginal, especially compared to the increased sharpness by avoiding chroma resampling (and also any chroma shift).

See the following images:

ResampleHQ
http://img840.imageshack.us/img840/6493/resamplehq.png

DitherTools
http://img11.imageshack.us/img11/2398/dithertools.png

cretindesalpes
15th December 2011, 12:46
You probably forgot the Dither_linear_to_gamma() after Dither_resize16().

You can also do the linear<->gamma conversion in the RGB colorspace:

Dither_convert_yuv_to_rgb (output="rgb48y")
Dither_y_gamma_to_linear (tv_range_in=false, tv_range_out=false, u=1, v=1)
Dither_resize16 (w, h, u=1, v=1)
Dither_y_linear_to_gamma (tv_range_in=false, tv_range_out=false, u=1, v=1)
Dither_convert_rgb_to_yuv (
\ SelectEvery (3, 0), SelectEvery (3, 1), SelectEvery (3, 2),
\ lsb=false)

redfordxx
16th December 2011, 21:26
I like the kernel visualization very much. I have additional question:
Is it maybe so, that in case of downsizing some kernels do not ring or blur so much or are sharper, than it is visualized in the chart?
For example started to use Bicubic everywhere because I am afraid of ringing, but maybe, there should be better choice in case of downsizing.

ajp_anton
21st December 2011, 01:50
Weird things are going on with ResampleHQ, especially in dark areas:

ResampleHQ -> Dither_resize16 -> Spline36resize
http://img217.imageshack.us/img217/2378/rhq1.th.png (http://img217.imageshack.us/img217/2378/rhq1.png) http://img594.imageshack.us/img594/7687/dither1.th.png (http://img594.imageshack.us/img594/7687/dither1.png) http://img833.imageshack.us/img833/908/s361.th.png (http://img833.imageshack.us/img833/908/s361.png)

http://img100.imageshack.us/img100/5602/rhq2.th.png (http://img100.imageshack.us/img100/5602/rhq2.png) http://img407.imageshack.us/img407/8373/dither2.th.png (http://img407.imageshack.us/img407/8373/dither2.png) http://img341.imageshack.us/img341/1762/s362.th.png (http://img341.imageshack.us/img341/1762/s362.png)

Sapo84
26th December 2011, 22:53
This is probably is a bug report.

I was evaluating various resize methods with an anime source.

Dither_y_gamma_to_linear()
Dither_resize16(1280, 720)
Dither_y_linear_to_gamma()
http://img37.imageshack.us/img37/7812/mawarugamma1.png

ResampleHQ(1280,720,srcmatrix="TV.709",dstmatrix="TV.709",dstcolorspace="YV12",kernel="SPLINE36")
http://img851.imageshack.us/img851/4793/mawarugamma3.png

Spline36Resize(1280,720)
http://img832.imageshack.us/img832/6792/mawarugamma4.png

The PNGs are taken with AvsPmod (Rec.709 matrix).

The luma plane is correct with dither_resize16 and ResampleHQ, which is what I expected.
The chroma planes, instead, look very different with ResampleHQ, the reds are much "darker".

http://img42.imageshack.us/img42/69/mawarugamma5.png
The source frame.

Moreover if we convert to RGB and then resize with ResampleHQ (just use the last png as source, if you want to test), the result is again very different.
http://img42.imageshack.us/img42/6609/mawarugamma6.png

I think there is a bug in how ResampleHQ handles chroma in YV12 mode.

lexor
18th January 2012, 20:05
I am interested in learning more about the techniques and algorithms behind this. The author has started a blog series on http://int64.org but there were no updates since July of last year. And the 2 articles there don't contain much detail. Are there particularly good books/papers/blogs on the subject that I can look into?

IanB
18th January 2012, 21:51
Scan all of this thread, various links are sprinkled throughout.

:search: http://www.google.com.au/search?q=gamma+resize+image

:search: http://www.google.com.au/search?q=dither+image

Abradoks
18th January 2012, 23:01
Are there particularly good books/papers/blogs on the subject that I can look into?
You may find ImageMagick documentation, source code and forums interesting. For example, that (http://imagemagick.org/Usage/resize/) page.

PhrostByte
19th January 2012, 05:35
I am interested in learning more about the techniques and algorithms behind this. The author has started a blog series on http://int64.org but there were no updates since July of last year. And the 2 articles there don't contain much detail. Are there particularly good books/papers/blogs on the subject that I can look into?

I got a bit distracted with some real life things, but I'll be posting something new soon with more technical details.

What are you interested in learning about? Gamma correctness? Resampling? Colorspace conversion?

SilaSurfer
29th April 2012, 18:37
Weird things are going on with ResampleHQ, especially in dark areas:

ResampleHQ -> Dither_resize16 -> Spline36resize
http://img217.imageshack.us/img217/2378/rhq1.th.png (http://img217.imageshack.us/img217/2378/rhq1.png) http://img594.imageshack.us/img594/7687/dither1.th.png (http://img594.imageshack.us/img594/7687/dither1.png) http://img833.imageshack.us/img833/908/s361.th.png (http://img833.imageshack.us/img833/908/s361.png)

http://img100.imageshack.us/img100/5602/rhq2.th.png (http://img100.imageshack.us/img100/5602/rhq2.png) http://img407.imageshack.us/img407/8373/dither2.th.png (http://img407.imageshack.us/img407/8373/dither2.png) http://img341.imageshack.us/img341/1762/s362.th.png (http://img341.imageshack.us/img341/1762/s362.png)

This is probably is a bug report.

I was evaluating various resize methods with an anime source.

Dither_y_gamma_to_linear()
Dither_resize16(1280, 720)
Dither_y_linear_to_gamma()
http://img37.imageshack.us/img37/7812/mawarugamma1.png

ResampleHQ(1280,720,srcmatrix="TV.709",dstmatrix="TV.709",dstcolorspace="YV12",kernel="SPLINE36")
http://img851.imageshack.us/img851/4793/mawarugamma3.png

Spline36Resize(1280,720)
http://img832.imageshack.us/img832/6792/mawarugamma4.png

The PNGs are taken with AvsPmod (Rec.709 matrix).

The luma plane is correct with dither_resize16 and ResampleHQ, which is what I expected.
The chroma planes, instead, look very different with ResampleHQ, the reds are much "darker".

http://img42.imageshack.us/img42/69/mawarugamma5.png
The source frame.

Moreover if we convert to RGB and then resize with ResampleHQ (just use the last png as source, if you want to test), the result is again very different.
http://img42.imageshack.us/img42/6609/mawarugamma6.png

I think there is a bug in how ResampleHQ handles chroma in YV12 mode.

Does anyone know if these bugs have been fixed?

SilaSurfer
7th May 2012, 13:33
Double post I know. Actually over at Anime Music Videos forum user Mister Hatt explains that PhrostByte didn't find any major bugs with chroma, PhrostByte apperantly reported that over IRC channel.

Here is the link to that thread and Mister Hatt's statement:

http://www.animemusicvideos.org/forum/viewtopic.php?f=45&t=108819#p1433031

Here is what the next version of Reasmple-Hq will bring:

Changelog from http://svn.int64.org/viewvc/int64/resamplehq/doc/index.html
Resample-HQ Version 9 (Pending)

Bug fix: fix resizing very small frames.
Bug fix: infinite loop with certain invalid arguments.
FMA3 color conversions for Intel Haswell.
FMA3/FMA4 vertical resampler.

No mention of chroma bugs.

Just wanted to share.

Sapo84
7th May 2012, 19:51
The bug is actually in avisynth 2.58, 2.6 is fine (I think the avisynth bug was found while talking to mirkosp in IRC soon after that post).

Never actually bothered to update the post with the new info.

mirkosp
8th May 2012, 06:15
It's not a bug. It was just that the specific frame had very fine detail (red on white), so when downscaling the two get mixed and so the red becomes slightly darker. Using extremely sharp kernels for chroma (sinc with 8 taps) mitigates the issue (the colours are lighter) and no visible artefacts are introduced despite being sinc (since it's only on the chroma).
The issue was very evident in that case since due to :reasons: rgb input was getting downscaled to yuv (I blame Adobe), so obviously introducing a colourspace conversion is gonna make the colour shifting a lot more obvious. There is, however, a slight difference in rgb->yuv conversion output between 2.58 and 2.6, with 2.6 being very slightly better. But obviously, if you start doing rgb->yuv->rgb->yuv you're just getting the reds darker at every conversion back to yuv with that image (converting to rgb doesn't really shift the colours, it's just switching them back that introduces the issue).
Obviously, this is all completely unrelated to resamplehq and I'd guess avisynth isn't really at fault either. You can't expect black magic when dealing with colourspace conversions.

Mug Funky
19th July 2012, 05:46
i wondered if the new(ish) deepcolour tools could be used with internal temporalsoften? my intuition tells me this would be a bad idea.

the reason is that, like the spatial filtering in resampleHQ, temporal filtering is strongly affected by working in linear space.

my canon DSLR workflow involves the adding of motion blur (shoot without to allow better stabilization, add back later), and it just wasn't quite convincing me. wrapping the whole sorry mess in converttorgb and levels(0,1/2.2,255,0,255) showed there was a benefit to the way the motion blur worked out, but of course a massive detriment on account of the banding from that quick proof-of-concept.

so now i'm on the hunt for a way to step this up to higher bit depths in order to get a more natural looking motion blur.

this might have an effect on denoising as well, though whether it's positive or negative remains to be seen (i think it's worth a try).

infoeater
1st August 2012, 19:29
Are RGB24 and RGB32 in ResampleHQ in fact sRGB (or maybe system colorspace?)?

Is following formula used for conversion between linear RGB and ITU‐R BT.709?
V= 1.099*L^0.45 – 0.099 for 1 ≥ L ≥ 0.018
V = 4.500*L for 0.018 > L ≥ 0
where:
L: luminance of the image 0 ≤ L ≤ 1
V: corresponding
I am asking because theoretically different formula is recommend for displays and for cameras (which I consider generally as mistake - formula should be the same and watching conditions should be tuned to the formula, not the opposite).

Is FCC the NTSC color space?

Is it possible to use ResampleHQ to convert sRGB to TV.709?

Finally, am I correct that VirtualDub is not color space aware and is displaying everything in sRGB/system colorspace?

Asmodian
3rd August 2012, 21:12
RGB isn't sRGB or system color space or anything; it is just RGB values. You have to know what kind of RGB it is if you want to convert it to another gamut.

ResampleHQ's docs do state it uses sRGB gamma equations. Most modern digital video (blurays, YouTube, etc) are supposed to be mastered to sRGB gamut (sRGB uses the same primaries and white point as BT.709). I assume HD cameras try to get as close as they can to BT.709 but given how bad consumer monitors and TVs are I wouldn't expect it to be that close except in the very high end. Each camera probably needs its own calibration. It would be interesting to know if there are cameras that target a different gamut.

I do not know of any video tools available to convert from custom gamuts, i.e. convert from a custom measured color space of a camera to BT.709. There must be some though.

I normally think of the NTSC color space as NTSC (1987) = BT.601 but there are others one might call NTSC as well.

It is easy to use ResampleHQ to convert to TV.709, just set dstmatrix="TV.709".

You are right VirutalDub is not color space aware and always uses the same coefficients when converting to RGB for display. Note that all programs must convert to RGB at some point during display; VirtualDub doesn't know which matrix YUV it is getting so has to assume one. I would be nice to have a setting for this.

Gser
4th August 2012, 16:59
I was wondering if it would be possible to add pointresize to ResampleHQ?

jmac698
5th August 2012, 01:32
Umm.. there wouldn't be any point, just use pointresize.

henryho_hk
6th August 2012, 07:10
PointResize does not involve interpolation.

infoeater
14th August 2012, 15:43
Sorry for delay and thank you for your explanations Asmodian.

So ResampleHQ ignore (small) gamma differences between BT.709 and sRGB and use sRBG coefficients and gamma for its internal linear colorspace?

High-end consumer video cameras (~1000 USD) often offer really very good calibration to BT.709. In fact it's often only limited by color accuracy of the sensor and cannot be improved in automatic postprocessing. There are some tests at http://www.camcorderinfo.com/. Consumer TV's on the other hand offer usually poor calibration (because many customers like oversaturated colors and cold (high Kelvin) white point), which can be improved, manually by calibration in higher models.

Canon PowerShot SD950 IS use BT.601 for its videos.

Panasonic and Sony consumer camcorders offer "http://en.wikipedia.org/wiki/XvYCC" as an option, which can be disabled in menu.
It is compatible with BT.709, just allows values out of range that define extra colors. It is possible to disable it, because normally camera tries to convert such colors to colors in range, allowing better perceived color accuracy on displays not supporting xvYCC.

BTW I am interested how ResampleHQ will handle out of range xvYCC colors when resizing TV.709 to TV.709? Will it lose them somewhere in it's internal color space?

Asmodian
14th August 2012, 20:32
Yes, ResampleHQ uses sRGB gamma for its linear color space but I am sure it would be impossible to tell the difference after converting back.

I believe all color space conversions done in Avisynth, including ResampleHQ's, use "absolute" color conversions. Any out of range colors are clamped to the nearest valid color. However ResamplesHQ's internal color space is in 32-bit float and any clamping occurs at the final conversion to TV.709.

It is good to know cameras actually try for accurate colors. I wonder if/when Windows will ever be gamut aware. The thumbnail generator in Windows 7 is color space aware, a photo tagged as anything but sRGB is converted to sRGB, but not the rest of the OS and it cannot use a calibrated color space instead of sRGB. This means wide gamut displays are bad, not just useless, for anything but a Mac or Photoshop type work. I also really hate all the "fluid motion" features and similar that new TVs have but they cannot get the color even close to correct. Why are all the new Android tablets and phones using 60% of sRGB's gamut and a 7500K+ white point?! What is the point of a 1920x1200 10" screen if not image quality?

Sorry about the rant, I couldn't stop myself. :o

active1
10th September 2012, 09:42
how could i know that my image is linear and i need a gamma-correction?

Asmodian
11th September 2012, 22:35
Images are never in linear light, they all have a gamma curve (I am sure there are formats which use linear light, but no consumer ones do). At 8 bits per sample linear light is a bad idea as there aren't enough steps in the black/dark grey and too many in the almost white. It is good ResampleHQ uses 32bits for its linear color space. Using linear light when resizing to a smaller resolution allows for a more "optically correct" resize but you never leave the image in linear light for display.

ResampleHQ is not for doing gamma conversions, just resizing.

active1
12th September 2012, 12:00
Images are never in linear light, they all have a gamma curve (I am sure there are formats which use linear light, but no consumer ones do). At 8 bits per sample linear light is a bad idea as there aren't enough steps in the black/dark grey and too many in the almost white. It is good ResampleHQ uses 32bits for its linear color space. Using linear light when resizing to a smaller resolution allows for a more "optically correct" resize but you never leave the image in linear light for display.

so when i need to do gamma-correction?
plus i tried ResampleHQ on different images, and i didn't see much different from the other avisynth resizers, but in the earth light image (which is included with resamplehq-x86.dll) the difference was clear

ajp_anton
12th September 2012, 15:02
When you have small bright spots or thin lines with sharp high contrast edges, "normal" resizers tend to lower that contrast a bit.


Say the resizer needs to average a bright spot with intensity 1 with a dark background with intensity 0.
"Normal" resizers will simply average this to 0.5, which becomes the new brightness of this bright spot.
Obviously it should get darker when you downsize, but not this much.

Converting to linear light (value^2.2): both 1 and 0 stay as they are. Average = 0.5.
Inverting the previous conversion on this value: 0.5^(1/2.2) = 0.73, which is brighter than 0.5, and is what your eyes would actually see in the real world.

The gamma-curved representation of pixel light intensities doesn't represent actual light intensity, so averaging pixels here doesn't give correct results. It does however work as a good enough approximation in most real-life scenarios.

Asmodian
13th September 2012, 19:21
so when i need to do gamma-correction?

Only when wanting to view content on a display with a different gamma than intended but that isn't related to ResampleHQ.

TheElix
24th September 2012, 10:53
Is this script meant for real-time usage (for watching videos with)?

Asmodian
24th September 2012, 21:06
This isn't a script, just a plugin, but it is fast enough to run real time. I am not sure why you would though, MadVR offers linear-light options for resizing at playback.

Also resizing in linear light is most important when resizing to a smaller resolution which is (I assume) rarely done at playback.

pancserzso
28th June 2013, 21:28
Hi,

I'm trying to import a AVCHD file using ffms2 from a Panasonic GH2 camera, which is 4:2:0. I'm looking for the best possible quality. Can you help me which of these are the best?

Is there any point using this plugin when there is no resolution resize, just chroma YV12 -> RGB conversion and Chroma upsample?

Color conversion by FFVideoSource:

FFVideoSource( "mts.mts", seekmode = -1, colorspace = "RGB24", resizer = "LANCZOS" )

Color conversion by AviSynth 2.60:

FFVideoSource( "mts.mts", seekmode = -1 )
ConvertToRGB24( matrix = "Rec709", chromaresample = "lanczos" )

Color conversion by ResampleHQ:

FFVideoSource( "mts.mts", seekmode = -1 )
ResampleHQ( dstcolorspace = "RGB24", srcmatrix = "TV.709", kernel = "lanczos" )

pbristow
28th June 2013, 23:28
pancserzso: You need to ask your question in the usage forum, not the development one. Also, open a fresh thread rather than tacking it onto an existing one. That will help you by bringing your question to the attention of more people, and will avoid irritating/confusing people who come to *this* thread looking for info about the stated topic. ("Gamma-aware, dithered colorspace conversion and resizing")

Good luck! :)

[EDIT: OK, Perhaps I'm being too hasty. Your question *does* have to do with the ResampleHQ plugin, after all. But it is more of a usage question than a development one.

Maybe I should just shut up and let someone else talk. :o ]

pancserzso
28th June 2013, 23:51
pancserzso: You need to ask your question in the usage forum, not the development one. Also, open a fresh thread rather than tacking it onto an existing one. That will help you by bringing your question to the attention of more people, and will avoid irritating/confusing people who come to *this* thread looking for info about the stated topic. ("Gamma-aware, dithered colorspace conversion and resizing")

Good luck! :)

[EDIT: OK, Perhaps I'm being too hasty. Your question *does* have to do with the ResampleHQ plugin, after all. But it is more of a usage question than a development one.

Maybe I should just shut up and let someone else talk. :o ]

I especially want to ask in in the ResampleHQ thread, since I believe this is the place where the developer and experts of ResampleHQ are. Also, this is the official forum linked in the ResampleHQ docs, I believe I can ask this question here.

So, I think ResampleHQ gives me the highest quality, I just want to hear some expert opinion on:
1. Whether there is any point using ResampleHQ only for chroma upsampling when doing color space conversion as well.
2. What kernel is recommended for the highest quality 4:2:0 -> RGB conversion + chroma upsampling, if the image dimensions don't change?

Asmodian
29th June 2013, 02:32
I think this is an ok place to ask about ResampleHQ, development seems to be done so it can/has turned into more of a support thread. :)

I would say it is fine to use ResampleHQ for converting to RGB but U and V do not use gamma so the "gamma-aware" doesn't help in this case. However, as ResampleHQ does the conversion in 32‐bit floating‐point and dithers to R'G'B', I do not believe another option would provide higher quality.

I don't think the normal Avisynth ConverttoRGB() uses dithering. Note that FS dithering (like that used by ResampleHQ) tends to get lost when doing a lossy compression (H.264) unless using very high bit rates.

I like Catmull-Rom, Blackman3, Blackman4, or Spline36 depending on ringing vs sharpness but I have never done or seen any good testing of the kernel choice for YUV 4:2:0 to RGB outside of MadVR. For MadVR the the consensus seems to be Jinc3 or bicubic75 but there are fewer choices in MadVR and ResampleHQ doesn't offer Jinc. I am sure that all choices have tradeoffs. I would think Blackman3 would be good, sharper than some but also low ringing and not blurring. Catmull-Rom (bicubic b=0.0, c=0.5) or bicubic75 (b=0.0, c=0.75 - sharper with more ringing) would also be good choices.

If you have chroma artifacts in the source a little blurring might be good so you could use Mitchell-Netravali or Robidoux.

Sorry, I know I have suggested half the kernels but I don't think there is a right answer for kernel choice. I wouldn't go too ringing and I don't like the stronger blurring of Softcubic unless the chroma is in a bad state.

note: 4:2:0 -> RGB includes chroma upsampling by definition. You cannot have subsampled color with RGB. ;)

edit:
If/when you do pick a kernel please let us know which one.

pancserzso
29th June 2013, 03:09
I think this is an ok place to ask about ResampleHQ, development seems to be done so it can/has turned into more of a support thread. :)

I would say it is fine to use ResampleHQ for converting to RGB but U and V do not use gamma so the "gamma-aware" doesn't help in this case. However, as ResampleHQ does the conversion in 32‐bit floating‐point and dithers to R'G'B', I do not believe another option would provide higher quality.

I don't think the normal Avisynth ConverttoRGB() uses dithering. Note that FS dithering (like that used by ResampleHQ) tends to get lost when doing a lossy compression (H.264) unless using very high bit rates.

I like Catmull-Rom, Blackman3, Blackman4, or Spline36 depending on ringing vs sharpness but I have never done or seen any good testing of the kernel choice for YUV 4:2:0 to RGB outside of MadVR. For MadVR the the consensus seems to be Jinc3 or bicubic75 but there are fewer choices in MadVR and ResampleHQ doesn't offer Jinc. I am sure that all choices have tradeoffs. I would think Blackman3 would be good, sharper than some but also low ringing and not blurring. Catmull-Rom (bicubic b=0.0, c=0.5) or bicubic75 (b=0.0, c=0.75 - sharper with more ringing) would also be good choices.

If you have chroma artifacts in the source a little blurring might be good so you could use Mitchell-Netravali or Robidoux.

Sorry, I know I have suggested half the kernels but I don't think there is a right answer for kernel choice. I wouldn't go too ringing and I don't like the stronger blurring of Softcubic unless the chroma is in a bad state.

note: 4:2:0 -> RGB includes chroma upsampling by definition. You cannot have subsampled color with RGB. ;)

edit:
If/when you do pick a kernel please let us know which one.

Thanks a lot! I've compared it a bit more, and I'm confident in using ResampleHQ for the task.

Some results I've found out:
using dither gave me no visual difference (I seriously cannot see the effect on my source), while it slows down the script extremely. In my case it was 3.7 fps vs. 22 fps with dither = false

for the normal kernel, I've played around and for downsampling 1920x1080 -> 1280x720, I concluded that:
- Lanczos is too sharp / ringy for my liking
- The best filter for my liking was Mitchell

for the chroma kernel, the honest conclusion was:
- there is almost no difference visible at least on my soft real-camera source
- the only exception is SoftCubic, which is actually visibly too soft on red lights, like LEDs
- the PNG file sizes go like this:
softbicubic, bicubic = mitchell, catmull, lanczos

I think I'll choose mitchell here as well.

ResampleHQ( width = 1280, height = 720, dstcolorspace = "RGB24", srcmatrix = "TV.709", kernel = "MitchellNetravali", chroma_kernel = "MitchellNetravali" )

creaothceann
30th June 2013, 23:25
using dither gave me no visual difference (I seriously cannot see the effect on my source)

Watch for color banding.

01 (http://bakashots.me/guide/index.php?prob=band&num=1)
02 (http://bakashots.me/guide/index.php?prob=band&num=2)
03 (http://bakashots.me/guide/index.php?prob=band&num=3)

(pictures change upon mouseover)

IanB
30th June 2013, 23:45
Image links are all "Forbidden"

Sparktank
30th June 2013, 23:59
That's strange. They work for me.
Country-dependent access? :erm:

pancserzso
1st July 2013, 02:20
Thanks for the samples. My source is my own Panasonic GH2 camera, which cannot make such perfect smooth gradient like on the images you've linked, but I might try taking a video of the sky or sunset or something which is like that. On normal, everyday scenes, it didn't happen.

astronob
6th October 2013, 09:37
I can't get this filter to work with cinema craft encodersp3. I get a small black mpv file with the words in red on top "Unknown ResampleHQ Internal Error" Any suggestions?

Asmodian
6th October 2013, 20:16
please :script:

astronob
7th October 2013, 01:52
Hi Asmodian,

here's my little avisynth script. I can get this to work with CCE 2.5, but CCE SP3 won't work, nor will Tmpgenc with it. I need to go RGB to use the Virtualdub DeLogo plugin with Avisynth, then back to YUY2 for avisynth to use ResampleHQ. Also a question. One person said that the Dither plugin gave a sharper output to ResampleHQ. Is this so? I'd like to try it and compare encodes with it. What would be an equivalent Dither script I could use, if someone could suggest one? Thanks.

LoadPlugin("C:\Program Files\AviSynth 2.5\plugins\DGDecode.dll")
LoadPlugin("C:\Program Files\AviSynth 2.5\plugins\ColorMatrix.dll")
LoadPlugin("C:\Program Files\AviSynth 2.5\plugins\NicAudio.dll")
mpeg2source("O:\The Runaways - School Days (RAGE SD).d2v", info=3)
converttorgb32()
LoadVirtualDubPlugin("C:\VirtualDubMod_1_5_10_2_All_inclusive\plugins\delogo.vdf", "delogo")
delogo(1,"","C:/Delogo/Mask Files/Deblend.bmp", "C:/Delogo/Mask Files/Alpha.bmp", "c:/Delogo/Mask Files/Color.bmp", "C:/Delogo/Mask Files/Repair.bmp", 15, 40, 1, 0)
crop(98,2,-94,-0)
ResampleHQ(width=720, height=576, dstcolorspace="YUY2", srcmatrix="TV.601", kernel="spline36", chroma_kernel="spline36")
ConvertToYUY2

Asmodian
12th October 2013, 21:34
You are going back to YUY2 after ResampleHQ but that is ok as ResampleHQ supports RGB color spaces.

Maybe the one person who thought Dither is sharper was in the context of YV12 or YUY2? Dither is "sharper" than ResampleHQ because dithering is not currently supported for YV12 and YUY2 in ResampleHQ. Dithering is mostly destroyed by DCT compression.

Here is an example Dither script to implement a ResampleHQ like resize. Like with ResampleHQ I suggest you only use liner light resize when downsampling.
Dither_convert_8_to_16()
Dither_y_gamma_to_linear()
Dither_resize16(1280, 720)
Dither_y_linear_to_gamma()
DitherPost()

If you want an anti-ringing algorithem applied you can replace Dither_resize16 with Dither_resize16nr. There are good examples in the Dither docs.

astronob
27th October 2013, 08:24
Thanks, but putting "dither" in the script, gives me "DitherPost: Input Must Be Planar." I have no idea what that means. Also, can someone PLEASE explain why ResampleHQ won't work with Tmpgenc but works fine with old version of cinema craft encoder? When I try and frameserve the script to Tmpgenc, I get a line in red letters "ResampleHQ Internal Error:". The latest version of CCE won't work either. I'm at a loss. Is there something extra I need to put in the script so Tmpgenc will work? Thanks. Also, I don't think ResampleHQ supports RGB color space. If I put "RGB" instead of "YUY2" in the script. It won't work. Has ResampleHQ been updated to work with RGB color space now? Thanks.

cretindesalpes
27th October 2013, 08:50
Thanks, but putting "dither" in the script, gives me "DitherPost: Input Must Be Planar." I have no idea what that means.
YUY2 is not a planar colorspace, Y, U and V components are interleaved and packed in pairs of pixels. You can convert first your clip with ConvertToYV16(), which is the same as YUY2 but in a planar form.

astronob
27th October 2013, 09:01
Doesn't work, colors are stuffed up. In addition, no one has offered an explanation for the "ResampleHQ Internal Error" error message.

Richard1485
30th October 2013, 22:53
I received that error only when I used Avisynth MT. The normal Avisynth has always been fine. My two cents!

De-M-oN
4th February 2014, 16:19
Please integrate YV24 support.

l33tmeatwad
15th May 2015, 19:34
This projected seems to be dormant since 2011, but there was a newer source code posted and since version 8 did not include a 64-bit plugin I decided to build it. I can't promise it will be stable as it was never released by the creator, but it does appear to be working. I included a compile of the x86 version too, but I would trust version 8 over this one.

Download (http://www.mediafire.com/download/4m31za3np4o5d24)

burfadel
15th May 2015, 19:42
This projected seems to be dormant since 2011, but there was a newer source code posted and since version 8 did not include a 64-bit plugin I decided to build it. I can't promise it will be stable as it was never released by the creator, but it does appear to be working. I included a compile of the x86 version too, but I would trust version 8 over this one.

Download (http://www.mediafire.com/download/4m31za3np4o5d24)

It's unfortunate development hasn't continued on it. The plugin seems to produce a subtle, but nice, improvement over the standard spline filters.

De-M-oN
15th May 2015, 19:51
Spline100 has the best compressability which is awesome for youtube.

Also I like the ringing free scaling by Spline100 in general :)


edit: oh I thought it was the SplineResize Thread instead of ResampleHQ. sorry.

edit 2: But I can add something to this thread as well:

The documentation of ResampleHQ says youtube uses tv.601

But thats wrong. They use tv.709.

Treaties Of Warp
10th April 2020, 06:21
BUMP!!!

Is there any way to add Spline100 and Spline144 to ResampleHQ?

Upscale_Lover
29th March 2021, 02:21
Any way to downscale 4k SDR content to 720p using ResampleHQ? What is the source matrix value for 4k?

DTL
29th March 2021, 05:06
Any way to downscale 4k SDR content to 720p using ResampleHQ? What is the source matrix value for 4k?

Possibly that plugin https://forum.doom9.org/showthread.php?p=1843107#post1843107 will helps with SDR too.

With
ConvertYUVtoLinearRGB()
Do_resample()
ConvertLinearRGBtoYUV()

"What is the source matrix value for 4k?"

It depends on content source. May be any of 601/709/2020 for SDR. Try to look in metadata if available.

joearmstrong
20th July 2021, 07:39
Since v2.1.0 ResampleHQ supports HDR sources in Vapoursynth. Unfortunately there's no update for the Avisynth version. Someone should compile a new version for Avisynth from the latest Vapoursynth release.

Reel.Deel
20th July 2021, 10:36
Since v2.1.0 ResampleHQ supports HDR sources in Vapoursynth. Unfortunately there's no update for the Avisynth version. Someone should compile a new version for Avisynth from the latest Vapoursynth release.

ResampleHQ for VapourSynth is a script using core filters to convert to linear light and resize. It's not a plugin like the AviSynth version. Regardless, the same can be accomplished with avsresize. Take a look at the ">8bit (AVIsynth+) linear/gamma light aware resizing? (https://forum.doom9.org/showthread.php?t=175428)" thread.

joearmstrong
20th July 2021, 14:23
I confused something. Thanks for the explanation. What is the correct script for HDR gamma-aware resize?

My Idea:
z_ConvertFormat(pixel_type="RGBPS",colorspace_op="2020ncl:st2084:2020:l=>rgb:linear:2020:l",resample_filter="spline36",resample_filter_uv="spline36",approximate_gamma=false)
Spline36Resize(1920,1080)
z_ConvertFormat(pixel_type="YUV422P10",colorspace_op="rgb:linear:2020:l=>2020ncl:st2084:2020:l",resample_filter="spline36",resample_filter_uv="spline36",approximate_gamma=false)

Boulder
20th July 2021, 15:10
I think the HDRTools plugin makes it even easier.

z_ConvertFormat(chromaloc_op="top_left=>mpeg2")
ConvertYUVtoLinearRGB(color=1, outputmode=2)
Spline36Resize(1920,1080)
ConvertLinearRGBtoYUV(color=1, outputmode=2)
z_ConvertFormat(chromaloc_op="mpeg2=>top_left")

It should return a 16-bit YV12 clip you can feed to the encoder. I think the chroma location should also be changed before and after resizing because the standard resizer does not use the UHD one.

StvG
21st July 2021, 01:20
I confused something. Thanks for the explanation. What is the correct script for HDR gamma-aware resize?

My Idea:
z_ConvertFormat(pixel_type="RGBPS",colorspace_op="2020ncl:st2084:2020:l=>rgb:linear:2020:l",resample_filter="spline36",resample_filter_uv="spline36",approximate_gamma=false)
Spline36Resize(1920,1080)
z_ConvertFormat(pixel_type="YUV422P10",colorspace_op="rgb:linear:2020:l=>2020ncl:st2084:2020:l",resample_filter="spline36",resample_filter_uv="spline36",approximate_gamma=false)

Here version with removed redundant stuff:z_ConvertFormat(pixel_type="RGBPS",colorspace_op="2020ncl:st2084=>rgb:linear",resample_filter="spline36",approximate_gamma=false)
z_ConvertFormat(1920,1080,pixel_type="YUV422P10",colorspace_op="rgb:linear=>2020ncl:st2084",resample_filter="spline36",approximate_gamma=false)

Reel.Deel
21st July 2021, 05:47
Here version with removed redundant stuff:

z_ConvertFormat(pixel_type="RGBPS",colorspace_op="2020ncl:st2084=>rgb:linear",resample_filter="spline36",approximate_gamma=false)
z_ConvertFormat(1920,1080,pixel_type="YUV422P10",colorspace_op="rgb:linear=>2020ncl:st2084",resample_filter="spline36",approximate_gamma=false)


I want to add some linear light downscaling examples to the wiki:


For 1080p HD (Rec709) content:
z_ConvertFormat(pixel_type="RGBPS", colorspace_op="709:709:709:limited=>rgb:linear:709:full", resample_filter="spline36", approximate_gamma=false)
z_ConvertFormat(width=1280, height=720, pixel_type="YUV420P16", colorspace_op="rgb:linear:709:full=>709:709:709:limited", resample_filter="spline36", approximate_gamma=false)

And if for some reason you wanted to resize SD NTSC content:
z_ConvertFormat(pixel_type="RGBPS", colorspace_op="470bg:601:170m:limited=>rgb:linear:170m:full", resample_filter="spline36", approximate_gamma=false)
z_ConvertFormat(width=320, height=240, pixel_type="YUV420P16", colorspace_op="rgb:linear:170m:full=>470bg:601:170m:limited", resample_filter="spline36", approximate_gamma=false)

And regular RGB content:
z_ConvertFormat(pixel_type="RGBPS", colorspace_op="rgb:srgb:709:full=>rgb:linear:709:full", resample_filter="spline36", approximate_gamma=false)
z_ConvertFormat(width=1280, height=720, pixel_type="RGBP16", colorspace_op="rgb:linear:709:full=>rgb:srgb:709:full", resample_filter="spline36", approximate_gamma=false)


Is that the correct way of doing it?

StvG
21st July 2021, 09:10
Is that the correct way of doing it?

Yes, the syntax is correct.
"approximate_gamma=false" will dramatically decrease the speed and probably doesn't worth it.
For UHD scaling if there is no chromaloc property, chromaloc_op="top_left=>top_left" should be added to both lines.

Scaling in linear light could easily lead to increased/created haloing. The chance is very high using spline36.

Boulder
21st July 2021, 12:04
Does PAL SD use the same coefficients as HD?

StvG
21st July 2021, 12:11
Does PAL SD use the same coefficients as HD?

What do you mean?

Boulder
21st July 2021, 12:16
What do you mean?

Would it be "709:709:709:limited=>rgb:linear:709:full" and vice versa when converting back?

StvG
21st July 2021, 13:37
Would it be "709:709:709:limited=>rgb:linear:709:full" and vice versa when converting back?

PAL SD is the same as SD NTSC from @Reel.Deel post. Matrix 470bg=170m. source_primaries=destination_primaries means no primaries change (x:x:2020=>y:y:2020 is the same as x:x:170m=>y:y:170m).

joearmstrong
21st July 2021, 14:49
Yes, the syntax is correct.
"approximate_gamma=false" will dramatically decrease the speed and probably doesn't worth it.
For UHD scaling if there is no chromaloc property, chromaloc_op="top_left=>top_left" should be added to both lines.

Scaling in linear light could easily lead to increased/created haloing. The chance is very high using spline36.


Which resize filter is more suitable for this operation?

StvG
21st July 2021, 16:56
Which resize filter is more suitable for this operation?

That depends on the source (sharp, blurred) and the scaling ratio. Kernels that don't overshoot.

Here an example - https://imgbox.com/g/9E2Wj5Mm7r

# first image
FFVideoSource(1080p)
Crop(0, 130, -0, -130)
z_ConvertFormat(pixel_type="RGBPS", colorspace_op="709:709:470bg:limited=>rgb:linear:470bg:full", resample_filter="spline36", approximate_gamma=false)
z_ConvertFormat(width=854, height=364, pixel_type="YUV420P8", colorspace_op="rgb:linear:470bg:full=>709:709:470bg:limited", resample_filter="spline36", approximate_gamma=false)

# second image
FFVideoSource(1080p)
Crop(0, 130, -0, -130)
z_ConvertFormat(pixel_type="RGBPS", colorspace_op="709:709:470bg:limited=>rgb:linear:470bg:full", filter_param_a=-0.6, filter_param_b=0, approximate_gamma=false)
z_ConvertFormat(width=854, height=364, pixel_type="YUV420P8", colorspace_op="rgb:linear:470bg:full=>709:709:470bg:limited", filter_param_a=-0.6, filter_param_b=0, approximate_gamma=false)

Third image is the source.

Reel.Deel
22nd July 2021, 00:21
PAL SD is the same as SD NTSC from @Reel.Deel post. Matrix 470bg=170m. source_primaries=destination_primaries means no primaries change (x:x:2020=>y:y:2020 is the same as x:x:170m=>y:y:170m).

From my understanding SD NTSC and SD PAL use different primaries. For the following lets assume we are converting to linear light RGB as per post #239 (https://forum.doom9.org/showthread.php?p=1948131#post1948131).

SD NTSC:

colorspace_op="470bg:601:170m:limited=>rgb:linear:170m:full"

SD PAL:

colorspace_op="470bg:601:470bg:limited=>rgb:linear:470bg:full"

Jpeg:
colorspace_op="601:601:470bg:full=>rgb:linear:470bg:full"

Jpeg conversion also needs chromaloc_op="center=>center" unless it's already YUV444.

StvG
22nd July 2021, 02:56
From my understanding SD NTSC and SD PAL use different primaries. For the following lets assume we are converting to linear light RGB as per post #239 (https://forum.doom9.org/showthread.php?p=1948131#post1948131).

PAL SD is the same as SD NTSC from @Reel.Deel post. Matrix 470bg=170m. source_primaries=destination_primaries means no primaries change (x:x:2020=>y:y:2020 is the same as x:x:170m=>y:y:170m).

z_ConvertFormat(pixel_type="RGBPS", colorspace_op="470bg:601:170m:limited=>rgb:linear:170m:full", resample_filter="spline36", approximate_gamma=false)
z_ConvertFormat(width=320, height=240, pixel_type="YUV420P16", colorspace_op="rgb:linear:170m:full=>470bg:601:170m:limited", resample_filter="spline36", approximate_gamma=false)

z_ConvertFormat(pixel_type="RGBPS", colorspace_op="470bg:601:470bg:limited=>rgb:linear:470bg:full", resample_filter="spline36", approximate_gamma=false)
z_ConvertFormat(width=320, height=240, pixel_type="YUV420P16", colorspace_op="rgb:linear:470bg:full=>470bg:601:470bg:limited", resample_filter="spline36", approximate_gamma=false)

z_ConvertFormat(pixel_type="RGBPS", colorspace_op="470bg:601:2020:limited=>rgb:linear:2020:full", resample_filter="spline36", approximate_gamma=false)
z_ConvertFormat(width=320, height=240, pixel_type="YUV420P16", colorspace_op="rgb:linear:2020:full=>470bg:601:2020:limited", resample_filter="spline36", approximate_gamma=false)

z_ConvertFormat(pixel_type="RGBPS", colorspace_op="470bg:601=>rgb:linear", resample_filter="spline36", approximate_gamma=false)
z_ConvertFormat(width=320, height=240, pixel_type="YUV420P16", colorspace_op="rgb:linear=>470bg:601", resample_filter="spline36", approximate_gamma=false)

z_ConvertFormat(pixel_type="RGBPS", colorspace_op="470bg:601:709:limited=>rgb:linear:709:full", resample_filter="spline36", approximate_gamma=false)
z_ConvertFormat(width=320, height=240, pixel_type="YUV420P16", colorspace_op="rgb:linear:709:full=>470bg:601:709:limited", resample_filter="spline36", approximate_gamma=false)

All above codes give the same result.

Reel.Deel
22nd July 2021, 03:26
All above codes give the same result.
source_primaries=destination_primaries means no primaries change (x:x:2020=>y:y:2020 is the same as x:x:170m=>y:y:170m).

I see what you mean now. Still a bit confusing to use 2020 primaries for a DVD source :p

I'll add the examples on the wiki similar to post #239.

DTL
22nd August 2021, 10:07
About quality with processing in linear RGB but typically using Y'U'V' 4:2:0 for storage and broadcast/release.
The idea of perform resample in linear itself do not have issues. But to make linear RGB for resampling we need to resample U'V' from 4:2:0 to Y'U'V' 4:4:4 first. And this resampling will have U'V' channels damaged a bit because I think it is impossible to have data to be conditioned against Gibbs ringing in both linear and system non-linear form at once. I still do not have math ideas how to solve this issue without going in non-linear data processing. So we have nice workflow for Y channel but still need to go into non-linear nightmare when living with subsampled chroma channels in Y'U'V' 4:2:0. The distortions are not very great but for perfectionists may still be. Simple bilinear or even worse point resize for 4:4:4<->4:2:0 conversions are not perfect and long sinc-based can not be used because of non-linearly distorted Y'U'V' data for process.

Resizing of Y'U'V' 4:2:0 with linear-RGB stage is practically long and sad procedure of:
Y'U'V' 4:2:0 -> resample U'V' in non-linear -> Y'U'V' 4:4:4 -> R'G'B' 4:4:4 -> RGB -> resample RGB in linear -> R'G'B' 4:4:4 -> Y'U'V' 4:4:4 -> resample U'V' in non-linear -> Y'U'V' 4:2:0.
With 2 stages of upsample and downsample of UV in non-linear form.

DTL
22nd August 2021, 23:46
Some idea about less destructive conversion from linear RGB 4:4:4 typically in the main resampler path back to storage YUV 4:2:0 and decoding back to display linear 4:4:4 RGB.

It still not 100% compatible with recommended workflow of ITU recs like BT.601 and other because it recommend to low-pass and downsample CbCr (UV) data from R'G'B' data. This example uses for UV generation separated RGB linear path with half size of the RGB linear source. And UV is generated from downsampled RGB in linear form. Also backward upsampling of UV before final convertion to RGB output linear performed in linear form.
The most debatable point of this method is how to restore the best Y' data array in the space of UV data size of 4:2:0 color format at receiver's side. Because it is skipped at 4:2:0 dowconvertor stage and not delivered in final output 4:2:0 data array. Currently is it 2x downsampling of Y' data array from input 4:2:0 with SinPowResize method in its input form (without linearing, or other magic).


LoadPlugin("RawSourcePlus.dll")
LoadPlugin("ResampleMT.dll")
LoadPlugin("HDRTools.dll")

RawSourcePlus("out16.raw", 288,288, "Y16")

ConvertToRGB64(matrix="PC.709")

RGBAdjust(r=0.01,g=0.01) # make saturated color, comment out for no color

AddBorders(10,10,10,10,color=$101010)

# here current is 4:4:4 linear conditioned RGB source

rgb_lin_d2=SinPowResizeMT(width/2, height/2, p=2.9)

ConvertLinearRGBtoYUV(Color=4)
yuv_d2=ConvertLinearRGBtoYUV(rgb_lin_d2,Color=4)

yuv_old=ConvertToYUV420()

yuv420_new=CombinePlanes(yuv_old, yuv_d2, yuv_d2, planes="YUV", source_planes="YUV", pixel_type="YUV420P16")

#create receiver Y'/2 for backward dematrix
rsv_Ydash_div2=SinPowResizeMT(yuv420_new.ConvertToY(), yuv420_new.width/2, yuv420_new.height/2, p=2.9) # test or select Y'/2 resampler engine !

rsv_YUV_new_Y=CombinePlanes(rsv_Ydash_div2, yuv420_new, yuv420_new, planes="YUV", source_planes="YUV", pixel_type="YUV444P16")

rsv_RGB_linear_d2=ConvertYUVtoLinearRGB(rsv_YUV_new_Y,Color=4)

rsv_RGB_linear_x2=SincLin2ResizeMT(rsv_RGB_linear_d2,rsv_RGB_linear_d2.width*2, rsv_RGB_linear_d2.height*2, taps=16)

rsv_YUV_x2=ConvertLinearRGBtoYUV(rsv_RGB_linear_x2,Color=4)

rsv_return=CombinePlanes(yuv_old, rsv_YUV_x2, rsv_YUV_x2, planes="YUV", source_planes="YUV", pixel_type="YUV444P16")

ConvertYUVtoLinearRGB(rsv_return,Color=4)
#ConvertYUVtoLinearRGB(yuv420_new,Color=4)
#ConvertYUVtoLinearRGB(yuv_old,Color=4)

SincLin2ResizeMT(width*2, height*2, taps=32)

ConvertBits(8)


The source test pattern is hyperbolic zoneplate generated by https://github.com/DTL2020/hpzp tool with arguments hpzp.exe 268 20 0.02.

If processing no-color data (RGBAdjust(r=0.01,g=0.01) commented out) all ways return Y-only processed image without distortions. But if processing high-saturated colors with low Y-values like saturated blue there is the difference:

Standard Avisynth+ conversion from YUV 4:4:4 to 4:2:0 and playback to linear RGB:
https://i5.imageban.ru/out/2021/08/23/c2ebd5364c01bac0e8776bc250592bf1.png

Linear UV path method:
https://i3.imageban.ru/out/2021/08/23/2eace952fed3cb10d60045d6c4d333f2.png

Standard 4:2:0 to 4:4:4 decoding of linearly prepared UV:
https://i5.imageban.ru/out/2021/08/23/528673b7a5a8d60de42b8ddcc157ac93.png

FranceBB
23rd August 2021, 00:18
you said that going for instance from 4:2:0 to Linear RGB and then back to 4:2:0 will affect the quality and this is true as we have an intermediate step to a non linear conversion for chroma as we're expanding it to 4:4:4 and then reducing it to 4:2:0 again.
This is correct.
However this is only 'cause when we apply such a conversion we're literally upscaling the chroma and it doesn't matter which resizing kernel / resampler we're gonna use (PoinResize / Nearest Neighborh, Bilinear, Bicubic, Lanczos, Spline etc) we're always gonna have a problem cause when we upscale the chroma we're gonna introduce blur and when we downscale it we're not gonna get rid of it, therefore going from yv12 to RGB and back to yv12 is not lossless.

So far so good, in the sense that we've been aware of this for ages and we haven't discovered anything new.

The question though is about what you're trying to do: I mean, theoretically speaking, wouldn't it be as easy as inverting the kernel used to upscale?

Let me rephrase: I'm pretty sure you're familiar with filters like DeBilinearResizeMT(), DeBicubicResizeMT() etc from Jean Philippe, right?
Those assume that a user knows the original dimensions of a source and the kernel used to upscale it and feeds the filter with them so that it's possible to perform not just a simple downscale using another silly interpolation, but rather inverting the kernel to get back exactly what the source was.
Now, with this in mind, wouldn't applying a resampling to go to 4:4:4 and RGB and then invert it solve the problem?

DTL
23rd August 2021, 01:07
When we go from 4:2:0 OETFed to linear RGB 4:4:4 for resizing we can not use reversed-kernel aporoach to get undistorted 4:2:0 back. Because after RGB resize the samples are different in values and number. After resize the RGB array should be treated as fresh image source and the resizer output must provide RGB linear array free of aliasing and gibbs ringing to the encoder to 4:2:0.
The example of workflow in the provided script shows the possibility to have less aliasing distortions with typical distribution and storage format 4:2:0 and high enough saturated images. I not tested many available 'linear-light-resizers' yet if they also provide the way of process color-difference data in linear form. For example as I see ResampleHQ need RGB in gamma-corrected from as only available RGB input and I not sure if built-in Avisynth gamma adjust functions can simulate required gamma correction with enough precision.
Also the typical YUV-RGBlinear subsampled conversions for speed may use only one scaler and one matrix and one OETF/EOTF engine. And the provided example with linear UV process reqiure 2 matrices and 2 OETF and one scaler for encoder and 2 scalers and 3 matrices and 3 OETF/EOTF for decoder so it may not be very in common use in old days of slow hardware.

DTL
23rd August 2021, 10:49
I made drawings of structural schematics of 2 different approaches for RGB to YUV 4:2:0 encoding and decoding:
Linear UV:
https://i7.imageban.ru/out/2021/08/23/edf9acfcf1214f73028372e89b8d16a3.jpg

And 'classic' with spectrum-limiting and downsampling in OETFed domain:
https://i1.imageban.ru/out/2021/08/23/a92995b8a07c04314bba9649a06dea87.jpg

" therefore going from yv12 to RGB and back to yv12 is not lossless."

If we do not scale Y plane (actual image) the conversion from 4:2:0 to 4:4:4 and back may be virtually lossles. But the downscaler in 4:4:4 to 4:2:0 must be hinted about spectral state of input 4:4:4 - do it full band (UV or RB) components (for example initial 4:4:4 full-band source) or half band (4:4:4 upconverted from 4:2:0).
Currently build-in Avisynth+ Convert() can get the chromaresample parameter but as I see can not get required arguments for kernel's adjustments and available kernels are only built-in.
For virtually lossless 4:2:0->4:4:4->4:2:0 (same size of Y planes and UV planes) we need sinc ideal LPF in scaler for both color planes in upsampler and downsampler.
For initial (production) 4:4:4->4:2:0 (really band-reduction operaion for UV) we need special spectrum shaping LPF for anti-gibbs processing like Gauss/SinPow/UserDefined and other kernels. It is not clear defined in ITU Recs but was published in separated ITU publications.
Also as I see the point of close to ideal LPF in chroma subsampled channels in ITU Recs - it helps to eliminate additional out of band components produced with scaling in non-linear domain. But if we prepare UV in linear domain it is not needed.

I will try to ask jpsdr to implement the linear UV scaling approach because it is based on already implemented functions in ResampleMT and HDRTools. In scriting form it make more non-needed calculations and in compiled binary functions may be significally faster.

FranceBB
23rd August 2021, 12:09
Thanks for the clarification and the paper drawn schematics, they made your point much more clear.

Currently build-in Avisynth+ Convert() can get the chromaresample parameter but as I see can not get required arguments for kernel's adjustments and available kernels are only built-in.

Yep, only the built in kernels are supported and with no additional parameters, so that is actually limiting.
On the other hand, I think around 5% of the Doom9 population is actually even bothering to specify the kernel, but anyway I'm in favor of a full args support in the default built-in conversion, to be fair.


I will try to ask jpsdr to implement the linear UV scaling approach because it is based on already implemented functions in ResampleMT and HDRTools.

Nice. If he has time and he wants to, why not.

DTL
23rd August 2021, 22:46
Well - at many real footages the difference may be very small. So currently make as a functions:


LoadPlugin("plugins_JPSDR.dll")
function YUV420P16ToLinearRGB_linUV(clip c, int ColorSystem)
{
Ydash_div2=SinPowResizeMT(c.ConvertToY(), c.width/2, c.height/2, p=2.7) # test or select Y'/2 resampler engine !
YUV_new_Y444=CombinePlanes(Ydash_div2, c, c, planes="YUV", source_planes="YUV", pixel_type="YUV444P16")
RGB_linear_div2=ConvertYUVtoLinearRGB(YUV_new_Y444,Color=ColorSystem)
RGB_linear_half_band=SincLin2ResizeMT(RGB_linear_div2,RGB_linear_div2.width*2, RGB_linear_div2.height*2, taps=8)
YUV_x2=ConvertLinearRGBtoYUV(RGB_linear_half_band,Color=ColorSystem)
to_out=CombinePlanes(c, YUV_x2, YUV_x2, planes="YUV", source_planes="YUV", pixel_type="YUV444P16")

return ConvertYUVtoLinearRGB(to_out,Color=ColorSystem)

}

function YUV422P16ToLinearRGB_linUV(clip c, int ColorSystem)
{
Ydash_div2=SinPowResizeMT(c.ConvertToY(), c.width/2, c.height, p=2.7) # test or select Y'/2 resampler engine !
YUV_new_Y444=CombinePlanes(Ydash_div2, c, c, planes="YUV", source_planes="YUV", pixel_type="YUV444P16")
RGB_linear_div2=ConvertYUVtoLinearRGB(YUV_new_Y444,Color=ColorSystem)
RGB_linear_half_band=SincLin2ResizeMT(RGB_linear_div2,RGB_linear_div2.width*2, RGB_linear_div2.height, taps=8)
YUV_x2=ConvertLinearRGBtoYUV(RGB_linear_half_band,Color=ColorSystem)
to_out=CombinePlanes(c, YUV_x2, YUV_x2, planes="YUV", source_planes="YUV", pixel_type="YUV444P16")

return ConvertYUVtoLinearRGB(to_out,Color=ColorSystem)

}


function LinearRGBToYUV420P16_linUV(clip c, int ColorSystem, bool ColorFullBand)
{
rgb_lin_div2 = ColorFullBand ? SinPowResizeMT(c, c.width/2, c.height/2, p=2.7) : SincLin2ResizeMT(c, c.width/2, c.height/2, taps=8)

yuv_d2=ConvertLinearRGBtoYUV(rgb_lin_div2,Color=ColorSystem)
y = ConvertLinearRGBtoYUV(c,Color=ColorSystem)

return CombinePlanes(y, yuv_d2, yuv_d2, planes="YUV", source_planes="YUV", pixel_type="YUV420P16")
}

function LinearRGBToYUV422P16_linUV(clip c, int ColorSystem, bool ColorFullBand)
{
rgb_lin_div2 = ColorFullBand ? SinPowResizeMT(c, c.width/2, c.height, p=2.7) : SincLin2ResizeMT(c, c.width/2, c.height, taps=8)

yuv_d2=ConvertLinearRGBtoYUV(rgb_lin_div2,Color=ColorSystem)
y = ConvertLinearRGBtoYUV(c,Color=ColorSystem)

return CombinePlanes(y, yuv_d2, yuv_d2, planes="YUV", source_planes="YUV", pixel_type="YUV422P16")
}


Params: ColorSystem = Color for ConvertLinearRGBToYUV and back in HDRTools, ColorFullBand = true for convert full band RGB to YUV subsampled and ColorFullBand = false for half-band color (for example YUV4xx->RGBlinear->YUV4xx). Currently made only for 16bits per component.

jpsdr
24th August 2021, 17:31
The linear part aside, there was here a long time ago a big talk about converting, the proper way to respect the chroma placement, summary is :

http://forum.doom9.org/showthread.php?t=170029
http://forum.doom9.org/showpost.php?p=1506374&postcount=385
http://forum.doom9.org/showpost.php?p=1705237&postcount=34

So here is a little recap.

1) When resizing in horizontally subsampled color spaces the standard resizers produce a slight horizontal chroma shift (see this post and following). To overcome this we can do the resize the manual way and apply the necessary shift to the chroma planes (U, and V) via the src_left argument of the resizer.

To prevent the shift when resizing in all horizontally subsampled color spaces (except 4:1:1!) src_left can be calculated as follows.

src_left = 0.25 * (1 - Width_in / Width_out)

Example resize from any horizontally subsampled color space (except 4:1:1!) to 704x576 YV12 (src_left is calculated automatically).

Code:

Y = ConvertToY8().Spline16Resize(704, 576)
U = UToY8().Spline16Resize(Width(Y)/2, Height(Y)/2, src_left=0.25*(1-Float(Width(Last))/Width(Y)))
V = VToY8().Spline16Resize(Width(Y)/2, Height(Y)/2, src_left=0.25*(1-Float(Width(Last))/Width(Y)))
YToUV(U, V, Y)

2) When resizing from a 4:2:0 or 4:2:2 subsampled color space to 4:4:4 (YV24) the shift for U and V is always constant.

src_left = 0.25

3) When resizing from 4:4:4 (YV24) to a horizontally subsampled color space (excluding 4:1:1!) the shift can be calculated as follows:

src_left = -0.50 * Width_in / Width_out

For an example with automatically calculated src_left see colours' post above.

Unless i'm wrong, which is possible because i'm not 100% sure with this case as you trick by downsamling Y, maybe somewhere your scripts miss the necessay adjustments. But the issue is that the Y/C adjustements can't be done on RGB ! So, this is something to think about, i think...
Example 4:2:0 -> 4:4:4 =>
Y=ConvertToY8(video)
U=UtoY8(video).BlackmanResizeMT(Width(Y),Height(Y),src_left=0.25,range=3)
V=VtoY8(video).BlackmanResizeMT(Width(Y),Height(Y),src_left=0.25,range=3)
YtoUV(U,V,Y)
Example 4:4:4 -> 4:2:0 =>
Y=ConvertToY8(video)
U=UtoY8(video).Spline36ResizeMT(Width(Y)/2,Height(Y)/2,src_left=-0.5,range=3)
V=VtoY8(video).Spline36ResizeMT(Width(Y)/2,Height(Y)/2,src_left=-0.5,range=3)
YtoUV(U,V,Y)

jpsdr
24th August 2021, 18:01
I think also there is another issue. If the encoder is made the "classic" way, the decoder has to be done the "classic" way too. You'll have wrong result if you decode according the "complex" way something encoded the "classic" way.
So, how do you know how the encoder was ?

cretindesalpes
24th August 2021, 18:55
Unless i'm wrong, which is possible because i'm not 100% sure with this case as you trick by downsamling Y, maybe somewhere your scripts miss the necessay adjustments. But the issue is that the Y/C adjustements can't be done on RGB ! So, this is something to think about, i think...
I can confirm that your src_left values are correct.

DTL
24th August 2021, 20:30
maybe somewhere your scripts miss the necessay adjustments.


Yes - may be. I still not test it about possible sub-sample chroma shift. It still the very early versions about this idea.


For backward upsampling I currently think it is not needed because half-color-band path upsampling performed in RGB. It may be wrong and require additional testing. May be the half-size Y' downsampling need additional sub-sample alignment.

"If the encoder is made the "classic" way, the decoder has to be done the "classic" way too."

Test results with hyperbolic zoneplate is (Avisynth+ ConvertToYUV420() used with default chromaresample that wiki says bicubic):

https://i7.imageban.ru/out/2021/08/24/debf851bc6f73791ec9f0625b57f8db5.png
https://i5.imageban.ru/out/2021/08/24/ae133c2a7e860e1d77a8d74d8031242e.png
https://i2.imageban.ru/out/2021/08/24/30b36a714770bea59beb3597e503cdd0.png

The use of new method with classic encoder still gives less aliasing in valid 4:2:0 color frequencies band but can not fix out of band aliasing passed via encoder. The power of aliasing in out-of-band frequencies is about the same with classic and new decoder.

"how do you know how the encoder was ?"

It is really very big and hard question for the current digital moving images industry. It still miss lots of required supplementary metadata about spatial properties of the content. It possibly need to go up to the ITU and may be many other standard organisations asking to add new metadata fields in the ISO MPEG (TS) and MP4 and other formats. Because as I see current world is filled with lots of digital content with not equal target renderer and current standards only partially cover the required supplementary metadata. Most of metadata relative to Fourier spectrum of data is missed.

I try to use new method on some TV broadcasting from BBC 2012 olympics and it cause significant ringing at CG content and also in vertical direction of interlaced broadcast video camera data. So it show the use of long sinc kernel resizers is not valid even for part of broadcast content and the H and V Fourier spectrums are not equally processed (conditioned). Even in 2012 broadcast interlaced HD1080 video cameras do not put correct anti-gibbs conditioning in V direction. Though for broadcast TV with CRT displays it looks never was critical.
So in current form of functions with SincLin2 upsamplers it moslty good only for progressive film content without unconditioned CG titling and with equally conditioned H and V directions. For other content may be it required to change upsamplers to something more poor but universal like down to Bicubic.

It is really exist some 'perfect motion pictures world' with rules for classic DSP with sinc-based resamplers and no aliasing and ringing and real much less perfect world of awful mix of image content with partial or no conditioned against gibbs ringing and aliasing present. And it not any marked with required metadata. One reason for the non-perfect ways is because they typically looks sharper at low pixel/sample count.

I tryed to change chromaresampler to sinc in avisynth+ ConvertToYUV420(chromaresample="sinc") and with new method of decoder and with used by HDRtools ConvertYUVToLinearRGB it still passes too many out of band frequencies and cause significant aliasing in out of band for 4:2:0 area: (attempt to ConvertToYUV444(,chromaresample="sinc") before HDRtools ConvertYUVToLinearRGB change almost nothing)

https://i2.imageban.ru/out/2021/08/24/82696d631f8f1fe8c65586693d41f7cc.png
With real low and medium saturated content it much less visible I think.
May be part source of this out of band aliasing is performing 4:2:0 downsampling with non-linear data. It is main point this idea about.
If skipping OETF transform (and backward) and assume out linear data as YUV 4:4:4 (adding Convert(RGB)to YUV444) classic Avisynth+ ConvertTo420 and back to 444 works better:
https://i7.imageban.ru/out/2021/08/24/f405dbf3b3e7fe7cd8d15499418f45a8.png
So performing down/upsampling of UV in non-linear domain is significant source of aliasing distortions (as expected).
OETF/EOTF operations are bitdepth compression/decompression (reversible without significant distortions) but performing spatial down/upscaling in this compressed form cause (irreversible ?) aliasing distortions.

Hyperbolic zoneplate (achromatic at least) is still official test pattern in EBU test patterns set for Tech 3320/3325 (monitors testing). So some hope still exist the digital motion pictures world still not completly falls in darkness. I not sure if color hyperbolic zoneplate will be included in new test patterns of updated Tech 3325 but if yes - it opens this new questions about 4:2:0 encoding and decoding (same for 4:2:2 for H direction only).

DTL
14th September 2021, 16:18
Oh - it looks some hidden feature not clearly typed in old rec.601 standard but being non-significant at time of analog displays in PAL:

https://tech.ebu.ch/docs/techreview/trev_304-rec601_bbc.pdf
More satisfactory was the consideration of chrominance filtering which recognized the need for
sharp-cut filters at all conversions except the last one. This allowed the bandwidth needed for
chroma-key and other processing to be retained through the system; however, the inclusion of a
slow roll-off in the composite coder for analogue broadcasts or in the picture monitor for direct
component signals avoided the dreadful chrominance ringing that would otherwise occur.

So for the all production chain except final display YUV->RGB conversion the spectrum-limiting LPF need to be ideal (hard-cut off) and suppression of Gibbs-ringing at time of rec.601 system assumed to be at the end of chain in the Cb Cr (non-linear) data. I.e. 'digital' rec.601 system actually designed to be ended with 'analog' PAL coder with slow roll-off of UV filters inside valid frequencies. And only in this case the chrominance ringing will be fixed (mostly). For 'full-digital' chains it mean there must be 'conditioning' in OETFed domain filter in the display YUV->RGB conversion. It can be in simple form simulated with Blur() at UV channels. Though the exact filter responce looks like not standartized and lost in the past.
For the 'linearUV' functions above it means bool ColorFullBand param need always be 'false' and can be removed. But the final YUV(subsampled)->RGB transform for display or monitoring need to be checked for having non-sharp cut-off LPF at UV channels.

I update the Rec.601-based chroma subsampled system 'classic' drawing with 2 versions of decoder to RGB - the cascadable and 'final display/monitor' :
https://i2.imageban.ru/out/2021/09/14/340ac9573c8ea5f1c93d14aaaa704e86.png

And it looks for the tasks of scaling in linear domain the 'monitor'-type decoder must be used to restore RGB in least distorted form as possible.

kedautinh12
14th September 2021, 16:44
Last ver ResampleHQ is r385 if anyone care
https://svn.code.sf.net/p/int64/svn/resamplehq/

DTL
15th September 2021, 12:35
I made functions for testing:

LoadPlugin("ResampleMT.dll")
Function ConvertRGB24To422(clip c)
{
yuv444=ConvertToYUV444(c)
uc=UToY(yuv444)
vc=VToY(yuv444)
uc=SincLin2ResizeMT(uc, uc.width/2, uc.height, taps=16)
vc=SincLin2ResizeMT(vc, vc.width/2, vc.height, taps=16)
return CombinePlanes(yuv444, uc, vc, planes="YUV", source_planes="YYY", pixel_type="YV16")
}


Function Convert422ToRGB24(clip c)
{
uc=UToY(c)
vc=VToY(c)
uc=SincLin2ResizeMT(uc, src_left=0.5, uc.width*2, uc.height, taps=16)
vc=SincLin2ResizeMT(vc, src_left=0.5, vc.width*2, vc.height, taps=16)
yuv444=CombinePlanes(c, uc, vc, planes="YUV", source_planes="YYY", pixel_type="YV24")
return ConvertToRGB24(yuv444)
}

Function Convert422ToRGB24mon(clip c)
{
uc=UToY(c)
vc=VToY(c)
uc=UserDefined2ResizeMT(uc,src_left=0.001,uc.width, uc.height, b=95, c=-10)
vc=UserDefined2ResizeMT(vc,src_left=0.001,vc.width, vc.height, b=95, c=-10)
# uc=UserDefined2ResizeMT(uc,src_left=0.001,uc.width, uc.height, b=80, c=-20)
# vc=UserDefined2ResizeMT(vc,src_left=0.001,vc.width, vc.height, b=80, c=-20)
uc=SincLin2ResizeMT(uc, src_left=0.5, uc.width*2, uc.height, taps=16)
vc=SincLin2ResizeMT(vc, src_left=0.5, vc.width*2, vc.height, taps=16)
yuv444=CombinePlanes(c, uc, vc, planes="YUV", source_planes="YYY", pixel_type="YV24")
return ConvertToRGB24(yuv444)
}


Results really shows difference:
https://i7.imageban.ru/out/2021/09/15/5d88cb415c7aa662e18b9b9e08e11a06.png

The build-in Avisynth functions ConvertToYUV422() and ConvertToRGB24() looks like designed to be 'average' between ringing and sharpness of transients. So when using built-in functions the difference is lower. But using that functions may cause more colour-sharpness degradation if using for mult-stage processing.

In the example above the UserDefined2ResizeMT() with (uc,src_left=0.001,uc.width,) params used to enable filter-processing (convolution with kernel) without actual resizing of UV channels. As filter with slow roll-off.
The adjustments of b and c params allow to adjust of colour-sharpness because exact required filter response looks like non standard-defined.

I not test yet but may be for speed 2 processings

vc=UserDefined2ResizeMT(vc,src_left=0.001,vc.width, vc.height, b=95, c=-10)
vc=SincLin2ResizeMT(vc, src_left=0.5, vc.width*2, vc.height, taps=16)


may be made at once like

vc=UserDefined2ResizeMT(vc,src_left=0.5,vc.width*2, vc.height, b=95, c=-10)

But it may possibly degrades quality a bit because of too small actual 'support' size of UserDefined2ResizeMT. Though it require testing.

Balling
2nd October 2021, 01:13
LOL, @DTL did you get that from my document I left on the other thread? Cool.

P.S. This is insane if you really get 1 color only instead of crazy artifacts.

DTL
2nd October 2021, 06:58
'instead of crazy artifacts'

As practice shows the current ITU-defined digital moving images colour systems are contain built-in bugs so no linear high-quality conversion from full-band 4:4:4 family members to subsampled 4:2:2 and 4:2:0 possible. The non-linear content-adaptive will give better quality but need to be designed.
Also it looks some normativing work need to put standard on response of antiringing filter of chroma datachannel in display decoder of subsampled family members. It possibly just started the long enough process.

Svirito
29th January 2022, 03:34
Last ver ResampleHQ is r385 if anyone care
https://svn.code.sf.net/p/int64/svn/resamplehq/

Does anyone have color_avx2.cpp ?

tormento
23rd September 2024, 13:43
I have tried the x64 version found there

there is also a 64bit dll: https://forum.doom9.org/showthread.php?p=1722300#post1722300

but it throws me a generic error. Perhaps an AVX2 only version? I need plain or AVX.

Anyone?