View Full Version : Konformigi() - Resize limited by rectangle and keeping the SAR
Caroliano
10th September 2010, 02:07
I want to convert many videos, with many resolutions and aspect ratios, for my cellphone, using avisynth. But I needed to resize the videos to an smaller size, for fluid and battery-saving playback.
I searched in avisynth wiki and a bit on the forums, but the best I have found was ZoomBox() (http://forum.doom9.org/showthread.php?p=1111789#post1111789), but it necessarily adds borders to the image, and I could not adapt it not to do it. So I made my solution from scratch:
# Konformigi() v. 1.0 - 2010/09/09
#
# Resize the video for the largest resolution that still fits an defined box/rectangle, retaining video's SAR (Storage Aspect Ratio).
# Useful for re-encodes to cellphones, upscales for your screen, etc. Basically, makes what every decent video player do when you ask it to go "full screen".
#
Function Konformigi(clip c, int "width", int "height", string "ResizeMethod",
\ int "modW", int "modH", string "roundmode")
{
# Set Defaults
width = Default(width, c.width()) # box width
height = Default(height, c.height()) # box height
ResizeMethod = Default(ResizeMethod, "Spline36Resize") #chose your favorite resizer
modW = Default(modW, 4) #defaults for YV12
modH = Default(modH, 2) #defaults for YV12
roundmode = Default(roundmode, "nearest") #can be "up" or "down" too
# Hack for assert work. I don't know why I can't put this inside the assert function
widthtAssert = (width/modW)*modW
heightAssert = (height/modH)*modH
# Quick sanity check, to guarantee the desired resolution, and the desired roundmode
Assert( width == widthtAssert , "Your box width needs to obey the modW you have set")
Assert( height == heightassert , "Your box height needs to obey the modH you have set")
Assert( roundmode == "down" || roundmode == "up" || roundmode == "nearest" , """Your roundmode needs to be "down" or "up" or "nearest". """)
# Calculate the scale factor
scaleWidth = Float(Width)/Float(c.width())
scaleHeight = Float(Height)/Float(c.Height())
scaleFactor = Min(scaleWidth,scaleHeight)
# Apply the scale factor and convert to integer using the desired rounding
newWidth = roundmode == "nearest" ? (Round((c.Width() * scaleFactor)/modW))*modW :
\ roundmode == "up" ? Ceil((c.Width() * scaleFactor)/modW)*modW :
\ (Int(c.Width() * scaleFactor)/modW)*modW # roundmode == "down"
newHeight = roundmode == "nearest" ? (Round((c.Height() * scaleFactor)/modH))*modH :
\ roundmode == "up" ? Ceil((c.Height() * scaleFactor)/modH)*modH :
\ (Int(c.Height() * scaleFactor)/modH)*modH # roundmode == "down"
# I think the following is needed to guarantee that the box limits are keeped when rounding up. I'm not 100% sure, but it won't hurt.
newWidth = (newWidth > Width) ? width : newWidth
newHeight = (newHeight > Height) ? Height : newHeight
# Apply the desired resizer
Eval(ResizeMethod + "(c, " + String(newWidth) + ", " + String(newHeight) + ")")
return last
}
Example usage:
#Downsizes for my cellphone screen, maximizing the compression/minimizing the size.
konformigi(480,320, roundmode = "down", modH=16, modW=16)
If an filter like this was never made, I may extend the the documentation. I have in my head also an simple modification to turn this script in "turn this clip into MOD x" type of script also. Is there already a plugin that does that automaticaly? I could not find.
Comments?
Motenai Yoda ^.^
10th September 2010, 03:06
round function shouldn't so "precise" return floor if the decimal part < .5, ceil if >.5 and the nearest even number if == .5
Round half to even
A tie-breaking rule that is even less biased is round half to even, namely
If the fraction of y is 0.5, then q is the even integer nearest to y.
Thus, for example, +23.5 becomes +24, +22.5 becomes +22, −22.5 becomes −22, and −23.5 becomes −24.
This method also treats positive and negative values symmetrically, and therefore is free of overall bias if the original numbers are positive or negative with equal probability. In addition, for most reasonable distributions of y values, the expected (average) value of the rounded numbers is essentially the same as that of the original numbers, even if the latter are all positive (or all negative). However, this rule will still introduce a positive bias for even numbers (including zero), and a negative bias for the odd ones.
This variant of the round-to-nearest method is also called unbiased rounding (ambiguously, and a bit abusively), convergent rounding, statistician's rounding, Dutch rounding, Gaussian rounding, or bankers' rounding. This is widely used in bookkeeping.
It is the default rounding mode used in IEEE 754 computing functions and operators (and in various computing languages such as ANSI/ISO C, C++, and Java, for their float and double types).
u should compare the original ar with ceil-mod's ar and floor-mod's ar and use the most similar.
otherwise rounding can escape the target limits... so this
newWidth = (newWidth > Width) ? width : newWidth
newHeight = (newHeight > Height) ? Height : newHeight
while Width should be width and Height the same (no I can't remember if avisynth is case-sensitive)
the correction can change the dar.
eg
function calc(clip c, int width, int height, int modW, int modH, string "ResizeMethod")
{
ar=c.width.float/c.height.float
type=(ar >= (width.float/height)) ? true : false
ceilWidth = (type) ? width : modH*ceil((c.width.float*height)/(c.height.float*modH))
ceilHeight = (type) ? modW*ceil((c.height.float*ceilWidth)/(c.width*modW)) : height
floorWidth = (type) ? width : modH*floor((c.width.float*height)/(c.height.float*modH))
floorHeight = (type) ? modW*floor((c.height.float*floorHeight)/(c.width*modW)) : height
cAr = ceilWidth.float/ceilHeight
fAr = floorWidth.float/floorHeight
roundingCeil = (abs(cAr-ar) < abs(fAr-ar)) ? true : false
newWidth = (roundingCeil) ? ceilWidth : floorWidth
newHeight = (roundingCeil) ? ceilHeight : floorHeight
return (width > newWidth && height > newHeight) ? Eval(ResizeMethod + "(c, " + String(newWidth) + ", " + String(newHeight) + ")") : calc(c,width-modW,height-modH,modW,modH, ResizeMethod)
}
edit: seems that avisynth don't support yet recursion...
function calc(clip c, int width, int height, int modW, int modH, bool re, string "ResizeMethod")
{
re = Default(re, false)
width=(re)? width-modW:width
height=(re)? height-modH:height
ar=c.width.float/c.height.float
type=(ar >= (width.float/height)) ? true : false
ceilWidth = (type) ? modW*round(width.float/modW) : modH*ceil((c.width.float*height)/(c.height.float*modH))
ceilHeight = (type) ? modW*ceil((c.height.float*ceilWidth)/(c.width*modW)) : modH*round(height.float/modH)
floorWidth = (type) ? modW*round(width.float/modW) : modH*floor((c.width.float*height)/(c.height.float*modH))
floorHeight = (type) ? modW*floor((c.height.float*floorWidth)/(c.width*modW)) : modH*round(height.float/modH)
cAr = ceilWidth.float/ceilHeight
fAr = floorWidth.float/floorHeight
roundingCeil = (abs(cAr-ar) < abs(fAr-ar)) ? true : false
newWidth = (roundingCeil) ? ceilWidth : floorWidth
newHeight = (roundingCeil) ? ceilHeight : floorHeight
return Eval(ResizeMethod + "(c, " + String(newWidth) + ", " + String(newHeight) + ")")
}
function parResize(clip c, int "width", int "height", int "modW", int "modH", string "ResizeMethod")
{
width = Default(width, c.width()) # box width
height = Default(height, c.height()) # box height
ResizeMethod = Default(ResizeMethod, "Spline36Resize") #chose your favorite resizer
modW = Default(modW, 4) #defaults for x264 (YV12 is limited to mod2 only)
modH = Default(modH, modW) #if not setted use modW
b=calc(c,width,height,modW,modH, false, ResizeMethod)
return (width >= b.width && height >= b.Height) ? b : calc(c,width,height,modW,modH, true, ResizeMethod)
}
re-edit recursion is supported, I'm an idiot!
function parResize(clip c, int "width", int "height", int "modW", int "modH", string "ResizeMethod", bool "re")
{
width = Default(width, c.width()) # box width
height = Default(height, c.height()) # box height
ResizeMethod = Default(ResizeMethod, "Spline36Resize") #chose your favorite resizer
modW = Default(modW, 4) #defaults for x264 (YV12 is limited to mod2 only)
modH = Default(modH, modW) #if not setted use modW
re = Default(re, false)
modW = ((c.isYV12() || c.isYUY2()) && (modW%2 != 0)) ? 2*modW : modW
modH = (c.isYV12() && (modH%2 != 0)) ? 2*modH: modH
width=(re)? width-modW:width
height=(re)? height-modH:height
ar=c.width.float/c.height.float
type=(ar >= (width.float/height)) ? true : false
roundedWidth=modW*round(width.float/modW)
roundedHeight=modH*round(height.float/modH)
ceilWidth = (type) ? roundedWidth : modH*ceil((c.width.float*roundedHeight)/(c.height.float*modH))
ceilHeight = (type) ? modW*ceil((c.height.float*roundedWidth)/(c.width*modW)) : roundedHeight
floorWidth = (type) ? roundedWidth : modH*floor((c.width.float*roundedHeight)/(c.height.float*modH))
floorHeight = (type) ? modW*floor((c.height.float*roundedWidth)/(c.width*modW)) : roundedHeight
cAr = ceilWidth.float/ceilHeight
fAr = floorWidth.float/floorHeight
roundingCeil = (abs(cAr-ar) < abs(fAr-ar)) ? true : false
newWidth = (roundingCeil) ? ceilWidth : floorWidth
newHeight = (roundingCeil) ? ceilHeight : floorHeight
return (width >= newWidth && height >= newHeight || re) ? Eval(ResizeMethod + "(c, " + String(newWidth) + ", " + String(newHeight) + ")") : parResize(c,width,height,modW,modH, ResizeMethod,true)
}
note: modW and modH are checked for mod2 if colorspace is yv12 or yuy2 and to avoid errors are doubled (eg modW = 3, 2*3=6, a clip that is mod6 is also mod3)
Robert Martens
10th September 2010, 22:12
Ah, someone who shares my affinity for inventing cute names; "Konformigi" has a great ring to it!
I took a crack at what I believe you're describing: http://forum.doom9.org/showthread.php?t=153860 Almost all of my posts on Doom9 so far are about this script, but I don't yet have the expertise to offer much help in other areas. You can also see turbojet's AutoResizeMod8 thread for more discussion of the subject: http://forum.doom9.org/showthread.php?t=155780 I'm sure there are more around here somewhere, I believe this is a relatively popular topic.
SSU considers pixel and/or display aspect, handles mod concerns (default 16), and offers custom output sizes/shapes in addition to a collection of presets for common uses. To produce what you're after, assuming input and output are square pixel, you'd use
SimpleSlugUpscale(outwidth=480,outheight=320)
Add prog=true to your arguments if you have progressive footage, otherwise TempGaussMC beta 2 will be used to deinterlace the clip.
There's an auto letter/pillarboxing function, but the default is to crop the input clip to match the output, keeping one dimension intact (if the input is wider than the output frame, it'll keep the height and chop off the sides; if it's taller, it'll keep the width).
I know the script is woefully uncommented, but it's on my to do list. If you have any questions, I'm happy to answer them, and if you or anyone else have any suggestions I'm always open to learn something.
As far as comments on what you've got so far, I'm hardly an expert, but I'll play with it a little bit and see if there's anything I can offer.
Caroliano
10th September 2010, 23:41
Doing a new search in the forum, I found your script (after posting this topic). But at first look it looked more centered in DV input, has many dependencies (maybe all for deinterlacing, I haven't checked), and was a bit complex for me. Now that you showed me how to handle it, it seems better. :p
Other two interesting threads about that subject that I found were Handy resizing script (http://forum.doom9.org/showthread.php?t=110641) and Auto Resize: Keep Aspect Ratio w/ AddBorder (http://forum.doom9.org/showthread.php?t=135229). I did not found this "Help with autoresize function" that you linked in your post, but I'm looking at it now. None is quite equivalent to my or Motenai's script, so this is not pure repetition.
I'm now looking at the latest Motenai Yoda ^.^'s algorithm, and it seems more precise than mine regarding DAR, and perfect for my usage. But on the other hand, it isn't easily turned in an good MOD-only corrector. If you give an 480x318 clip to it, and do not specify an resolution restriction, it will resize to 464x304, not 480x320. I will look at it now, and at the possibility of croping too.
Ah, someone who shares my affinity for inventing cute names; "Konformigi" has a great ring to it!
Yeah, it does sounds good, and is unique. That is why chose it. ^^
It means "make [something] fit" in esperanto.
Robert Martens
11th September 2010, 01:40
I do tend to scare people away with my walls of text, I suppose, but the script I linked isn't as complicated as my interminable explanations may make it seem. There are no dependencies for progressive footage, and for interlaced material the dependencies are only those of TempGaussMC_beta2. Earlier versions used the VariableBlur plugin to achieve the "boxbg" effect, but I wanted to add as little overhead to users' scripts as possible, so I found a way to achieve a similar blur effect with GaussResize. Ultimately, SimpleSlug's documentation takes more work to read than the script does to use. Once you read through the instructions it should prove less troublesome.
But enough about me. I have only a few comments on your script for the time being, as I'm still wrapping my head around Motenai's suggestions. They're very intriguing, but I'll need some time to process what's going on there, it's a little over my head.
What I can offer is that for starters, I don't think you need that "assert hack". I removed the lines you used there, and moved the math into the actual Assert function, and everything continues working correctly. That is to say, instead of this:
widthtAssert = (width/modW)*modW
heightAssert = (height/modH)*modH
Assert( width == widthtAssert , "Your box width needs to obey the modW you have set")
Assert( height == heightassert , "Your box height needs to obey the modH you have set")
I use this:
Assert( width == (width/modW)*modW , "Your box width needs to obey the modW you have set")
Assert( height == (height/modH)*modH , "Your box height needs to obey the modH you have set")
The results are the same, and exceptions are thrown as expected when you pass invalid arguments into the function.
Next, you can change that Eval() at the bottom of the script to an Apply(), something I learned from Gavino in the aforementioned turbojet thread (http://forum.doom9.org/showthread.php?p=1421045#post1421045):
Apply(ResizeMethod,c,newWidth,newHeight)
Makes for cleaner script, but note that you must explicitly pass the name of the clip variable into the Apply, as it doesn't implicitly pass 'last' like so many other filters do.
Finally, though it's not the end of the world, you can remove the "return last" line you have at the bottom there, the Apply() will take care of that.
I have a few other ideas, but no concrete suggestions for changes so far. I learned quite a variety of things working on my own script, and if I'm not careful I'll just end up telling you how to do things the way I did them, which isn't really helpful.
Motenai Yoda ^.^
11th September 2010, 02:12
If you give an 480x318 clip to it, and do not specify an resolution restriction, it will resize to 464x304, not 480x320. I will look at it now, and at the possibility of croping too.
because
width = Default(width, c.width()) # box width
height = Default(height, c.height()) # box height
if width=480
and height=318
then it round 318 to mod16 = 320
at the condition
return (width >= newWidth && height >= newHeight || re)
320 is > than 318
so it make a recursion and use width-16 and height-16...
it avoid upsampling if restriction of box is unsetted.
now i think if changing with
roundedWidth=modW*ceil(width.float/modW)
roundedHeight=modH*ceil(height.float/modH)
Caroliano
11th September 2010, 02:39
Sorry, of course it is doing the right thing for what it is designed to do. What I was trying to say is that that behaviour isn't compatible with MOD adjust only script, and I don't know an simple way to adapt it. I still haven't looked much around it. Needi3() caught my atention in another thread. ^^''
Motenai Yoda ^.^
11th September 2010, 13:20
to adapt it is sufficient change
return (width >= newWidth && height >= newHeight || re)
to
return (roundedWidth >= newWidth && roundedHeight >= newHeight || re)
mikeytown2
12th September 2010, 09:16
quick tip about zoombox; try playing around with Align. Negative numbers add a border; positive numbers crop.
ZoomBox(480,320, Align=5)
vBulletin® v3.8.11, Copyright ©2000-2025, vBulletin Solutions Inc.