View Full Version : When is PointResize NOT Reversible?
zerowalker
14th May 2014, 02:40
Not sure if this only rules for Pixel games, but as you may know, PointResize can be used to increase the size, and then if you want you can decrease it and it will be identical.
However, to do this you must follow certain rules, and i am not completely sure of those rules, though i think i know it, but rather ask here.
For example, if i want a resolution from 240x160 to come as close to a height of 1200, do i have to take 160 and simply multiply it until it get's close?
Meaning it can never reach 1200 exactly, and i can only choose from 1120/1280?
Or is there some workaround?
Conclusion Below:
PointResize is Only reversible when it's multiplied by an integer. 120x1.5 = Wrong, 120x2 = Correct.
However there is a way to bypass that according to Gavino:
PointResize can also be reversed (as all the original pixels are still there), but it requires using the 'offset' parameters src_top and src_left.
For example, starting with a 320x240 clip,
PointResize(800, 600) # 2.5x upscale, AB->AAABB
is not recovered by
PointResize(320, 240) # AAABB->AA
but can be losslessly reversed by
PointResize(320, 240, 1, 1) # AAABB->AB
The actual offsets required are different for each case and can be tricky to work out.
For RGB inputs, you also have to remember that Avisynth stores them upside down, so the vertical offset may be different.
Leaving PointResize to be quite Flexible, though you would need to do the manual calculation to reverse it, (perhaps it could be made Automatic if it knew the Original Size?).
Thanks for all information:)
JReiginsei
14th May 2014, 03:09
Maybe you can use the technique from this post:
http://www.libretro.com/forums/viewtopic.php?f=31&t=1712
PointResize to 1280 and then downscale to 1200 with Bilinear or another resizer.
zerowalker
14th May 2014, 03:23
That isn't exactly what i am looking for, any resize besides Point will break the pixels causing a huge difference in compression, and also cause a blurriness to the eyes, even though that site talks about using 2 resizes to minimal loss, but still a loss is a loss.
Guest
14th May 2014, 04:04
For example, if i want a resolution from 240x160 to come as close to a height of 1200, do i have to take 160 and simply multiply it until it get's close?
Meaning it can never reach 1200 exactly, and i can only choose from 1120/1280?
Or is there some workaround? For point resize you need an integer ratio. 1200 / 160 is not an integer.
But you could have a metapattern of point replication, i.e, alternate repeating 7 pixels and repeating 8 pixels. Why do you need reversibility?
zerowalker
14th May 2014, 04:16
For point resize you need an integer ratio. 1200 / 160 is not an integer.
Came to that conclusion, and this proves it, which sadly limit things.
But you could have a metapattern of point replication, i.e, alternate repeating 7 pixels and repeating 8 pixels. Why do you need reversibility?
Have no idea what you mean with the metapattern and repeating pixels, could you explain it simplier?
I am guessing you mean something like, i can only explain it with Framerate, where you repeat frames differently to keep a certain rate, 3:2 and such things, but with pixels?
Why do i need reversibility?
Good question, it's more of a way to keep it lossless and knowing it's correct.
Till now, i though that, as long as i follow the Aspect Ratio, Pixel Games etc will be showing correctly, lossless so to speak, as i noticed Pixels and PointResize go hand in hand (probably easy to know, but didn't think of it before to long ago).
So that means, i have seen games wrong, luckily the difference it minimal, and pretty much just means that some pixels may be 2 width instead of 3, and such things, but an error is an error nevertheless.
As for the reversibility, it's pretty much a thing that adds to the equation, if i want to show the pixels correct, i need to have reversibility, so both points towards the same goal.
Guest
14th May 2014, 05:46
Have no idea what you mean with the metapattern and repeating pixels, could you explain it simpler? Point resize is implemented by repeating pixels. A resize factor of 7.5 in the horizontal dimension can be achieved by:
AB -> AAAAAAABBBBBBBB
It's like telecine but in the spatial domain.
I do not know of any filters that implement this idea. It might be fun to make one. Large upscaling is always going to look blocky, however. That is why point resize is not used much.
Guest
14th May 2014, 17:10
Please remain on topic for the thread title. OT posts were removed.
You can change the thread title if you want to broaden the discussion, but we expect thread content to match the thread title. Followup to PM if needed. Thank you.
zerowalker
14th May 2014, 17:18
The Topic is pretty much done at this point i think.
The answer is as following:
Pointresize can Only be lossless/reversible If it's increased in size that's a multiple Integer (x2,x3,x4) etc.
In other cases, it will fail. However if you use some pattern or specialize method as neuron2 pointed out, there is probably a way, it will however look different on upscale but my be reversible if you use the same transformation,
this is however not common and you would probably have to do it yourself, i myself so no real point to it as it breaks the looks, but it may be of use for someone:)
Gavino
14th May 2014, 18:00
Although not useful for zerowalker's purpose here, non-integer upsizing with PointResize can also be reversed (as all the original pixels are still there), but it requires using the 'offset' parameters src_top and src_left.
For example, starting with a 320x240 clip,
PointResize(800, 600) # 2.5x upscale, AB->AAABB
is not recovered by
PointResize(320, 240) # AAABB->AA
but can be losslessly reversed by
PointResize(320, 240, 1, 1) # AAABB->AB
The actual offsets required are different for each case and can be tricky to work out.
For RGB inputs, you also have to remember that Avisynth stores them upside down, so the vertical offset may be different.
zerowalker
14th May 2014, 18:06
Ah, that's indeed useful, it explains how to reverse even when it's "illegal".
Thought it would be harder than that, not that it looks easy though.
colours
14th May 2014, 21:10
Point resize is implemented by repeating pixels. A resize factor of 7.5 in the horizontal dimension can be achieved by:
AB -> AAAAAAABBBBBBBB
It's like telecine but in the spatial domain.
I do not know of any filters that implement this idea. It might be fun to make one. Large upscaling is always going to look blocky, however. That is why point resize is not used much.
SeparateRows/WeaveRows (along with the column versions) and SelectEvery could be used for this, but it'd be slow and doing exactly the same thing as PointResize.
Also, I want to add that while all the other core resizers treat the pixels as being sampled at half-integers, PointResize is the one exception, treating them as being sampled at the integers. (In other words, it's wrong and it can't be changed because I'm sure there's someone relying on this broken behaviour.) As Gavino stated, reversing a box upscale is possible, but doing so with Avisynth's PointResize requires a fudge factor for this reason.
zerowalker
14th May 2014, 21:24
I am not sure i understand, are you saying that PointResize doesn't work as intended by treating them as being sampled at the integers?
I thought that was the idea, it treats is as an integer, so it would always have the pixel there, so it's reversible and all that (as long as you don't break the structure, reducing the resolution beyond the original).
If that's not the case, and it's broken, that would mean it's not reversible and working to some sense, this would prevent me from using it in this sense,
so could you tell me in easier words what you mean?
Thanks
colours
14th May 2014, 21:35
It's reversible, but doing it in Avisynth just needs a fudge factor.
The correct way to map a destination coordinate to a source coordinate is with (x+0.5)*src_width/dst_width-0.5 (which is used by all the core resizers except PointResize), but PointResize uses just x*src_width/dst_width.
It does happen to work as expected for upscaling by an integer factor, if that's what you're worried about.
zerowalker
14th May 2014, 21:42
Seems to be out of my league, my mathematical knowledge is close to none;S
But if it work as i expect in the cases i talked about, then it's okay for me.
Still if you think it should change, you probably should take it up with an Avisynth Developer, it's better to notify then ignore it:)
Gavino
14th May 2014, 23:59
It's reversible, but doing it in Avisynth just needs a fudge factor.
The correct way to map a destination coordinate to a source coordinate is with (x+0.5)*src_width/dst_width-0.5 (which is used by all the core resizers except PointResize), but PointResize uses just x*src_width/dst_width.
To get reversibility, you would also need to make PointResize a true 'nearest neighbour' resizer.
The way it currently works is to use, for each output pixel, the nearest source pixel looking above [below for RGB] and to the left (hence not strictly 'nearest' neighbour, as it ignores nearer pixels below [above for RGB] or to the right).
zerowalker
15th May 2014, 00:10
So, pointresize only checks SouthWest pixels?
And if it checked all around it could be more robust to reversibility?
hmm, guess that would need to be it's own resizer, If someone thinks of doing it or have thought on how it can be made, please make a topic on it.
I would clearly be interested in it at the very least:)
StainlessS
15th May 2014, 01:42
If pointresize is to modified in any way, then it needs to be called by another name.
Pointresize works differerent to other reiszers, because it does not do 'area' sampling and aggregation of those sampled results.
zerowalker
16th May 2014, 03:00
Probably, easier that way never the less.
(Updated the Thread Opening Post with the "Answer" of the Topic)
colours
16th May 2014, 19:09
No manual calculation is needed if the original size is known and src_top/left/width/height aren't used in PointResize.
function depoint(clip c, int target_width, int target_height)
{ # c.PointResize(w, h).depoint(c.width(), c.height()) gives exactly the same pixels as c
c
Assert(target_width <= width() && target_height <= height(), "depoint cannot be used for upscaling")
x = width() == target_width ? 0 : width() / (2.0 * target_width) + 0.5
y = height() == target_height ? 0 : height() / (2.0 * target_height) + 0.5
PointResize(target_width, target_height, x, IsRGB() ? -y : y)
}
Like debilinear (http://rgb.chromashift.org/), but for PointResize. Except not using least-squares, so it's not really anything like debilinear, I guess.
StainlessS
16th May 2014, 19:33
@Colors,
Debilinea sound interesting, got a link for it ?
I got no hits on D9 and only about 5 hits in Google (all in what looks like it might be in Italian or similar [Latin maybe])
and none of them look to be related.
Thank you for your time.
@StainlessS
Google (https://www.google.com/search?q=debilinear&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:en-US:official&client=firefox-a&channel=rcs&gfe_rd=cr&) -> homepage? (http://rgb.chromashift.org/)
SamKook
16th May 2014, 20:59
I'm just saying since I don't know the details of how it works at all, but wouldn't it be possible to analyse the picture and deduce the original resolution if all it does is duplicate pixels? That way you could pretty much always easily reverse it.
I assume there's no filters to do this only because of lack of interest(unless it's more complicated than I think it is).
Gavino
16th May 2014, 23:11
y = height() == target_height ? 0 : height() / (2.0 * target_height) + 0.5
Aren't you forgetting what I said earlier?
For RGB inputs, you also have to remember that Avisynth stores them upside down, so the vertical offset may be different.
I think for RGB you need a negative vertical offset - probably you just have to reverse the sign of y in the RGB case (ie same magnitude but negative).
colours
17th May 2014, 06:08
Aren't you forgetting what I said earlier?
I think for RGB you need a negative vertical offset - probably you just have to reverse the sign of y in the RGB case (ie same magnitude but negative).
It still works correctly on RGB. The sampling isn't affected if all you work with are the pixel coordinates without caring about whether the scanning order is right-to-left or bottom-to-top or whatever.
Gavino
17th May 2014, 09:33
No, that's wrong.
For PointResize, the scanning order determines whether the source pixel chosen for a non-integral sampling position is rounded up or down.
As I said before:
The way it currently works is to use, for each output pixel, the nearest source pixel looking ... below for RGB ...
So a negative offset is required for RGB to recover all the original pixels.
This script demonstrates it:
BlankClip(1,320,120) #320x120 rgb32
Interleave(last,Invert()).AssumeFieldBased()
Weave() # Height=240; white, black, white, black, ...
# Upscale x2.5
PointResize(320, 600) # WB->WWBBB
# Downscale with various offsets
Interleave( \
PointResize(320, 240), /* all black */ \
PointResize(320, 240, 0, 1.75), /* BWBW...BB : no good */ \
PointResize(320, 240, 0, -1.75) /* WBWB...WB : orig recovered */ \
)
In fact, the magnitude of the offset can be anything satisfying
ceil(r)-r <= offset < r
where r is the upscaling ratio (>1).
In your function, you use r/2.0+0.5, which can be shown to satisfy this condition.
The difference between RGB and YUV in the way offsets work with PointResize is a long-standing 'feature' of Avisynth. For example, see here.
colours
17th May 2014, 20:35
May I be damned, you're absolutely right. An embarrassing mistake on my part; I forgot that src_top isn't measured from first row, but from the top.
zerowalker
19th May 2014, 16:29
Can 240x160 resized to 1575x1050 be reversed?
Here is what it should look like when resized to this size: https://docs.google.com/uc?export=download&id=0B_UKJFH8rbiNYTZBN0ZHLS01TjQ
Here is the Failed Resize, which i would like to reverse: https://docs.google.com/uc?export=download&id=0B_UKJFH8rbiNS2NoZENGZU1yYTA
The original size is 240x160 for both files, and the Correct one is identical to that one, the other one was made wrong.
EDIT:
The closest i can get is using:
depoint(240,160)
PointResize(240*7, 160*7, src_left=0, src_top=-1, src_width=0, src_height=-1)
On the failed one, this makes it identical, except for the first rows, but only on the right side, i am guessing it has to do with colors?
I think it should be solvable as it looks almost correct otherwise, but i don't know how.
This may have to do with it looking to the SW pixel i guess?
colours
20th May 2014, 01:07
I put the wrong sign in when editing it to work with RGB, causing it to be wrong for both RGB and YUV. Double fail. I edited my initial post again to correct this mistake; depoint works correctly with the fix. (And you don't need to specify any parameters other than 240*7 and 160*7 when upscaling again.)
For that matter, I'm not entirely sure it works with chroma subsampling correctly (and I don't really care), but using a wrapper function to separate the chroma planes is relatively trivial.
Edit: To clarify a little, reversing upscales with an upscale factor not less than 2 is relatively trivial—using an offset of 1 vertically and horizontally does the job. (As hinted by Gavino's ⌈r⌉−r≤offset<r, which is satisfied for all values of r>2 when offset=1, though I suspect the inequality is not sufficient for correctness when 1<r<2.) The function was only written as a proof of concept working with arbitrary upscale factors between 1 and 2, which wasn't so trivial.
zerowalker
20th May 2014, 03:33
Great, now it work as expected, not sure how it's done really, but it works.
Even in this scenario where it was an odd number, which i was very skeptical about.
Well i personally don't care much for chroma subsampling and reversing either, if i want to do it, i would subsample After doing the resizing or whatever.
Really great function, you should upload it as an .Avsi and post it in a topic or here, instead of just the script text.
I find it very useful, and it would be great if people got notice of it.
Thanks
Xebika
20th May 2014, 04:04
Does the function working with upscaling in YV12 colorspace??
Gavino
21st May 2014, 00:00
(As hinted by Gavino's ⌈r⌉−r≤offset<r, which is satisfied for all values of r>2 when offset=1, though I suspect the inequality is not sufficient for correctness when 1<r<2.)
I believe it is sufficient for all r >= 1.
Have you found any cases where it is not?
Does the function working with upscaling in YV12 colorspace??
Because of the chroma subsampling, it doesn't work for some values of the upscaling ratio (r).
Specifically, it fails to restore chroma when 1<r<1.4 or 2<r<2.2.
For these ratios, you would need to separate the chroma and resize it independently as colours suggested in post #28.
vBulletin® v3.8.11, Copyright ©2000-2025, vBulletin Solutions Inc.