Log in

View Full Version : KenBurnsEffect() - Zoom, Pan & Rotate Clip. New Version Released May 27th, 2009!


Pages : [1] 2 3

mikeytown2
12th March 2008, 10:28
http://en.wikipedia.org/wiki/Ken_Burns_Effect

# KenBurnsEffect() - May 27th, 2009
# Given a clip, zooms and pans clip with the Ken Burns Effect.
#
# Requirements:
# zoom.dll
# http://forum.doom9.org/showthread.php?t=49429 -Original zoom thread
# http://avisynth.org/warpenterprises/files/zoom_25_dll_20050122.zip -Direct Download
# CalcBox(), ZoomBoxIt()
# http://forum.doom9.org/showthread.php?p=1111789#post1111789
#
# Inputs:
# clip c: input clip, needs to be RGB32() if useZoomBox = 0 or 1
# Optional Parameters:
## <Starting Position> ##
# Mode 2 - Starting Alignment:
# int startAlign: -9 to +9 (0=Do not use Align). Positive values - fit with no black borders, may crop clip. Negative values - fit with black borders, may letterbox clip.
# 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.
#
# Mode 1 - Starting Box:
# float startX1: upper left x cord
# float startY1: upper left y cord
# float startX2: lower right x cord
# float startY2: lower right y cord
# 3 or 4 out of 4 points must be defined when using Mode 1
# when omitting a single point, it will calculate the missing value, with the Aspect Ratio in mind.
#
# float startZoomFactor: 100 = 100%, ect...
# Negative values is the zoom of the pixels, positive values is the zoom of the frame.
# When converting AR, this isn't perfect.
# float startPanX: shift the clip x pixels. Value in source pixels. - left, + right
# float startPanY: shift the clip x pixels. Value in source pixels. - up, + down
# float startAngle: Rotate clip so many degrees. Positive is Clockwise.
## </Starting Position> ##
#
## <Ending Position> ##
# Mode 2 - Ending Alignment:
# int endAlign: -9 to +9 (0=Do not use Align). Positive values - fit with no black borders, may crop clip. Negative values - fit with black borders, may letterbox clip.
# 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.
#
# Mode 1 - Ending Box:
# float endX1: upper left x cord
# float endY1: upper left y cord
# float endX2: lower right x cord
# float endY2: lower right y cord
# 3 or 4 out of 4 points must be defined when using Mode 1
# when omitting a single point, it will calculate the missing value, with the Aspect Ratio in mind.
#
# float endZoomFactor: 100 = 100%, ect...
# Negative values is the zoom of the pixels, positive values is the zoom of the frame.
# When converting AR, this isn't perfect.
# float endPanX: shift the clip x pixels. Value in source pixels. - left, + right
# float endPanY: shift the clip x pixels. Value in source pixels. - up, + down
# float endAngle: Rotate clip so many degrees. Positive is Clockwise.
## </Ending Position> ##
#
# int width: Output Width
# int height: Output Height
# int startFrame: starting frame of pan and zoom
# int endFrame: ending frame of pan and zoom
# bool KeepState: If using start/end Frame, it keeps the clip at the start & end zoom level. Default = true
# string ResizeMethod: name of resize function. Default = BilinearResize
# float SourceDAR: Display Aspect Ratio of the Source. If 0 then it uses the source aspect ratio.
# float TargetDAR: Display Aspect Ratio of the Target. Useful for DVD's. If 0 then it uses the source aspect ratio.
#
# int useZoomBox: 0 - Never, 1 - for static parts, 2 - for everything. default 2
# float Speed: 1 is "normal". For high quality set to something like 0.25. For speed set to 5+. Relevant if useZoomBox=0 or 1.
# int cubic: Type of zoom, pan & rotate.
# int cubicX: Type of pan in the x direction.
# int cubicY: Type of pan in the y direction.
# int cubicA: Type of rotation.
# int cubicZ: Type of zoom.
# int color: Color of letterbox border. Default: $000000 (Black). Irrelevant if useZoomBox=0 or 1.
#
#
# Notes:
# Clip should be deinterlaced for best visual quality.
# Aspect ratio for output and box(x1,y1,x2,y2) should be the same, unless you want to distort the clip.
# The aspect ratio for the 2 boxes as well as the output should to be the same.
# Default behavior is to center clip by adding borders (Align=-5).
# If you specify Align (Mode 2) and x1,y1,x2,y2 (Mode 1), Mode 1 will be used and the align will control the position of the zoomFactor.
# Mode 1 (x1,y1,x2,y2) can take values from a crop operation. x2 and y2 must be negative though; so if x2 or y2 equals 0, replace 0 with -0.00001.

function KenBurnsEffect(clip c,
\ int "startAlign", float "startX1", float "startY1", float "startX2", float "startY2", float "startZoomFactor", float "startPanX", float "startPanY", float "startAngle",
\ int "endAlign", float "endX1", float "endY1", float "endX2", float "endY2", float "endZoomFactor", float "endPanX", float "endPanY", float "endAngle",
\ int "width", int "height", int "StartFrame", int "EndFrame", bool "KeepState", string "ResizeMethod", float "SourcePAR", float "SourceDAR", float "TargetPAR", float "TargetDAR",
\ int "useZoomBox", float "speed", int "cubic", int "cubicX", int "cubicY", int "cubicA", int "cubicZ", int "color")

{
#Set Defaults
startAlign = Default(startAlign, -5)
endAlign = Default(endAlign, -5)
startZoomFactor = Default(startZoomFactor, 100.0)
endZoomFactor = Default(endZoomFactor, 100.0)
startPanX = Default(startPanX, 0.0)
startPanY = Default(startPanY, 0.0)
endPanX = Default(endPanX, 0.0)
endPanY = Default(endPanY, 0.0)
startAngle = Default(startAngle, 0.0)
endAngle = Default(endAngle, 0.0)
width = Default(width, c.width())
height = Default(height, c.height())
length = c.Framecount()-1
StartFrame = Default(StartFrame, 0)
EndFrame = Default(EndFrame, length)
KeepState = Default(KeepState, True)
ResizeMethod = Default(ResizeMethod, "BilinearResize")
SourceAR = float(c.width())/float(c.height())
TargetAR = float(width)/float(height)
useZoomBox = Default(useZoomBox, 2)
speed = Default(speed, 1)
cubic = Default(cubic, 0)
cubicX = Default(cubicX, cubic)
cubicY = Default(cubicY, cubic)
cubicZ = Default(cubicZ, cubic)
cubicA = Default(cubicA, cubic)
color = Default(color, $000000)

#Calculate Defaults
modzoom = Max(Float(c.width())/Float(width),Float(c.height())/Float(height))
startZoomFactor = startZoomFactor<0 ? (abs(startZoomFactor)/100.0)*modzoom : (abs(startZoomFactor)/100.0)
endZoomFactor = endZoomFactor<0 ? (abs(endZoomFactor)/100.0)*modzoom : (abs(endZoomFactor)/100.0)

#Check For Any Unreasonable Inputs
Assert(startZoomFactor<>0, "KenBurnsEffect: startZoomFactor can not be zero.")
Assert(endZoomFactor<>0, "KenBurnsEffect: endZoomFactor can not be zero.")
Assert((Defined(startX1) && Defined(startY1) && (Defined(startX2) || Defined(startY2))) || !(Defined(startX1) && Defined(startY1) && Defined(startX2) && Defined(startY2)), "KenBurnsEffect: when using Mode 1, you must define startX1,startY1, startX2 and/or startY2")
Assert((Defined(endX1) && Defined(endY1) && (Defined(endX2) || Defined(endY2))) || !(Defined(endX1) && Defined(endY1) && Defined(endX2) && Defined(endY2)), "KenBurnsEffect: when using Mode 1, you must define endX1,endY1, endX2 and/or endY2")
Assert(startAlign<9 || startAlign>-9, "KenBurnsEffect: startAlign [" + String(startAlign) + "] should be between -9 and 9.")
Assert(endAlign<9 || endAlign>-9, "KenBurnsEffect: endAlign [" + String(endAlign) + "] should be between -9 and 9.")
Assert(IsRGB32(c) || useZoomBox==2, "KenBurnsEffect: Clip Needs To Be RGB32. Use ConvertToRGB32() or set useZoomBox=2")
Assert(!((cubic>0 || cubicX>0 || cubicY>0 || cubicZ>0 || cubicA>0) && useZoomBox==2), "KenBurnsEffect: Can not use the Cubic option when useZoomBox=2. Set useZoomBox to 0 or 1 or don't use cubic.")
Assert(endFrame-startFrame<=length, "KenBurnsEffect: Transition length[" + String(endFrame-startFrame) + "] greater then clip lenght[" + String(length) + "]")
Assert(startFrame<endFrame, "KenBurnsEffect: Starting Frame[" + String(startFrame) + "] greater then Ending Frame[" + String(endFrame) + "]")
#Assert(useZoomBox == 0 && !(startAngle == 0), "KenBurnsEffect: You must set useZoomBox=0, if using startAngle [" + String(startAngle) + "]")
#Assert(useZoomBox == 0 && !(endAngle == 0), "KenBurnsEffect: You must set useZoomBox=0, if using endAngle [" + String(endAngle) + "]")


#Do Some Magic
Eval (CalcBox(c, 2, width, height, TargetAR, SourceAR, startZoomFactor, startPanX, startPanY, startAlign, startX1, startY1, startX2, startY2, SourcePAR, SourceDAR, TargetPAR, TargetDAR))
Eval (CalcBox(c, 3, width, height, TargetAR, SourceAR, endZoomFactor, endPanX, endPanY, endAlign, endX1, endY1, endX2, endY2, SourcePAR, SourceDAR, TargetPAR, TargetDAR))


#Check For Any Unreasonable Inputs
Assert(startX1<startX2, "KenBurnsEffect: Start X1[" + String(startX1) + "] point larger then Start X2 Point[" + String(startX2) + "]")
Assert(startY1<startY2, "KenBurnsEffect: Start Y1[" + String(startY1) + "] point larger then Start Y2 Point[" + String(startY2) + "]")
Assert(endX1<endX2, "KenBurnsEffect: End X1[" + String(endX1) + "] point larger then End X2 Point[" + String(endX2) + "]")
Assert(endY1<endY2, "KenBurnsEffect: End Y1[" + String(endY1) + "] point larger then End Y2 Point[" + String(endY2) + "]")


#non pan frames
start = useZoomBox>0 && startFrame>0 ? KeepState ? c.Trim(0, -startFrame).ZoomBoxIt(width, height, ResizeMethod, startX1, startY1, startX2, startY2, color) : c.Trim(0, -startFrame) : nop()
end = useZoomBox>0 && endFrame<length ? KeepState ? c.Trim(endFrame+1, 0).ZoomBoxIt(width, height, ResizeMethod, endX1, endY1, endX2, endY2, color) : c.Trim(endFrame+1, 0) : nop()
#zoom and pan frames
cAlt = c.Trim(startFrame, endFrame)
cAlt = useZoomBox==2 ? Animate(0, cAlt.framecount()-1, "ZoomBoxIt", cAlt, width, height, ResizeMethod, Float(startX1),Float(startY1), Float(startX2),Float(startY2), color, cAlt, width, height, ResizeMethod, Float(endX1),Float(endY1), Float(endX2),Float(endY2), color) :nop()


#add in static frames
cAlt = useZoomBox==2 && startFrame>0 ? start + cAlt : cAlt
cAlt = useZoomBox==2 && endFrame<length ? cAlt + end : cAlt

#get center of start rectangle from first box
startCenterX = startX1+((startX2-startX1)/2.0)-0.5
startCenterY = startY1+((startY2-startY1)/2.0)-0.5

#get center of end rectangle from second box
endCenterX = endX1+((endX2-endX1)/2.0)-0.5
endCenterY = endY1+((endY2-endY1)/2.0)-0.5

#Speed Logic pt 1 - Resize clip
width = Float(width)/speed
height = Float(height)/speed

#get starting zoom factor from first box
startZoomFactorX = width/float(startX2-startX1)
startZoomFactorY = height/float(startY2-startY1)

#get ending zoom factor from second box
endZoomFactorX = width/float(endX2-endX1)
endZoomFactorY = height/float(endY2-endY1)


#Pan starting and ending x point
srcxSE = SplineCalc(c, cubicX, startFrame, startCenterX, endFrame, endCenterX)

#Pan starting and ending y point
srcySE = SplineCalc(c, cubicY, startFrame, startCenterY, endFrame, endCenterY)

#Zoom X
factor_x_SE = SplineCalc(c, cubicZ, startFrame, startZoomFactorX, endFrame, endZoomFactorX)

#Zoom Y
factor_y_SE = SplineCalc(c, cubicZ, startFrame, startZoomFactorY, endFrame, endZoomFactorY)

#Rotation
angleSE = SplineCalc(c, cubicA, startFrame, startAngle, endFrame, endAngle)


#non pan frames
start = useZoomBox==0 ? c.Zoom(srcx=String(startCenterX), srcy=String(startCenterY), factorx=String(startZoomFactorX), factory=String(startZoomFactorY), width=Round(width), height=Round(height), angle=String(startAngle)).Trim(0, -startFrame) : start
end = useZoomBox==0 ? c.Zoom(srcx=String(endCenterX), srcy=String(endCenterY), factorx=String(endZoomFactorX), factory=String(endZoomFactorY), width=Round(width), height=Round(height), angle=String(endAngle)).Trim(endFrame+1, 0) : end

#Do the zoom/pan
c = useZoomBox<2 ? c.Zoom(srcx=srcxSE, srcy=srcySE, factorx=factor_x_SE, factory=factor_y_SE, width=Round(width), height=Round(height), angle=angleSE).Trim(startFrame, endFrame) : nop()

#speed Logic pt 2 - Scale back up or down depending on speed set
c = useZoomBox==1 ? Eval(ResizeMethod + "(c, " + String(Round(width*speed)) + ", " + String(Round(height*speed)) + ")" ) : c

#Add in static frames
c = useZoomBox<2 && startFrame>0 ? start + c : c
c = useZoomBox<2 && endFrame<length ? c + end : c

#speed Logic pt 2 - Scale back up or down depending on speed set
c = useZoomBox==0 ? Eval(ResizeMethod + "(c, " + String(Round(width*speed)) + ", " + String(Round(height*speed)) + ")" ) : c
useZoomBox==2 ? cAlt :c
}


KenBurnsEffect needs zoom.dll (http://avisynth.org/warpenterprises/files/zoom_25_dll_20050122.zip) and ZoomBoxIt(), CalcBox() (http://forum.doom9.org/showthread.php?p=1111789#post1111789) (next post).
Original zoom.dll Thread http://forum.doom9.org/showthread.php?t=49429

Details in Next Post (scroll down)

mikeytown2
13th March 2008, 06:33
ZoomBox(), ZoomBoxIt(), CalcBox(), SplineCalc()


# ZoomBox() - June 12st, 2008
# Put a "box" around a clip. Box can be used to zoom in or out. Accepts Any Colorspace. Can correct for DAR (Display Aspect Ratio).
#
#
# Inputs
# clip c: Accepts Any Colorspace.
# Optional Parameters:
# int width: output width
# int height: output height
# string ResizeMethod: name of resize function. Default = BilinearResize
# float ModAR: Set the Output Aspect Ratio. If 0 then it uses the source aspect ratio (needed for animate).
#
# Mode 2 - Align clip
# int Align: -9 to +9 (0=Do not use Align). Positive values - fit with no black borders, may crop clip. Negative values - fit with black borders, may letterbox clip.
# 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.
#
# Mode 1 - Coordinates for ZoomBox:
# float x1: upper left x cord
# float y1: upper left y cord
# float x2: lower right x cord
# float y2: lower right y cord
# 3 or 4 out of 4 points must be defined when using Mode 1
# when omitting a single point, it will calculate the missing value, with the Aspect Ratio in mind.
#
# float zoomFactor: 100 = 100%, ect...
# Negative values is the zoom of the pixels, positive values is the zoom of the frame.
# When converting AR, this isn't perfect.
# float panX: shift the clip x pixels. Value in source pixels. - left, + right
# float panY: shift the clip x pixels. Value in source pixels. - up, + down
# int color: Color of letterbox border. Default: $000000 (Black).
#
#
# Notes
# Clip should be deinterlaced for best visual quality.
# Aspect ratio for output and box(x1,y1,x2,y2) should be the same, unless you want to distort the clip.
# Default behavor is to center clip by adding borders (Align=-5).
# Useful for resizing clip sources (like pictures) to match the dimension of another clip.
# If you specify Align (Mode 2) and x1,y1,x2,y2 (Mode 1), Mode 1 will be used and the align will controll the position of the zoomFactor.
# Mode 1 (x1,y1,x2,y2) can take values from a crop opperation. x2 and y2 must be negative though; so if x2 or y2 equals 0, replace 0 with -0.00001.

Function ZoomBox(clip c, int "width", int "height", string "ResizeMethod",
\ float "SourcePAR", float "SourceDAR", float "TargetPAR", float "TargetDAR",
\ int "Align", float "x1", float "y1", float "x2", float "y2", float "zoomFactor", float "panX", float "panY",
\ int "color")
{
#Set Defaults
width = Default(width, c.width())
height = Default(height, c.height())
ResizeMethod = Default(ResizeMethod, "BilinearResize")
SourceAR = float(c.width())/float(c.height())
TargetAR = float(width)/float(height)
Align = Default(Align, -5) #Align=-5 (center and add borders to fit).
zoomFactor = Default(zoomFactor, 100.0)
panX = Default(panX, 0)
panY = Default(panY, 0)
color = Default(color, $000000)

modzoom = Max(Float(c.width())/Float(width),Float(c.height())/Float(height))
zoomFactor = zoomFactor<0 ? (abs(zoomFactor)/100.0)*modzoom : (abs(zoomFactor)/100.0)

#Check Inputs
Assert(zoomFactor<>0, "ZoomBox: zoomFactor can not be zero.")
Assert((Defined(x1) && Defined(y1) && (Defined(x2) || Defined(y2))) || !(Defined(x1) && Defined(y1) && Defined(x2) && Defined(y2)), "ZoomBox: when using Mode 1, you must define x1,y1, x2 and/or y2")
Assert(Align<9 || Align>-9, "ZoomBox: Align [" + String(Align) + "] should be between -9 and 9.")

#Do Some Magic
Eval (CalcBox(c, 1, width, height, TargetAR, SourceAR, zoomFactor, panX, panY, Align, x1, y1, x2, y2, SourcePAR, SourceDAR, TargetPAR, TargetDAR))

BoxAR = Float(x2-x1)/Float(y2-y1)
#Check for any unreasonable inputs before resize opperation
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) + "]")


ZoomBoxIt(c, width, height, ResizeMethod, x1, y1, x2, y2, color)
}

Function ZoomBoxIt(clip c, int width, int height, string ResizeMethod, float x1, float y1, float x2, float y2, int color)
{
#Pad clip so resizer interpolates from border when zooming out.
#Conditional Borders... only add if it's going to be used. Border size is size of input frame. Prevents "streaking" when zooming out alot.
borderLeft = x1 < 0 ? c.width():0
borderTop = y1 < 0 ? c.height():0
borderRight = x2 > c.width() ? c.width():0
borderBottom = y2 > c.height() ? c.height():0
c = c.AddBorders(borderLeft,borderTop,borderRight,borderBottom,color)

#Do it! Yes there are only 2 lines that directly act upon the clip.
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) + ")")
}

Function CalcBox(clip c, int mode, int width, int height, float TargetAR, float SourceAR, float zoomFactor, float panX, float panY, float Align, float "x1", float "y1", float "x2", float "y2", float "SourcePAR", float "SourceDAR", float "TargetPAR", float "TargetDAR")
{
#PAR/DAR Calculations
SourceDAR = Defined(SourcePAR) ?
\ SourcePAR==0 ? SourceAR : SourcePAR*SourceAR
\ : Defined(SourceDAR) ?
\ SourceDAR==0 ? SourceAR : Float(SourceDAR)
\ : SourceAR
TargetDAR = Defined(TargetPAR) ?
\ TargetPAR==0 ? TargetAR : TargetPAR*TargetAR
\ : Defined(TargetDAR) ?
\ TargetDAR==0 ? TargetAR : Float(TargetDAR)
\ : TargetAR

#Calc ModAR
ModAR = SourceDAR*TargetAR/TargetDAR


#If Align=5 or -5 then center clip. -5: Add borders. 5: Crop. "Mode 2"
#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 && ModAR==TargetAR ?
\ "x1=0
x2=c.width()
y1=0
y2=c.height()"


\ : (Align==-5 || Align==-4 || Align==-6) && ModAR>TargetAR ?
\ "y1=0 - ((height*ModAR-width)/2.0)*(c.height()/Float(width))
y2=c.height() + ((height*ModAR-width)/2.0)*(c.height()/Float(width))
x1=0" + "
x2=c.width()"
\ : (Align==5 || Align==2 || Align==8) && ModAR>TargetAR ?
\ "x1=0 + ((height-width/ModAR)/2.0)*(c.width()/Float(height))
x2=c.width() - ((height-width/ModAR)/2.0)*(c.width()/Float(height))
y1=0
y2=c.height()"
\ : (Align==-5 || Align==-2 || Align==-8) && ModAR<TargetAR ?
\ "x1=0 - ((width/ModAR-height)/2.0)*(c.width()/Float(height))
x2=c.width() + ((width/ModAR-height)/2.0)*(c.width()/Float(height))
y1=0
y2=c.height()"
\ : (Align==5 || Align==4 || Align==6) && ModAR<TargetAR ?
\ "y1=0 + ((width-height*ModAR)/2.0)*(c.height()/Float(width))
y2=c.height() - ((width-height*ModAR)/2.0)*(c.height()/Float(width))
x1=0
x2=c.width()"


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


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


\ : ""
Defined(x1) || Defined(y1) || Defined(x2) || Defined(y2) ? nop() : Eval(EvalString)

#For non Align Input "Mode 1"
x1tmp = Default(x1, 0)
y1tmp = Default(y1, 0)
x2tmp = Default(x2, c.width())
y2tmp = Default(y2, c.height())

#Take Crop Like Input
x2tmp = x2tmp<=x1tmp && x2tmp<0 ? c.width() + x2tmp : x2tmp
y2tmp = y2tmp<=y1tmp && y2tmp<0 ? c.height() + y2tmp : y2tmp

#Set Optional parameters "Mode 1"
test = 0
test = Defined(x1) ? test+1 : test+0
test = Defined(x2) ? test+1 : test+0
test = Defined(y1) ? test+1 : test+0
test = Defined(y2) ? test+1 : test+0
Assert(test>=3, "ZoomBox/KenBurnsEffect: At least 3 out of 4 x1, y1, x2, y2 points must be defined; or do not set any")

y2t = !Defined(y2) && Defined(y1) && Defined(x1) && Defined(x2) ? y1tmp + ((x2tmp-x1tmp)/TargetAR)/(SourceAR/ModAR) : y2tmp
x2t = !Defined(x2) && Defined(x1) && Defined(y1) && Defined(y2) ? x1tmp + ((y2tmp-y1tmp)*TargetAR)*(SourceAR/ModAR) : x2tmp
y1t = !Defined(y1) && Defined(y2) && Defined(x1) && Defined(x2) ? y2tmp - ((x2tmp-x1tmp)/TargetAR)/(SourceAR/ModAR) : y1tmp
x1t = !Defined(x1) && Defined(x2) && Defined(y1) && Defined(y2) ? x2tmp - ((y2tmp-y1tmp)*TargetAR)*(SourceAR/ModAR) : x1tmp

#Calc Pan Factor
x1 = x1t-panX
y1 = y1t-panY
x2 = x2t-panX
y2 = y2t-panY

#Calc Zoom Factor
CenterX = (x2-x1)/2.0
CenterY = (y2-y1)/2.0
CenterY = (Align<0 && ModAR>TargetAR)? CenterY*(TargetAR/ModAR): (Align>0 && ModAR<TargetAR)? CenterY*(TargetAR/ModAR): CenterY
CenterX = (Align>0 && ModAR>TargetAR)? CenterX/(TargetAR/ModAR): (Align<0 && ModAR<TargetAR)? CenterX/(TargetAR/ModAR): CenterX

Align = abs(Align)
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 ? 1.0/zoomFactor*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 ? 1.0/zoomFactor*CenterY+(y2-CenterY)/zoomFactor : y2


startString = "startX1=" + String(x1) + "
startY1=" + String(y1) + "
startX2=" + String(x2) + "
startY2=" + String(y2) + ""

endString = "endX1=" + String(x1) + "
endY1=" + String(y1) + "
endX2=" + String(x2) + "
endY2=" + String(y2) + ""

boxString = "x1=" + String(x1) + "
y1=" + String(y1) + "
x2=" + String(x2) + "
y2=" + String(y2) + ""

Return mode==1 ? boxString : mode==2 ? startString : mode==3 ? endString : ""
}


Function SplineCalc(clip c, int mode, int startFrame, float startF, int endFrame, float endF)
{
splineString = mode==1 ?
\ "spline(n, "
\ + String(startFrame-1) + "," + String(startF) + ", "
\ + String(startFrame) + "," + String(startF) + ", "
\ + String(endFrame) + "," + String(endF) + ", "
\ + String(endFrame+1) + "," + String(endF) + ", true)"

\ : mode==2 ? "spline(n, "
\ + String(startFrame) + "," + String(startF) + ", "
\ + String(startFrame+(endFrame-startFrame)/3.0) + "," + String(startF) + ", "
\ + String(endFrame-(endFrame-startFrame)/3.0) + "," + String(endF) + ", "
\ + String(endFrame) + "," + String(endF) + ", true)"

\ : mode==3 ? "spline(n, "
\ + String(startFrame) + "," + String(startF) + ", "
\ + String(startFrame+(endFrame-startFrame)/3.0) + "," + String(endF) + ", "
\ + String(endFrame-(endFrame-startFrame)/3.0) + "," + String(startF) + ", "
\ + String(endFrame) + "," + String(endF) + ", true)"

\ : mode==4 ? "spline(n, "
\ + String(startFrame) + "," + String(startF) + ", "
\ + String((endFrame-startFrame)/2.0) + "," + String(startF) + ", "
\ + String(endFrame) + "," + String(endF) + ", true)"

\ : mode==5 ? "spline(n, "
\ + String(startFrame) + "," + String(startF) + ", "
\ + String((endFrame-startFrame)/2.0) + "," + String(endF) + ", "
\ + String(endFrame) + "," + String(endF) + ", true)"

\ : "spline(n, "
\ + String(startFrame) + "," + String(startF) + ", "
\ + String(endFrame) + "," + String(endF) + ", true)"
Return splineString
}



Edits:
Dec 20th, 2009: Addedin missing function splinecalc
May 12th, 2008: Fixed some bugs. Will no longer auto correct width/height, resize will throw an error if its incorrect with the current color space.
May 13th, 2008: Quick Bug Fix with BoxAR.
May 15th, 2008: Can set OutputAR. Useful for clips that use DAR.
May 23rd, 2008: Fixed Most Aspect Ratio Errors. Use of 0,0,0,0 and -1,0,0,0 work correctly now. Finding the 4th point when given 3 isn't exact. Any help would be nice.
May 24th, 2008: All inputs optional. Input parameters reordered and changed. Should make usage easier. There are now no AR calculation errors! Thanks Gavion.
June 1st, 2008: Added Align, Pan(XY), zoomFactor. Split function up. Inputs are reordered!
June 3rd, 2008: Fixed DAR Float Bug.
June 6th, 2008: DisplayAR was incorrectly labeled, and is being replaced by SourceDAR and TargetDAR.
June 7th, 2008: Changed Pan(XY) to correctly act like it's supposed to in the documentation (negative is left or up).
June 12th, 2008: Added PAR. Any 3 out of 4 points can null, not just x2 or y2.

Example (http://forum.doom9.org/showthread.php?p=1140888#post1140888)

Gavino
13th March 2008, 17:40
function KenBurnsEffect(string filename, int outWidth, int outHeight, int startPZFrame, int endPZFrame, int length, int startX1, int startY1, int startX2, int startY2, int endX1, int endY1, int endX2, int endY2, bool "fast", bool "qubic")
...


For some reason if you try to call the function with variable names in place it fails. filename="Stil\DSCN1091.JPG" fails.

That's because AviSynth only supports the 'named argument' syntax for 'optional' parameters (those names in quotes in the function definition).

mikeytown2
14th March 2008, 01:45
Ken Burns Effect Part 2

Future Ideas:

Add a cubic option(s) to allow a circle as a path.
Make Negative ZoomFactor work correctly in all cases.

This is a RFC (Request For Comments) any input is greatly appreciated!

Footnotes:
Older Concept Scripts
http://forum.doom9.org/showthread.php?t=47974
http://forum.doom9.org/showthread.php?t=32884
ZoomInFramesAnimate() (http://avisynth.org/ZoomInFrames)

Here are some images i used for testing
http://img136.imageshack.us/img136/3356/testp2cz4.th.png (http://img136.imageshack.us/my.php?image=testp2cz4.png)
http://img230.imageshack.us/img230/8213/keyarenatt9.th.jpg (http://img230.imageshack.us/my.php?image=keyarenatt9.jpg)

This function is semi similar to:

MS Photo Story 3 (http://www.microsoft.com/windowsxp/using/digitalphotography/photostory/default.mspx)
DVDslideshowGUI (uses AviSynth!) (http://download.videohelp.com/tin2tin/)



Edit:
May 27th, 2009: added bool KeepState: If using start/end Frame, it keeps the clip at the start & end zoom level. Default = true
May 10th, 2008: Completely redid the speed logic. because zoom.dll's resize function is point resize, set speed to 0.25 for high quality results. The Cubic option now works at all times, and you can select it for x only or y only if wanted (will make an arc then). The use of ZoomBox for static parts is now optional, default: it doesn't use it. Fixed a minor bug with the total frame count. (Thanks Gavino). Fixed small error in the error code, now displays the correct info. Small change to the inputs of ZoomBox. Can now only use ZoomBox(). ZoomBox's sub pixel accuracy is set with the speed option here. subpixel = 1/speed.
May 11th, 2008: Fixed a simple, but semi major bug with useZoomBox.
May 12th, 2008: Small changes that take into account ZoomBox() changes. ResizeKAR() no longer needed. Fixed some bugs. Updated Example. Fixed a color space bug. Slight Speed Increase.
May 13th, 2008: Take Crop Like Input (negative x2 or y2). If (+-1 or 0),0,0,0 then assume clip is to be centered; -1 add borders, 0 or 1 zoom in.
May 15th, 2008: Can set OutputAR. Useful for clips that use DAR.
May 23rd, 2008: Fixed Most Aspect Ratio Errors. Use of 0,0,0,0 and -1,0,0,0 work correctly now. Finding the 4th point when given 3 isn't exact.
May 24th, 2008: No AR calculation errors! (thanks Gavino). Changed some internals so input into ZoomBox works.
June 1st, 2008: Added Align, Pan(XY), zoomFactor. Split function up. Inputs are reordered!
June 6th, 2008: DisplayAR was incorrectly labeled, and is being replaced by SourceDAR and TargetDAR.
June 7th, 2008: Added startAngle and endAngle. Can only be used when useZoomBox=0. Split off the spline code into its own function. Added cubicA to do cubic style angle rotations. Changed Pan(XY) to act correctly.
June 12th, 2008: Any 3 out of 4 points can null, not just x2 or y2. Cubic option is now an int with multiple presets (0-5 currently). Set CubicX different from CubicY for fun results! Reminder that Cubic can only be used when useZoomBox=0.


ZoomBox Examples
Resize 6 different sources (example, pictures) so they all fit in a single clip.
Width=640
Height=480
Resize="BlackmanResize"
Align=-5

a=ColorBars(320,480, "YV12").Trim(0,-1).ZoomBox(Width,Height,Resize, Align=Align)
b=ColorBars(480,480, "YV12").Trim(0,-1).ZoomBox(Width,Height,Resize, Align=Align)
c=ColorBars(640,480, "YV12").Trim(0,-1).ZoomBox(Width,Height,Resize, Align=Align)
d=ColorBars(720,480, "YV12").Trim(0,-1).ZoomBox(Width,Height,Resize, Align=Align)
e=ColorBars(854,480, "YV12").Trim(0,-1).ZoomBox(Width,Height,Resize, Align=Align)
f=ColorBars(960,480, "YV12").Trim(0,-1).ZoomBox(Width,Height,Resize, Align=Align)

a+b+c+d+e+f


Convert an anamorphic (16/9) DVD to square pixels

Width=854
Height=480
Resize="Lanczos4Resize"

MPEG2Source("AnamorphicDVD.d2v")
ZoomBox(Width,Height,Resize, SourceDAR=16.0/9.0)



Convert a square pixel source to anamorphic (16/9) DVD

Width=720
Height=480

ColorBars()
ZoomBox(Width, Height, TargetDAR=16.0/9.0)


Convert a anamorphic (16/9) DVD source to (4/3) DVD

Width=720
Height=480

MPEG2Source("AnamorphicDVD.d2v")
ZoomBox(Width, Height, SourceDAR=16.0/9.0, TargetDAR=4.0/3.0)



Convert DV Cam Pixels to Square Pixels

Width=640
Height=480
Align=5

ColorBars(720,480)
ZoomBox(Width, Height, SourcePAR=10.0/11.0, Align=Align)



Resize interlaced material, keeping the interlacing after resize.

AVISource("interlaced.avi")
AssumeTFF() #set order
bob()
ZoomBox(1280,720)
separatefields()
selectevery(4,0,3)
weave()

Replace bob() with your favorite bobber for higher quality results.


KenBurnsEffect Examples
Zoom out a clip 50%, move clip around the 4 corners of the screen, then zoom back to 100%.

a = ColorBars().Trim(0,99)

KenBurnsEffect(a, startAlign=5, endAlign=5, endZoomFactor=50)
last + KenBurnsEffect(a, startZoomFactor=50, startAlign=5, endAlign=1, endZoomFactor=50)
last + KenBurnsEffect(a, startZoomFactor=50, startAlign=1, endAlign=3, endZoomFactor=50)
last + KenBurnsEffect(a, startZoomFactor=50, startAlign=3, endAlign=9, endZoomFactor=50)
last + KenBurnsEffect(a, startZoomFactor=50, startAlign=9, endAlign=7, endZoomFactor=50)
last + KenBurnsEffect(a, startZoomFactor=50, startAlign=7, endAlign=1, endZoomFactor=50)
last + KenBurnsEffect(a, startZoomFactor=50, startAlign=1, endAlign=5)



Pan a clip left to right, the right to left, then zoom out

Width=640
Height=480

a=ColorBars(2000,480).Trim(0,99)
a.KenBurnsEffect(StartAlign=4,EndAlign=6, Width=Width, Height=Height)
last+ a.KenBurnsEffect(StartAlign=6,EndAlign=4, Width=Width, Height=Height)
last+ a.KenBurnsEffect(StartAlign=4,EndAlign=-5, Width=Width, Height=Height)



KenBurnsEffect & ZoomBox AvsP Function Definitions
Go to your AvsP dir
Open up filterdb.dat with notepad
At the end of the file is a section called [USERFUNCTIONS]
Add this to the end of that section and save


KenBurnsEffect(
clip c,
int "startAlign"=-5 (-9 to 9),
float "startX1",
float "startY1",
float "startX2",
float "startY2",
float "startZoomFactor=100",
float "startPanX",
float "startPanY",
float "startAngle",
int "endAlign=-5 (-9 to 9)",
float "endX1",
float "endY1",
float "endX2",
float "endY2",
float "endZoomFactor=100",
float "endPanX",
float "endPanY",
float "endAngle",
int "width",
int "height",
int "StartFrame",
int "EndFrame",
string "ResizeMethod"="BilinearResize" ("PointResize"/"BilinearResize"/"BilinearResize"/"LanczosResize"/"Lanczos4Resize"/"BlackmanResize"/"Spline16Resize"/"Spline36Resize"/"Spline64Resize"),
float "SourcePAR",
float "SourceDAR",
float "TargetPAR",
float "TargetDAR",
int "useZoomBox",
float "speed",
int "cubic",
int "cubicX",
int "cubicY",
int "cubicA",
int "cubicZ",
int "color"
)

ZoomBox(
clip c,
int "width",
int "height",
string "ResizeMethod"="BilinearResize" ("PointResize"/"BilinearResize"/"BilinearResize"/"LanczosResize"/"Lanczos4Resize"/"BlackmanResize"/"Spline16Resize"/"Spline36Resize"/"Spline64Resize"),
float "SourcePAR",
float "SourceDAR",
float "TargetPAR",
float "TargetDAR",
int "Align"=-5 (-9 to 9),
float "x1",
float "y1",
float "x2",
float "y2",
float "zoomFactor"=100,
float "panX",
float "panY",
int "color"
)

FlimsyFeet
14th March 2008, 14:07
So basically this function means you can make stuff like Microsoft's Photo Story 3 (http://www.microsoft.com/windowsxp/using/digitalphotography/photostory/default.mspx) but witihin AviSynth?

That's a pretty neat function.

mikeytown2
14th March 2008, 20:47
Nice find with Photo Story 3, i gave it a spin, it has a fairly good gui; its also fast.

To answer your question, yes this does exactly that. To get the same transition effects that are in Photo Story 3 i would use TransAll (http://avisynth.org/vcmohan/TransAll/docs/index.html). If your looking for more effects, take a peek at the wiki http://avisynth.org/mediawiki/External_filters#Effects.

tin3tin
15th March 2008, 00:21
In DVD slideshow GUI there is a simple gui for zoom.dll, with up to 20 keypoints, so if you want to play around with more keypoints and overshooting splines and afterwards take a look at the avisynth code - the animation/slideshow can be exported to .avs.

Btw. I think there is a FreeFrame plugin(which can be accessed with an avisynth plugin) which can do all the pos/rot/zoom stuff and it's very fast.

mikeytown2
15th March 2008, 02:11
FreeFrame avisynth plugin
http://forum.doom9.org/showthread.php?threadid=92174
http://avisynth.org/warpenterprises/files/freeframe_25_dll_20050426.zip

FreeFrame webpage
http://freeframe.sourceforge.net/

@tin3tin Thanks for making that sweet software, I took a look at the generated avs files. The only problem is the zoom values are hard coded in so it can be hard to use generally. Feel free to include my function into your software if you want. I'll be looking into FreeFrame. Do you have any examples where you use FreeFrame? Also do you have any other ideas on how i can improve this function?

mikeytown2
15th March 2008, 03:17
I've been playing around briefly with FreeFrame, it is fast! I've maped out the behavior of PetePanSpinZoom.dll (http://www.petewarden.com/PetesPlugins_FreeFrame1.15.zip)
# Freeframe
# clip c
# string dllname: dll location (full path)
# bool showgui: show dll gui?
# dll paramaters:PetePanSpinZoom.dll - can take RGB32 or RGB24.
# float from 0 to 1: orgin in x cords: center 0.5. 1 puts video far right, 0 puts video far left
# float from 0 to 1: orgin in y cords: center 0.5. 1 puts video on top, 0 puts video on bottom
# float from 0 to 1: rotation: 0 = 0, 1 = 360. 0.5 = 180
# float from 0 to 1: scale: normal 0.2. Zoom Range 0 = 0.3(in) to 1 = 4(out), when 0.2 = 1 is same.

ConvertToRGB32()
Freeframe("C:\Program Files\AviSynth 2.5\plugins\PetePanSpinZoom.dll",true,0.5,0.5,0,0.2) #doesn't change picture, and shows gui

mikeytown2
15th March 2008, 07:34
Using the test2b.png file and this code I've tried to calibrate the input values.

KenBurnsEffecter("testP2.png", 640, 480, 10, 20, 30, 0, 0, 640, 480, 320, 240, 640, 480, true, false)

function KenBurnsEffecter(string filename, int outWidth, int outHeight, int startPZFrame, int endPZFrame, int length, int startX1, int startY1, int startX2, int startY2, int endX1, int endY1, int endX2, int endY2, bool "fast", bool "cubic")
{
#set defaults
fast = Default(fast, false)
cubic = Default(cubic, false)

#Check For Any Unreasonable Inputs
Assert(startX1<startX2, "KenBurnsEffect: Start X1[" + String(startX1) + "] point larger then X2 Point[" + String(startX1) + "]")
Assert(startY1<startY2, "KenBurnsEffect: Start Y1[" + String(startY1) + "] point larger then Y2 Point[" + String(startY1) + "]")
Assert(endX1<endX2, "KenBurnsEffect: End X1[" + String(endX1) + "] point larger then X2 Point[" + String(endX1) + "]")
Assert(endY1<endY2, "KenBurnsEffect: End Y1[" + String(endY1) + "] point larger then Y2 Point[" + String(endY1) + "]")
Assert(startPZFrame<endPZFrame, "KenBurnsEffect: Starting Frame[" + String(startPZFrame) + "] greater then Ending Frame[" + String(endPZFrame) + "]")
Assert(endPZFrame-startPZFrame<=length, "KenBurnsEffect: Transition length[" + String(endPZFrame-startPZFrame) + "] greater then clip lenght[" + String(length) + "]")
Assert(Float(startX2-startX1)/Float(startY2-startY1) == Float(endX2-endX1)/Float(endY2-endY1), "Starting Aspect Ratio[" + String(Float(startX2-startX1)/Float(startY2-startY1)) + "] does not equal ending Aspect Ratio [" + string(Float(endX2-endX1)/Float(endY2-endY1)) + "]")
Assert(Float(startX2-startX1)/Float(startY2-startY1) == Float(outWidth)/Float(outHeight), "Box Aspect Ratio[" + String(Float(startX2-startX1)/Float(startY2-startY1)) + "] does not equal clip output Aspect Ratio [" + string(Float(outWidth)/Float(outHeight)) + "]")

#load image
img = ImageSource(filename, start=0, end=length, fps=30).ConvertToRGB32()

#fix aspect ratio
ratioS = Float(img.width())/Float(img.height())
ratioD = Float(outWidth)/Float(outHeight)
BorderAddWidth = height(img)-Round(img.width()*ratioD/2)*2
BorderAddHeight = width(img)-Round(img.height()/ratioD/2)*2

img = (ratioS>ratioD) ? img.AddBorders(0, 0, 0, BorderAddWidth/4) : (ratioS<ratioD) ? img.AddBorders(0, 0, BorderAddHeight/4, 0) : img

#get center of start rectangle
startCenterX = startX1+((startX2-startX1)/2)-0.5
startCenterY = startY1+((startY2-startY1)/2)-0.5

#get center of end rectangle
endCenterX = endX1+((endX2-endX1)/2)-0.5
endCenterY = endY1+((endY2-endY1)/2)-0.5

#get starting zoom factor
startZoomFactor = (float(img.width())/float(startX2-startX1) + float(img.height())/float(startY2-startY1))/2

#get ending zoom factor
endZoomFactor = (float(img.width())/float(endX2-endX1) + float(img.height())/float(endY2-endY1))/2

#Switch To Fast Mode
startCenterX = fast ? startCenterX/(Float(img.width())/Float(outWidth)): startCenterX
startCenterY = fast ? startCenterY/(Float(img.height())/Float(outHeight)): startCenterY
endCenterX = fast ? endCenterX/(Float(img.width())/Float(outWidth)): endCenterX
endCenterY = fast ? endCenterY/(Float(img.height())/Float(outHeight)): endCenterY
img = fast ? Spline64Resize(img, outWidth, outHeight): img

#Pan starting and ending x point
srcx = "spline(n, " + String(startPZFrame-1) + "," + String(startCenterX) + ", " + String(startPZFrame) + ", " + String(startCenterX) + ", " + String(endPZFrame) + "," + String(endCenterX) + ", " + String(endPZFrame+1) + "," + String(endCenterX) + ", " + String(cubic) + ")"

#Pan starting and ending y point
srcy = "spline(n, " + String(startPZFrame-1) + "," + String(startCenterY) + ", " + String(startPZFrame) + "," + String(startCenterY) + ", " + String(endPZFrame) + "," + String(endCenterY) + ", " + String(endPZFrame+1) + "," + String(endCenterY) + ", " + String(cubic) + ")"

#Zoom
factor = "spline(n, " + String(startPZFrame-1) + "," + String(startZoomFactor) + ", " + String(startPZFrame) + "," + String(startZoomFactor) + ", " + String(endPZFrame) + "," + String(endZoomFactor) + ", " + String(endPZFrame+1) + "," + String(endZoomFactor) + ", " + String(cubic) + ")"

#do it
img.Zoom(srcx=srcx, srcy=srcy, factor=factor, show=true).Spline64Resize(outWidth, outHeight)
#img = img.AddBorders(img.width()/2, img.height()/2, img.width()/2, img.height()/2)

x = float(img.width())/float(startCenterX+0.5)/4
y = float(startCenterY+0.5)/float(img.height())
z = 5/startZoomFactor/25
last + img.Freeframe("C:\Program Files\AviSynth 2.5\plugins\PetePanSpinZoom.dll",false,x,y,0,z).Spline64Resize(outWidth, outHeight).Subtitle(" x:" + string(x) + " y:" + string(y) + " z:" + string(z))
x = float(img.width())/float(endCenterX+0.5)/4
y = float(endCenterY+0.5)/float(img.height())
z = 5/endZoomFactor/25
return last + img.Freeframe("C:\Program Files\AviSynth 2.5\plugins\PetePanSpinZoom.dll",false,x,y,0,z).Spline64Resize(outWidth, outHeight).Subtitle("x: " + string(x) + " y:" + string(y) + " z:" + string(z))

}


This gets close, but to make the last 1/4 of the video correct
x value should be 0.000 instead of 1/3
y value should be 1.000 instead of 3/4
z value should be 1/15 instead of 1/10

Which maxes out the function for x & y. In order to zoom in more i would have to shift the picture. This gets ugly fast. I don't plan on pursuing this venture, but if someone wants to pick up where i left off, by all means continue. PetePanSpinZoom.dll seems to give higher quality results too.


Looks like if this is going to get faster, optimization of zoom.dll is needed.

Gavino
15th March 2008, 18:02
Looks like if this is going to get faster, optimization of zoom.dll is needed.
Have you considered using the width and height parameters of zoom?

With judicious use of these parameters, it ought to be possible to speed up your function a lot.

At the moment you are zooming the entire image (albeit a reduced one in fast mode), but often most of the pixels will get thrown away in the final result.

It might involve changing the logic of your script a fair bit, but it's worth looking into, if you haven't already.

(Not sure if your experiments with FreeFrame, etc, make my suggestion redundant, as I haven't caught up with that part of the discussion yet.:))

mikeytown2
16th March 2008, 06:40
Have you considered using the width and height parameters of zoom?

With judicious use of these parameters, it ought to be possible to speed up your function a lot.

At the moment you are zooming the entire image (albeit a reduced one in fast mode), but often most of the pixels will get thrown away in the final result.

It might involve changing the logic of your script a fair bit, but it's worth looking into, if you haven't already.

(Not sure if your experiments with FreeFrame, etc, make my suggestion redundant, as I haven't caught up with that part of the discussion yet.:))

I've taken a stab at using the other parameters of zoom(), and I've given up on it. I took your suggestion though and improved my other function ZoomBox() :).


Here is a very BAD example of what the ZoomBox can do...:devil:

Global w=0
Global x=0
Global y=640
Global z=640
Global Resizer = "Spline16Resize"
Global zoomstep = -8

a = ImageSource("testP2.png", end=1, fps=30).ConvertToRGB32().ResizeKAR(640,640, Resizer).Trim(0,-1)

VeryBadIdea(a)
Global zoomstep = 8
last + VeryBadIdea(a)
Global zoomstep = 8
last + VeryBadIdea(a)

Function BadIdea(clip c)
{
Global w = w+zoomstep
Global x = x+zoomstep
GLobal y = y-zoomstep
Global z = z-zoomstep
return c
}


Function VeryBadIdea(clip a)
{
a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
last + a.ZoomBox(w, x, y, z, Resizer=Resizer).ZoomBox(0, 80, 640, 560, 640, 480, Resizer=Resizer).Subtitle(" w: " + String(w) + " x: " + String(x) + " y: " + String(y) + " z: " + String(z)).BadIdea()
}


# ZoomBox() - March 15th, 2008
# Put a "box" around a clip. Box can be used to zoom in or out.
#
# Cordinates for ZoomBox:
# int x1: upper left x cord
# int y1: upper left y cord
# int x2: lower right x cord
# int y2: lower right y cord
# Optional Parameters
# int w: output width
# int h: output height
# string Resizer: name of resize function. Default = BilinearResize
#
# Notes
# Aspect ratio for output and box must be the same.
# Be aware of colorspace resctictions.

Function ZoomBox(clip c, int x1, int y1, int x2, int y2, int "w", int "h", string "Resizer")
{
#set defaults
w = Default(w, c.width())
h = Default(h, c.height())
Resizer = Default(Resizer, "BilinearResize")

#Check For Any Unreasonable Inputs
Assert(x1<x2, "ZoomBox: Start x1[" + String(x1) + "] point larger then x2 Point[" + String(x2) + "]")
Assert(y1<y2, "ZoomBox: Start y1[" + String(y1) + "] point larger then y2 Point[" + String(y2) + "]")
Assert(Float(x2-x1)/Float(y2-y1) == Float(w)/Float(h), "ZoomBox: Box Aspect Ratio [" + String(Float(x2-x1)/Float(y2-y1)) + "] does not equal clip output Aspect Ratio [" + string(Float(w)/Float(h)) + "]")

#inverse zoomfactor
zx = float(w)/float(x2-x1)
zy = float(h)/float(y2-y1)

#shrinkpic before for speed boost when zooming out
wOut = zx<1 ? zx*c.width() : c.width()
x1 = zx<1 ? zx*x1 : x1
x2 = zx<1 ? zx*x2 : x2
hOut = zy<1 ? zy*c.height() : c.height()
y1 = zy<1 ? zy*y1 : y1
y2 = zy<1 ? zy*y2 : y2
c = Eval(Resizer + "(c," + String(Round(wOut)) + "," + String(Round(hOut)) + ")")

#Add Borders If Needed
left = x1 < 0 ? -x1 : 0
top = y1 < 0 ? -y1 : 0
right = x2-c.width() > 0 ? x2-c.width() : 0
bottom = y2-c.height() > 0 ? y2-c.height() : 0
d = AddBorders(c, round(left), round(top), round(right), round(bottom))

#Crop If Needed
left = x1 > 0 ? x1 : 0
top = y1 > 0 ? y1 : 0
right = x2-c.width() < 0 ? x2-c.width() : 0
bottom = y2-c.height() < 0 ? y2-c.height() : 0
c = Crop(d, round(left), round(top), round(right), round(bottom))

#Resize for output
Return Eval(Resizer + "(c," + String(w) + "," + String(h) + ")")
}

function ResizeKAR(clip c, int maxW, int maxH, string "ResizeMethod", int "BackgroundColor")
{
BackgroundColor = Default(BackgroundColor, $000000)
ResizeMethod = Default(ResizeMethod, "BilinearResize")
ratioS = Float(width(c))/Float(height(c))
ratioD = Float(maxW)/Float(maxH)
newW = Round(maxH*ratioS/2)*2
newH = Round(maxW/ratioS/2)*2


#Dest Higher Then Source; Dest Wider Then Source; Same Ratio
c =
\ (ratioS>ratioD) ?
\ Eval(ResizeMethod + "(c, " + String(maxW) + ", " + String(newH) + ")").
\ AddBorders(0, Round((maxH-newH)/2), 0, Round((maxH-newH)/2), BackgroundColor) :
\ (ratioS<ratioD) ?
\ Eval(ResizeMethod + "(c, " + String(newW) + ", " + String(maxH) + ")").
\ AddBorders(Round((maxW-newW)/2), 0, Round((maxW-newW)/2), 0, BackgroundColor) :
\ (ratioS==ratioD) ?
\ Eval(ResizeMethod + "(c, " + String(maxW) + ", " + String(maxH) + ")" ) :
\ nop()

#fix 1px changes, works only with 4:4:4
c =
\ IsInterleaved(c) && (maxW>width(c)) ? c.AddBorders(0, 0, 1, 0) :
\ IsInterleaved(c) && (maxH>height(c)) ? c.AddBorders(0, 0, 0, 1) :
\ c
return c
}

This code requires no DLL's. It is a good way to see how a resizer effects the picture in terms of ringing.

mikeytown2
17th March 2008, 13:39
If anyone could explain why the picture likes to jump around when i use animate with zoombox, i would appreciate it. Or i guess i should ask why does this jump and zoom.dll not jump around? Any ideas on how i can fix it?

#SetMemoryMax(512)
#b = ImageSource("New Folder\testp2.png", end=99, fps=60)
b = colorbars().trim(0,99)

Animate(0, 99, "ZoomBoxer", b, 0.0, 0.0, 640.0, 480.0, 1, b, 320.0, 240.0, 640.0, 480.0, 1)
last + Animate(0, 99, "ZoomBoxer", b, 320.0, 240.0, 640.0, 480.0, 1, b, 416.0, 312.0, 480.0, 360.0, 1)
last + Animate(0, 99, "ZoomBoxer", b, 416.0, 312.0, 480.0, 360.0, 1, b, 0.0, 0.0, 640.0, 480.0, 1)
last + Animate(0, 99, "ZoomBoxer", b, 0.0, 0.0, 640.0, 480.0, 1, b, 288.0, 216.0, 352.0, 264.0, 1)

# ZoomBoxer() - March 17th, 2008
# Put a "box" around a clip. Box can be used to zoom in or out.
#
# Coordinates for ZoomBox:
# float x1: upper left x cord
# float y1: upper left y cord
# float x2: lower right x cord
# float y2: lower right y cord
# Optional Parameters
# int IgnoreAR: 1 - Ignore Warnings; 0 - Show Warnings. Default=0, show warings
# bool smooth: at the cost of speed (maybe quality) make zoom in's smoother. Default false
# string Resizer: name of resize function. Default = BilinearResize
# int w: output width
# int h: output height
#
# Notes
# Aspect ratio for output and box must be the same.
# Be aware of colors space restrictions.

Function ZoomBoxer(clip c, float x1, float y1, float x2, float y2, int "IgnoreAR", bool "smooth", string "Resizer", int "w", int "h")
{
#set defaults
w = Default(w, c.width())
h = Default(h, c.height())
Resizer = Default(Resizer, "BilinearResize")
IgnoreAR = Default(IgnoreAR, 0)
smooth = Default(smooth, false)
wOut = c.width()
hOut = c.height()

#Check For Any Unreasonable Inputs
Assert(x1<x2, "ZoomBox: Start x1[" + String(x1) + "] point larger then x2 Point[" + String(x2) + "]")
Assert(y1<y2, "ZoomBox: Start y1[" + String(y1) + "] point larger then y2 Point[" + String(y2) + "]")
Assert(IgnoreAR>0 || Float(x2-x1)/Float(y2-y1) == Float(w)/Float(h), "ZoomBox: Box Aspect Ratio [" + String(Float(x2-x1)/Float(y2-y1)) + "] does not equal clip output Aspect Ratio [" + string(Float(w)/Float(h)) + "]")

#fix aspect ratio
y3 = c.height()*(x2-x1)/Float(c.width())
x3 = c.width()*(y2-y1)/Float(c.height())
#x2=x3
#y2=y3

#inverse zoomfactor, used to shrink or grow clip if needed
zx = float(w)/float(x2-x1)
zy = float(h)/float(y2-y1)
#smoothA = smooth && zx>1 && zy>1 ? false : true
#smooth = smooth ? smoothA : false

#Shrink clip before for speed boost when zooming out, or blow up for smoother pic when zooming in.
wOut = smooth || zx<1 ? zx*wOut : wOut
x1 = smooth || zx<1 ? zx*x1 : x1
x2 = smooth || zx<1 ? zx*x2 : x2
hOut = smooth || zy<1 ? zy*hOut : hOut
y1 = smooth || zy<1 ? zy*y1 : y1
y2 = smooth || zy<1 ? zy*y2 : y2

#Check ColorSpace
x1 = c.IsYV12() || c.IsYUY2() ? Round(x1/2)*2 : x1
x2 = c.IsYV12() || c.IsYUY2() ? Round(x2/2)*2 : x2
y1 = c.IsYV12() || c.IsYUY2() ? Round(y1/2)*2 : y1
y2 = c.IsYV12() || c.IsYUY2() ? Round(y2/2)*2 : y2
wOut = c.IsYV12() || c.IsYUY2() ? Round(wOut/2)*2 : wOut
hOut = c.IsYV12() || c.IsYUY2() ? Round(hOut/2)*2 : hOut

#resize clip if needed
c = Eval(Resizer + "(c," + String(Int(wOut)) + "," + String(Int(hOut)) + ")")

#Add Borders If Needed
left = x1<0 ? -x1 : 0
top = y1<0 ? -y1 : 0
right = x2-c.width()>0 ? x2-c.width() : 0
bottom = y2-c.height()>0 ? y2-c.height() : 0
d = AddBorders(c, Int(left)+8, Int(top)+8, Int(right)+8, Int(bottom)+8)

#Crop If Needed
left = x1 > 0 ? x1 : 0
top = y1 > 0 ? y1 : 0
right = x2-c.width() < 0 ? x2-c.width() : 0
bottom = y2-c.height() < 0 ? y2-c.height() : 0

d = Crop(d, Int(left)+8, Int(top)+8, Int(right)-8, Int(bottom)-8)
#Resize for output
Return Eval(Resizer + "(d," + String(w) + "," + String(h) + ")")#+ ",src_left=" + String(Int(left)+8) + ",src_top=" + String(Int(top)+8) + ",src_width=" + String(c.width() + right) + ",src_height=" + String(c.height() + bottom) + ")")
}

mikeytown2
21st March 2008, 12:40
Function and example updated. Parameter order changed.

Given up on making a function to replace zoom.dll - too much work and the ability to select your own resize function not worth the effort. I do have a nice zoombox() function though.

mikeytown2
9th May 2008, 05:07
KenBurnsEffect() Changes:

You only have to know 3 out of the 4 points for the 2 boxes. Can omit X2 or Y2 but not both. Set X2 to X1, or Y2 to Y1, in order for this to auto calc the appropriate missing point, while keeping the Output Aspect Ratio in mind. (Very Helpful)
Changed some variable names.
Fixed a Bug in the ZoomY if x and y zooms where different.
Speed Boost!


ZoomBox() Changes:

Located Here (http://forum.doom9.org/showthread.php?p=1111789#post1111789)
Use of ResizeKAR makes this behave much better when it is Animated.


With these changes, KenBurnsEffect() is semi usable, before it was very hard because of all the aspect ratio calculations.

mikeytown2
10th May 2008, 10:03
KenBurnsEffect() Changes:

Speed Logic Redone
Cubic option works for any situation.
Added a CubicX and CubicY options so the fast, slow, fast will only occur on that axis is desired. (useful for drawing a arc)
Use of ZoomBox in static parts optional.
Reordered inputs and made the start and end frames optional.

Dreassica
10th May 2008, 10:32
Would it be possible to use one of these functions to recreate a screwed up sidewards pan using a single panoramic created picture?

mikeytown2
10th May 2008, 10:46
Would it be possible to use one of these functions to recreate a screwed up sidewards pan using a single panoramic created picture?

by "screwed up" do you mean it is rotated, something like this?
http://en.wikipedia.org/wiki/Dutch_angle

The sidewards pan (I'm assuming something like left to right) is very doable! use KenBurnsEffect() and load the image into a clip. If you describe the desired movement (drawings always help), i can show you how to use this. The dimensions of the panoramic will be needed.

As a side note, did you use hugin (http://hugin.sourceforge.net/) to make the panoramic?

Gavino
10th May 2008, 16:45
Nice work, mikeytown. I was having a few problems with the version you posted on 8th May, but this latest one works pretty well.

Still, one bug remains - the output clip is missing the last frame of the panned region.

Fix:

#Do the zoom/pan
c = c.Zoom(srcx=srcxSE, srcy=srcySE, factorx=factor_x_SE, factory=factor_y_SE, width=Round(outWidth), height=Round(outHeight)).Trim(startPZFrame, endPZFrame-1)

- Replace endPZFrame-1 by endPZFrame in Trim

Dreassica
10th May 2008, 19:51
by "screwed up" do you mean it is rotated, something like this?
http://en.wikipedia.org/wiki/Dutch_angle

The sidewards pan (I'm assuming something like left to right) is very doable! use KenBurnsEffect() and load the image into a clip. If you describe the desired movement (drawings always help), i can show you how to use this. The dimensions of the panoramic will be needed.

As a side note, did you use hugin (http://hugin.sourceforge.net/) to make the panoramic?


No as in it cant be properly ivtced/fieldmatched as it has shit frames etc. I just selected a few good frames, used photoshop to append them to a panoramic view picture. Successfully did one such frame the manual way using allot of croppings to 640x480 shifting an x number of pixels. Just too timeconsuming, and I thought maybe this scripts could do it much faster and easier.

mikeytown2
10th May 2008, 21:05
KenBurnsEffect() Changes:

Fixed a minor bug with the total frame count. (Thanks Gavino)





No as in it cant be properly ivtced/fieldmatched as it has shit frames etc. I just selected a few good frames, used photoshop to append them to a panoramic view picture. Successfully did one such frame the manual way using allot of croppings to 640x480 shifting an x number of pixels. Just too timeconsuming, and I thought maybe this scripts could do it much faster and easier.

I understand what your mean. I think hand picking frames and putting them together with hugin is your fastest option. What you suggested would be an interesting way of fixing very bad sources when the movement is a static pan. I would follow the scanned image tutorial, it should be faster then photoshop.
http://hugin.sourceforge.net/tutorials/scans/en.shtml

Dreassica
10th May 2008, 21:09
KenBurnsEffect() Changes:

Fixed a minor bug with the total frame count. (Thanks Gavino)







I understand what your mean. I think hand picking frames and putting them together with hugin is your fastest option. What you suggested would be an interesting way of fixing very bad sources when the movement is a static pan. I would follow the scanned image tutorial, it should be faster then photoshop.
http://hugin.sourceforge.net/tutorials/scans/en.shtml

it's not really the process of combining a few frames to make a panoramic picture that's timeconsuming for me, but manually doing crops etc to recreate all fames that is, thought an automated wayt using oen of your scripts could simplify that.

mikeytown2
10th May 2008, 21:32
it's not really the process of combining a few frames to make a panoramic picture that's timeconsuming for me, but manually doing crops etc to recreate all fames that is, thought an automated wayt using oen of your scripts could simplify that.

Could you upload one of your stitched panoramic pictures? http://imageshack.us/

And also upload the clip that it came from? http://www.megaupload.com/

And then we can go from there

Dreassica
10th May 2008, 22:05
Don't have access to my usual pc for a few days, so i can't provide samples. I do still know characteristics of the last scene i worked on.
a sidepanscene of 144 frames, framerate 23.976, panoramic picture is 1504x480, and every framestep is 6 pixels x 144.

mikeytown2
10th May 2008, 22:20
Don't have access to my usual pc for a few days, so i can't provide samples. I do still know characteristics of the last scene i worked on.
a sidepanscene of 144 frames, framerate 23.976, panoramic picture is 1504x480, and every framestep is 6 pixels x 144.

This pans left to right. replace colorbars with your image, and it should work.

colorbars().trim(0,143).BilinearResize(1504,480)

KenBurnsEffect(last, 0,0, 720,0, 784,0, 1504,0, 720,480, IgnoreAR=1)


Same as this

colorbars().trim(0,143).BilinearResize(1504,480)

KenBurnsEffect(last, 0,0, 0,480, 784,0, 784,480, 720,480, IgnoreAR=1)


Left to right, then right to left

X = colorbars().trim(0,143).BilinearResize(1504,480)

KenBurnsEffect(x, 0,0, 0,480, 784,0, 784,480, 720,480, IgnoreAR=1)
last + KenBurnsEffect(x, 784,0, 784,480, 0,0, 0,480, 720,480, IgnoreAR=1)

Dreassica
10th May 2008, 22:35
tested it on a custom made picture, seemed to work as intended, only thing is, output resolution should be 640x480 not 720x480.Also, no way to do this without rgb32 conversion?

mikeytown2
10th May 2008, 23:12
KenBurnsEffect() Changes:

Fixed small error in the error code, now displays the correct info.
Matched Input of new ZoomBox()


ZoomBox() Changes:

Reorder inputs so it matches KBE() more



tested it on a custom made picture, seemed to work as intended, only thing is, output resolution should be 640x480 not 720x480.Also, no way to do this without rgb32 conversion?

zoom.dll requires rgb32, because there is no zooming only panning you can use my ZoomBox and animate it to get your desired effect. If there is zooming it still works, but the result can be ugly sometimes (limitations of Animate).

This example is more generalized, so it might be harder to follow.

WidthFinal = 640
HeightFinal = 480
X = colorbars().trim(0,143).BilinearResize(1504,480)

KenBurnsEffect(x, 0,0, 0,HeightFinal, width(x)-WidthFinal,0, width(x)-WidthFinal,HeightFinal, WidthFinal,HeightFinal, IgnoreAR=1)
last + KenBurnsEffect(x, width(x)-WidthFinal,0, width(x)-WidthFinal,HeightFinal, 0,0, 0,HeightFinal, WidthFinal,HeightFinal, IgnoreAR=1)
last.ConvertToYV12()

x = x.ConvertToYV12()
last + Animate(0, x.framecount()-1, "ZoomBox", x, 0.0,0.0, 0.0,Float(HeightFinal), WidthFinal, HeightFinal,1, x, Float(width(x)-WidthFinal),0.0, Float(width(x)-WidthFinal),Float(HeightFinal), WidthFinal, HeightFinal,1)
last + Animate(0, x.framecount()-1, "ZoomBox", x, Float(width(x)-WidthFinal),0.0, Float(width(x)-WidthFinal),Float(HeightFinal), WidthFinal, HeightFinal,1, x, 0.0,0.0, 0.0,Float(HeightFinal), WidthFinal, HeightFinal,1)



I use floats whenever i use Animate, because it reduces the rounding errors. You also need to Re-copy/Paste KenBurnsEffect() and ZoomBox() for this latest example to work. You will notice that ZoomBox is faster and has the potential for a sharper image when compared to zoom.dll, only downside is Animate messes up when zooming; that is why i use zoom.dll, it works every time. zoom.dll also has sub-pixel accuracy, which ZoomBox does not have.

Dreassica
11th May 2008, 00:02
Well, I won't need zoom because all the scenes I want to fix are strictly pans.

mikeytown2
11th May 2008, 01:47
KenBurnsEffect() Changes:

Will work with any color space if useZoomBox=2.

ZoomBox() Changes:

Added SubPixel Accuracy


Dreassica I made another change, KenBurnsEffect will now accept any colorspace if you set useZoomBox=2.

Here is your example again, with the latest changes


WidthFinal = 640
HeightFinal = 480
x = colorbars().trim(0,143).BilinearResize(1504,480).ConvertToYV12()

KenBurnsEffect(x, 0,0, 0,HeightFinal, width(x)-WidthFinal,0, width(x)-WidthFinal,HeightFinal, WidthFinal,HeightFinal, IgnoreAR=1, useZoomBox=2)
last + KenBurnsEffect(x, width(x)-WidthFinal,0, width(x)-WidthFinal,HeightFinal, 0,0, 0,HeightFinal, WidthFinal,HeightFinal, IgnoreAR=1, useZoomBox=2)




Once again Re-copy/Paste KenBurnsEffect() and ZoomBox()

Dreassica
11th May 2008, 21:13
A simple Animate(0,143,"Crop", 864,0,640,480, 0,0,640,480) seems to do the job just fine it seems. Guess I was thinking way too complicated.

Gavino
11th May 2008, 23:09
A simple Animate(0,143,"Crop", 864,0,640,480, 0,0,640,480) seems to do the job just fine it seems. Guess I was thinking way too complicated.
I had to laugh when I saw this. You mean you've managed to reduce about 300 lines of script code to just one?
Surely that's against the spirit of this thread? :)

There's a lesson here for all of us who have been following this thread - the simple approach is usually the best. To be fair, your requirements were also simpler - pure panning without zooming.

Regarding your solution, if you find the movement jerky, it can be made smoother by using the subpixel cropping feature of the resizers, instead of simple Crop, ie
Animate(0,143,"Lanczos4Resize",640,480, 864.0,0.0, 640,480, 640,480, 0.0,0.0, 640,480)
(note decimal points are necessary)

@mikeytown2: your latest version seems to allow only zoombox=2, is this intentional?

mikeytown2
12th May 2008, 03:03
I had to laugh when I saw this. You mean you've managed to reduce about 300 lines of script code to just one?
Surely that's against the spirit of this thread? :)

There's a lesson here for all of us who have been following this thread - the simple approach is usually the best. To be fair, your requirements were also simpler - pure panning without zooming.

Regarding your solution, if you find the movement jerky, it can be made smoother by using the subpixel cropping feature of the resizers, instead of simple Crop, ie
Animate(0,143,"Lanczos4Resize",640,480, 864.0,0.0, 640,480, 640,480, 0.0,0.0, 640,480)
(note decimal points are necessary)

@mikeytown2: your latest version seems to allow only zoombox=2, is this intentional?

Yes, what was requested is quite simple! The majority of the code in KBE() is to translate the requested input into something that zoom.dll can use. If you follow the processes inside the function when zoombox=2, with the above example, the only thing that is done is a crop.

Only allowing zoombox=2 was a bug, i commented out the one check that keeps doing that. I can't seem to make it work, i want to check that if they use the cubic option, zoombox should equal 1 or 0, not 2. I also thought the nop() would make this other line not execute, but it still returned.

#short circuit function, return here if only using zoombox
Return (useZoomBox==2) ? cAlt :nop()

This is now at the bottom, thus no short circuit.

As for using a resize to do the crop, i didn't realize that it can take a float as input!
http://avisynth.org/mediawiki/Resize
I'm going to try to get my ZoomBox code to use this.


KenBurnsEffect() Updated

mikeytown2
12th May 2008, 10:13
As for using a resize to do the crop, i didn't realize that it can take a float as input!
http://avisynth.org/mediawiki/Resize
I'm going to try to get my ZoomBox code to use this.

Got it!

Both Code bases have been updated. ZoomBox quality went through the roof! I highly recommend setting useZoomBox=2 when ever using KenBurnsEffect().

Gavino
12th May 2008, 10:39
Only allowing zoombox=2 was a bug, i commented out the one check that keeps doing that. I can't seem to make it work, i want to check that if they use the cubic option, zoombox should equal 1 or 0, not 2.

You want to use:
Assert(!((cubic || cubicX || cubicY) && useZoomBox==2), "...")
(By the way, I wasn't getting at you personally with my earlier (ironic) comment. Having spent a lot of time following this thread, I myself had overlooked that Dreassica's needs could be met with a simple animated Crop. Sometimes it's just impossible to see the wood for the trees!)

Gavino
12th May 2008, 19:56
Both Code bases have been updated. ZoomBox quality went through the roof!
Well done, this looks very promising.

As often happens with new releases, your latest changes have also introduced a couple of bugs:
- KBE wrong when useZoomBox=1 since using wrong clips start and end (seen more easily when in addition speed!=1, since fails completely);
- ZoomBox fails with YV12 or YUY2 since wOut is no longer defined.

There is also a minor gotcha with the new ZoomBox method: the extra parameters are not in the same place for all resizers, so have to be passed by name, which has to be taken into account when constructing the Eval string. (In fact only BicubicResize fails on this score, at least in 2.57, so it's not a showstopper).

mikeytown2
12th May 2008, 21:40
Well done, this looks very promising.

As often happens with new releases, your latest changes have also introduced a couple of bugs:
- KBE wrong when useZoomBox=1 since using wrong clips start and end (seen more easily when in addition speed!=1, since fails completely);
- ZoomBox fails with YV12 or YUY2 since wOut is no longer defined.

There is also a minor gotcha with the new ZoomBox method: the extra parameters are not in the same place for all resizers, so have to be passed by name, which has to be taken into account when constructing the Eval string. (In fact only BicubicResize fails on this score, at least in 2.57, so it's not a showstopper).

Thanks for all your testing, all the reported bugs have been fixed. I have a question, should zoombox fix the output if its not mod 2, or should i throw a warning?

Gavino
12th May 2008, 23:41
Thanks for all your testing, all the reported bugs have been fixed. I have a question, should zoombox fix the output if its not mod 2, or should i throw a warning?
You're welcome - glad to help. Most of my 'testing' was done by just eyeballing the source code. I'm a relative newbie at video processing, but after several decades developing software, I have an eagle eye when it comes to spotting coding errors!

Personally, I would go for a warning if the output size doesn't match the colorspace requirements, since if I ask for a given size I would expect to get exactly that, rather than have it corrected.

mikeytown2
13th May 2008, 00:49
You're welcome - glad to help. Most of my 'testing' was done by just eyeballing the source code. I'm a relative newbie at video processing, but after several decades developing software, I have an eagle eye when it comes to spotting coding errors!

Personally, I would go for a warning if the output size doesn't match the colorspace requirements, since if I ask for a given size I would expect to get exactly that, rather than have it corrected.

After looking at this, I decided to let the Resize function handle the width/height error.
http://avisynth.org/mediawiki/Filter_SDK/Data_storage#Part_2:_How_does_this_affect_me_as_a_user.3F


Fixed A bug with KBE() if useZoomBox=2 and its not RGB. ZoomBox updated as well.

Gavino
13th May 2008, 15:34
Fixed A bug with KBE() if useZoomBox=2 and its not RGB. ZoomBox updated as well.
Hi, Eagle Eye here again. :)
In the latest ZoomBox, this line:
BoxAR = Float(x2-x1)/Float(y2-y1)
needs to come after the part that handles the cases x2=x1 or y2=y1.

mikeytown2
13th May 2008, 19:09
Hi, Eagle Eye here again. :)
In the latest ZoomBox, this line:
BoxAR = Float(x2-x1)/Float(y2-y1)
needs to come after the part that handles the cases x2=x1 or y2=y1.

Thanks! ZoomBox updated.

mikeytown2
14th May 2008, 02:55
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 (http://avisynth.org/stickboy/ternary_eval.html) 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.

Load the image/clip into AvsP
Go Video -> Crop Editor...
Draw the box
Apply
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)
Repeat for Box #2

mikeytown2
14th May 2008, 21:44
Added an example code block near the bottom of post 2 (http://forum.doom9.org/showthread.php?p=1111789#post1111789) (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
16th May 2008, 18:45
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 (http://forum.doom9.org/showthread.php?p=1112615#post1112615)

Here is code using Effect Rotation (http://avisynth.org/vcmohan/EffectsMany/EffectRotation.html).

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
22nd May 2008, 21:51
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 (http://forum.doom9.org/showthread.php?t=137534) 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


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.
:thanks:

mikeytown2
23rd May 2008, 22:46
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)
http://img179.imageshack.us/img179/2015/pardarfarby3.th.png (http://img179.imageshack.us/my.php?image=pardarfarby3.png)

This doesn't work (Still Camera)
http://img179.imageshack.us/img179/1953/darfarxp9.th.png (http://img179.imageshack.us/my.php?image=darfarxp9.png)

Current Code Base


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.

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.

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.

Global W = 720
Global H = 720
Global Resizer = "BlackmanResize"

ImageReader("2.jpg",0,0)
ZoomBox(930, 0, 3300, 0, W, H, 1, ResizeMethod=Resizer)

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

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())

mikeytown2
24th May 2008, 07:13
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.

Gavino
24th May 2008, 22:02
"#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):

y2 = (y2==y1) ? (((x2-x1)/FinalAR + y1)/(SAR/DAR)) : y2
x2 = (x2==x1) ? (((y2-y1)*FinalAR + x1)*(SAR/DAR)) : x2

should be:

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)

mikeytown2
25th May 2008, 00:34
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 (http://forum.doom9.org/showthread.php?p=1140888#post1140888) to reflect these changes

mikeytown2
25th May 2008, 04:04
Starting to play with the Align option
Here is my test image
http://img355.imageshack.us/img355/2955/traingr4.th.jpg (http://img355.imageshack.us/my.php?image=traingr4.jpg)
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


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.

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.

tacman1123
26th May 2008, 15:34
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