Welcome to Doom9's Forum, THE in-place to be for everyone interested in DVD conversion.

Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules.

 

Go Back   Doom9's Forum > Capturing and Editing Video > Avisynth Usage

Reply
 
Thread Tools Search this Thread Display Modes
Old 14th May 2008, 02:55   #41  |  Link
mikeytown2
Resize Abuser
 
mikeytown2's Avatar
 
Join Date: Apr 2005
Location: Seattle, WA
Posts: 623
KenBurnsEffect() Updated

KenBurnsEffect() Changes
  • Take input like crop (-Values)
  • If a box is 0,0,0,0 or 1,0,0,0 it will be centered and zoomed in so no black borders
  • If a box is -1,0,0,0 centered and zoomed out showing black borders
  • I used Stickboy's Example to accomplish this
  • Everything else moved to post 2, i keep hitting the 16000 mark!

With these changes I can speed up my work flow.
  1. Load the image/clip into AvsP
  2. Go Video -> Crop Editor...
  3. Draw the box
  4. Apply
  5. Then take the 4 numbers it gives you and set x2 or y2 to x1 or y1, when you insert it into KenBurnsEffect() (for the AR)
  6. Repeat for Box #2

Last edited by mikeytown2; 14th May 2008 at 04:28.
mikeytown2 is offline   Reply With Quote
Old 14th May 2008, 21:44   #42  |  Link
mikeytown2
Resize Abuser
 
mikeytown2's Avatar
 
Join Date: Apr 2005
Location: Seattle, WA
Posts: 623
Added an example code block near the bottom of post 2 (Simple Usage Example). This should help in understanding how to use KenBurnsEffect(). Be sure to change the OutputWidth and OutputHeight. Trying different output aspect ratios will hopefully make it clear how useful KBE() is.
mikeytown2 is offline   Reply With Quote
Old 16th May 2008, 18:45   #43  |  Link
mikeytown2
Resize Abuser
 
mikeytown2's Avatar
 
Join Date: Apr 2005
Location: Seattle, WA
Posts: 623
If no one see's any problems with this filter, i'll start to look into rotation. using zoom.dll to do rotation is fairly straightforward, but i am looking at the other 2 options for rotating a clip. FreeFrame's PetePanSpinZoom and EffectsMany's EffectRotation.
I posted about FreeFrame previously in this thread on post # 8-10

Here is code using Effect Rotation.
Code:
version()#240 Frames Long


stackVertical(last,last)
stackVertical(last,last,last)
stackHorizontal(last,last)
a = last.ConvertToYV12()

EffectRotation(a,sf=49,ef=149,id=0, fd=90, cc=$000000).Trim(0,149)
last+EffectRotation(a,sf=150,ef=239,id=90, fd=90, cc=$000000).Trim(150,0)
Yes, it supports YV12!
mikeytown2 is offline   Reply With Quote
Old 22nd May 2008, 21:51   #44  |  Link
mikeytown2
Resize Abuser
 
mikeytown2's Avatar
 
Join Date: Apr 2005
Location: Seattle, WA
Posts: 623
I decided to get the Align parameter done before i go further. This is what I'm thinking... what are your thoughts?

int Start/End Align: negative values (-) will position where the potential border is placed, to make it fit the given output dimensions. so -5 would be center, center with a border on top/bottom or left/right. -5 would be the same as -1,0,0,0. On the other hand 5 would be the same as 0,0,0,0. The negative option will make the code of Split Screen easier. I can then fully replace ResizeKAR with ZoomBox.

Positive values will be what is shown no mater what. So 5 means that the center point will be in the center of the frame. 1 means that the top left pixel will be in the top left, with cropping so there are no black borders.

If the aspect ratio is the same across the board then this won't do much. I plan on making all parameters optional and using x/y 1,2 to let you say how many pixels to go.

So if i set Align=9 (bottom right), i can set x1 or y1, or both to override the aspect ratio. If i set Align=1 (top left) i can set x2 or y2, or both to override the aspect ratio. Positive x/y values will count from the top left, negative x/y values from the bottom right. This means that using align you can never zoom out to the point of having a black border all the way around your picture.

Align=5 (middle center), if i only set x1 then that is the width of the center box; y1 hight of the center box. i can set all 4 values x1,y1,x2,y2 or just 3 to keep AR.

Align=1 (top left), can set x2, y2
Align=2 (top center), can set x1, x2, y2
Align=3 (top right), can set x1, y2
Align=4 (middle left), can set x2, y1, y2
Align=5 (middle center), can set x1, x2, y1, y2
Align=6 (middle bottom), can set x1, y1, y2
Align=7 (bottom left), can set x2, y1
Align=8 (bottom center), can set x1, x2, y1
Align=9 (bottom right), can set x1, y1

x1,y1 = top left of a rectangle
x2,y2 = bottom right of a rectangle

Code:
1:top left.     2:top center.     3:top right. 
4:middle left.  5:middle center.  6:middle bottom. 
7:bottom left.  8:bottom center.  9:bottom right.
Let me know if you think i am going the right direction with this. Or if you don't follow I'll try to explain my idea better.
mikeytown2 is offline   Reply With Quote
Old 23rd May 2008, 22:46   #45  |  Link
mikeytown2
Resize Abuser
 
mikeytown2's Avatar
 
Join Date: Apr 2005
Location: Seattle, WA
Posts: 623
I need some help with some Aspect Ratio Math... I am close, but for certain cases, it doesn't work correctly. I develop the ZoomBox Code and then port it to KBE. So here is the latest ZB, i've been trying to correct the DAR/PAR & Final AR. It acts odd when using the (0,0,0,0) or (-1,0,0,0) method.

This Works (HDV Source)


This doesn't work (Still Camera)


Current Code Base
Code:
Function ZoomBox(clip c, float x1, float y1, float x2, float y2, int "width", int "height", int "IgnoreAR", string "ResizeMethod", int "OutputARWidth", int "OutputARHeight")
{
	#set defaults
	width = Default(width, c.width())
	height = Default(height, c.height())
	ResizeMethod = Default(ResizeMethod, "BilinearResize")
	IgnoreAR = Default(IgnoreAR, 0)
	PAR = float(c.width())/float(c.height())
	FinalAR = float(width)/float(height)
	OutputARWidth = Default(OutputARWidth, c.width())
	OutputARHeight = Default(OutputARHeight, c.height())
	DAR = Float(OutputARWidth)/Float(OutputARHeight)
	

	#Take Crop Like Input
	x2 = x2<=x1 && x2 < 0 ? c.width() + x2 : x2
	y2 = y2<=y1 && y2 < 0 ? c.height() + y2 : y2
	
	#If All 0, and x1 =+-1 or 0 then assume clip is to be centered
	#Display Aspect Ratio = Final Output Ratio. No Change, Show All Pixels
	EvalString = (x1==1 || x1==0 || x1==-1) && y1==0 && x2==0 && y2==0 && DAR==FinalAR ?
	\ "x1=0" + "
	   x2="  + String(c.width()) + "
	   y1=0" + "
	   y2="  + String(c.height()) + "" : "x1=x1"
	Eval(EvalString)
	#Display Aspect Ratio > Final Output Ratio. Add Height or Crop Width 
	EvalString = x1==-1 && y1==0 && x2==0 && y2==0 && DAR>FinalAR ?
	\ "y1=" + String((c.height()*(FinalAR/DAR)-c.width()/PAR)/2.0) + "
	   y2=" + String(c.height() - (c.height()*(FinalAR/DAR)-c.width()/PAR)/2.0) + "
	   x1=0" + "
	   x2=" + String(c.width())
	\ : (x1==1 || x1==0) && y1==0 && x2==0 && y2==0 && DAR>FinalAR ?
	\ "x1=" + String((c.width()/(FinalAR/DAR)-c.height()*PAR)/2.0) + "
	   x2=" + String(c.width() - (c.width()/(FinalAR/DAR)-c.height()*PAR)/2.0) + "
	   y1=0" + "
	   y2=" + String(c.height()) + "" : "x1=x1"
	   Eval(EvalString)
	#Display Aspect Ratio < Final Output Ratio. Add Width or Crop Height 
	EvalString = x1==-1 && y1==0 && x2==0 && y2==0 && DAR<FinalAR ?
	\ "x1=" + String((c.width()/PAR-c.height()*(FinalAR/DAR))/2.0) + "
	   x2=" + String(c.width() - (c.width()/PAR-c.height()*(FinalAR/DAR))/2.0) + "
	   y1=0" + "
	   y2=" + String(c.height()) + ""
	\ : (x1==1 || x1==0) && y1==0 && x2==0 && y2==0 && DAR<FinalAR  ?
	\ "y1=" + String((c.height()*(FinalAR/DAR)-c.width()/PAR)/2.0) + "
	   y2=" + String(c.height() - (c.height()*(FinalAR/DAR)-c.width()/PAR)/2.0) + "
	   x1=0" + "
	   x2=" + String(c.width()) : "x1=x1"
	Eval(EvalString)


	#Check if x2 or y2 needs to be calculated
	Assert( ((x2==x1) && (y2==y1))==False, "x2 [" + String(x2) + "] or y2 [" + String(y2) + "] needs a value that is different from x1 [" + String(x1) + "] or y1 [" + String(y1) + "]")
	y2 = (y2==y1) ? (((x2-x1)/FinalAR + y1)/(PAR/DAR)) : y2
	x2 = (x2==x1) ? (((y2-y1)*FinalAR + x1)*(PAR/DAR)) : x2
	
	BoxAR = Float(x2-x1)/Float(y2-y1)
	#Check For Any Unreasonable Inputs
	Assert(x1<x2, "ZoomBox: x1[" + String(x1) + "] point larger then x2 Point[" + String(x2) + "]")
	Assert(y1<y2, "ZoomBox: y1[" + String(y1) + "] point larger then y2 Point[" + String(y2) + "]")
	Assert(IgnoreAR>0 || BoxAR == FinalAR, "ZoomBox: Box Aspect Ratio [" + String(BoxAR) + "] does not equal clip output Aspect Ratio [" + string(FinalAR) + "]")
	
	#Do it all
	c = c.AddBorders(16,16,16,16)
	c = Eval(ResizeMethod + "(c, " + String(Round(width)) + ", " + String(Round(height)) + ", src_left=" + String(x1) + "+16, src_top=" + String(y1) + "+16, src_width=" + String(x2-x1) + ", src_height=" + String(y2-y1) + ")")	
		
	c
	Subtitle(String(x1) + "," + String(y1) + "  " + String(x2) + "," + String(y2) + "  " + String(BoxAR),y=40)
}
HELP!


Example: Change W or H and you get the correct image.
Code:
Global W = 720
Global H = 720
Global Resizer = "BlackmanResize"

Global HDV_Full = HDV.TDeint().ZoomBox( -1,0,0,0, W, H, IgnoreAR=1, ResizeMethod=Resizer, OutputARWidth=1920, OutputARHeight=1080 )
Global HDV_Full_Crop = HDV.TDeint().ZoomBox( 0,0,0,0, W, H, IgnoreAR=1, ResizeMethod=Resizer, OutputARWidth=1920, OutputARHeight=1080 )
Global HDV_Fast = HDV.SeparateFields().SelectEven().ZoomBox( -1,0,0,0, W, H, IgnoreAR=1, ResizeMethod=Resizer, OutputARWidth=1920, OutputARHeight=1080 )
Global HDV_Fast_Crop = HDV.SeparateFields().SelectEven().ZoomBox( 1,0,0,0, W, H, IgnoreAR=1, ResizeMethod=Resizer, OutputARWidth=1920, OutputARHeight=1080 )
Example:Change W or H and you get the wrong image, unless the output is 4:3 since the input is 4:3.
Code:
Global W = 720
Global H = 720
Global Resizer = "BlackmanResize"

ImageReader("92.JPG",0,0)
ZoomBox(last, 0, 0, 0, 0, W, H, IgnoreAR=1, ResizeMethod=Resizer)

The "#Check if x2 or y2 needs to be calculated" code seems to give correct output, it takes what ever you throw at it, and handles it correctly. So that is a good starting point.
Code:
Global W = 720
Global H = 720
Global Resizer = "BlackmanResize"

ImageReader("2.jpg",0,0)
ZoomBox(930, 0, 3300, 0, W, H, 1, ResizeMethod=Resizer)
Code:
Global W = 720
Global H = 720
Global Resizer = "BlackmanResize"

HDV.TDeint()
ZoomBox( 0,0,960,0, W, H, IgnoreAR=1, ResizeMethod=Resizer, OutputARWidth=1920, OutputARHeight=1080 )

EDIT
This appears to be the correct formula. I only have the first part done
Code:
	EvalString = x1==-1 && y1==0 && x2==0 && y2==0 && DAR>FinalAR ?
	\ "y1=" + String(0 - ((height*DAR-width)/2.0)*(c.height()/Float(width))) + "
	   y2=" + String(c.height() + ((height*DAR-width)/2.0)*(c.height()/Float(width))) + "
	   x1=0" + "
	   x2=" + String(c.width())

Last edited by mikeytown2; 24th May 2008 at 04:27.
mikeytown2 is offline   Reply With Quote
Old 24th May 2008, 07:13   #46  |  Link
mikeytown2
Resize Abuser
 
mikeytown2's Avatar
 
Join Date: Apr 2005
Location: Seattle, WA
Posts: 623
KenBurnsEffect() & ZoomBox() Updated

Changes:
  • 0,0,0,0 and -1,0,0,0 now works correctly with any input.
  • Changed Defaults. UseZoomBox is now defaulted to 2, IgnoreAR defaulted to 4.
  • KBE takes floats for the 2 boxes.
  • StartPZFrame changed to StartFrame. EndPZFrame changed to EndFrame.

Issues:
  • "#Check if x2 or y2 needs to be calculated" isn't perfect. Any help with this would be appreciated.

Last edited by mikeytown2; 24th May 2008 at 08:33.
mikeytown2 is offline   Reply With Quote
Old 24th May 2008, 22:02   #47  |  Link
Gavino
Avisynth language lover
 
Join Date: Dec 2007
Location: Spain
Posts: 3,431
Quote:
Originally Posted by mikeytown2 View Post
"#Check if x2 or y2 needs to be calculated" isn't perfect. Any help with this would be appreciated.
I think the following lines (in ZoomBox):
Code:
y2 = (y2==y1) ? (((x2-x1)/FinalAR + y1)/(SAR/DAR)) : y2
x2 = (x2==x1) ? (((y2-y1)*FinalAR + x1)*(SAR/DAR)) : x2
should be:
Code:
y2 = (y2==y1) ? (((x2-x1)/FinalAR)/(SAR/DAR) + y1) : y2
x2 = (x2==x1) ? (((y2-y1)*FinalAR)*(SAR/DAR) + x1) : x2
with similar changes in the KBE script.

(You can see the logic behind this if you consider that x2-x1 must end up in the required ratio to y2-y1)
Gavino is offline   Reply With Quote
Old 25th May 2008, 00:34   #48  |  Link
mikeytown2
Resize Abuser
 
mikeytown2's Avatar
 
Join Date: Apr 2005
Location: Seattle, WA
Posts: 623
Thanks Gavino! I used your way in KBE and in ZB. They both work correctly now. My "i give up" method still didn't work in all cases... man this is not easy.


Updated KBE & ZB. Parameters changed in ZB. I think ZoomBox is easier to use. Changed my huge example to reflect these changes

Last edited by mikeytown2; 25th May 2008 at 01:27.
mikeytown2 is offline   Reply With Quote
Old 25th May 2008, 04:04   #49  |  Link
mikeytown2
Resize Abuser
 
mikeytown2's Avatar
 
Join Date: Apr 2005
Location: Seattle, WA
Posts: 623
Starting to play with the Align option
Here is my test image

I'm working on negative Align values first because it is the easiest to do. Got rid of inputs x1,x2,y1,y2 just for this.

Example Test Code
Code:
E = ImageReader("traingr4.jpg")

E.ZoomBoxer(640,480, "BilinearResize", 16.0/9.0, -3)
StackHorizontal(last,E.ZoomBoxer(640,320, "BilinearResize", 16.0/9.0, -7).AddBorders(0,160,0,0,$FF0000))

Function ZoomBoxer(clip c, int "width", int "height", string "ResizeMethod", float "DisplayAR", int "Align", int "color", int "IgnoreAR")
{
	#set defaults
	ResizeMethod = Default(ResizeMethod, "BilinearResize")
	IgnoreAR = Default(IgnoreAR, 1)
	color = Default(color, $000000)
	width = Default(width, c.width())
	height = Default(height, c.height())
	Align = Default(Align, 0)
	
	SourceAR = float(c.width())/float(c.height())
	FinalAR = float(width)/float(height)
	DisplayAR = Default(DisplayAR, Float(c.width())/Float(c.height()))
	DisplayAR = DisplayAR == 0 ? Float(c.width())/Float(c.height()) : DisplayAR
	#BoxAR = ((c.width() + ((width/DisplayAR-height)/2.0)*(c.width()/Float(height)))-(((width/DisplayAR-height)/2.0)*(c.width()/Float(height))))/c.height()
	
	#If Align=5 or -5 then center clip. -5: Add borders. 5: Crop.
	#Display Aspect Ratio = Final Output Ratio. No Change, Show All Pixels
	#Display Aspect Ratio > Final Output Ratio. Add Height or Crop Width 
	#Display Aspect Ratio < Final Output Ratio. Add Width or Crop Height 
	EvalString = 
	\   Align<>0 && DisplayAR==FinalAR ?
	\ "x1=0" + "
	   x2="  + String(c.width()) + "
	   y1=0" + "
	   y2="  + String(c.height()) + "" 
	   
	   
	\ : (Align==-5 || Align==-4 || Align==-6) && DisplayAR>FinalAR ?
	\ "y1=" + String(0 - ((height*DisplayAR-width)/2.0)*(c.height()/Float(width))) + "
	   y2=" + String(c.height() + ((height*DisplayAR-width)/2.0)*(c.height()/Float(width))) + "
	   x1=0" + "
	   x2=" + String(c.width())
	\ : Align==5 && DisplayAR>FinalAR ?
	\ "x1=" + String(0 + ((height-width/DisplayAR)/2.0)*(c.width()/Float(height))) + "
	   x2=" + String(c.width() - ((height-width/DisplayAR)/2.0)*(c.width()/Float(height))) + "
	   y1=0" + "
	   y2=" + String(c.height()) + "" 
	\ : (Align==-5 || Align==-2 || Align==-8)  && DisplayAR<FinalAR ?
	\ "x1=" + String(0 - ((width/DisplayAR-height)/2.0)*(c.width()/Float(height))) + "
	   x2=" + String(c.width() + ((width/DisplayAR-height)/2.0)*(c.width()/Float(height))) + "
	   y1=0" + "
	   y2=" + String(c.height()) + ""
	\ : Align==5  && DisplayAR<FinalAR  ?
	\ "y1=" + String(0 + ((width-height*DisplayAR)/2.0)*(c.height()/Float(width))) + "
	   y2=" + String(c.height() - ((width-height*DisplayAR)/2.0)*(c.height()/Float(width))) + "
	   x1=0" + "
	   x2=" + String(c.width()) 


	\ : (Align==-1 || Align==-3) && DisplayAR>FinalAR ?
	\ "y1=0" + "
	   y2=" + String(c.height() + ((height*DisplayAR-width)/1.0)*(c.height()/Float(width))) + "
	   x1=0" + "
	   x2=" + String(c.width())
	\ : (Align==-1 || Align==-7)  && DisplayAR<FinalAR ?
	\ "x1=0" + "
	   x2=" + String(c.width() + ((width/DisplayAR-height)/1.0)*(c.width()/Float(height))) + "
	   y1=0" + "
	   y2=" + String(c.height()) + ""


	\ : ""
	Eval(EvalString)
	
	#Take Crop Like Input
	x2 = x2<=x1 && x2 < 0 ? c.width() + x2 : x2
	y2 = y2<=y1 && y2 < 0 ? c.height() + y2 : y2
	
	#Check if x2 or y2 needs to be calculated
	Assert( ((x2==x1) && (y2==y1))==False, "x2 [" + String(x2) + "] or y2 [" + String(y2) + "] needs a value that is different from x1 [" + String(x1) + "] or y1 [" + String(y1) + "]")
	y2 = (y2==y1) ? (((x2-x1)/FinalAR)/(SourceAR/DisplayAR) + y1) : y2
	x2 = (x2==x1) ? (((y2-y1)*FinalAR)*(SourceAR/DisplayAR) + x1) : x2
	
	BoxAR = Float(x2-x1)/Float(y2-y1)
	#Check For Any Unreasonable Inputs
	Assert(x1<x2, "ZoomBox: x1[" + String(x1) + "] point larger then x2 Point[" + String(x2) + "]")
	Assert(y1<y2, "ZoomBox: y1[" + String(y1) + "] point larger then y2 Point[" + String(y2) + "]")
	Assert(IgnoreAR>0 || BoxAR == FinalAR, "ZoomBox: Box Aspect Ratio [" + String(BoxAR) + "] does not equal clip output Aspect Ratio [" + string(FinalAR) + "]")
	
	#Pad clip so resizer interpolates from border when zooming out. 64 for spline64
	c = c.AddBorders(64,64,64,64,color)
	#Do it
	c = Eval(ResizeMethod + "(c, " + String(Round(width)) + ", " + String(Round(height)) + ", src_left=" + String(x1) + "+64, src_top=" + String(y1) + "+64, src_width=" + String(x2-x1) + ", src_height=" + String(y2-y1) + ")")	
	
	c
	Subtitle(String(x1) + ", " + String(y1) + "    " + String(x2) + ", " + String(y2) + "    BoxAR " + String(BoxAR) + "  " + String())
}

I've also got the "easy way" Example here. Using FlipHorizontal() & FlipVertical() Inside SplitScreener.
Code:
A = ColorBars().Crop(10, 20, -30, -400).ConvertToYV12()
B = ColorBars().invert().FlipHorizontal().Crop(10, 20, -300, -40).ConvertToYV12()
C = ColorBars().FlipVertical().Crop(10, 200, -30, -40).ConvertToYV12()
D = ColorBars().invert().FlipVertical().FlipHorizontal().Crop(100, 20, -30, -40).ConvertToYV12()

#SplitScreener(640, 480, 4, A, B, C, D)

function SplitScreener(int Width, int Height, int Border, clip A, clip B, clip C, clip D, string "ResizeMethod", bool "AudioMix")
{
	#Check Clips For Full Chroma - 4:4:4
	#Assert((IsYV12(A) || IsYUY2(A))==False, "Clip A is not at full chroma (4:4:4). Convert to RGB")
	#Assert((IsYV12(B) || IsYUY2(B))==False, "Clip B is not at full chroma (4:4:4). Convert to RGB")
	#Assert((IsYV12(C) || IsYUY2(C))==False, "Clip C is not at full chroma (4:4:4). Convert to RGB")
	#Assert((IsYV12(D) || IsYUY2(D))==False, "Clip D is not at full chroma (4:4:4). Convert to RGB")
	
	#Set Defaults
	ResizeMethod = Default(ResizeMethod, "BilinearResize")
	AudioMix = Default(AudioMix, true)
	
	#Set Borders
	BorderH = Border
	BorderW = Border
	
	#Set Width and Height of individual clips
	NewW = Round(float(Width)/2.0 - float(BorderW)*1.5)
	NewH = Round(float(Height)/2.0 - float(BorderH)*1.5)
	
	#Process Video
	A = A.FlipHorizontal().FlipVertical().ZoomBox(NewW, NewH, ResizeMethod, 0,  0,0, width(C),0).FlipHorizontal().FlipVertical()
	A = A.AddBorders(BorderW, BorderH, 0, 0)
	B = B.FlipVertical().ZoomBox(NewW, NewH, ResizeMethod, 0,  0,0, 0,height(B)).FlipVertical()
	B = B.AddBorders(BorderW, BorderH, 0, 0)
	C = C.FlipHorizontal().ZoomBox(NewW, NewH, ResizeMethod, 0,  0,0, width(C),0).FlipHorizontal()
	C = C.AddBorders(BorderW, BorderH, 0, 0)
	D = D.ZoomBox(NewW, NewH, ResizeMethod, 0,  0,0, 0,height(D))
	D = D.AddBorders(BorderW, BorderH, 0, 0)
	
	#Merge Clips
	X = StackHorizontal(A, B).AddBorders(0,0,BorderW,0)
	Y = StackHorizontal(C, D).AddBorders(0,0,BorderW,0)
	StackVertical(X, Y).AddBorders(0,0,0,BorderH).KillAudio()
	
	#Fix Audio
	LongestClip = Int(Max(Framecount(A), Framecount(B), Framecount(C), Framecount(D)))
	A = (Framecount(A) <> LongestClip) ? A ++ BlankClip(A, LongestClip-Framecount(A)) : A
	B = (Framecount(B) <> LongestClip) ? B ++ BlankClip(B, LongestClip-Framecount(B)) : B
	C = (Framecount(C) <> LongestClip) ? C ++ BlankClip(C, LongestClip-Framecount(C)) : C
	D = (Framecount(D) <> LongestClip) ? D ++ BlankClip(D, LongestClip-Framecount(D)) : D
	
	#Mix Audio
	Sound = (AudioMix) ? MergeChannels(MixAudio(ConvertToMono(A).Amplify(0.49), ConvertToMono(C).Amplify(0.49)), MixAudio(ConvertToMono(B).Amplify(0.49), ConvertToMono(D).Amplify(0.49))):
		\ MergeChannels(GetLeftChannel(A), GetRightChannel(A), GetLeftChannel(B), GetRightChannel(B), GetLeftChannel(C), GetRightChannel(C), GetLeftChannel(D), GetRightChannel(D))
	AudioDub(last, Sound)
}
I'll be working on other things, so if anyone wants to pick this up, feel free. otherwise it might be a week or 2.
mikeytown2 is offline   Reply With Quote
Old 26th May 2008, 15:34   #50  |  Link
tacman1123
Registered User
 
Join Date: Jun 2007
Location: Washington, DC
Posts: 130
Mike,

Have you looked at the UI and capabilities of Proshow Gold/Producer? If not, I encourage you to take a look at it, and consider using their parameters for panning, zoom and rotation. Rather than choosing starting and ending X and Y coordinates for upper left / lower right, their system pans by referencing a center point (0,0), so panning from left to right would simply be -15, 0 => +15, 0. Zoom is done by percentage, and X and Y zoom are locked together by default, but that can be "broken" so the aspect ratio can change.

I've been trying to figure out how to convert some Proshow shows to Avisynth, and your KBE is the key to the conversion.

Anyway, you posted about trying to figure out a good way to handle the parameters, a bonus of using Proshow would be that there would be a way to review the effect and get the parameter values. Proshow is great for photos and for a very easy UI to do some amazing stuff, my whole project was based on this before I realized that large videos will frequently crash it (and it's painfully slow with video). Avisynth is awesome for scripting (and amazingly fast for preview), but coding in all the numbers can be overwhelming.

Proshow has a eval/preview version, it's worth checking out as you continue to improve your KBE, just pop a photo on the timeline, double-click, then click on the Motion tab and play around with the values.

Tac
tacman1123 is offline   Reply With Quote
Old 26th May 2008, 20:44   #51  |  Link
mikeytown2
Resize Abuser
 
mikeytown2's Avatar
 
Join Date: Apr 2005
Location: Seattle, WA
Posts: 623
Quote:
Originally Posted by tacman1123 View Post
Mike,

Have you looked at the UI and capabilities of Proshow Gold/Producer? If not, I encourage you to take a look at it, and consider using their parameters for panning, zoom and rotation. Rather than choosing starting and ending X and Y coordinates for upper left / lower right, their system pans by referencing a center point (0,0), so panning from left to right would simply be -15, 0 => +15, 0. Zoom is done by percentage, and X and Y zoom are locked together by default, but that can be "broken" so the aspect ratio can change.

I've been trying to figure out how to convert some Proshow shows to Avisynth, and your KBE is the key to the conversion.

Anyway, you posted about trying to figure out a good way to handle the parameters, a bonus of using Proshow would be that there would be a way to review the effect and get the parameter values. Proshow is great for photos and for a very easy UI to do some amazing stuff, my whole project was based on this before I realized that large videos will frequently crash it (and it's painfully slow with video). Avisynth is awesome for scripting (and amazingly fast for preview), but coding in all the numbers can be overwhelming.

Proshow has a eval/preview version, it's worth checking out as you continue to improve your KBE, just pop a photo on the timeline, double-click, then click on the Motion tab and play around with the values.

Tac
Sweet Program! Those parameters would be perfect in combination with the Align option. I would still keep the x1,y1 x2,y2 because it can take crop values directly, and it give you complete control over the "box". I think now the program would have 2 modes. Mode 1: use X1,Y1 X2,Y2 values. Mode 2: align with zoom pan. Thus the pan values don't always have to start from the center of the clip. Do you guys think going this route will be too much? Also, for this to really take off, a GUI is needed. I would make one in AutoIt, but i don't think AutoIt can do it. For right now, AvsP's Crop Editor, does the trick (FYI, you can use your mouse to drag the crop lines). Zooming out still isn't easy though...

After looking at Proshow, there are multiple ways to do rotate (before or after zoom, xy location), so I'll keep them in mind when i finally take the plunge and add it. I'll probably use the zoom.dll rotate option, when using zoom(), and Effect Rotation with ZoomBox(). This won't be added for some time though...

In case your wondering, I will fully develop the Align option, then add in the zoom pan to it after. Going this route prevents this from being stalled from the dev being too hard. So align will make the initial box, and then use the pan zoom on that box, thus i shouldn't have to redo a lot of code, since it will be 2 different code blocks. This also will allow pan zoom in Mode 1, although it would be kinda odd to use it that way. This of course brings up the question of, when align is not at 5, should it expand into the black area, or should it avoid it all all costs? I personally think it should avoid it at all costs, thus zooming out 2000% with align=1, and the image is in the upper left corner. If it does it the other way then when zooming out 2000% the image will be a little off center.

Please keep the input coming in. The more ideas I have, the better this can be.
mikeytown2 is offline   Reply With Quote
Old 27th May 2008, 03:26   #52  |  Link
mikeytown2
Resize Abuser
 
mikeytown2's Avatar
 
Join Date: Apr 2005
Location: Seattle, WA
Posts: 623
So i had a brain storm, and decided to code. If i could get some testing of ZB, that would be great! Here is my test code block...

Code:
A = ColorBars().Crop(10, 20, -30, -400).ConvertToYV12()
B = ColorBars().invert().FlipHorizontal().Crop(10, 20, -300, -40).ConvertToYV12()
C = ColorBars().FlipVertical().Crop(10, 200, -30, -40).ConvertToYV12()
D = ColorBars().invert().FlipVertical().FlipHorizontal().Crop(100, 20, -30, -40).ConvertToYV12()
E = ImageReader("traingr4.jpg")

SplitScreener(640, 480, 4, A, B, C, D, ZoomToFill=1)


E.ZoomBoxer(640,480, "BilinearResize", DisplayAR=16.0/9.0, Align=1, zoomFactor=-1, panX=-500, panY=-20)





function SplitScreener(int Width, int Height, int Border, clip A, clip B, clip C, clip D, int "ZoomToFill", string "ResizeMethod", bool "AudioMix")
{
	#Set Defaults
	ResizeMethod = Default(ResizeMethod, "BilinearResize")
	AudioMix = Default(AudioMix, true)
	ZoomToFill = Default(ZoomToFill, -1)
	
	#Check Inputs
	Assert(ZoomToFill==1 || ZoomToFill==-1, "ZoomToFill must be 1 or -1. Input of " + String(ZoomToFill) + " doesn't work")
	
	
	#Set Borders
	BorderH = Border
	BorderW = Border
	
	#Set Width and Height of individual clips
	NewW = Round(float(Width)/2.0 - float(BorderW)*1.5)
	NewH = Round(float(Height)/2.0 - float(BorderH)*1.5)
	NewAR = Float(NewW)/Float(NewH)
	OutAR = Float(Width)/Float(Height)
	
	#Process Video
	A = A.ZoomBoxer(NewW, NewH, ResizeMethod, Float(A.width())/Float(A.height())*(NewAR/OutAR), ZoomToFill*(9))
	A = A.AddBorders(BorderW, BorderH, 0, 0)
	B = B.ZoomBoxer(NewW, NewH, ResizeMethod, Float(B.width())/Float(B.height())*(NewAR/OutAR), ZoomToFill*(7))
	B = B.AddBorders(BorderW, BorderH, 0, 0)
	C = C.ZoomBoxer(NewW, NewH, ResizeMethod, Float(C.width())/Float(C.height())*(NewAR/OutAR), ZoomToFill*(3))
	C = C.AddBorders(BorderW, BorderH, 0, 0)
	D = D.ZoomBoxer(NewW, NewH, ResizeMethod, Float(D.width())/Float(D.height())*(NewAR/OutAR), ZoomToFill*(1))
	D = D.AddBorders(BorderW, BorderH, 0, 0)
	
	#Merge Clips
	X = StackHorizontal(A, B).AddBorders(0,0,BorderW,0)
	Y = StackHorizontal(C, D).AddBorders(0,0,BorderW,0)
	StackVertical(X, Y).AddBorders(0,0,0,BorderH).KillAudio()
	
	#Fix Audio
	LongestClip = Int(Max(Framecount(A), Framecount(B), Framecount(C), Framecount(D)))
	A = (Framecount(A) <> LongestClip) ? A ++ BlankClip(A, LongestClip-Framecount(A)) : A
	B = (Framecount(B) <> LongestClip) ? B ++ BlankClip(B, LongestClip-Framecount(B)) : B
	C = (Framecount(C) <> LongestClip) ? C ++ BlankClip(C, LongestClip-Framecount(C)) : C
	D = (Framecount(D) <> LongestClip) ? D ++ BlankClip(D, LongestClip-Framecount(D)) : D
	
	#Mix Audio
	Sound = (AudioMix) ? MergeChannels(MixAudio(ConvertToMono(A).Amplify(0.49), ConvertToMono(C).Amplify(0.49)), MixAudio(ConvertToMono(B).Amplify(0.49), ConvertToMono(D).Amplify(0.49))):
		\ MergeChannels(GetLeftChannel(A), GetRightChannel(A), GetLeftChannel(B), GetRightChannel(B), GetLeftChannel(C), GetRightChannel(C), GetLeftChannel(D), GetRightChannel(D))
	AudioDub(last, Sound)
}


Function ZoomBoxer(clip c, int "width", int "height", string "ResizeMethod", float "DisplayAR", int "Align", float "zoomFactor", float "panX", float "panY", int "color", int "IgnoreAR")
{
	#set defaults
	ResizeMethod = Default(ResizeMethod, "BilinearResize")
	IgnoreAR = Default(IgnoreAR, 1)
	color = Default(color, $000000)
	width = Default(width, c.width())
	height = Default(height, c.height())
	Align = Default(Align, 0)
	zoomFactor = Default(-zoomFactor, 0.0)
	panX = Default(panX, 0)
	panY = Default(panY, 0)
	
	SourceAR = float(c.width())/float(c.height())
	FinalAR = float(width)/float(height)
	DisplayAR = Default(DisplayAR, Float(c.width())/Float(c.height()))
	DisplayAR = DisplayAR == 0 ? Float(c.width())/Float(c.height()) : DisplayAR
	
	#If Align=5 or -5 then center clip. -5: Add borders. 5: Crop.
	#Display Aspect Ratio = Final Output Ratio. No Change, Show All Pixels
	#Display Aspect Ratio > Final Output Ratio. Add Height or Crop Width 
	#Display Aspect Ratio < Final Output Ratio. Add Width or Crop Height 
	EvalString = 
	\   Align<>0 && DisplayAR==FinalAR ?
	\ "x1=0" + "
	   x2="  + String(c.width()) + "
	   y1=0" + "
	   y2="  + String(c.height()) + "" 
	   
	   
	\ : (Align==-5 || Align==-4 || Align==-6) && DisplayAR>FinalAR ?
	\ "y1=" + String(0 - ((height*DisplayAR-width)/2.0)*(c.height()/Float(width))) + "
	   y2=" + String(c.height() + ((height*DisplayAR-width)/2.0)*(c.height()/Float(width))) + "
	   x1=0" + "
	   x2=" + String(c.width())
	\ : (Align==5 || Align==2 || Align==8) && DisplayAR>FinalAR ?
	\ "x1=" + String(0 + ((height-width/DisplayAR)/2.0)*(c.width()/Float(height))) + "
	   x2=" + String(c.width() - ((height-width/DisplayAR)/2.0)*(c.width()/Float(height))) + "
	   y1=0" + "
	   y2=" + String(c.height()) + "" 
	\ : (Align==-5 || Align==-2 || Align==-8)  && DisplayAR<FinalAR ?
	\ "x1=" + String(0 - ((width/DisplayAR-height)/2.0)*(c.width()/Float(height))) + "
	   x2=" + String(c.width() + ((width/DisplayAR-height)/2.0)*(c.width()/Float(height))) + "
	   y1=0" + "
	   y2=" + String(c.height()) + ""
	\ : (Align==5 || Align==4 || Align==6)  && DisplayAR<FinalAR  ?
	\ "y1=" + String(0 + ((width-height*DisplayAR)/2.0)*(c.height()/Float(width))) + "
	   y2=" + String(c.height() - ((width-height*DisplayAR)/2.0)*(c.height()/Float(width))) + "
	   x1=0" + "
	   x2=" + String(c.width()) 


	\ : (Align==-1 || Align==-2 || Align==-3) && DisplayAR>FinalAR ?
	\ "y1=" + String(0) + "
	   y2=" + String(c.height() + ((height*DisplayAR-width)/1.0)*(c.height()/Float(width))) + "
	   x1=0" + "
	   x2=" + String(c.width())
	\ : (Align==-1 || Align==-4 || Align==-7)  && DisplayAR<FinalAR ?
	\ "x1=" + String(0) + "
	   x2=" + String(c.width() + ((width/DisplayAR-height)/1.0)*(c.width()/Float(height))) + "
	   y1=0" + "
	   y2=" + String(c.height()) + ""
	\ : (Align==-9 || Align==-8 || Align==-7) && DisplayAR>FinalAR ?
	\ "y1=" + String(0 - ((height*DisplayAR-width)/1.0)*(c.height()/Float(width))) + "
	   y2=" + String(c.height()) + "
	   x1=0" + "
	   x2=" + String(c.width())
	\ : (Align==-9 || Align==-6 || Align==-3)  && DisplayAR<FinalAR ?
	\ "x1=" + String(0 - ((width/DisplayAR-height)/1.0)*(c.width()/Float(height))) + "
	   x2=" + String(c.width()) + "
	   y1=0" + "
	   y2=" + String(c.height()) + ""


	\ : (Align==2 || Align==1 || Align==3) && DisplayAR<FinalAR  ?
	\ "y1=" + String(0) + "
	   y2=" + String(c.height() - ((width-height*DisplayAR)/1.0)*(c.height()/Float(width))) + "
	   x1=0" + "
	   x2=" + String(c.width()) 
	\ : (Align==8 || Align==7 || Align==9) && DisplayAR<FinalAR  ?
	\ "y1=" + String(0 + ((width-height*DisplayAR)/1.0)*(c.height()/Float(width))) + "
	   y2=" + String(c.height()) + "
	   x1=0" + "
	   x2=" + String(c.width()) 
	\ : (Align==4 || Align==1 || Align==7) && DisplayAR>FinalAR ?
	\ "x1=" + String(0) + "
	   x2=" + String(c.width() - ((height-width/DisplayAR)/1.0)*(c.width()/Float(height))) + "
	   y1=0" + "
	   y2=" + String(c.height()) + "" 
	\ : (Align==6 || Align==3 || Align==9) && DisplayAR>FinalAR ?
	\ "x1=" + String(0 + ((height-width/DisplayAR)/1.0)*(c.width()/Float(height))) + "
	   x2=" + String(c.width()) + "
	   y1=0" + "
	   y2=" + String(c.height()) + "" 



	\ : ""
	Eval(EvalString)
	
	#Take Crop Like Input
	x2 = x2<=x1 && x2 < 0 ? c.width() + x2 : x2
	y2 = y2<=y1 && y2 < 0 ? c.height() + y2 : y2
	
	#Check if x2 or y2 needs to be calculated
	Assert( ((x2==x1) && (y2==y1))==False, "x2 [" + String(x2) + "] or y2 [" + String(y2) + "] needs a value that is different from x1 [" + String(x1) + "] or y1 [" + String(y1) + "]")
	y2 = (y2==y1) ? (((x2-x1)/FinalAR)/(SourceAR/DisplayAR) + y1) : y2
	x2 = (x2==x1) ? (((y2-y1)*FinalAR)*(SourceAR/DisplayAR) + x1) : x2
	
	#Calc Zoom Factor
	Align = abs(Align)
	x1 = Align==0 || Align==5 || Align==2 || Align==3 || Align==8 || Align==9 ? x1-(x2-x1)*zoomFactor/4.0 : Align==6 ? x1-((x2-x1)*zoomFactor)/2.4 : x1
	y1 = Align==0 || Align==5 || Align==4 || Align==6 || Align==7 || Align==9 ? y1-(y2-y1)*zoomFactor/4.0 : Align==8 ? y1-((y2-y1)*zoomFactor)/2.4 : y1
	x2 = Align==0 || Align==5 || Align==1 || Align==2 || Align==7 || Align==8 ? x2+(x2-x1)*zoomFactor/4.0 : Align==4 ? x2+((x2-x1)*zoomFactor)/2.4 : x2
	y2 = Align==0 || Align==5 || Align==1 || Align==3 || Align==4 || Align==6 ? y2+(y2-y1)*zoomFactor/4.0 : Align==2 ? y2+((y2-y1)*zoomFactor)/2.4 : y2
	
	#Calc Pan Factor
	x1 = x1+panX
	y1 = y1+panY
	x2 = x2+panX
	y2 = y2+panY
	
	BoxAR = Float(x2-x1)/Float(y2-y1)
	#Check For Any Unreasonable Inputs
	Assert(x1<x2, "ZoomBox: x1[" + String(x1) + "] point larger then x2 Point[" + String(x2) + "]")
	Assert(y1<y2, "ZoomBox: y1[" + String(y1) + "] point larger then y2 Point[" + String(y2) + "]")
	Assert(IgnoreAR>0 || BoxAR == FinalAR, "ZoomBox: Box Aspect Ratio [" + String(BoxAR) + "] does not equal clip output Aspect Ratio [" + string(FinalAR) + "]")
	
	#Pad clip so resizer interpolates from border when zooming out. 64 for spline64
	#Conditional Borders... only add if it's going to be used.
	borderSize = 64
	borderLeft   = x1 < 0 ? borderSize : 0
	borderTop    = y1 < 0 ? borderSize : 0
	borderRight  = x2 > c.width() ? borderSize : 0
	borderBottom = y2 > c.height() ? borderSize : 0
	c = c.AddBorders(borderLeft,borderTop,borderRight,borderBottom,color)
	
	#Do it
	c = Eval(ResizeMethod + "(c, " + String(Round(width)) + ", " + String(Round(height)) + ", src_left=" + String(x1+borderLeft) + ", src_top=" + String(y1+borderTop) + ", src_width=" + String(x2-x1) + ", src_height=" + String(y2-y1) + ")")	
	
	c
	Subtitle(String(x1) + ", " + String(y1) + "    " + String(x2) + ", " + String(y2) + "    BoxAR " + String(BoxAR) + "  " + String())
}
Please let me know that it works correctly. The AR is slightly off with Align 2,4,6,8 with the usage of zoomFactor. There has to be a better way to code the zoom. Right now 0 is no zoom. Negative values zoom out, positive values zoom in. BTW zoomFactor=2 is really zoomed in, and it will throw an error if its too much. I also made the adding of borders before the resize smarter, picture looks better on the edge now. If anyone has a better way to code a zoom I'm all ears! Also should the pan go before or after the zoom?

Last edited by mikeytown2; 27th May 2008 at 08:46.
mikeytown2 is offline   Reply With Quote
Old 27th May 2008, 14:28   #53  |  Link
Gavino
Avisynth language lover
 
Join Date: Dec 2007
Location: Spain
Posts: 3,431
Quote:
Originally Posted by mikeytown2 View Post
So i had a brain storm, and decided to code. If i could get some testing of ZB, that would be great! Here is my test code block...

Please let me know that it works correctly.
I tried using your example exactly as given via
Code:
A = ColorBars().Crop(10, 20, -30, -400).ConvertToYV12()
B = ColorBars().invert().FlipHorizontal().Crop(10, 20, -300, -40).ConvertToYV12()
C = ColorBars().FlipVertical().Crop(10, 200, -30, -40).ConvertToYV12()
D = ColorBars().invert().FlipVertical().FlipHorizontal().Crop(100, 20, -30, -40).ConvertToYV12()
SplitScreener(640, 480, 4, A, B, C, D, ZoomToFill=1)
and it failed due to this line in ZoomBoxer:
Code:
zoomFactor = Default(-zoomFactor, 0.0)
Is the minus sign simply a typo? Or perhaps you meant
Code:
zoomFactor = -Default(zoomFactor, 0.0)
Either way, I found the example still won't work because of YV12 mod4 width restrictions.
Quote:
The AR is slightly off with Align 2,4,6,8 with the usage of zoomFactor. There has to be a better way to code the zoom. Right now 0 is no zoom. Negative values zoom out, positive values zoom in. BTW zoomFactor=2 is really zoomed in, and it will throw an error if its too much.
To me, it would be more natural if zoomFactor was a simple scale factor, rather than (as I understand it) the proportion to add or subtract. In other words, zoomFactor=1 would mean no zoom. That way only positive values would be meaningful.
Gavino is offline   Reply With Quote
Old 27th May 2008, 14:31   #54  |  Link
tacman1123
Registered User
 
Join Date: Jun 2007
Location: Washington, DC
Posts: 130
I'd also prefer to see something like zoom=100 mean that there was no zoom, rather than having negative zoom go in and positive zoom go out. It fits into the common percentage model -- show this picture at 25%, or 200%.
tacman1123 is offline   Reply With Quote
Old 27th May 2008, 20:59   #55  |  Link
Gavino
Avisynth language lover
 
Join Date: Dec 2007
Location: Spain
Posts: 3,431
I've ditched SplitScreener from your example and used ZoomBoxer directly with my own test image. It seems to work fine for the simple cases I tried. However, I have a few questions and comments.

What is the meaning of align=0 (the default value)? In the case align=0 and the ARs match (DisplayAR=FinalAR), x1 etc are undefined as there is no code to handle this combination.

Are panX and panY in pixel units of the input clip or the output clip? It seems to be the former, but how are they meant to interact with zoom?

I'm still confused about the intended meaning of zoomFactor - I think this is partly because there is already an implicit zoom happening if the input and output clips differ in size. Can you explain this further please?

In any case (whatever the answer to the above), the code to recalculate x1 (etc) based on zoomFactor looks wrong to me because x2 and y2 are calculated using the possibly already changed values of x1 and y1 (and where on earth does the value 2.4 come from?)

Last edited by Gavino; 27th May 2008 at 21:02.
Gavino is offline   Reply With Quote
Old 27th May 2008, 21:45   #56  |  Link
mikeytown2
Resize Abuser
 
mikeytown2's Avatar
 
Join Date: Apr 2005
Location: Seattle, WA
Posts: 623
Quote:
Originally Posted by Gavino View Post
I've ditched SplitScreener from your example and used ZoomBoxer directly with my own test image.
My guess on why it isn't working is that you are using Avisynth 2.57. I'm currently using 2.58. Changelog documents this "Relax YV12 resizer width restriction, now mod 2 was mod 4."


Quote:
Originally Posted by Gavino View Post
It seems to work fine for the simple cases I tried. However, I have a few questions and comments.

What is the meaning of align=0 (the default value)? In the case align=0 and the ARs match (DisplayAR=FinalAR), x1 etc are undefined as there is no code to handle this combination.
If Align is not specified, then the float inputs of x1,y1,x2,y2 will be used. That is what Align=0 is for. I took out x1,y1,x2,y2 so i could test align by it's self. The final version will have what i call Mode 1: x1,y1,x2,y2 and Mode 2: Align.


Quote:
Originally Posted by Gavino View Post
Are panX and panY in pixel units of the input clip or the output clip? It seems to be the former, but how are they meant to interact with zoom?
You are correct, panX/panY are in pixel units of the input clip. Pan could be used before zoom, or after zoom. For large values of zoom, I think it will make a difference. Now that i think about it, pan should go in before zoom, that way it is independent of zoom.


Quote:
Originally Posted by Gavino View Post
I'm still confused about the intended meaning of zoomFactor - I think this is partly because there is already an implicit zoom happening if the input and output clips differ in size. Can you explain this further please?
zoomFactor is very useful when using align. If it wasn't for align, zoomFactor is quite useless. In the end ZB() will either take x1,y1,x2,y2 or Align. When only using Align, it would be impossible to zoom in/out to your desired level. Tac offered a better way of doing things, when compared to my orginal idea on how to use Align.



Quote:
Originally Posted by Gavino View Post
In any case (whatever the answer to the above), the code to recalculate x1 (etc) based on zoomFactor looks wrong to me
because x2 and y2 are calculated using the possibly already changed values of x1 and y1 (and where on earth does the value 2.4 come from?)
Thank you for pointing that x2 and y2 are calculated using the already changed values of x1 and y1. I didn't see it! The 2.4 was originally 2, but through trial and error, 2.4 gave better results then 2. 2 is half of 4, so that is where it comes from.



I'm looking on the web for code on how to do the zoom. Right now mine is linear, which is why it messes up when zooming in too much. I think it needs to be shaped like a Logarithm, thus 100*.01=1, and it can never reach 0 when zooming out. I just need to figure out how to limit the zooming in so that the zoom point doesn't cross it's self. I'll post some new code in an hr or 2... but if you can point me to some code where zoom of 100% is unchanged and 200% is twice as much, ect... i would appreciate it.
mikeytown2 is offline   Reply With Quote
Old 27th May 2008, 22:27   #57  |  Link
Gavino
Avisynth language lover
 
Join Date: Dec 2007
Location: Spain
Posts: 3,431
Quote:
Originally Posted by mikeytown2 View Post
My guess on why it isn't working is that you are using Avisynth 2.57.
Yes, you are correct.

Quote:
zoomFactor is very useful when using align. If it wasn't for align, zoomFactor is quite useless. In the end ZB() will either take x1,y1,x2,y2 or Align. When only using Align, it would be impossible to zoom in/out to your desired level.
Yes, I see, but I was looking for a more exact specification, explaining how align interacts with zoom (I guess the alignment point is the zoom center?) and what it means to say zoomFactor=x when the input and output clips are in the ratio y.
Quote:
Thank you for pointing that x2 and y2 are calculated using the already changed values of x1 and y1. I didn't see it! The 2.4 was originally 2, but through trial and error, 2.4 gave better results then 2.
That's probably because of the error I pointed out.
Quote:
I'm looking on the web for code on how to do the zoom. Right now mine is linear, which is why it messes up when zooming in too much. I think it needs to be shaped like a Logarithm, thus 100*.01=1, and it can never reach 0 when zooming out. I just need to figure out how to limit the zooming in so that the zoom point doesn't cross it's self. I'll post some new code in an hr or 2... but if you can point me to some code where zoom of 100% is unchanged and 200% is twice as much, ect... i would appreciate it.
I think a simple linear approach is easier to understand. The basis would be that to scale by a factor k about the point (x0, y0), the point (x, y) is mapped to the point (x0+k*(x-x0), y0+k*(y-y0). (If I understood exactly how you meant zoom to operate, I'd write the code for you).

For limiting, you just have to add a validation check that the requested zoom (scale) factor is > 0.
Gavino is offline   Reply With Quote
Old 28th May 2008, 01:05   #58  |  Link
mikeytown2
Resize Abuser
 
mikeytown2's Avatar
 
Join Date: Apr 2005
Location: Seattle, WA
Posts: 623
I fixed the bug in zoomFactor with my current logic (Thanks Gavino!) I also gave Log() a shot... it's sorta close. Keep in mind that when zooming out, x1,y1 needs to go negative and x2,y2 need to go positive. Zooming in, x1,y1 gets larger, x2,y2 gets smaller.


After checking in GIMP, this is 200%. I would like it to behave like this, how GIMP does.

If you could code a better way then what i got, shouldn't be that hard, lol, i would greatly appreciate it!


Code:
A = ColorBars().Crop(10, 20, -30, -400).ConvertToYV12()
B = ColorBars().invert().FlipHorizontal().Crop(10, 20, -300, -40).ConvertToYV12()
C = ColorBars().FlipVertical().Crop(10, 200, -30, -40).ConvertToYV12()
D = ColorBars().invert().FlipVertical().FlipHorizontal().Crop(100, 20, -30, -40).ConvertToYV12()
E = ImageReader("testp2cz4.png",0,0)
E = E.ConvertToYV12().AssumeFPS("ntsc_video")
W = 640
H = 480
DAR = 0 #16.0/9.0
Resize = "BilinearResize"

#SplitScreener(640, 480, 8, A, B, C, D, ZoomToFill=1).Trim(0,4).KillAudio()

E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=50, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-2, zoomFactor=50, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-3, zoomFactor=50, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-4, zoomFactor=50, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-5, zoomFactor=50, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-6, zoomFactor=50, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-7, zoomFactor=50, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-8, zoomFactor=50, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-9, zoomFactor=50, panX=0, panY=0)

last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=100, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=200, panX=0, panY=0).Subtitle("Incorrect at 200%", y=200)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=272, panX=0, panY=0).Subtitle("Correct for 200%", y=200)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=400, panX=0, panY=0).Subtitle("Incorrect at 400%", y=200)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=448, panX=0, panY=0).Subtitle("Correct for 400%", y=200)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=576, panX=0, panY=0).Subtitle("Correct for 800%", y=200)

last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=100, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=75, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=50, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=25, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=10, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=1, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=.1, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=.01, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=.001, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=.0001, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=.00001, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=.0000000000000000000000001, panX=0, panY=0)



Function ZoomBoxer(clip c, int "width", int "height", string "ResizeMethod", float "DisplayAR", int "Align", float "zoomFactor", float "panX", float "panY", int "color", int "IgnoreAR")
{
	#set defaults
	ResizeMethod = Default(ResizeMethod, "BilinearResize")
	IgnoreAR = Default(IgnoreAR, 1)
	color = Default(color, $000000)
	width = Default(width, c.width())
	height = Default(height, c.height())
	Align = Default(Align, 0)
	zoomFactor = -Log(Default(zoomFactor, 100.0)*0.01)
	panX = Default(panX, 0)
	panY = Default(panY, 0)
	
	SourceAR = float(c.width())/float(c.height())
	FinalAR = float(width)/float(height)
	DisplayAR = Default(DisplayAR, Float(c.width())/Float(c.height()))
	DisplayAR = DisplayAR == 0 ? Float(c.width())/Float(c.height()) : DisplayAR
	
	#If Align=5 or -5 then center clip. -5: Add borders. 5: Crop.
	#Display Aspect Ratio = Final Output Ratio. No Change, Show All Pixels
	#Display Aspect Ratio > Final Output Ratio. Add Height or Crop Width 
	#Display Aspect Ratio < Final Output Ratio. Add Width or Crop Height 
	EvalString = 
	\   Align<>0 && DisplayAR==FinalAR ?
	\ "x1=0" + "
	   x2="  + String(c.width()) + "
	   y1=0" + "
	   y2="  + String(c.height()) + "" 
	   
	   
	\ : (Align==-5 || Align==-4 || Align==-6) && DisplayAR>FinalAR ?
	\ "y1=" + String(0 - ((height*DisplayAR-width)/2.0)*(c.height()/Float(width))) + "
	   y2=" + String(c.height() + ((height*DisplayAR-width)/2.0)*(c.height()/Float(width))) + "
	   x1=0" + "
	   x2=" + String(c.width())
	\ : (Align==5 || Align==2 || Align==8) && DisplayAR>FinalAR ?
	\ "x1=" + String(0 + ((height-width/DisplayAR)/2.0)*(c.width()/Float(height))) + "
	   x2=" + String(c.width() - ((height-width/DisplayAR)/2.0)*(c.width()/Float(height))) + "
	   y1=0" + "
	   y2=" + String(c.height()) + "" 
	\ : (Align==-5 || Align==-2 || Align==-8)  && DisplayAR<FinalAR ?
	\ "x1=" + String(0 - ((width/DisplayAR-height)/2.0)*(c.width()/Float(height))) + "
	   x2=" + String(c.width() + ((width/DisplayAR-height)/2.0)*(c.width()/Float(height))) + "
	   y1=0" + "
	   y2=" + String(c.height()) + ""
	\ : (Align==5 || Align==4 || Align==6)  && DisplayAR<FinalAR  ?
	\ "y1=" + String(0 + ((width-height*DisplayAR)/2.0)*(c.height()/Float(width))) + "
	   y2=" + String(c.height() - ((width-height*DisplayAR)/2.0)*(c.height()/Float(width))) + "
	   x1=0" + "
	   x2=" + String(c.width()) 


	\ : (Align==-1 || Align==-2 || Align==-3) && DisplayAR>FinalAR ?
	\ "y1=" + String(0) + "
	   y2=" + String(c.height() + ((height*DisplayAR-width)/1.0)*(c.height()/Float(width))) + "
	   x1=0" + "
	   x2=" + String(c.width())
	\ : (Align==-1 || Align==-4 || Align==-7)  && DisplayAR<FinalAR ?
	\ "x1=" + String(0) + "
	   x2=" + String(c.width() + ((width/DisplayAR-height)/1.0)*(c.width()/Float(height))) + "
	   y1=0" + "
	   y2=" + String(c.height()) + ""
	\ : (Align==-9 || Align==-8 || Align==-7) && DisplayAR>FinalAR ?
	\ "y1=" + String(0 - ((height*DisplayAR-width)/1.0)*(c.height()/Float(width))) + "
	   y2=" + String(c.height()) + "
	   x1=0" + "
	   x2=" + String(c.width())
	\ : (Align==-9 || Align==-6 || Align==-3)  && DisplayAR<FinalAR ?
	\ "x1=" + String(0 - ((width/DisplayAR-height)/1.0)*(c.width()/Float(height))) + "
	   x2=" + String(c.width()) + "
	   y1=0" + "
	   y2=" + String(c.height()) + ""


	\ : (Align==2 || Align==1 || Align==3) && DisplayAR<FinalAR  ?
	\ "y1=" + String(0) + "
	   y2=" + String(c.height() - ((width-height*DisplayAR)/1.0)*(c.height()/Float(width))) + "
	   x1=0" + "
	   x2=" + String(c.width()) 
	\ : (Align==8 || Align==7 || Align==9) && DisplayAR<FinalAR  ?
	\ "y1=" + String(0 + ((width-height*DisplayAR)/1.0)*(c.height()/Float(width))) + "
	   y2=" + String(c.height()) + "
	   x1=0" + "
	   x2=" + String(c.width()) 
	\ : (Align==4 || Align==1 || Align==7) && DisplayAR>FinalAR ?
	\ "x1=" + String(0) + "
	   x2=" + String(c.width() - ((height-width/DisplayAR)/1.0)*(c.width()/Float(height))) + "
	   y1=0" + "
	   y2=" + String(c.height()) + "" 
	\ : (Align==6 || Align==3 || Align==9) && DisplayAR>FinalAR ?
	\ "x1=" + String(0 + ((height-width/DisplayAR)/1.0)*(c.width()/Float(height))) + "
	   x2=" + String(c.width()) + "
	   y1=0" + "
	   y2=" + String(c.height()) + "" 



	\ : ""
	Eval(EvalString)
	
	#Take Crop Like Input
	x2 = x2<=x1 && x2 < 0 ? c.width() + x2 : x2
	y2 = y2<=y1 && y2 < 0 ? c.height() + y2 : y2
	
	#Check if x2 or y2 needs to be calculated
	Assert( ((x2==x1) && (y2==y1))==False, "x2 [" + String(x2) + "] or y2 [" + String(y2) + "] needs a value that is different from x1 [" + String(x1) + "] or y1 [" + String(y1) + "]")
	y2 = (y2==y1) ? (((x2-x1)/FinalAR)/(SourceAR/DisplayAR) + y1) : y2
	x2 = (x2==x1) ? (((y2-y1)*FinalAR)*(SourceAR/DisplayAR) + x1) : x2
	
	SubString = "Align=" + String(Align) + "  zoomFactor=" + String(zoomFactor) + "  panX=" + String(panX) + "  panY=" + String(panY)
	
	#Calc Pan Factor
	x1 = x1+panX
	y1 = y1+panY
	x2 = x2+panX
	y2 = y2+panY
	
	#Calc Zoom Factor
	Align = abs(Align)
	x1tmp = Align==0 || Align==5 || Align==2 || Align==8 ? x1-(x2-x1)*zoomFactor/4.0 : Align==3 || Align==6 || Align==9 ? x1-((x2-x1)*zoomFactor)/2.0 : x1
	y1tmp = Align==0 || Align==5 || Align==4 || Align==6 ? y1-(y2-y1)*zoomFactor/4.0 : Align==7 || Align==8 || Align==9 ? y1-((y2-y1)*zoomFactor)/2.0 : y1
	x2    = Align==0 || Align==5 || Align==2 || Align==8 ? x2+(x2-x1)*zoomFactor/4.0 : Align==1 || Align==4 || Align==7 ? x2+((x2-x1)*zoomFactor)/2.0 : x2
	y2    = Align==0 || Align==5 || Align==4 || Align==6 ? y2+(y2-y1)*zoomFactor/4.0 : Align==1 || Align==2 || Align==3 ? y2+((y2-y1)*zoomFactor)/2.0 : y2
	
	x1 = x1tmp
	y1 = y1tmp

	
	BoxAR = Float(x2-x1)/Float(y2-y1)
	#Check For Any Unreasonable Inputs
	Assert(x1<x2, "ZoomBox: x1[" + String(x1) + "] point larger then x2 Point[" + String(x2) + "]")
	Assert(y1<y2, "ZoomBox: y1[" + String(y1) + "] point larger then y2 Point[" + String(y2) + "]")
	Assert(IgnoreAR>0 || BoxAR == FinalAR, "ZoomBox: Box Aspect Ratio [" + String(BoxAR) + "] does not equal clip output Aspect Ratio [" + string(FinalAR) + "]")
	
	#Pad clip so resizer interpolates from border when zooming out. 64 for spline64
	#Conditional Borders... only add if it's going to be used.
	borderSize = 64
	borderLeft   = x1 < 0 ? borderSize : 0
	borderTop    = y1 < 0 ? borderSize : 0
	borderRight  = x2 > c.width() ? borderSize : 0
	borderBottom = y2 > c.height() ? borderSize : 0
	c = c.AddBorders(borderLeft,borderTop,borderRight,borderBottom,color)
	
	#Do it
	c = Eval(ResizeMethod + "(c, " + String(Round(width)) + ", " + String(Round(height)) + ", src_left=" + String(x1+borderLeft) + ", src_top=" + String(y1+borderTop) + ", src_width=" + String(x2-x1) + ", src_height=" + String(y2-y1) + ")")	
	
	c
	Subtitle(String(x1) + ", " + String(y1) + "    " + String(x2) + ", " + String(y2) + "    BoxAR " + String(BoxAR) + "  " + String())
	Subtitle(SubString, y=100)
}







function SplitScreener(int Width, int Height, int Border, clip A, clip B, clip C, clip D, int "ZoomToFill", string "ResizeMethod", bool "AudioMix")
{
	#Set Defaults
	ResizeMethod = Default(ResizeMethod, "BilinearResize")
	AudioMix = Default(AudioMix, true)
	ZoomToFill = Default(ZoomToFill, -1)
	
	#Check Inputs
	Assert(ZoomToFill==1 || ZoomToFill==-1, "ZoomToFill must be 1 or -1. Input of " + String(ZoomToFill) + " doesn't work")
	
	
	#Set Borders
	BorderH = Border
	BorderW = Border
	
	#Set Width and Height of individual clips
	NewW = Round(float(Width)/2.0 - float(BorderW)*1.5)
	NewH = Round(float(Height)/2.0 - float(BorderH)*1.5)
	NewAR = Float(NewW)/Float(NewH)
	OutAR = Float(Width)/Float(Height)
	
	#Process Video
	A = A.ZoomBoxer(NewW, NewH, ResizeMethod, Float(A.width())/Float(A.height())*(NewAR/OutAR), ZoomToFill*(9))
	A = A.AddBorders(BorderW, BorderH, 0, 0)
	B = B.ZoomBoxer(NewW, NewH, ResizeMethod, Float(B.width())/Float(B.height())*(NewAR/OutAR), ZoomToFill*(7))
	B = B.AddBorders(BorderW, BorderH, 0, 0)
	C = C.ZoomBoxer(NewW, NewH, ResizeMethod, Float(C.width())/Float(C.height())*(NewAR/OutAR), ZoomToFill*(3))
	C = C.AddBorders(BorderW, BorderH, 0, 0)
	D = D.ZoomBoxer(NewW, NewH, ResizeMethod, Float(D.width())/Float(D.height())*(NewAR/OutAR), ZoomToFill*(1))
	D = D.AddBorders(BorderW, BorderH, 0, 0)
	
	#Merge Clips
	X = StackHorizontal(A, B).AddBorders(0,0,BorderW,0)
	Y = StackHorizontal(C, D).AddBorders(0,0,BorderW,0)
	StackVertical(X, Y).AddBorders(0,0,0,BorderH).KillAudio()
	
	#Fix Audio
	LongestClip = Int(Max(Framecount(A), Framecount(B), Framecount(C), Framecount(D)))
	A = (Framecount(A) <> LongestClip) ? A ++ BlankClip(A, LongestClip-Framecount(A)) : A
	B = (Framecount(B) <> LongestClip) ? B ++ BlankClip(B, LongestClip-Framecount(B)) : B
	C = (Framecount(C) <> LongestClip) ? C ++ BlankClip(C, LongestClip-Framecount(C)) : C
	D = (Framecount(D) <> LongestClip) ? D ++ BlankClip(D, LongestClip-Framecount(D)) : D
	
	#Mix Audio
	Sound = (AudioMix) ? MergeChannels(MixAudio(ConvertToMono(A).Amplify(0.49), ConvertToMono(C).Amplify(0.49)), MixAudio(ConvertToMono(B).Amplify(0.49), ConvertToMono(D).Amplify(0.49))):
		\ MergeChannels(GetLeftChannel(A), GetRightChannel(A), GetLeftChannel(B), GetRightChannel(B), GetLeftChannel(C), GetRightChannel(C), GetLeftChannel(D), GetRightChannel(D))
	AudioDub(last, Sound)
}
Using example pic from 2nd post

Last edited by mikeytown2; 28th May 2008 at 01:07.
mikeytown2 is offline   Reply With Quote
Old 28th May 2008, 08:50   #59  |  Link
mikeytown2
Resize Abuser
 
mikeytown2's Avatar
 
Join Date: Apr 2005
Location: Seattle, WA
Posts: 623
I got this really close to being done... zoomFactor works correctly at align=5,6,8,9. when using zoomfactor it will not "cross over" on the zoom-in anymore; any positive number you give it, it should be able to use.

Code:
A = ColorBars().Crop(10, 20, -30, -400).ConvertToYV12()
B = ColorBars().invert().FlipHorizontal().Crop(10, 20, -300, -40).ConvertToYV12()
C = ColorBars().FlipVertical().Crop(10, 200, -30, -40).ConvertToYV12()
D = ColorBars().invert().FlipVertical().FlipHorizontal().Crop(100, 20, -30, -40).ConvertToYV12()
E = ImageReader("testp2cz4.png",0,0)
E = E.ConvertToYV12().AssumeFPS("ntsc_video")
Global W = 640
Global H = 480
Global DAR = 0 #16.0/9.0
Global Resize = "BilinearResize"

SplitScreener(W, H, 8, A, B, C, D, ZoomToFill=1).Trim(0,-1).KillAudio()
last + SplitScreener(W, H, 8, A, B, C, D, ZoomToFill=-1).Trim(0,-1).KillAudio()

last + TestC(E)


#Try different image, it fails...
E = ImageReader("traingr4.jpg",0,0)
E = E.ConvertToYV12().AssumeFPS("ntsc_video")
Global DAR = 16.0/9.0


last + TestC(E)

Return Last




Function TestC(Clip E)
{
	TestA(E,-1)
	last + TestA(E,-2)
	last + TestA(E,-3)
	last + TestA(E,-4)
	last + TestA(E,-5)
	last + TestA(E,5)
	last + TestA(E,-6)
	last + TestA(E,-7)
	last + TestA(E,-8)
	last + TestA(E,-9)

	last + TestB(E, 25)
	last + TestB(E, 50)
	last + TestB(E, 75)
}


Function TestA(clip E, int al)
{
	E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=100, panX=0, panY=0)
	last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=75, panX=0, panY=0)
	last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=50, panX=0, panY=0)
	last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=25, panX=0, panY=0)
	last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=10, panX=0, panY=0)
	last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=5, panX=0, panY=0)
	last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=2, panX=0, panY=0)
	
	last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=75, panX=0, panY=0)
	last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=100, panX=0, panY=0)
	last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=200, panX=0, panY=0)
	last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=400, panX=0, panY=0)
	last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=600, panX=0, panY=0)
	last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=800, panX=0, panY=0)
	last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=2000, panX=0, panY=0)
	last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=20000, panX=0, panY=0)
}

Function TestB(clip E, int zf)
{
	E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-5, zoomFactor=zf, panX=0, panY=0)
	last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=zf, panX=0, panY=0)
	last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-3, zoomFactor=zf, panX=0, panY=0)
	last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-7, zoomFactor=zf, panX=0, panY=0)
	last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-9, zoomFactor=zf, panX=0, panY=0)
	last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-2, zoomFactor=zf, panX=0, panY=0)
	last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-4, zoomFactor=zf, panX=0, panY=0)
	last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-6, zoomFactor=zf, panX=0, panY=0)
	last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-8, zoomFactor=zf, panX=0, panY=0)

}





Function ZoomBoxer(clip c, int "width", int "height", string "ResizeMethod", float "DisplayAR", int "Align", float "zoomFactor", float "panX", float "panY", int "color", int "IgnoreAR")
{
	#set defaults
	ResizeMethod = Default(ResizeMethod, "BilinearResize")
	IgnoreAR = Default(IgnoreAR, 1)
	color = Default(color, $000000)
	width = Default(width, c.width())
	height = Default(height, c.height())
	Align = Default(Align, 0)
	zoomFactor = Default(zoomFactor, 100.0)
	zoomFactor = (zoomFactor/100.0)
	#zoomFactor = -(Log(zoomFactor*0.01)/Log(4))
	panX = Default(panX, 0)
	panY = Default(panY, 0)
	
	SourceAR = float(c.width())/float(c.height())
	FinalAR = float(width)/float(height)
	DisplayAR = Default(DisplayAR, Float(c.width())/Float(c.height()))
	DisplayAR = DisplayAR == 0 ? Float(c.width())/Float(c.height()) : DisplayAR
	
	#If Align=5 or -5 then center clip. -5: Add borders. 5: Crop.
	#Display Aspect Ratio = Final Output Ratio. No Change, Show All Pixels
	#Display Aspect Ratio > Final Output Ratio. Add Height or Crop Width 
	#Display Aspect Ratio < Final Output Ratio. Add Width or Crop Height 
	EvalString = 
	\   Align<>0 && DisplayAR==FinalAR ?
	\ "x1=0" + "
	   x2="  + String(c.width()) + "
	   y1=0" + "
	   y2="  + String(c.height()) + "" 
	   
	   
	\ : (Align==-5 || Align==-4 || Align==-6) && DisplayAR>FinalAR ?
	\ "y1=" + String(0 - ((height*DisplayAR-width)/2.0)*(c.height()/Float(width))) + "
	   y2=" + String(c.height() + ((height*DisplayAR-width)/2.0)*(c.height()/Float(width))) + "
	   x1=0" + "
	   x2=" + String(c.width())
	\ : (Align==5 || Align==2 || Align==8) && DisplayAR>FinalAR ?
	\ "x1=" + String(0 + ((height-width/DisplayAR)/2.0)*(c.width()/Float(height))) + "
	   x2=" + String(c.width() - ((height-width/DisplayAR)/2.0)*(c.width()/Float(height))) + "
	   y1=0" + "
	   y2=" + String(c.height()) + "" 
	\ : (Align==-5 || Align==-2 || Align==-8)  && DisplayAR<FinalAR ?
	\ "x1=" + String(0 - ((width/DisplayAR-height)/2.0)*(c.width()/Float(height))) + "
	   x2=" + String(c.width() + ((width/DisplayAR-height)/2.0)*(c.width()/Float(height))) + "
	   y1=0" + "
	   y2=" + String(c.height()) + ""
	\ : (Align==5 || Align==4 || Align==6)  && DisplayAR<FinalAR  ?
	\ "y1=" + String(0 + ((width-height*DisplayAR)/2.0)*(c.height()/Float(width))) + "
	   y2=" + String(c.height() - ((width-height*DisplayAR)/2.0)*(c.height()/Float(width))) + "
	   x1=0" + "
	   x2=" + String(c.width()) 


	\ : (Align==-1 || Align==-2 || Align==-3) && DisplayAR>FinalAR ?
	\ "y1=" + String(0) + "
	   y2=" + String(c.height() + ((height*DisplayAR-width)/1.0)*(c.height()/Float(width))) + "
	   x1=0" + "
	   x2=" + String(c.width())
	\ : (Align==-1 || Align==-4 || Align==-7)  && DisplayAR<FinalAR ?
	\ "x1=" + String(0) + "
	   x2=" + String(c.width() + ((width/DisplayAR-height)/1.0)*(c.width()/Float(height))) + "
	   y1=0" + "
	   y2=" + String(c.height()) + ""
	\ : (Align==-9 || Align==-8 || Align==-7) && DisplayAR>FinalAR ?
	\ "y1=" + String(0 - ((height*DisplayAR-width)/1.0)*(c.height()/Float(width))) + "
	   y2=" + String(c.height()) + "
	   x1=0" + "
	   x2=" + String(c.width())
	\ : (Align==-9 || Align==-6 || Align==-3)  && DisplayAR<FinalAR ?
	\ "x1=" + String(0 - ((width/DisplayAR-height)/1.0)*(c.width()/Float(height))) + "
	   x2=" + String(c.width()) + "
	   y1=0" + "
	   y2=" + String(c.height()) + ""


	\ : (Align==2 || Align==1 || Align==3) && DisplayAR<FinalAR  ?
	\ "y1=" + String(0) + "
	   y2=" + String(c.height() - ((width-height*DisplayAR)/1.0)*(c.height()/Float(width))) + "
	   x1=0" + "
	   x2=" + String(c.width()) 
	\ : (Align==8 || Align==7 || Align==9) && DisplayAR<FinalAR  ?
	\ "y1=" + String(0 + ((width-height*DisplayAR)/1.0)*(c.height()/Float(width))) + "
	   y2=" + String(c.height()) + "
	   x1=0" + "
	   x2=" + String(c.width()) 
	\ : (Align==4 || Align==1 || Align==7) && DisplayAR>FinalAR ?
	\ "x1=" + String(0) + "
	   x2=" + String(c.width() - ((height-width/DisplayAR)/1.0)*(c.width()/Float(height))) + "
	   y1=0" + "
	   y2=" + String(c.height()) + "" 
	\ : (Align==6 || Align==3 || Align==9) && DisplayAR>FinalAR ?
	\ "x1=" + String(0 + ((height-width/DisplayAR)/1.0)*(c.width()/Float(height))) + "
	   x2=" + String(c.width()) + "
	   y1=0" + "
	   y2=" + String(c.height()) + "" 



	\ : ""
	Eval(EvalString)
	
	#Take Crop Like Input
	x2 = x2<=x1 && x2 < 0 ? c.width() + x2 : x2
	y2 = y2<=y1 && y2 < 0 ? c.height() + y2 : y2
	
	#Check if x2 or y2 needs to be calculated
	Assert( ((x2==x1) && (y2==y1))==False, "x2 [" + String(x2) + "] or y2 [" + String(y2) + "] needs a value that is different from x1 [" + String(x1) + "] or y1 [" + String(y1) + "]")
	y2 = (y2==y1) ? (((x2-x1)/FinalAR)/(SourceAR/DisplayAR) + y1) : y2
	x2 = (x2==x1) ? (((y2-y1)*FinalAR)*(SourceAR/DisplayAR) + x1) : x2
	
	SubString = "Align=" + String(Align) + "  zoomFactor=" + String(zoomFactor*100) + "  panX=" + String(panX) + "  panY=" + String(panY)
	
	#Calc Pan Factor
	x1 = x1+panX
	y1 = y1+panY
	x2 = x2+panX
	y2 = y2+panY
	
	#Calc Zoom Factor
	BoxAR = Float(x2-x1)/Float(y2-y1)

	CenterX = (x2-x1)/2.0
	CenterY = (y2-y1)/2.0
	
	CenterY = (Align<0 && DisplayAR>FinalAR)? CenterY*(FinalAR/DisplayAR): (Align>0 && DisplayAR<FinalAR)? CenterY*(FinalAR/DisplayAR): CenterY 
	CenterX = (Align>0 && DisplayAR>FinalAR)? CenterX/(FinalAR/DisplayAR): (Align<0 && DisplayAR<FinalAR)? CenterX/(FinalAR/DisplayAR): CenterX
	
	Align = abs(Align)
	sY = " CenterY: " + String(CenterY) + "  y2: " + String(y2) + "  y1: " + String(y1)
	sX = " CenterX: " + String(CenterX) + "  x2: " + String(x2) + "  x1: " + String(x1)
	x1 = (Align==0 || Align==5 || Align==2 || Align==8) && zoomFactor<>1 ? CenterX-((CenterX-x1)/(zoomFactor)) : (Align==3 || Align==6 || Align==9) && zoomFactor<>1 ? CenterX*2.0-((CenterX*2.0-x1)/zoomFactor) : x1
	y1 = (Align==0 || Align==5 || Align==4 || Align==6) && zoomFactor<>1 ? CenterY-((CenterY-y1)/(zoomFactor)) : (Align==7 || Align==8 || Align==9) && zoomFactor<>1 ? CenterY*2.0-((CenterY*2.0-y1)/zoomFactor) : y1
	x2 = (Align==0 || Align==5 || Align==2 || Align==8) && zoomFactor<>1 ? CenterX+((x2-CenterX)/(zoomFactor)) : (Align==7 || Align==4 || Align==1) && zoomFactor<>1 ? CenterX+((x2-CenterX)/zoomFactor) : x2
	y2 = (Align==0 || Align==5 || Align==4 || Align==6) && zoomFactor<>1 ? CenterY+((y2-CenterY)/(zoomFactor)) : (Align==3 || Align==2 || Align==1) && zoomFactor<>1 ? CenterY+((y2-CenterY)/zoomFactor) : y2

	
	
	BoxAR = Float(x2-x1)/Float(y2-y1)
	#Check For Any Unreasonable Inputs
	Assert(x1<x2, "ZoomBox: x1[" + String(x1) + "] point larger then x2 Point[" + String(x2) + "]")
	Assert(y1<y2, "ZoomBox: y1[" + String(y1) + "] point larger then y2 Point[" + String(y2) + "]")
	Assert(IgnoreAR>0 || BoxAR == FinalAR, "ZoomBox: Box Aspect Ratio [" + String(BoxAR) + "] does not equal clip output Aspect Ratio [" + string(FinalAR) + "]")
	
	#Pad clip so resizer interpolates from border when zooming out. 64 for spline64
	#Conditional Borders... only add if it's going to be used.
	borderSize = 64
	borderLeft   = x1 < 0 ? borderSize : 0
	borderTop    = y1 < 0 ? borderSize : 0
	borderRight  = x2 > c.width() ? borderSize : 0
	borderBottom = y2 > c.height() ? borderSize : 0
	c = c.AddBorders(borderLeft,borderTop,borderRight,borderBottom,color)
	
	#Do it
	c = Eval(ResizeMethod + "(c, " + String(Round(width)) + ", " + String(Round(height)) + ", src_left=" + String(x1+borderLeft) + ", src_top=" + String(y1+borderTop) + ", src_width=" + String(x2-x1) + ", src_height=" + String(y2-y1) + ")")	
	
	c
	Subtitle(String(x1) + ", " + String(y1) + "    " + String(x2) + ", " + String(y2) + "    BoxAR " + String(BoxAR) + "  " + String())
	Subtitle(SubString, y=100)
	Subtitle(sY, y=140)
	Subtitle(sX, y=160)
}







function SplitScreener(int Width, int Height, int Border, clip A, clip B, clip C, clip D, int "ZoomToFill", string "ResizeMethod", bool "AudioMix")
{
	#Set Defaults
	ResizeMethod = Default(ResizeMethod, "BilinearResize")
	AudioMix = Default(AudioMix, true)
	ZoomToFill = Default(ZoomToFill, -1)
	
	#Check Inputs
	Assert(ZoomToFill==1 || ZoomToFill==-1, "ZoomToFill must be 1 or -1. Input of " + String(ZoomToFill) + " doesn't work")
	
	
	#Set Borders
	BorderH = Border
	BorderW = Border
	
	#Set Width and Height of individual clips
	NewW = Round(float(Width)/2.0 - float(BorderW)*1.5)
	NewH = Round(float(Height)/2.0 - float(BorderH)*1.5)
	NewAR = Float(NewW)/Float(NewH)
	OutAR = Float(Width)/Float(Height)
	
	#Process Video
	A = A.ZoomBoxer(NewW, NewH, ResizeMethod, Float(A.width())/Float(A.height())*(NewAR/OutAR), ZoomToFill*(9))
	A = A.AddBorders(BorderW, BorderH, 0, 0)
	B = B.ZoomBoxer(NewW, NewH, ResizeMethod, Float(B.width())/Float(B.height())*(NewAR/OutAR), ZoomToFill*(7))
	B = B.AddBorders(BorderW, BorderH, 0, 0)
	C = C.ZoomBoxer(NewW, NewH, ResizeMethod, Float(C.width())/Float(C.height())*(NewAR/OutAR), ZoomToFill*(3))
	C = C.AddBorders(BorderW, BorderH, 0, 0)
	D = D.ZoomBoxer(NewW, NewH, ResizeMethod, Float(D.width())/Float(D.height())*(NewAR/OutAR), ZoomToFill*(1))
	D = D.AddBorders(BorderW, BorderH, 0, 0)
	
	#Merge Clips
	X = StackHorizontal(A, B).AddBorders(0,0,BorderW,0)
	Y = StackHorizontal(C, D).AddBorders(0,0,BorderW,0)
	StackVertical(X, Y).AddBorders(0,0,0,BorderH).KillAudio()
	
	#Fix Audio
	LongestClip = Int(Max(Framecount(A), Framecount(B), Framecount(C), Framecount(D)))
	A = (Framecount(A) <> LongestClip) ? A ++ BlankClip(A, LongestClip-Framecount(A)) : A
	B = (Framecount(B) <> LongestClip) ? B ++ BlankClip(B, LongestClip-Framecount(B)) : B
	C = (Framecount(C) <> LongestClip) ? C ++ BlankClip(C, LongestClip-Framecount(C)) : C
	D = (Framecount(D) <> LongestClip) ? D ++ BlankClip(D, LongestClip-Framecount(D)) : D
	
	#Mix Audio
	Sound = (AudioMix) ? MergeChannels(MixAudio(ConvertToMono(A).Amplify(0.49), ConvertToMono(C).Amplify(0.49)), MixAudio(ConvertToMono(B).Amplify(0.49), ConvertToMono(D).Amplify(0.49))):
		\ MergeChannels(GetLeftChannel(A), GetRightChannel(A), GetLeftChannel(B), GetRightChannel(B), GetLeftChannel(C), GetRightChannel(C), GetLeftChannel(D), GetRightChannel(D))
	AudioDub(last, Sound)
}
at the end of the zoom factor code where x2 = _ and y2 = _ is where i can't figure it out. the *2.0 was what i call lucky guessing right above where x1=, y1=. That code is what makes 6,8,9 work. Once again i'm asking for help here on x2,y2... Most of the zoomfactor code was brute force/trial and error, so hopefully it works in all cases.
mikeytown2 is offline   Reply With Quote
Old 28th May 2008, 19:01   #60  |  Link
Gavino
Avisynth language lover
 
Join Date: Dec 2007
Location: Spain
Posts: 3,431
Quote:
Originally Posted by mikeytown2 View Post
Most of the zoomfactor code was brute force/trial and error, so hopefully it works in all cases.
LOL - In my experience, programming by trial and error, and hoping for the best, are unlikely to give correct results (indeed, where I used to work, it would get you fired). And it's hard to say if a program is 'correct' without a specification of its intended behaviour, so let's return to that.

I said I was confused about the details of your zoom feature, and I now realise why. In my view, there are two different sorts of zooming required:
  • what we might call 'stretch-to-fit', where the clip is expanded to fit the width and/or height of the output frame, depending on the alignment and relative dimensions;
  • explicitly requested scaling by x% (where 100% means clip remains at its original resolution).

It seems that your current scheme mixes these up together (and in a hard-to-understand way), when for me they should be separate.

Here's an example to help explain what I mean. Let's say we have an input clip 640x480 and we want to select the top left quadrant at its original resolution. I would like to say
Code:
ZoomBoxer(320, 240, align=1, zoomFactor=100)
but this actually results in showing the complete clip at half its original resolution, because the zoom factor works on top of the stretch-to-fit resizing, which cannot be switched off.
Ah, perhaps I can just increase the zoomFactor (to 200, say) to compensate? In fact, I found no matter how much I increased it (even with ridiculous values like 1000000) the clip never reached the desired resolution!

So it's very difficult (and in the above example, impossible) for a user to figure out what value of zoomFactor to use to achieve the effect he/she desires.

It might be that what I'm seeing is due to bugs in the implementation rather than something you intended, but in any case, to my mind the following scheme would be more useful:
  • use zoomFactor=0 to mean 'stretch-to-fit', equivalent to zoomFactor=100 in current scheme;
  • zoomFactor > 0 to mean scale by exactly that (%age) factor, regardless of clip dimensions and AR, the clip then being aligned appropriately in the output frame and cropped or padded if necessary. In this mode, negative align values make no sense and would be rejected.

What do you (and others) think?

Last edited by Gavino; 28th May 2008 at 19:16.
Gavino is offline   Reply With Quote
Reply

Tags
anamorphic, crop, dar, pan and scan, resize

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +1. The time now is 08:59.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.