View Full Version : KenBurnsEffect() - Zoom, Pan & Rotate Clip. New Version Released May 27th, 2009!
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
mikeytown2
26th May 2008, 20:44
Mike,
Have you looked at the UI and capabilities of Proshow Gold/Producer? If not, I encourage you to take a look at it, and consider using their parameters for panning, zoom and rotation. Rather than choosing starting and ending X and Y coordinates for upper left / lower right, their system pans by referencing a center point (0,0), so panning from left to right would simply be -15, 0 => +15, 0. Zoom is done by percentage, and X and Y zoom are locked together by default, but that can be "broken" so the aspect ratio can change.
I've been trying to figure out how to convert some Proshow shows to Avisynth, and your KBE is the key to the conversion.
Anyway, you posted about trying to figure out a good way to handle the parameters, a bonus of using Proshow would be that there would be a way to review the effect and get the parameter values. Proshow is great for photos and for a very easy UI to do some amazing stuff, my whole project was based on this before I realized that large videos will frequently crash it (and it's painfully slow with video). Avisynth is awesome for scripting (and amazingly fast for preview), but coding in all the numbers can be overwhelming.
Proshow has a eval/preview version, it's worth checking out as you continue to improve your KBE, just pop a photo on the timeline, double-click, then click on the Motion tab and play around with the values.
Tac
Sweet Program! Those parameters would be perfect in combination with the Align option. I would still keep the x1,y1 x2,y2 because it can take crop values directly, and it give you complete control over the "box". I think now the program would have 2 modes. Mode 1: use X1,Y1 X2,Y2 values. Mode 2: align with zoom pan. Thus the pan values don't always have to start from the center of the clip. Do you guys think going this route will be too much? Also, for this to really take off, a GUI is needed. I would make one in AutoIt (http://www.autoitscript.com/autoit3/), but i don't think AutoIt can do it. For right now, AvsP's Crop Editor, does the trick (FYI, you can use your mouse to drag the crop lines). Zooming out still isn't easy though...
After looking at Proshow (http://www.photodex.com/products/proshowgold/), there are multiple ways to do rotate (before or after zoom, xy location), so I'll keep them in mind when i finally take the plunge and add it. I'll probably use the zoom.dll rotate option, when using zoom(), and Effect Rotation with ZoomBox(). This won't be added for some time though...
In case your wondering, I will fully develop the Align option, then add in the zoom pan to it after. Going this route prevents this from being stalled from the dev being too hard. So align will make the initial box, and then use the pan zoom on that box, thus i shouldn't have to redo a lot of code, since it will be 2 different code blocks. This also will allow pan zoom in Mode 1, although it would be kinda odd to use it that way. This of course brings up the question of, when align is not at 5, should it expand into the black area, or should it avoid it all all costs? I personally think it should avoid it at all costs, thus zooming out 2000% with align=1, and the image is in the upper left corner. If it does it the other way then when zooming out 2000% the image will be a little off center.
Please keep the input coming in. The more ideas I have, the better this can be.
mikeytown2
27th May 2008, 03:26
So i had a brain storm, and decided to code. If i could get some testing of ZB, that would be great! Here is my test code block...
A = ColorBars().Crop(10, 20, -30, -400).ConvertToYV12()
B = ColorBars().invert().FlipHorizontal().Crop(10, 20, -300, -40).ConvertToYV12()
C = ColorBars().FlipVertical().Crop(10, 200, -30, -40).ConvertToYV12()
D = ColorBars().invert().FlipVertical().FlipHorizontal().Crop(100, 20, -30, -40).ConvertToYV12()
E = ImageReader("traingr4.jpg")
SplitScreener(640, 480, 4, A, B, C, D, ZoomToFill=1)
E.ZoomBoxer(640,480, "BilinearResize", DisplayAR=16.0/9.0, Align=1, zoomFactor=-1, panX=-500, panY=-20)
function SplitScreener(int Width, int Height, int Border, clip A, clip B, clip C, clip D, int "ZoomToFill", string "ResizeMethod", bool "AudioMix")
{
#Set Defaults
ResizeMethod = Default(ResizeMethod, "BilinearResize")
AudioMix = Default(AudioMix, true)
ZoomToFill = Default(ZoomToFill, -1)
#Check Inputs
Assert(ZoomToFill==1 || ZoomToFill==-1, "ZoomToFill must be 1 or -1. Input of " + String(ZoomToFill) + " doesn't work")
#Set Borders
BorderH = Border
BorderW = Border
#Set Width and Height of individual clips
NewW = Round(float(Width)/2.0 - float(BorderW)*1.5)
NewH = Round(float(Height)/2.0 - float(BorderH)*1.5)
NewAR = Float(NewW)/Float(NewH)
OutAR = Float(Width)/Float(Height)
#Process Video
A = A.ZoomBoxer(NewW, NewH, ResizeMethod, Float(A.width())/Float(A.height())*(NewAR/OutAR), ZoomToFill*(9))
A = A.AddBorders(BorderW, BorderH, 0, 0)
B = B.ZoomBoxer(NewW, NewH, ResizeMethod, Float(B.width())/Float(B.height())*(NewAR/OutAR), ZoomToFill*(7))
B = B.AddBorders(BorderW, BorderH, 0, 0)
C = C.ZoomBoxer(NewW, NewH, ResizeMethod, Float(C.width())/Float(C.height())*(NewAR/OutAR), ZoomToFill*(3))
C = C.AddBorders(BorderW, BorderH, 0, 0)
D = D.ZoomBoxer(NewW, NewH, ResizeMethod, Float(D.width())/Float(D.height())*(NewAR/OutAR), ZoomToFill*(1))
D = D.AddBorders(BorderW, BorderH, 0, 0)
#Merge Clips
X = StackHorizontal(A, B).AddBorders(0,0,BorderW,0)
Y = StackHorizontal(C, D).AddBorders(0,0,BorderW,0)
StackVertical(X, Y).AddBorders(0,0,0,BorderH).KillAudio()
#Fix Audio
LongestClip = Int(Max(Framecount(A), Framecount(B), Framecount(C), Framecount(D)))
A = (Framecount(A) <> LongestClip) ? A ++ BlankClip(A, LongestClip-Framecount(A)) : A
B = (Framecount(B) <> LongestClip) ? B ++ BlankClip(B, LongestClip-Framecount(B)) : B
C = (Framecount(C) <> LongestClip) ? C ++ BlankClip(C, LongestClip-Framecount(C)) : C
D = (Framecount(D) <> LongestClip) ? D ++ BlankClip(D, LongestClip-Framecount(D)) : D
#Mix Audio
Sound = (AudioMix) ? MergeChannels(MixAudio(ConvertToMono(A).Amplify(0.49), ConvertToMono(C).Amplify(0.49)), MixAudio(ConvertToMono(B).Amplify(0.49), ConvertToMono(D).Amplify(0.49))):
\ MergeChannels(GetLeftChannel(A), GetRightChannel(A), GetLeftChannel(B), GetRightChannel(B), GetLeftChannel(C), GetRightChannel(C), GetLeftChannel(D), GetRightChannel(D))
AudioDub(last, Sound)
}
Function ZoomBoxer(clip c, int "width", int "height", string "ResizeMethod", float "DisplayAR", int "Align", float "zoomFactor", float "panX", float "panY", int "color", int "IgnoreAR")
{
#set defaults
ResizeMethod = Default(ResizeMethod, "BilinearResize")
IgnoreAR = Default(IgnoreAR, 1)
color = Default(color, $000000)
width = Default(width, c.width())
height = Default(height, c.height())
Align = Default(Align, 0)
zoomFactor = Default(-zoomFactor, 0.0)
panX = Default(panX, 0)
panY = Default(panY, 0)
SourceAR = float(c.width())/float(c.height())
FinalAR = float(width)/float(height)
DisplayAR = Default(DisplayAR, Float(c.width())/Float(c.height()))
DisplayAR = DisplayAR == 0 ? Float(c.width())/Float(c.height()) : DisplayAR
#If Align=5 or -5 then center clip. -5: Add borders. 5: Crop.
#Display Aspect Ratio = Final Output Ratio. No Change, Show All Pixels
#Display Aspect Ratio > Final Output Ratio. Add Height or Crop Width
#Display Aspect Ratio < Final Output Ratio. Add Width or Crop Height
EvalString =
\ Align<>0 && DisplayAR==FinalAR ?
\ "x1=0" + "
x2=" + String(c.width()) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : (Align==-5 || Align==-4 || Align==-6) && DisplayAR>FinalAR ?
\ "y1=" + String(0 - ((height*DisplayAR-width)/2.0)*(c.height()/Float(width))) + "
y2=" + String(c.height() + ((height*DisplayAR-width)/2.0)*(c.height()/Float(width))) + "
x1=0" + "
x2=" + String(c.width())
\ : (Align==5 || Align==2 || Align==8) && DisplayAR>FinalAR ?
\ "x1=" + String(0 + ((height-width/DisplayAR)/2.0)*(c.width()/Float(height))) + "
x2=" + String(c.width() - ((height-width/DisplayAR)/2.0)*(c.width()/Float(height))) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : (Align==-5 || Align==-2 || Align==-8) && DisplayAR<FinalAR ?
\ "x1=" + String(0 - ((width/DisplayAR-height)/2.0)*(c.width()/Float(height))) + "
x2=" + String(c.width() + ((width/DisplayAR-height)/2.0)*(c.width()/Float(height))) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : (Align==5 || Align==4 || Align==6) && DisplayAR<FinalAR ?
\ "y1=" + String(0 + ((width-height*DisplayAR)/2.0)*(c.height()/Float(width))) + "
y2=" + String(c.height() - ((width-height*DisplayAR)/2.0)*(c.height()/Float(width))) + "
x1=0" + "
x2=" + String(c.width())
\ : (Align==-1 || Align==-2 || Align==-3) && DisplayAR>FinalAR ?
\ "y1=" + String(0) + "
y2=" + String(c.height() + ((height*DisplayAR-width)/1.0)*(c.height()/Float(width))) + "
x1=0" + "
x2=" + String(c.width())
\ : (Align==-1 || Align==-4 || Align==-7) && DisplayAR<FinalAR ?
\ "x1=" + String(0) + "
x2=" + String(c.width() + ((width/DisplayAR-height)/1.0)*(c.width()/Float(height))) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : (Align==-9 || Align==-8 || Align==-7) && DisplayAR>FinalAR ?
\ "y1=" + String(0 - ((height*DisplayAR-width)/1.0)*(c.height()/Float(width))) + "
y2=" + String(c.height()) + "
x1=0" + "
x2=" + String(c.width())
\ : (Align==-9 || Align==-6 || Align==-3) && DisplayAR<FinalAR ?
\ "x1=" + String(0 - ((width/DisplayAR-height)/1.0)*(c.width()/Float(height))) + "
x2=" + String(c.width()) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : (Align==2 || Align==1 || Align==3) && DisplayAR<FinalAR ?
\ "y1=" + String(0) + "
y2=" + String(c.height() - ((width-height*DisplayAR)/1.0)*(c.height()/Float(width))) + "
x1=0" + "
x2=" + String(c.width())
\ : (Align==8 || Align==7 || Align==9) && DisplayAR<FinalAR ?
\ "y1=" + String(0 + ((width-height*DisplayAR)/1.0)*(c.height()/Float(width))) + "
y2=" + String(c.height()) + "
x1=0" + "
x2=" + String(c.width())
\ : (Align==4 || Align==1 || Align==7) && DisplayAR>FinalAR ?
\ "x1=" + String(0) + "
x2=" + String(c.width() - ((height-width/DisplayAR)/1.0)*(c.width()/Float(height))) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : (Align==6 || Align==3 || Align==9) && DisplayAR>FinalAR ?
\ "x1=" + String(0 + ((height-width/DisplayAR)/1.0)*(c.width()/Float(height))) + "
x2=" + String(c.width()) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : ""
Eval(EvalString)
#Take Crop Like Input
x2 = x2<=x1 && x2 < 0 ? c.width() + x2 : x2
y2 = y2<=y1 && y2 < 0 ? c.height() + y2 : y2
#Check if x2 or y2 needs to be calculated
Assert( ((x2==x1) && (y2==y1))==False, "x2 [" + String(x2) + "] or y2 [" + String(y2) + "] needs a value that is different from x1 [" + String(x1) + "] or y1 [" + String(y1) + "]")
y2 = (y2==y1) ? (((x2-x1)/FinalAR)/(SourceAR/DisplayAR) + y1) : y2
x2 = (x2==x1) ? (((y2-y1)*FinalAR)*(SourceAR/DisplayAR) + x1) : x2
#Calc Zoom Factor
Align = abs(Align)
x1 = Align==0 || Align==5 || Align==2 || Align==3 || Align==8 || Align==9 ? x1-(x2-x1)*zoomFactor/4.0 : Align==6 ? x1-((x2-x1)*zoomFactor)/2.4 : x1
y1 = Align==0 || Align==5 || Align==4 || Align==6 || Align==7 || Align==9 ? y1-(y2-y1)*zoomFactor/4.0 : Align==8 ? y1-((y2-y1)*zoomFactor)/2.4 : y1
x2 = Align==0 || Align==5 || Align==1 || Align==2 || Align==7 || Align==8 ? x2+(x2-x1)*zoomFactor/4.0 : Align==4 ? x2+((x2-x1)*zoomFactor)/2.4 : x2
y2 = Align==0 || Align==5 || Align==1 || Align==3 || Align==4 || Align==6 ? y2+(y2-y1)*zoomFactor/4.0 : Align==2 ? y2+((y2-y1)*zoomFactor)/2.4 : y2
#Calc Pan Factor
x1 = x1+panX
y1 = y1+panY
x2 = x2+panX
y2 = y2+panY
BoxAR = Float(x2-x1)/Float(y2-y1)
#Check For Any Unreasonable Inputs
Assert(x1<x2, "ZoomBox: x1[" + String(x1) + "] point larger then x2 Point[" + String(x2) + "]")
Assert(y1<y2, "ZoomBox: y1[" + String(y1) + "] point larger then y2 Point[" + String(y2) + "]")
Assert(IgnoreAR>0 || BoxAR == FinalAR, "ZoomBox: Box Aspect Ratio [" + String(BoxAR) + "] does not equal clip output Aspect Ratio [" + string(FinalAR) + "]")
#Pad clip so resizer interpolates from border when zooming out. 64 for spline64
#Conditional Borders... only add if it's going to be used.
borderSize = 64
borderLeft = x1 < 0 ? borderSize : 0
borderTop = y1 < 0 ? borderSize : 0
borderRight = x2 > c.width() ? borderSize : 0
borderBottom = y2 > c.height() ? borderSize : 0
c = c.AddBorders(borderLeft,borderTop,borderRight,borderBottom,color)
#Do it
c = Eval(ResizeMethod + "(c, " + String(Round(width)) + ", " + String(Round(height)) + ", src_left=" + String(x1+borderLeft) + ", src_top=" + String(y1+borderTop) + ", src_width=" + String(x2-x1) + ", src_height=" + String(y2-y1) + ")")
c
Subtitle(String(x1) + ", " + String(y1) + " " + String(x2) + ", " + String(y2) + " BoxAR " + String(BoxAR) + " " + String())
}
Please let me know that it works correctly. The AR is slightly off with Align 2,4,6,8 with the usage of zoomFactor. There has to be a better way to code the zoom. Right now 0 is no zoom. Negative values zoom out, positive values zoom in. BTW zoomFactor=2 is really zoomed in, and it will throw an error if its too much. I also made the adding of borders before the resize smarter, picture looks better on the edge now. If anyone has a better way to code a zoom I'm all ears! Also should the pan go before or after the zoom?
Gavino
27th May 2008, 14:28
So i had a brain storm, and decided to code. If i could get some testing of ZB, that would be great! Here is my test code block...
Please let me know that it works correctly.
I tried using your example exactly as given via
A = ColorBars().Crop(10, 20, -30, -400).ConvertToYV12()
B = ColorBars().invert().FlipHorizontal().Crop(10, 20, -300, -40).ConvertToYV12()
C = ColorBars().FlipVertical().Crop(10, 200, -30, -40).ConvertToYV12()
D = ColorBars().invert().FlipVertical().FlipHorizontal().Crop(100, 20, -30, -40).ConvertToYV12()
SplitScreener(640, 480, 4, A, B, C, D, ZoomToFill=1)
and it failed due to this line in ZoomBoxer:
zoomFactor = Default(-zoomFactor, 0.0)
Is the minus sign simply a typo? Or perhaps you meant
zoomFactor = -Default(zoomFactor, 0.0)
Either way, I found the example still won't work because of YV12 mod4 width restrictions.
The AR is slightly off with Align 2,4,6,8 with the usage of zoomFactor. There has to be a better way to code the zoom. Right now 0 is no zoom. Negative values zoom out, positive values zoom in. BTW zoomFactor=2 is really zoomed in, and it will throw an error if its too much.
To me, it would be more natural if zoomFactor was a simple scale factor, rather than (as I understand it) the proportion to add or subtract. In other words, zoomFactor=1 would mean no zoom. That way only positive values would be meaningful.
tacman1123
27th May 2008, 14:31
I'd also prefer to see something like zoom=100 mean that there was no zoom, rather than having negative zoom go in and positive zoom go out. It fits into the common percentage model -- show this picture at 25%, or 200%.
Gavino
27th May 2008, 20:59
I've ditched SplitScreener from your example and used ZoomBoxer directly with my own test image. It seems to work fine for the simple cases I tried. However, I have a few questions and comments.
What is the meaning of align=0 (the default value)? In the case align=0 and the ARs match (DisplayAR=FinalAR), x1 etc are undefined as there is no code to handle this combination.
Are panX and panY in pixel units of the input clip or the output clip? It seems to be the former, but how are they meant to interact with zoom?
I'm still confused about the intended meaning of zoomFactor - I think this is partly because there is already an implicit zoom happening if the input and output clips differ in size. Can you explain this further please?
In any case (whatever the answer to the above), the code to recalculate x1 (etc) based on zoomFactor looks wrong to me because x2 and y2 are calculated using the possibly already changed values of x1 and y1 (and where on earth does the value 2.4 come from?)
mikeytown2
27th May 2008, 21:45
I've ditched SplitScreener from your example and used ZoomBoxer directly with my own test image.
My guess on why it isn't working is that you are using Avisynth 2.57. I'm currently using 2.58. Changelog (http://avisynth.org/mediawiki/Changelist_25#Changes) documents this "Relax YV12 resizer width restriction, now mod 2 was mod 4."
It seems to work fine for the simple cases I tried. However, I have a few questions and comments.
What is the meaning of align=0 (the default value)? In the case align=0 and the ARs match (DisplayAR=FinalAR), x1 etc are undefined as there is no code to handle this combination.
If Align is not specified, then the float inputs of x1,y1,x2,y2 will be used. That is what Align=0 is for. I took out x1,y1,x2,y2 so i could test align by it's self. The final version will have what i call Mode 1: x1,y1,x2,y2 and Mode 2: Align.
Are panX and panY in pixel units of the input clip or the output clip? It seems to be the former, but how are they meant to interact with zoom?
You are correct, panX/panY are in pixel units of the input clip. Pan could be used before zoom, or after zoom. For large values of zoom, I think it will make a difference. Now that i think about it, pan should go in before zoom, that way it is independent of zoom.
I'm still confused about the intended meaning of zoomFactor - I think this is partly because there is already an implicit zoom happening if the input and output clips differ in size. Can you explain this further please?
zoomFactor is very useful when using align. If it wasn't for align, zoomFactor is quite useless. In the end ZB() will either take x1,y1,x2,y2 or Align. When only using Align, it would be impossible to zoom in/out to your desired level. Tac offered a better way of doing things, when compared to my orginal idea (http://forum.doom9.org/showthread.php?p=1140854#post1140854) on how to use Align.
In any case (whatever the answer to the above), the code to recalculate x1 (etc) based on zoomFactor looks wrong to me
because x2 and y2 are calculated using the possibly already changed values of x1 and y1 (and where on earth does the value 2.4 come from?)
Thank you for pointing that x2 and y2 are calculated using the already changed values of x1 and y1. I didn't see it! The 2.4 was originally 2, but through trial and error, 2.4 gave better results then 2. 2 is half of 4, so that is where it comes from.
I'm looking on the web for code on how to do the zoom. Right now mine is linear, which is why it messes up when zooming in too much. I think it needs to be shaped like a Logarithm (http://en.wikipedia.org/wiki/Logarithm), thus 100*.01=1, and it can never reach 0 when zooming out. I just need to figure out how to limit the zooming in so that the zoom point doesn't cross it's self. I'll post some new code in an hr or 2... but if you can point me to some code where zoom of 100% is unchanged and 200% is twice as much, ect... i would appreciate it.
Gavino
27th May 2008, 22:27
My guess on why it isn't working is that you are using Avisynth 2.57.
Yes, you are correct.
zoomFactor is very useful when using align. If it wasn't for align, zoomFactor is quite useless. In the end ZB() will either take x1,y1,x2,y2 or Align. When only using Align, it would be impossible to zoom in/out to your desired level.
Yes, I see, but I was looking for a more exact specification, explaining how align interacts with zoom (I guess the alignment point is the zoom center?) and what it means to say zoomFactor=x when the input and output clips are in the ratio y.
Thank you for pointing that x2 and y2 are calculated using the already changed values of x1 and y1. I didn't see it! The 2.4 was originally 2, but through trial and error, 2.4 gave better results then 2.
That's probably because of the error I pointed out. :)
I'm looking on the web for code on how to do the zoom. Right now mine is linear, which is why it messes up when zooming in too much. I think it needs to be shaped like a Logarithm (http://en.wikipedia.org/wiki/Logarithm), thus 100*.01=1, and it can never reach 0 when zooming out. I just need to figure out how to limit the zooming in so that the zoom point doesn't cross it's self. I'll post some new code in an hr or 2... but if you can point me to some code where zoom of 100% is unchanged and 200% is twice as much, ect... i would appreciate it.
I think a simple linear approach is easier to understand. The basis would be that to scale by a factor k about the point (x0, y0), the point (x, y) is mapped to the point (x0+k*(x-x0), y0+k*(y-y0). (If I understood exactly how you meant zoom to operate, I'd write the code for you).
For limiting, you just have to add a validation check that the requested zoom (scale) factor is > 0.
mikeytown2
28th May 2008, 01:05
I fixed the bug in zoomFactor with my current logic (Thanks Gavino!) I also gave Log() a shot... it's sorta close. Keep in mind that when zooming out, x1,y1 needs to go negative and x2,y2 need to go positive. Zooming in, x1,y1 gets larger, x2,y2 gets smaller.
http://img529.imageshack.us/img529/3493/zoomexamplepe1.th.jpg (http://img529.imageshack.us/my.php?image=zoomexamplepe1.jpg)
After checking in GIMP, this is 200%. I would like it to behave like this, how GIMP does.
If you could code a better way then what i got, shouldn't be that hard, lol, i would greatly appreciate it!
A = ColorBars().Crop(10, 20, -30, -400).ConvertToYV12()
B = ColorBars().invert().FlipHorizontal().Crop(10, 20, -300, -40).ConvertToYV12()
C = ColorBars().FlipVertical().Crop(10, 200, -30, -40).ConvertToYV12()
D = ColorBars().invert().FlipVertical().FlipHorizontal().Crop(100, 20, -30, -40).ConvertToYV12()
E = ImageReader("testp2cz4.png",0,0)
E = E.ConvertToYV12().AssumeFPS("ntsc_video")
W = 640
H = 480
DAR = 0 #16.0/9.0
Resize = "BilinearResize"
#SplitScreener(640, 480, 8, A, B, C, D, ZoomToFill=1).Trim(0,4).KillAudio()
E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=50, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-2, zoomFactor=50, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-3, zoomFactor=50, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-4, zoomFactor=50, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-5, zoomFactor=50, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-6, zoomFactor=50, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-7, zoomFactor=50, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-8, zoomFactor=50, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-9, zoomFactor=50, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=100, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=200, panX=0, panY=0).Subtitle("Incorrect at 200%", y=200)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=272, panX=0, panY=0).Subtitle("Correct for 200%", y=200)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=400, panX=0, panY=0).Subtitle("Incorrect at 400%", y=200)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=448, panX=0, panY=0).Subtitle("Correct for 400%", y=200)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=576, panX=0, panY=0).Subtitle("Correct for 800%", y=200)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=100, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=75, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=50, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=25, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=10, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=1, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=.1, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=.01, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=.001, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=.0001, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=.00001, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=.0000000000000000000000001, panX=0, panY=0)
Function ZoomBoxer(clip c, int "width", int "height", string "ResizeMethod", float "DisplayAR", int "Align", float "zoomFactor", float "panX", float "panY", int "color", int "IgnoreAR")
{
#set defaults
ResizeMethod = Default(ResizeMethod, "BilinearResize")
IgnoreAR = Default(IgnoreAR, 1)
color = Default(color, $000000)
width = Default(width, c.width())
height = Default(height, c.height())
Align = Default(Align, 0)
zoomFactor = -Log(Default(zoomFactor, 100.0)*0.01)
panX = Default(panX, 0)
panY = Default(panY, 0)
SourceAR = float(c.width())/float(c.height())
FinalAR = float(width)/float(height)
DisplayAR = Default(DisplayAR, Float(c.width())/Float(c.height()))
DisplayAR = DisplayAR == 0 ? Float(c.width())/Float(c.height()) : DisplayAR
#If Align=5 or -5 then center clip. -5: Add borders. 5: Crop.
#Display Aspect Ratio = Final Output Ratio. No Change, Show All Pixels
#Display Aspect Ratio > Final Output Ratio. Add Height or Crop Width
#Display Aspect Ratio < Final Output Ratio. Add Width or Crop Height
EvalString =
\ Align<>0 && DisplayAR==FinalAR ?
\ "x1=0" + "
x2=" + String(c.width()) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : (Align==-5 || Align==-4 || Align==-6) && DisplayAR>FinalAR ?
\ "y1=" + String(0 - ((height*DisplayAR-width)/2.0)*(c.height()/Float(width))) + "
y2=" + String(c.height() + ((height*DisplayAR-width)/2.0)*(c.height()/Float(width))) + "
x1=0" + "
x2=" + String(c.width())
\ : (Align==5 || Align==2 || Align==8) && DisplayAR>FinalAR ?
\ "x1=" + String(0 + ((height-width/DisplayAR)/2.0)*(c.width()/Float(height))) + "
x2=" + String(c.width() - ((height-width/DisplayAR)/2.0)*(c.width()/Float(height))) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : (Align==-5 || Align==-2 || Align==-8) && DisplayAR<FinalAR ?
\ "x1=" + String(0 - ((width/DisplayAR-height)/2.0)*(c.width()/Float(height))) + "
x2=" + String(c.width() + ((width/DisplayAR-height)/2.0)*(c.width()/Float(height))) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : (Align==5 || Align==4 || Align==6) && DisplayAR<FinalAR ?
\ "y1=" + String(0 + ((width-height*DisplayAR)/2.0)*(c.height()/Float(width))) + "
y2=" + String(c.height() - ((width-height*DisplayAR)/2.0)*(c.height()/Float(width))) + "
x1=0" + "
x2=" + String(c.width())
\ : (Align==-1 || Align==-2 || Align==-3) && DisplayAR>FinalAR ?
\ "y1=" + String(0) + "
y2=" + String(c.height() + ((height*DisplayAR-width)/1.0)*(c.height()/Float(width))) + "
x1=0" + "
x2=" + String(c.width())
\ : (Align==-1 || Align==-4 || Align==-7) && DisplayAR<FinalAR ?
\ "x1=" + String(0) + "
x2=" + String(c.width() + ((width/DisplayAR-height)/1.0)*(c.width()/Float(height))) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : (Align==-9 || Align==-8 || Align==-7) && DisplayAR>FinalAR ?
\ "y1=" + String(0 - ((height*DisplayAR-width)/1.0)*(c.height()/Float(width))) + "
y2=" + String(c.height()) + "
x1=0" + "
x2=" + String(c.width())
\ : (Align==-9 || Align==-6 || Align==-3) && DisplayAR<FinalAR ?
\ "x1=" + String(0 - ((width/DisplayAR-height)/1.0)*(c.width()/Float(height))) + "
x2=" + String(c.width()) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : (Align==2 || Align==1 || Align==3) && DisplayAR<FinalAR ?
\ "y1=" + String(0) + "
y2=" + String(c.height() - ((width-height*DisplayAR)/1.0)*(c.height()/Float(width))) + "
x1=0" + "
x2=" + String(c.width())
\ : (Align==8 || Align==7 || Align==9) && DisplayAR<FinalAR ?
\ "y1=" + String(0 + ((width-height*DisplayAR)/1.0)*(c.height()/Float(width))) + "
y2=" + String(c.height()) + "
x1=0" + "
x2=" + String(c.width())
\ : (Align==4 || Align==1 || Align==7) && DisplayAR>FinalAR ?
\ "x1=" + String(0) + "
x2=" + String(c.width() - ((height-width/DisplayAR)/1.0)*(c.width()/Float(height))) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : (Align==6 || Align==3 || Align==9) && DisplayAR>FinalAR ?
\ "x1=" + String(0 + ((height-width/DisplayAR)/1.0)*(c.width()/Float(height))) + "
x2=" + String(c.width()) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : ""
Eval(EvalString)
#Take Crop Like Input
x2 = x2<=x1 && x2 < 0 ? c.width() + x2 : x2
y2 = y2<=y1 && y2 < 0 ? c.height() + y2 : y2
#Check if x2 or y2 needs to be calculated
Assert( ((x2==x1) && (y2==y1))==False, "x2 [" + String(x2) + "] or y2 [" + String(y2) + "] needs a value that is different from x1 [" + String(x1) + "] or y1 [" + String(y1) + "]")
y2 = (y2==y1) ? (((x2-x1)/FinalAR)/(SourceAR/DisplayAR) + y1) : y2
x2 = (x2==x1) ? (((y2-y1)*FinalAR)*(SourceAR/DisplayAR) + x1) : x2
SubString = "Align=" + String(Align) + " zoomFactor=" + String(zoomFactor) + " panX=" + String(panX) + " panY=" + String(panY)
#Calc Pan Factor
x1 = x1+panX
y1 = y1+panY
x2 = x2+panX
y2 = y2+panY
#Calc Zoom Factor
Align = abs(Align)
x1tmp = Align==0 || Align==5 || Align==2 || Align==8 ? x1-(x2-x1)*zoomFactor/4.0 : Align==3 || Align==6 || Align==9 ? x1-((x2-x1)*zoomFactor)/2.0 : x1
y1tmp = Align==0 || Align==5 || Align==4 || Align==6 ? y1-(y2-y1)*zoomFactor/4.0 : Align==7 || Align==8 || Align==9 ? y1-((y2-y1)*zoomFactor)/2.0 : y1
x2 = Align==0 || Align==5 || Align==2 || Align==8 ? x2+(x2-x1)*zoomFactor/4.0 : Align==1 || Align==4 || Align==7 ? x2+((x2-x1)*zoomFactor)/2.0 : x2
y2 = Align==0 || Align==5 || Align==4 || Align==6 ? y2+(y2-y1)*zoomFactor/4.0 : Align==1 || Align==2 || Align==3 ? y2+((y2-y1)*zoomFactor)/2.0 : y2
x1 = x1tmp
y1 = y1tmp
BoxAR = Float(x2-x1)/Float(y2-y1)
#Check For Any Unreasonable Inputs
Assert(x1<x2, "ZoomBox: x1[" + String(x1) + "] point larger then x2 Point[" + String(x2) + "]")
Assert(y1<y2, "ZoomBox: y1[" + String(y1) + "] point larger then y2 Point[" + String(y2) + "]")
Assert(IgnoreAR>0 || BoxAR == FinalAR, "ZoomBox: Box Aspect Ratio [" + String(BoxAR) + "] does not equal clip output Aspect Ratio [" + string(FinalAR) + "]")
#Pad clip so resizer interpolates from border when zooming out. 64 for spline64
#Conditional Borders... only add if it's going to be used.
borderSize = 64
borderLeft = x1 < 0 ? borderSize : 0
borderTop = y1 < 0 ? borderSize : 0
borderRight = x2 > c.width() ? borderSize : 0
borderBottom = y2 > c.height() ? borderSize : 0
c = c.AddBorders(borderLeft,borderTop,borderRight,borderBottom,color)
#Do it
c = Eval(ResizeMethod + "(c, " + String(Round(width)) + ", " + String(Round(height)) + ", src_left=" + String(x1+borderLeft) + ", src_top=" + String(y1+borderTop) + ", src_width=" + String(x2-x1) + ", src_height=" + String(y2-y1) + ")")
c
Subtitle(String(x1) + ", " + String(y1) + " " + String(x2) + ", " + String(y2) + " BoxAR " + String(BoxAR) + " " + String())
Subtitle(SubString, y=100)
}
function SplitScreener(int Width, int Height, int Border, clip A, clip B, clip C, clip D, int "ZoomToFill", string "ResizeMethod", bool "AudioMix")
{
#Set Defaults
ResizeMethod = Default(ResizeMethod, "BilinearResize")
AudioMix = Default(AudioMix, true)
ZoomToFill = Default(ZoomToFill, -1)
#Check Inputs
Assert(ZoomToFill==1 || ZoomToFill==-1, "ZoomToFill must be 1 or -1. Input of " + String(ZoomToFill) + " doesn't work")
#Set Borders
BorderH = Border
BorderW = Border
#Set Width and Height of individual clips
NewW = Round(float(Width)/2.0 - float(BorderW)*1.5)
NewH = Round(float(Height)/2.0 - float(BorderH)*1.5)
NewAR = Float(NewW)/Float(NewH)
OutAR = Float(Width)/Float(Height)
#Process Video
A = A.ZoomBoxer(NewW, NewH, ResizeMethod, Float(A.width())/Float(A.height())*(NewAR/OutAR), ZoomToFill*(9))
A = A.AddBorders(BorderW, BorderH, 0, 0)
B = B.ZoomBoxer(NewW, NewH, ResizeMethod, Float(B.width())/Float(B.height())*(NewAR/OutAR), ZoomToFill*(7))
B = B.AddBorders(BorderW, BorderH, 0, 0)
C = C.ZoomBoxer(NewW, NewH, ResizeMethod, Float(C.width())/Float(C.height())*(NewAR/OutAR), ZoomToFill*(3))
C = C.AddBorders(BorderW, BorderH, 0, 0)
D = D.ZoomBoxer(NewW, NewH, ResizeMethod, Float(D.width())/Float(D.height())*(NewAR/OutAR), ZoomToFill*(1))
D = D.AddBorders(BorderW, BorderH, 0, 0)
#Merge Clips
X = StackHorizontal(A, B).AddBorders(0,0,BorderW,0)
Y = StackHorizontal(C, D).AddBorders(0,0,BorderW,0)
StackVertical(X, Y).AddBorders(0,0,0,BorderH).KillAudio()
#Fix Audio
LongestClip = Int(Max(Framecount(A), Framecount(B), Framecount(C), Framecount(D)))
A = (Framecount(A) <> LongestClip) ? A ++ BlankClip(A, LongestClip-Framecount(A)) : A
B = (Framecount(B) <> LongestClip) ? B ++ BlankClip(B, LongestClip-Framecount(B)) : B
C = (Framecount(C) <> LongestClip) ? C ++ BlankClip(C, LongestClip-Framecount(C)) : C
D = (Framecount(D) <> LongestClip) ? D ++ BlankClip(D, LongestClip-Framecount(D)) : D
#Mix Audio
Sound = (AudioMix) ? MergeChannels(MixAudio(ConvertToMono(A).Amplify(0.49), ConvertToMono(C).Amplify(0.49)), MixAudio(ConvertToMono(B).Amplify(0.49), ConvertToMono(D).Amplify(0.49))):
\ MergeChannels(GetLeftChannel(A), GetRightChannel(A), GetLeftChannel(B), GetRightChannel(B), GetLeftChannel(C), GetRightChannel(C), GetLeftChannel(D), GetRightChannel(D))
AudioDub(last, Sound)
}
Using example pic from 2nd post
http://img136.imageshack.us/img136/3356/testp2cz4.th.png (http://img136.imageshack.us/my.php?image=testp2cz4.png)
mikeytown2
28th May 2008, 08:50
I got this really close to being done... zoomFactor works correctly at align=5,6,8,9. when using zoomfactor it will not "cross over" on the zoom-in anymore; any positive number you give it, it should be able to use.
A = ColorBars().Crop(10, 20, -30, -400).ConvertToYV12()
B = ColorBars().invert().FlipHorizontal().Crop(10, 20, -300, -40).ConvertToYV12()
C = ColorBars().FlipVertical().Crop(10, 200, -30, -40).ConvertToYV12()
D = ColorBars().invert().FlipVertical().FlipHorizontal().Crop(100, 20, -30, -40).ConvertToYV12()
E = ImageReader("testp2cz4.png",0,0)
E = E.ConvertToYV12().AssumeFPS("ntsc_video")
Global W = 640
Global H = 480
Global DAR = 0 #16.0/9.0
Global Resize = "BilinearResize"
SplitScreener(W, H, 8, A, B, C, D, ZoomToFill=1).Trim(0,-1).KillAudio()
last + SplitScreener(W, H, 8, A, B, C, D, ZoomToFill=-1).Trim(0,-1).KillAudio()
last + TestC(E)
#Try different image, it fails...
E = ImageReader("traingr4.jpg",0,0)
E = E.ConvertToYV12().AssumeFPS("ntsc_video")
Global DAR = 16.0/9.0
last + TestC(E)
Return Last
Function TestC(Clip E)
{
TestA(E,-1)
last + TestA(E,-2)
last + TestA(E,-3)
last + TestA(E,-4)
last + TestA(E,-5)
last + TestA(E,5)
last + TestA(E,-6)
last + TestA(E,-7)
last + TestA(E,-8)
last + TestA(E,-9)
last + TestB(E, 25)
last + TestB(E, 50)
last + TestB(E, 75)
}
Function TestA(clip E, int al)
{
E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=100, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=75, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=50, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=25, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=10, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=5, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=2, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=75, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=100, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=200, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=400, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=600, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=800, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=2000, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=20000, panX=0, panY=0)
}
Function TestB(clip E, int zf)
{
E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-5, zoomFactor=zf, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=zf, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-3, zoomFactor=zf, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-7, zoomFactor=zf, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-9, zoomFactor=zf, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-2, zoomFactor=zf, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-4, zoomFactor=zf, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-6, zoomFactor=zf, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-8, zoomFactor=zf, panX=0, panY=0)
}
Function ZoomBoxer(clip c, int "width", int "height", string "ResizeMethod", float "DisplayAR", int "Align", float "zoomFactor", float "panX", float "panY", int "color", int "IgnoreAR")
{
#set defaults
ResizeMethod = Default(ResizeMethod, "BilinearResize")
IgnoreAR = Default(IgnoreAR, 1)
color = Default(color, $000000)
width = Default(width, c.width())
height = Default(height, c.height())
Align = Default(Align, 0)
zoomFactor = Default(zoomFactor, 100.0)
zoomFactor = (zoomFactor/100.0)
#zoomFactor = -(Log(zoomFactor*0.01)/Log(4))
panX = Default(panX, 0)
panY = Default(panY, 0)
SourceAR = float(c.width())/float(c.height())
FinalAR = float(width)/float(height)
DisplayAR = Default(DisplayAR, Float(c.width())/Float(c.height()))
DisplayAR = DisplayAR == 0 ? Float(c.width())/Float(c.height()) : DisplayAR
#If Align=5 or -5 then center clip. -5: Add borders. 5: Crop.
#Display Aspect Ratio = Final Output Ratio. No Change, Show All Pixels
#Display Aspect Ratio > Final Output Ratio. Add Height or Crop Width
#Display Aspect Ratio < Final Output Ratio. Add Width or Crop Height
EvalString =
\ Align<>0 && DisplayAR==FinalAR ?
\ "x1=0" + "
x2=" + String(c.width()) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : (Align==-5 || Align==-4 || Align==-6) && DisplayAR>FinalAR ?
\ "y1=" + String(0 - ((height*DisplayAR-width)/2.0)*(c.height()/Float(width))) + "
y2=" + String(c.height() + ((height*DisplayAR-width)/2.0)*(c.height()/Float(width))) + "
x1=0" + "
x2=" + String(c.width())
\ : (Align==5 || Align==2 || Align==8) && DisplayAR>FinalAR ?
\ "x1=" + String(0 + ((height-width/DisplayAR)/2.0)*(c.width()/Float(height))) + "
x2=" + String(c.width() - ((height-width/DisplayAR)/2.0)*(c.width()/Float(height))) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : (Align==-5 || Align==-2 || Align==-8) && DisplayAR<FinalAR ?
\ "x1=" + String(0 - ((width/DisplayAR-height)/2.0)*(c.width()/Float(height))) + "
x2=" + String(c.width() + ((width/DisplayAR-height)/2.0)*(c.width()/Float(height))) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : (Align==5 || Align==4 || Align==6) && DisplayAR<FinalAR ?
\ "y1=" + String(0 + ((width-height*DisplayAR)/2.0)*(c.height()/Float(width))) + "
y2=" + String(c.height() - ((width-height*DisplayAR)/2.0)*(c.height()/Float(width))) + "
x1=0" + "
x2=" + String(c.width())
\ : (Align==-1 || Align==-2 || Align==-3) && DisplayAR>FinalAR ?
\ "y1=" + String(0) + "
y2=" + String(c.height() + ((height*DisplayAR-width)/1.0)*(c.height()/Float(width))) + "
x1=0" + "
x2=" + String(c.width())
\ : (Align==-1 || Align==-4 || Align==-7) && DisplayAR<FinalAR ?
\ "x1=" + String(0) + "
x2=" + String(c.width() + ((width/DisplayAR-height)/1.0)*(c.width()/Float(height))) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : (Align==-9 || Align==-8 || Align==-7) && DisplayAR>FinalAR ?
\ "y1=" + String(0 - ((height*DisplayAR-width)/1.0)*(c.height()/Float(width))) + "
y2=" + String(c.height()) + "
x1=0" + "
x2=" + String(c.width())
\ : (Align==-9 || Align==-6 || Align==-3) && DisplayAR<FinalAR ?
\ "x1=" + String(0 - ((width/DisplayAR-height)/1.0)*(c.width()/Float(height))) + "
x2=" + String(c.width()) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : (Align==2 || Align==1 || Align==3) && DisplayAR<FinalAR ?
\ "y1=" + String(0) + "
y2=" + String(c.height() - ((width-height*DisplayAR)/1.0)*(c.height()/Float(width))) + "
x1=0" + "
x2=" + String(c.width())
\ : (Align==8 || Align==7 || Align==9) && DisplayAR<FinalAR ?
\ "y1=" + String(0 + ((width-height*DisplayAR)/1.0)*(c.height()/Float(width))) + "
y2=" + String(c.height()) + "
x1=0" + "
x2=" + String(c.width())
\ : (Align==4 || Align==1 || Align==7) && DisplayAR>FinalAR ?
\ "x1=" + String(0) + "
x2=" + String(c.width() - ((height-width/DisplayAR)/1.0)*(c.width()/Float(height))) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : (Align==6 || Align==3 || Align==9) && DisplayAR>FinalAR ?
\ "x1=" + String(0 + ((height-width/DisplayAR)/1.0)*(c.width()/Float(height))) + "
x2=" + String(c.width()) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : ""
Eval(EvalString)
#Take Crop Like Input
x2 = x2<=x1 && x2 < 0 ? c.width() + x2 : x2
y2 = y2<=y1 && y2 < 0 ? c.height() + y2 : y2
#Check if x2 or y2 needs to be calculated
Assert( ((x2==x1) && (y2==y1))==False, "x2 [" + String(x2) + "] or y2 [" + String(y2) + "] needs a value that is different from x1 [" + String(x1) + "] or y1 [" + String(y1) + "]")
y2 = (y2==y1) ? (((x2-x1)/FinalAR)/(SourceAR/DisplayAR) + y1) : y2
x2 = (x2==x1) ? (((y2-y1)*FinalAR)*(SourceAR/DisplayAR) + x1) : x2
SubString = "Align=" + String(Align) + " zoomFactor=" + String(zoomFactor*100) + " panX=" + String(panX) + " panY=" + String(panY)
#Calc Pan Factor
x1 = x1+panX
y1 = y1+panY
x2 = x2+panX
y2 = y2+panY
#Calc Zoom Factor
BoxAR = Float(x2-x1)/Float(y2-y1)
CenterX = (x2-x1)/2.0
CenterY = (y2-y1)/2.0
CenterY = (Align<0 && DisplayAR>FinalAR)? CenterY*(FinalAR/DisplayAR): (Align>0 && DisplayAR<FinalAR)? CenterY*(FinalAR/DisplayAR): CenterY
CenterX = (Align>0 && DisplayAR>FinalAR)? CenterX/(FinalAR/DisplayAR): (Align<0 && DisplayAR<FinalAR)? CenterX/(FinalAR/DisplayAR): CenterX
Align = abs(Align)
sY = " CenterY: " + String(CenterY) + " y2: " + String(y2) + " y1: " + String(y1)
sX = " CenterX: " + String(CenterX) + " x2: " + String(x2) + " x1: " + String(x1)
x1 = (Align==0 || Align==5 || Align==2 || Align==8) && zoomFactor<>1 ? CenterX-((CenterX-x1)/(zoomFactor)) : (Align==3 || Align==6 || Align==9) && zoomFactor<>1 ? CenterX*2.0-((CenterX*2.0-x1)/zoomFactor) : x1
y1 = (Align==0 || Align==5 || Align==4 || Align==6) && zoomFactor<>1 ? CenterY-((CenterY-y1)/(zoomFactor)) : (Align==7 || Align==8 || Align==9) && zoomFactor<>1 ? CenterY*2.0-((CenterY*2.0-y1)/zoomFactor) : y1
x2 = (Align==0 || Align==5 || Align==2 || Align==8) && zoomFactor<>1 ? CenterX+((x2-CenterX)/(zoomFactor)) : (Align==7 || Align==4 || Align==1) && zoomFactor<>1 ? CenterX+((x2-CenterX)/zoomFactor) : x2
y2 = (Align==0 || Align==5 || Align==4 || Align==6) && zoomFactor<>1 ? CenterY+((y2-CenterY)/(zoomFactor)) : (Align==3 || Align==2 || Align==1) && zoomFactor<>1 ? CenterY+((y2-CenterY)/zoomFactor) : y2
BoxAR = Float(x2-x1)/Float(y2-y1)
#Check For Any Unreasonable Inputs
Assert(x1<x2, "ZoomBox: x1[" + String(x1) + "] point larger then x2 Point[" + String(x2) + "]")
Assert(y1<y2, "ZoomBox: y1[" + String(y1) + "] point larger then y2 Point[" + String(y2) + "]")
Assert(IgnoreAR>0 || BoxAR == FinalAR, "ZoomBox: Box Aspect Ratio [" + String(BoxAR) + "] does not equal clip output Aspect Ratio [" + string(FinalAR) + "]")
#Pad clip so resizer interpolates from border when zooming out. 64 for spline64
#Conditional Borders... only add if it's going to be used.
borderSize = 64
borderLeft = x1 < 0 ? borderSize : 0
borderTop = y1 < 0 ? borderSize : 0
borderRight = x2 > c.width() ? borderSize : 0
borderBottom = y2 > c.height() ? borderSize : 0
c = c.AddBorders(borderLeft,borderTop,borderRight,borderBottom,color)
#Do it
c = Eval(ResizeMethod + "(c, " + String(Round(width)) + ", " + String(Round(height)) + ", src_left=" + String(x1+borderLeft) + ", src_top=" + String(y1+borderTop) + ", src_width=" + String(x2-x1) + ", src_height=" + String(y2-y1) + ")")
c
Subtitle(String(x1) + ", " + String(y1) + " " + String(x2) + ", " + String(y2) + " BoxAR " + String(BoxAR) + " " + String())
Subtitle(SubString, y=100)
Subtitle(sY, y=140)
Subtitle(sX, y=160)
}
function SplitScreener(int Width, int Height, int Border, clip A, clip B, clip C, clip D, int "ZoomToFill", string "ResizeMethod", bool "AudioMix")
{
#Set Defaults
ResizeMethod = Default(ResizeMethod, "BilinearResize")
AudioMix = Default(AudioMix, true)
ZoomToFill = Default(ZoomToFill, -1)
#Check Inputs
Assert(ZoomToFill==1 || ZoomToFill==-1, "ZoomToFill must be 1 or -1. Input of " + String(ZoomToFill) + " doesn't work")
#Set Borders
BorderH = Border
BorderW = Border
#Set Width and Height of individual clips
NewW = Round(float(Width)/2.0 - float(BorderW)*1.5)
NewH = Round(float(Height)/2.0 - float(BorderH)*1.5)
NewAR = Float(NewW)/Float(NewH)
OutAR = Float(Width)/Float(Height)
#Process Video
A = A.ZoomBoxer(NewW, NewH, ResizeMethod, Float(A.width())/Float(A.height())*(NewAR/OutAR), ZoomToFill*(9))
A = A.AddBorders(BorderW, BorderH, 0, 0)
B = B.ZoomBoxer(NewW, NewH, ResizeMethod, Float(B.width())/Float(B.height())*(NewAR/OutAR), ZoomToFill*(7))
B = B.AddBorders(BorderW, BorderH, 0, 0)
C = C.ZoomBoxer(NewW, NewH, ResizeMethod, Float(C.width())/Float(C.height())*(NewAR/OutAR), ZoomToFill*(3))
C = C.AddBorders(BorderW, BorderH, 0, 0)
D = D.ZoomBoxer(NewW, NewH, ResizeMethod, Float(D.width())/Float(D.height())*(NewAR/OutAR), ZoomToFill*(1))
D = D.AddBorders(BorderW, BorderH, 0, 0)
#Merge Clips
X = StackHorizontal(A, B).AddBorders(0,0,BorderW,0)
Y = StackHorizontal(C, D).AddBorders(0,0,BorderW,0)
StackVertical(X, Y).AddBorders(0,0,0,BorderH).KillAudio()
#Fix Audio
LongestClip = Int(Max(Framecount(A), Framecount(B), Framecount(C), Framecount(D)))
A = (Framecount(A) <> LongestClip) ? A ++ BlankClip(A, LongestClip-Framecount(A)) : A
B = (Framecount(B) <> LongestClip) ? B ++ BlankClip(B, LongestClip-Framecount(B)) : B
C = (Framecount(C) <> LongestClip) ? C ++ BlankClip(C, LongestClip-Framecount(C)) : C
D = (Framecount(D) <> LongestClip) ? D ++ BlankClip(D, LongestClip-Framecount(D)) : D
#Mix Audio
Sound = (AudioMix) ? MergeChannels(MixAudio(ConvertToMono(A).Amplify(0.49), ConvertToMono(C).Amplify(0.49)), MixAudio(ConvertToMono(B).Amplify(0.49), ConvertToMono(D).Amplify(0.49))):
\ MergeChannels(GetLeftChannel(A), GetRightChannel(A), GetLeftChannel(B), GetRightChannel(B), GetLeftChannel(C), GetRightChannel(C), GetLeftChannel(D), GetRightChannel(D))
AudioDub(last, Sound)
}
at the end of the zoom factor code where x2 = _ and y2 = _ is where i can't figure it out. the *2.0 was what i call lucky guessing right above where x1=, y1=. That code is what makes 6,8,9 work. Once again i'm asking for help here on x2,y2... Most of the zoomfactor code was brute force/trial and error, so hopefully it works in all cases.
Gavino
28th May 2008, 19:01
Most of the zoomfactor code was brute force/trial and error, so hopefully it works in all cases.
LOL - In my experience, programming by trial and error, and hoping for the best, are unlikely to give correct results (indeed, where I used to work, it would get you fired). :) And it's hard to say if a program is 'correct' without a specification of its intended behaviour, so let's return to that.
I said I was confused about the details of your zoom feature, and I now realise why. In my view, there are two different sorts of zooming required:
what we might call 'stretch-to-fit', where the clip is expanded to fit the width and/or height of the output frame, depending on the alignment and relative dimensions;
explicitly requested scaling by x% (where 100% means clip remains at its original resolution).
It seems that your current scheme mixes these up together (and in a hard-to-understand way), when for me they should be separate.
Here's an example to help explain what I mean. Let's say we have an input clip 640x480 and we want to select the top left quadrant at its original resolution. I would like to say
ZoomBoxer(320, 240, align=1, zoomFactor=100)
but this actually results in showing the complete clip at half its original resolution, because the zoom factor works on top of the stretch-to-fit resizing, which cannot be switched off.
Ah, perhaps I can just increase the zoomFactor (to 200, say) to compensate? In fact, I found no matter how much I increased it (even with ridiculous values like 1000000) the clip never reached the desired resolution!
So it's very difficult (and in the above example, impossible) for a user to figure out what value of zoomFactor to use to achieve the effect he/she desires.
It might be that what I'm seeing is due to bugs in the implementation rather than something you intended, but in any case, to my mind the following scheme would be more useful:
use zoomFactor=0 to mean 'stretch-to-fit', equivalent to zoomFactor=100 in current scheme;
zoomFactor > 0 to mean scale by exactly that (%age) factor, regardless of clip dimensions and AR, the clip then being aligned appropriately in the output frame and cropped or padded if necessary. In this mode, negative align values make no sense and would be rejected.
What do you (and others) think?
mikeytown2
28th May 2008, 20:15
Try it with align=9 or -9. align=1,2,3,4,7 doesn't work correctly, the AR is off. The main point of align is that it will stretch-to-fit the image, using 2 different methods: black borders or no black borders. Once that image has been aligned and fitted, i may wish to zoom in or out. zoomFactor will never change the output dimensions, but it will allow you to zoom in or out of those pixels. If you want to change the resolution, use Width and Height. Try out the software that Tac suggested (http://www.photodex.com/products/proshowgold/), I liked what i saw.
For your example "input clip 640x480 and we want to select the top left quadrant at its original resolution" It would be
ZoomBoxer(640, 480, align=1, zoomFactor=100)
2x Zoom would be
ZoomBoxer(640, 480, align=1, zoomFactor=200)
Which is the same as
crop(0,0,-320,-240)
BilinearResize(640,480)
Once the resolution/dimensions are set, it will never change.
Using the same example
crop(0,0,-320,-240)
Would be the same as
ZoomBoxer(320, 240, align=1, zoomFactor=200)
Hopefully this helps. I can see what you mean though... i would be confused as well, if i didn't know how this was supposed to work.
My trial and error is a little overstated... i have about 3 pages of notes/calculations, it was trial and error in that, oh this should work... and it does except when doing "this". I can see why some commercial software packages only operate at a given resolution, makes life easy. But where i placed the *2.0 was purely guesswork.... i knew that it has to be twice as much because the other side of the image is not being scaled by the zoomFactor.
I think you where suggesting that
ZoomBoxer(160, 120, align=1, zoomFactor=100)
would be the same as
Crop(0,0,-480,-360)
where as right now it behaves like
BilinearResize(160,120)
And in order to get the desired effect as the crop line.
ZoomBoxer(160, 120, align=1, zoomFactor=400)
A fairly simple calculation of the input and output dimensions can make the zoom factor behave in the other manner. 640/160 = 4; 4*100 = 400.
Gavino
29th May 2008, 01:43
Sorry, I had forgotten you already said that align=1 wasn't working yet. Tried with align=9 and it works as you describe.
I probably got my terminology wrong too - by 'original resolution' I meant 'without resizing/resampling', and this would always correspond in my scheme to zoomFactor=100, regardless of input and output sizes. (In both schemes the output frame size is fixed by the corresponding parameters - supplied or defaulted).
My '640x480 top left quadrant' example corresponds to
ZoomBoxer(320, 240, align=1, zoomFactor=100)
in my scheme but zoomFactor=200 in yours.
Your final examples with output 160x120 do correctly reflect my suggestion and show how it differs from yours.
I now understand how you mean it to work, but it still seems counter-intuitive to me that (at least in this case) crop without resize corresponds to a zoom of 400 whereas actual resize equates to zoom=100. That's because I see zoom as something to be applied to the input (like the Zoom plugin) whereas you intend it (oddly, IMHO) to be applied to the 'stretched-to-fit' clip (a purely conceptual intermediate output).
This makes it harder to figure out what value of zoomFactor to use when the input and output sizes differ, especially if one is not a simple multiple of the other.
That plus I feel it would be better to separate the two different sorts of zooming as I described.
(BTW In all this I've been thinking purely about usability - I haven't considered whether my scheme makes the implementation any easier or harder.)
mikeytown2
29th May 2008, 02:00
Negative values in zoomFactor is the zoom of the pixels, positive values in zoomFactor is the zoom of the frame. The code for x2,y2 is quite odd... but it seems to work for the tests that I put it through. Had to map it out, then create a formula to match the offset. As for why *2.0 in x1,y1 works... dumb luck?
Please test this sucker out. It's good to go, as far as I can tell.
A = ColorBars().Crop(10, 20, -30, -400).ConvertToYV12()
B = ColorBars().invert().FlipHorizontal().Crop(10, 20, -300, -40).ConvertToYV12()
C = ColorBars().FlipVertical().Crop(10, 200, -30, -40).ConvertToYV12()
D = ColorBars().invert().FlipVertical().FlipHorizontal().Crop(100, 20, -30, -40).ConvertToYV12()
E = ImageReader("testp2cz4.png",0,0)
E1 = E.ConvertToYV12().AssumeFPS("ntsc_video")
Global W = 640
Global H = 480
Global DAR = 0 #16.0/9.0
Global Resize = "BilinearResize"
SplitScreener(W, H, 8, A, B, C, D, ZoomToFill=1).Trim(0,-1).KillAudio()
last + SplitScreener(W, H, 8, A, B, C, D, ZoomToFill=-1).Trim(0,-1).KillAudio()
last + TestC(E1)
#Try different image
E = ImageReader("traingr4.jpg",0,0)
E2 = E.ConvertToYV12().AssumeFPS("ntsc_video")
Global DAR = 16.0/9.0
last + TestC(E2)
Return Last
#E1.ZoomBoxer(W,H, Resize, DisplayAR=0, Align=1, zoomFactor=-100, panX=0, panY=0)
Function TestC(Clip E)
{
TestA(E,-1)
last + TestA(E,-2)
last + TestA(E,-3)
last + TestA(E,-4)
last + TestA(E,-5)
last + TestA(E,5)
last + TestA(E,-6)
last + TestA(E,-7)
last + TestA(E,-8)
last + TestA(E,-9)
last + TestB(E, 25)
last + TestB(E, 50)
last + TestB(E, 75)
}
Function TestA(clip E, int al)
{
E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=100, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=75, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=50, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=25, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=12.5, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=6.25, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=3.125, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=75, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=100, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=200, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=400, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=600, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=800, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=2000, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=al, zoomFactor=20000, panX=0, panY=0)
}
Function TestB(clip E, int zf)
{
E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-5, zoomFactor=zf, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-1, zoomFactor=zf, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-3, zoomFactor=zf, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-7, zoomFactor=zf, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-9, zoomFactor=zf, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-2, zoomFactor=zf, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-4, zoomFactor=zf, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-6, zoomFactor=zf, panX=0, panY=0)
last + E.ZoomBoxer(W,H, Resize, DisplayAR=DAR, Align=-8, zoomFactor=zf, panX=0, panY=0)
}
Function ZoomBoxer(clip c, int "width", int "height", string "ResizeMethod", float "DisplayAR", int "Align", float "zoomFactor", float "panX", float "panY", int "color", int "IgnoreAR")
{
#set defaults
ResizeMethod = Default(ResizeMethod, "BilinearResize")
IgnoreAR = Default(IgnoreAR, 1)
color = Default(color, $000000)
width = Default(width, c.width())
height = Default(height, c.height())
Align = Default(Align, 0)
zoomFactor = Default(zoomFactor, 100.0)
#zoomFactor = -(Log(zoomFactor*0.01)/Log(4))
panX = Default(panX, 0)
panY = Default(panY, 0)
modzoom = Max(Float(c.width())/Float(width),Float(c.height())/Float(height))
zoomFactor = zoomFactor<0 ? (abs(zoomFactor)/100.0)*modzoom : (abs(zoomFactor)/100.0)
SourceAR = float(c.width())/float(c.height())
FinalAR = float(width)/float(height)
DisplayAR = Default(DisplayAR, Float(c.width())/Float(c.height()))
DisplayAR = DisplayAR == 0 ? Float(c.width())/Float(c.height()) : DisplayAR
#If Align=5 or -5 then center clip. -5: Add borders. 5: Crop.
#Display Aspect Ratio = Final Output Ratio. No Change, Show All Pixels
#Display Aspect Ratio > Final Output Ratio. Add Height or Crop Width
#Display Aspect Ratio < Final Output Ratio. Add Width or Crop Height
EvalString =
\ Align<>0 && DisplayAR==FinalAR ?
\ "x1=0" + "
x2=" + String(c.width()) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : (Align==-5 || Align==-4 || Align==-6) && DisplayAR>FinalAR ?
\ "y1=" + String(0 - ((height*DisplayAR-width)/2.0)*(c.height()/Float(width))) + "
y2=" + String(c.height() + ((height*DisplayAR-width)/2.0)*(c.height()/Float(width))) + "
x1=0" + "
x2=" + String(c.width())
\ : (Align==5 || Align==2 || Align==8) && DisplayAR>FinalAR ?
\ "x1=" + String(0 + ((height-width/DisplayAR)/2.0)*(c.width()/Float(height))) + "
x2=" + String(c.width() - ((height-width/DisplayAR)/2.0)*(c.width()/Float(height))) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : (Align==-5 || Align==-2 || Align==-8) && DisplayAR<FinalAR ?
\ "x1=" + String(0 - ((width/DisplayAR-height)/2.0)*(c.width()/Float(height))) + "
x2=" + String(c.width() + ((width/DisplayAR-height)/2.0)*(c.width()/Float(height))) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : (Align==5 || Align==4 || Align==6) && DisplayAR<FinalAR ?
\ "y1=" + String(0 + ((width-height*DisplayAR)/2.0)*(c.height()/Float(width))) + "
y2=" + String(c.height() - ((width-height*DisplayAR)/2.0)*(c.height()/Float(width))) + "
x1=0" + "
x2=" + String(c.width())
\ : (Align==-1 || Align==-2 || Align==-3) && DisplayAR>FinalAR ?
\ "y1=" + String(0) + "
y2=" + String(c.height() + ((height*DisplayAR-width)/1.0)*(c.height()/Float(width))) + "
x1=0" + "
x2=" + String(c.width())
\ : (Align==-1 || Align==-4 || Align==-7) && DisplayAR<FinalAR ?
\ "x1=" + String(0) + "
x2=" + String(c.width() + ((width/DisplayAR-height)/1.0)*(c.width()/Float(height))) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : (Align==-9 || Align==-8 || Align==-7) && DisplayAR>FinalAR ?
\ "y1=" + String(0 - ((height*DisplayAR-width)/1.0)*(c.height()/Float(width))) + "
y2=" + String(c.height()) + "
x1=0" + "
x2=" + String(c.width())
\ : (Align==-9 || Align==-6 || Align==-3) && DisplayAR<FinalAR ?
\ "x1=" + String(0 - ((width/DisplayAR-height)/1.0)*(c.width()/Float(height))) + "
x2=" + String(c.width()) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : (Align==2 || Align==1 || Align==3) && DisplayAR<FinalAR ?
\ "y1=" + String(0) + "
y2=" + String(c.height() - ((width-height*DisplayAR)/1.0)*(c.height()/Float(width))) + "
x1=0" + "
x2=" + String(c.width())
\ : (Align==8 || Align==7 || Align==9) && DisplayAR<FinalAR ?
\ "y1=" + String(0 + ((width-height*DisplayAR)/1.0)*(c.height()/Float(width))) + "
y2=" + String(c.height()) + "
x1=0" + "
x2=" + String(c.width())
\ : (Align==4 || Align==1 || Align==7) && DisplayAR>FinalAR ?
\ "x1=" + String(0) + "
x2=" + String(c.width() - ((height-width/DisplayAR)/1.0)*(c.width()/Float(height))) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : (Align==6 || Align==3 || Align==9) && DisplayAR>FinalAR ?
\ "x1=" + String(0 + ((height-width/DisplayAR)/1.0)*(c.width()/Float(height))) + "
x2=" + String(c.width()) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : ""
Eval(EvalString)
#Take Crop Like Input
x2 = x2<=x1 && x2 < 0 ? c.width() + x2 : x2
y2 = y2<=y1 && y2 < 0 ? c.height() + y2 : y2
#Check if x2 or y2 needs to be calculated
Assert( ((x2==x1) && (y2==y1))==False, "x2 [" + String(x2) + "] or y2 [" + String(y2) + "] needs a value that is different from x1 [" + String(x1) + "] or y1 [" + String(y1) + "]")
y2 = (y2==y1) ? (((x2-x1)/FinalAR)/(SourceAR/DisplayAR) + y1) : y2
x2 = (x2==x1) ? (((y2-y1)*FinalAR)*(SourceAR/DisplayAR) + x1) : x2
SubString = "Align=" + String(Align) + " zoomFactor=" + String(zoomFactor*100) + " panX=" + String(panX) + " panY=" + String(panY)
#Calc Pan Factor
x1 = x1+panX
y1 = y1+panY
x2 = x2+panX
y2 = y2+panY
#Calc Zoom Factor
BoxAR = Float(x2-x1)/Float(y2-y1)
CenterX = (x2-x1)/2.0
CenterY = (y2-y1)/2.0
CenterY = (Align<0 && DisplayAR>FinalAR)? CenterY*(FinalAR/DisplayAR): (Align>0 && DisplayAR<FinalAR)? CenterY*(FinalAR/DisplayAR): CenterY
CenterX = (Align>0 && DisplayAR>FinalAR)? CenterX/(FinalAR/DisplayAR): (Align<0 && DisplayAR<FinalAR)? CenterX/(FinalAR/DisplayAR): CenterX
Align = abs(Align)
sY = " CenterY: " + String(CenterY) + " y2: " + String(y2) + " y1: " + String(y1)
sX = " CenterX: " + String(CenterX) + " x2: " + String(x2) + " x1: " + String(x1)
x1 = (Align==0 || Align==5 || Align==2 || Align==8) && zoomFactor<>1 ? CenterX-((CenterX-x1)/(zoomFactor)) : (Align==3 || Align==6 || Align==9) && zoomFactor<>1 ? CenterX*2.0-((CenterX*2.0-x1)/zoomFactor) : x1
y1 = (Align==0 || Align==5 || Align==4 || Align==6) && zoomFactor<>1 ? CenterY-((CenterY-y1)/(zoomFactor)) : (Align==7 || Align==8 || Align==9) && zoomFactor<>1 ? CenterY*2.0-((CenterY*2.0-y1)/zoomFactor) : y1
x2 = (Align==0 || Align==5 || Align==2 || Align==8) && zoomFactor<>1 ? CenterX+((x2-CenterX)/(zoomFactor)) : (Align==7 || Align==4 || Align==1) && zoomFactor<>1 ? CenterX+((x2-CenterX)/(zoomFactor))+((100.0/(zoomFactor*100.0))-1)*CenterX : x2
y2 = (Align==0 || Align==5 || Align==4 || Align==6) && zoomFactor<>1 ? CenterY+((y2-CenterY)/(zoomFactor)) : (Align==3 || Align==2 || Align==1) && zoomFactor<>1 ? CenterY+((y2-CenterY)/(zoomFactor))+((100.0/(zoomFactor*100.0))-1)*CenterY : y2
BoxAR = Float(x2-x1)/Float(y2-y1)
#Check For Any Unreasonable Inputs
Assert(x1<x2, "ZoomBox: x1[" + String(x1) + "] point larger then x2 Point[" + String(x2) + "]")
Assert(y1<y2, "ZoomBox: y1[" + String(y1) + "] point larger then y2 Point[" + String(y2) + "]")
Assert(IgnoreAR>0 || BoxAR == FinalAR, "ZoomBox: Box Aspect Ratio [" + String(BoxAR) + "] does not equal clip output Aspect Ratio [" + string(FinalAR) + "]")
#Pad clip so resizer interpolates from border when zooming out. 64 for spline64
#Conditional Borders... only add if it's going to be used.
borderSize = 64
borderLeft = x1 < 0 ? borderSize : 0
borderTop = y1 < 0 ? borderSize : 0
borderRight = x2 > c.width() ? borderSize : 0
borderBottom = y2 > c.height() ? borderSize : 0
c = c.AddBorders(borderLeft,borderTop,borderRight,borderBottom,color)
#Do it
c = Eval(ResizeMethod + "(c, " + String(Round(width)) + ", " + String(Round(height)) + ", src_left=" + String(x1+borderLeft) + ", src_top=" + String(y1+borderTop) + ", src_width=" + String(x2-x1) + ", src_height=" + String(y2-y1) + ")")
c
Subtitle("BoxAR " + String(BoxAR) + " " + String(x1) + ", " + String(y1) + " " + String(x2) + ", " + String(y2) + " " + String())
Subtitle(SubString, y=100)
Subtitle(sY, y=140)
Subtitle(sX, y=160)
}
function SplitScreener(int Width, int Height, int Border, clip A, clip B, clip C, clip D, int "ZoomToFill", string "ResizeMethod", bool "AudioMix")
{
#Set Defaults
ResizeMethod = Default(ResizeMethod, "BilinearResize")
AudioMix = Default(AudioMix, true)
ZoomToFill = Default(ZoomToFill, -1)
#Check Inputs
Assert(ZoomToFill==1 || ZoomToFill==-1, "ZoomToFill must be 1 or -1. Input of " + String(ZoomToFill) + " doesn't work")
#Set Borders
BorderH = Border
BorderW = Border
#Set Width and Height of individual clips
NewW = Round(float(Width)/2.0 - float(BorderW)*1.5)
NewH = Round(float(Height)/2.0 - float(BorderH)*1.5)
NewAR = Float(NewW)/Float(NewH)
OutAR = Float(Width)/Float(Height)
#Process Video
A = A.ZoomBoxer(NewW, NewH, ResizeMethod, Float(A.width())/Float(A.height())*(NewAR/OutAR), ZoomToFill*(9))
A = A.AddBorders(BorderW, BorderH, 0, 0)
B = B.ZoomBoxer(NewW, NewH, ResizeMethod, Float(B.width())/Float(B.height())*(NewAR/OutAR), ZoomToFill*(7))
B = B.AddBorders(BorderW, BorderH, 0, 0)
C = C.ZoomBoxer(NewW, NewH, ResizeMethod, Float(C.width())/Float(C.height())*(NewAR/OutAR), ZoomToFill*(3))
C = C.AddBorders(BorderW, BorderH, 0, 0)
D = D.ZoomBoxer(NewW, NewH, ResizeMethod, Float(D.width())/Float(D.height())*(NewAR/OutAR), ZoomToFill*(1))
D = D.AddBorders(BorderW, BorderH, 0, 0)
#Merge Clips
X = StackHorizontal(A, B).AddBorders(0,0,BorderW,0)
Y = StackHorizontal(C, D).AddBorders(0,0,BorderW,0)
StackVertical(X, Y).AddBorders(0,0,0,BorderH).KillAudio()
#Fix Audio
LongestClip = Int(Max(Framecount(A), Framecount(B), Framecount(C), Framecount(D)))
A = (Framecount(A) <> LongestClip) ? A ++ BlankClip(A, LongestClip-Framecount(A)) : A
B = (Framecount(B) <> LongestClip) ? B ++ BlankClip(B, LongestClip-Framecount(B)) : B
C = (Framecount(C) <> LongestClip) ? C ++ BlankClip(C, LongestClip-Framecount(C)) : C
D = (Framecount(D) <> LongestClip) ? D ++ BlankClip(D, LongestClip-Framecount(D)) : D
#Mix Audio
Sound = (AudioMix) ? MergeChannels(MixAudio(ConvertToMono(A).Amplify(0.49), ConvertToMono(C).Amplify(0.49)), MixAudio(ConvertToMono(B).Amplify(0.49), ConvertToMono(D).Amplify(0.49))):
\ MergeChannels(GetLeftChannel(A), GetRightChannel(A), GetLeftChannel(B), GetRightChannel(B), GetLeftChannel(C), GetRightChannel(C), GetLeftChannel(D), GetRightChannel(D))
AudioDub(last, Sound)
}
mikeytown2
29th May 2008, 11:15
This is the final code (for now) of zoombox(), unless there is a simple error to correct. I will not change the first post until I port it over to KBE(). I put back x1,y1,x2,y2 and added various checks of the input (assert x1,y1,x2,y2 doesn't work...). Align also works (controls where it is zoomed) when you specify the box (x1, y1, x2 and/or y2) and the zoomfactor. Negative zoomfactor if off a little when converting AR, its not a show stopper, so unless it's an easy fix, I'm going to ignore it for now.
# ZoomBox() - May 29th, 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 DisplayAR: 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 (required)
# float y1: upper left y cord (required)
# float x2: lower right x cord (optional)
# float y2: lower right y cord (optional)
# x2 and/or y2 must be defined when using Mode 1
# when omitting x2 or y2, 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).
# int IgnoreAR: 1 - Ignore Warnings; 0 - Show Warnings. Default=1, Ignore AR waring
#
#
# Notes
# Aspect ratio for output and box(x1,y1,x2,y2) should be the same, unless you want to distort the clip.
# Default behavior 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 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 ZoomBox(clip c, int "width", int "height", string "ResizeMethod", float "DisplayAR", int "Align", float "x1", float "y1", float "x2", float "y2", float "zoomFactor", float "panX", float "panY", int "color", int "IgnoreAR")
{
#Set Defaults
width = Default(width, c.width())
height = Default(height, c.height())
ResizeMethod = Default(ResizeMethod, "BilinearResize")
DisplayAR = Default(DisplayAR, Float(c.width())/Float(c.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)
IgnoreAR = Default(IgnoreAR, 1)
#Calc Defaults
SourceAR = float(c.width())/float(c.height())
FinalAR = float(width)/float(height)
DisplayAR = DisplayAR==0 ? Float(c.width())/Float(c.height()) : DisplayAR
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(DisplayAR>=0, "ZoomBox: DisplayAR [" + String(DisplayAR) + "] must be positive.")
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.")
#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 && DisplayAR==FinalAR ?
\ "x1=0" + "
x2=" + String(c.width()) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : (Align==-5 || Align==-4 || Align==-6) && DisplayAR>FinalAR ?
\ "y1=" + String(0 - ((height*DisplayAR-width)/2.0)*(c.height()/Float(width))) + "
y2=" + String(c.height() + ((height*DisplayAR-width)/2.0)*(c.height()/Float(width))) + "
x1=0" + "
x2=" + String(c.width())
\ : (Align==5 || Align==2 || Align==8) && DisplayAR>FinalAR ?
\ "x1=" + String(0 + ((height-width/DisplayAR)/2.0)*(c.width()/Float(height))) + "
x2=" + String(c.width() - ((height-width/DisplayAR)/2.0)*(c.width()/Float(height))) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : (Align==-5 || Align==-2 || Align==-8) && DisplayAR<FinalAR ?
\ "x1=" + String(0 - ((width/DisplayAR-height)/2.0)*(c.width()/Float(height))) + "
x2=" + String(c.width() + ((width/DisplayAR-height)/2.0)*(c.width()/Float(height))) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : (Align==5 || Align==4 || Align==6) && DisplayAR<FinalAR ?
\ "y1=" + String(0 + ((width-height*DisplayAR)/2.0)*(c.height()/Float(width))) + "
y2=" + String(c.height() - ((width-height*DisplayAR)/2.0)*(c.height()/Float(width))) + "
x1=0" + "
x2=" + String(c.width()) + ""
\ : (Align==-1 || Align==-2 || Align==-3) && DisplayAR>FinalAR ?
\ "y1=" + String(0) + "
y2=" + String(c.height() + ((height*DisplayAR-width)/1.0)*(c.height()/Float(width))) + "
x1=0" + "
x2=" + String(c.width())
\ : (Align==-1 || Align==-4 || Align==-7) && DisplayAR<FinalAR ?
\ "x1=" + String(0) + "
x2=" + String(c.width() + ((width/DisplayAR-height)/1.0)*(c.width()/Float(height))) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : (Align==-9 || Align==-8 || Align==-7) && DisplayAR>FinalAR ?
\ "y1=" + String(0 - ((height*DisplayAR-width)/1.0)*(c.height()/Float(width))) + "
y2=" + String(c.height()) + "
x1=0" + "
x2=" + String(c.width())
\ : (Align==-9 || Align==-6 || Align==-3) && DisplayAR<FinalAR ?
\ "x1=" + String(0 - ((width/DisplayAR-height)/1.0)*(c.width()/Float(height))) + "
x2=" + String(c.width()) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : (Align==2 || Align==1 || Align==3) && DisplayAR<FinalAR ?
\ "y1=" + String(0) + "
y2=" + String(c.height() - ((width-height*DisplayAR)/1.0)*(c.height()/Float(width))) + "
x1=0" + "
x2=" + String(c.width())
\ : (Align==8 || Align==7 || Align==9) && DisplayAR<FinalAR ?
\ "y1=" + String(0 + ((width-height*DisplayAR)/1.0)*(c.height()/Float(width))) + "
y2=" + String(c.height()) + "
x1=0" + "
x2=" + String(c.width())
\ : (Align==4 || Align==1 || Align==7) && DisplayAR>FinalAR ?
\ "x1=" + String(0) + "
x2=" + String(c.width() - ((height-width/DisplayAR)/1.0)*(c.width()/Float(height))) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : (Align==6 || Align==3 || Align==9) && DisplayAR>FinalAR ?
\ "x1=" + String(0 + ((height-width/DisplayAR)/1.0)*(c.width()/Float(height))) + "
x2=" + String(c.width()) + "
y1=0" + "
y2=" + String(c.height()) + ""
\ : ""
Defined(x1) ? nop() : Eval(EvalString)
#Set Optional parameters "Mode 1"
x2 = Defined(x1) && !Defined(x2) ? x1 : x2
y2 = Defined(y1) && !Defined(y2) ? y1 : y2
#For non Align Input "Mode 1"
#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 "Mode 1"
Assert( ((x2==x1) && (y2==y1))==False, "x2 [" + String(x2) + "] or y2 [" + String(y2) + "] needs a value that is different from x1 [" + String(x1) + "] or y1 [" + String(y1) + "]")
y2 = (y2==y1) ? (((x2-x1)/FinalAR)/(SourceAR/DisplayAR) + y1) : y2
x2 = (x2==x1) ? (((y2-y1)*FinalAR)*(SourceAR/DisplayAR) + x1) : x2
#Calc Pan Factor
x1 = x1+panX
y1 = y1+panY
x2 = x2+panX
y2 = y2+panY
#Calc Zoom Factor
CenterX = (x2-x1)/2.0
CenterY = (y2-y1)/2.0
CenterY = (Align<0 && DisplayAR>FinalAR)? CenterY*(FinalAR/DisplayAR): (Align>0 && DisplayAR<FinalAR)? CenterY*(FinalAR/DisplayAR): CenterY
CenterX = (Align>0 && DisplayAR>FinalAR)? CenterX/(FinalAR/DisplayAR): (Align<0 && DisplayAR<FinalAR)? CenterX/(FinalAR/DisplayAR): CenterX
Align = abs(Align)
x1 = (Align==0 || Align==5 || Align==2 || Align==8) && zoomFactor<>1 ? CenterX-((CenterX-x1)/(zoomFactor)) : (Align==3 || Align==6 || Align==9) && zoomFactor<>1 ? CenterX*2.0-((CenterX*2.0-x1)/zoomFactor) : x1
y1 = (Align==0 || Align==5 || Align==4 || Align==6) && zoomFactor<>1 ? CenterY-((CenterY-y1)/(zoomFactor)) : (Align==7 || Align==8 || Align==9) && zoomFactor<>1 ? CenterY*2.0-((CenterY*2.0-y1)/zoomFactor) : y1
x2 = (Align==0 || Align==5 || Align==2 || Align==8) && zoomFactor<>1 ? CenterX+((x2-CenterX)/(zoomFactor)) : (Align==7 || Align==4 || Align==1) && zoomFactor<>1 ? CenterX+((x2-CenterX)/(zoomFactor))+((100.0/(zoomFactor*100.0))-1)*CenterX : x2
y2 = (Align==0 || Align==5 || Align==4 || Align==6) && zoomFactor<>1 ? CenterY+((y2-CenterY)/(zoomFactor)) : (Align==3 || Align==2 || Align==1) && zoomFactor<>1 ? CenterY+((y2-CenterY)/(zoomFactor))+((100.0/(zoomFactor*100.0))-1)*CenterY : y2
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) + "]")
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.
#Conditional Borders... only add if it's going to be used. Max Border size is size of input frame. Prevents "streaking" when zooming out alot.
borderLeft = x1 < 0 ? Int(Min(Abs(x1),c.width())) : 0
borderTop = y1 < 0 ? Int(Min(Abs(y1),c.height())) : 0
borderRight = x2 > c.width() ? Int(Min(x2-c.width(),c.width())) : 0
borderBottom = y2 > c.height() ? Int(Min(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.
c = Eval(ResizeMethod + "(c, " + String(Round(width)) + ", " + String(Round(height)) + ", src_left=" + String(x1+borderLeft) + ", src_top=" + String(y1+borderTop) + ", src_width=" + String(x2-x1) + ", src_height=" + String(y2-y1) + ")")
c
}
Gavino
30th May 2008, 01:05
I haven't had time to study or try out your latest updates, but here's something that has just struck me - you don't need to construct your long eval strings for x1 (etc) bit-by-bit - just write them as normal expressions within a single (but still multi-line) string literal.
For example,
EvalString = Align<>0 && DisplayAR==FinalAR ?
\ "x1=0" + "
x2=" + String(c.width()) + "
y1=0" + "
y2=" + String(c.height()) + ""
# ... etc
can be written simply as
EvalString = Align<>0 && DisplayAR==FinalAR ?
\ "x1=0
x2=c.width()
y1=0
y2=c.height()"
# ... etc
which is certainly more readable and easier to maintain, almost like a 'real' program.
mikeytown2
2nd June 2008, 01:52
KenBurnsEffect/ZoomBox Changes
Align Added - Much easier to use now!
PanX/Y Added
zoomFactor Added
letterbox color can be set
KBE() should be slightly faster, with default settings, as a result of breaking up the function.
Read function headers (http://forum.doom9.org/showthread.php?t=135776) for more details.
almost like a 'real' program
It's Getting there, split this up into more functions, less repeating code. Thanks for the tip, should make the code slightly faster.
Huge example (http://forum.doom9.org/showthread.php?p=1140888#post1140888) has been updated as well.
Gavino
2nd June 2008, 15:35
Nice work, mikeytown2, it's looking good.
I like the idea of your your CalcBox function, which shows how to effectively get multiple return values (by returning a string containing multiple assignments which is then Eval'd). Cool.
mikeytown2
4th June 2008, 06:45
Been thinking about format conversions. Looked at this guide (http://lipas.uwasa.fi/~f76998/video/conversion/#conversion_table) as well as this calculator (http://resizecalc.somestuff.org/).
ZoomBox can do subpixel Resizes, thus no DAR error. This is what i got, I've never dealt with PAL, so help me out!
ntscdar_W = (4752.0/4739.0) / (4320.0/4739.0) * (486.0/486.0) * 640.0
ntscdar_H = (486.0/486.0) * 480
ntscDAR = ntscdar_W/ntscdar_H
ColorBars().Trim(0,-1).KillAudio().AssumeFPS(30)
a = BlankClip(last,1,720,480).Subtitle("""640×480 "industry standard" square pixels to 720×480 ITU-R BT.601 pixels""", align=5)
b = BilinearResize(720,480).Subtitle("Incorrect conversion from square pixel 640x480 to DVD frame size, 720x480", align=5)
c = BilinearResize(704,480).AddBorders(8,0,8,0).Subtitle(""" "Correct" conversion from square pixel 640x480 to DVD frame size, 720x480""", align=5)
d = ZoomBox(720,480, DisplayAR=ntscDAR, Align=-5).Subtitle("Correct conversion from square pixel 640x480 to DVD frame size, 720x480 DAR=" + String(ntscDAR), align=5)
e = ZoomBox(720,480, DisplayAR=ntscDAR, Align=5).Subtitle("Correct conversion from square pixel 640x480 to DVD frame size, 720x480 DAR=" + String(ntscDAR), align=5)
y = a+b+c+d+e
paldar_W = (768.0/767.0) / (4320.0/4739.0) * (486.0/576.0) * 768.0
paldar_H = (486.0/576.0) * 576.0
palDAR = paldar_W/paldar_H
f = BlankClip(last,1,720,480).Subtitle(""" "Industry standard" 625/50 square-pixel to 720×480 ITU-R BT.601 pixels""", align=5)
ImageReader("180pxpm5544768zx5.png",0,0,Pixel_type="RGB32").AssumeFPS(30)
g = BilinearResize(720,480).Subtitle("Incorrect conversion from square pixel 768x576 to DVD frame size, 720x480", align=5)
h = BilinearResize(712,486).crop(0,3,0,-3).addborders(4,0,4,0).Subtitle(""" "Correct" conversion from square pixel 768x576 to DVD frame size, 720x480""", align=5)
i = ZoomBox(720,480, DisplayAR=palDAR, Align=5).Subtitle(" Correct conversion from square pixel 768x576 to DVD frame size, 720x480 DAR=" + String(palDAR), align=5)
j = ZoomBox(720,480, DisplayAR=palDAR, Align=-5).Subtitle(" Correct conversion from square pixel 768x576 to DVD frame size, 720x480 DAR=" + String(palDAR), align=5)
z = f+g+h+i+j
y+z
http://img164.imageshack.us/img164/9330/180pxpm5544768zx5.th.png (http://img164.imageshack.us/my.php?image=180pxpm5544768zx5.png)
http://en.wikipedia.org/wiki/Test_card
Also minor update to ZoomBox, should work when DisplayAR is not given.
mikeytown2
5th June 2008, 10:43
Played around with the idea of emulating a multiplane camera (http://en.wikipedia.org/wiki/Multiplane_camera). If i can make a function based off of starting and ending "depth" of every clip, and let the code calc the zooms and pans, would it be worth it? Anyway, here are the Pic's I used and the corresponding code. I call this Paradise Drums...
http://img108.imageshack.us/img108/9752/drumkitan5.th.png (http://img108.imageshack.us/my.php?image=drumkitan5.png)
http://img338.imageshack.us/img338/5260/waterfall12803cboflxu2rj8.th.jpg (http://img338.imageshack.us/my.php?image=waterfall12803cboflxu2rj8.jpg)
http://img208.imageshack.us/img208/4738/55gallonng2.th.png (http://img208.imageshack.us/my.php?image=55gallonng2.png)
Width = 640
Height = 480
Frames = 199
Background = ImageReader("waterfall12803cboflxu2rj8.jpg", pixel_type="RGB32").Trim(0,Frames).KenBurnsEffect(width=width, height=height, startAlign=5, endAlign=5, endZoomFactor=120, endPanY=100)
DrumA = ImageReader("drumkitan5.png", pixel_type="RGB32").Trim(0,Frames).KenBurnsEffect(startAlign=-7, startZoomFactor=50, endAlign=-7, endZoomFactor=60, endPanX=140, endPanY=-140, width=width, height=height)
DrumB = ImageReader("55gallonng2.png", pixel_type="RGB32").Trim(0,Frames).KenBurnsEffect(startAlign=-9, startZoomFactor=50, endPanX=-360, endPanY=-360, endAlign=-9, endZoomFactor=120, width=width, height=height)
Background = Background.Animate(0,Frames-20,"BigBlur",1.58,-0.05)
DrumA = DrumA.Animate(0,Frames-100,"BigBlur",1.58,0.0).Animate(Frames-99,Frames,"BigBlur",0.0,1.58)
DrumB = DrumB.Animate(0,Frames-100,"BigBlur",0.0,1.58)
Layer(Background, DrumA)
Layer(last, DrumB)
Function BigBlur(clip C, float x)
{
c
return Blur(x).Blur(x).Blur(x).Blur(x).Blur(x).Blur(x).Blur(x).Blur(x).Blur(x)
}
Blur is unreliable if you chain it too many times, thus i think a reside down and back up will probably be the best option...
Got idea from here
http://www.reiji.net/ff-e/features.html
Also I experimented with Reform (http://avisynth.org/vcmohan/Reform/Reform.html), but its not sub pixel accurate, image jumps around... DeBarrel (http://avisynth.org/vcmohan/DeBarrel/DeBarrel.html) works when Animated, but the change vs time spent isn't worth it.
mikeytown2
6th June 2008, 21:22
KBE, ZB Updated
DisplayAR was incorrectly labeled, and is being replaced by SourceDAR and TargetDAR. Discussion about this (http://forum.doom9.org/showthread.php?p=1146127#post1146127)
Updated the example (http://forum.doom9.org/showthread.php?p=1140888#post1140888) so it reflects ready for DVD output. I tested this with HCenc and it looked great when I played it back in MPC.
So here is a quick cheat sheet, for me anyway.
Inputs:
for DV NTSC the SourceDAR=720.0/528.0 or is it 720.0/525.0
HDV SourceDAR = 1920.0/1080.0
Outputs:
DVD width:720, height:480
TargetDAR=4.0/3.0 for DVD
TargetDAR=16.0/9.0 for Anamorphic widescreen DVD
NerdWithNoLife
7th June 2008, 00:47
I love this idea but I've never gotten the dang thing to work. When I tried the colorbars example it said, "zoom factor cannot be zero."
I've done some very long scripts to accomplish panning in the past so if someone can help me figure out this filter it would be much appreciated.
mikeytown2
7th June 2008, 01:00
I love this idea but I've never gotten the dang thing to work. When I tried the colorbars example it said, "zoom factor cannot be zero."
I've done some very long scripts to accomplish panning in the past so if someone can help me figure out this filter it would be much appreciated.
The inputs for these groups of functions keep changing; it's the only way to progress. The main issue is the fact that i didn't name the inputs in my past examples.
I'll make up a new colorbars example for ya.
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)
Post some example code, or detailed descriptions and i should be able to give you a hand.
mikeytown2
7th June 2008, 10:34
Started to take a serious look at Rotation. Here is my script which uses the 3 different ways in AviSynth to rotate a clip
a = ColorBars().Trim(0,99)
Animate(0, a.framecount()-1, "Angle", a, float(-500), 1, a, float(510), 1)
last + Animate(0, a.framecount()-1, "Angle", a, float(510), 1, a, float(520), 1)
last + Animate(0, a.framecount()-1, "Angle", a, float(-500), 2, a, float(510), 2)
last + Animate(0, a.framecount()-1, "Angle", a, float(510), 2, a, float(520), 2)
last + Animate(0, a.framecount()-1, "Angle", a, float(-500), 3, a, float(510), 3)
last + Animate(0, a.framecount()-1, "Angle", a, float(510), 3, a, float(520), 3)
Function Angle(clip c, float a, int mode)
{
b = (Round(abs(a)*1000)%360000)/1000.0
d = a < 0 ? 1-(b/360.0) : b/360.0
b = a < 0 ? -b : b
c
mode == 1 ? Zoom(angle="spline(n, " + String(0) + "," + String(a) + ", " + String(1) + "," + String(a) + ", false)") :
\ mode == 2 ? Freeframe("C:\Program Files\AviSynth 2.5\plugins\PetePanSpinZoom.dll",false,0.5,0.5,d,0.2) :
\ EffectRotation(id=round(-b), cc=$000000)
}
Zoom is the highest quality. PetePanSpinZoom doesn't do subpixel calculations and EffectRotation doesn't take floats. EffectRotation is the slowest, PetePanSpinZoom is the fastest. Zoom appears to be the best choice! PetePanSpinZoom appears to have the side effect of using 100% cpu (in my case, with 2 cores: 50%) when doing nothing.
mikeytown2
7th June 2008, 11:35
Updated KBE and ZB
KBE can now rotate images
in ZB/KBE pan(XY) now follows the documentation. negative pan is left or up.
Simple demo of zoom, rotate & pan.
ColorBars().Trim(0,99)
KenBurnsEffect(startAngle=0, endAngle=30, startFrame=19, endFrame=79, usezoomBox=0, endzoomFactor=50, endPanY=-200, endPanX=-100)
rotate appears to operate on the center of the image, after the fact; or at least thats how its coded to work in KBE.
ColorBars().Trim(0,99)
KenBurnsEffect(startAngle=0, endAngle=360, startFrame=19, endFrame=79, usezoomBox=0, startzoomFactor=50, endzoomFactor=50, endPanY=-200, startPanY=-200)
mikeytown2
8th June 2008, 07:12
Played around with adding this interlace resize code (http://forum.doom9.org/showthread.php?p=1031317#post1031317) into KBE/ZB. The quality isn't that good when zooming out because of the black borders. Plus the zoom/pan is only using 1/2 the "frame rate" if you think about it.
Function ZoomBoxIt(clip c, int width, int height, string ResizeMethod, float x1, float y1, float x2, float y2, int color, bool InterlacedFastLQ)
{
#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)
Shift=(height/(y2-y1)-1.0)*0.25 # Field shift correction
InterlacedFastLQ ? Eval("""
c=c.SeparateFields()
d=c.SelectEven()
e=c.SelectOdd()
TF=Eval(ResizeMethod + "(d, " + String(Round(width)) + ", " + String(Round(height/2.0)) + ", src_left=" + String(x1+borderLeft) + ", src_top=" + String((y1+borderTop)/2.0-shift) + ", src_width=" + String(x2-x1) + ", src_height=" + String((y2-y1)/2.0) + ")")
BF=Eval(ResizeMethod + "(e, " + String(Round(width)) + ", " + String(Round(height/2.0)) + ", src_left=" + String(x1+borderLeft) + ", src_top=" + String((y1+borderTop)/2.0+shift) + ", src_width=" + String(x2-x1) + ", src_height=" + String((y2-y1)/2.0) + ")")
Interleave(TF, BF).Weave()""") : \
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) + ")")
}
Thus when using KBE/ZB with interlaced content, and wanting interlaced returned, this is the "general" way to do it. Replace bob() with your favorite bobber for higher quality results.
AVISource("dv.avi")
AssumeBFF() #set order
bob()
KenBurnsEffect(startFrame=100*2, endFrame=1600*2) #make sure to multiply startFrame and endFrame by 2 since the framerate has doubled.
separatefields()
selectevery(4,0,3)
weave()
NerdWithNoLife
9th June 2008, 02:24
The inputs for these groups of functions keep changing; it's the only way to progress. The main issue is the fact that i didn't name the inputs in my past examples.
I'll make up a new colorbars example for ya.
Aha - it worked. I understand this is still in development so thanks so much for A) working on this project B) helping dummies like me. Can't wait for the rotation capability. People like you make me jealous...
mikeytown2
9th June 2008, 02:30
Can't wait for the rotation capability.
It's ready! KBE has 2 different ways to do the "dirty work". One way is to animate ZoomBox, the other way is to use zoom.dll. If you set useZoomBox=0, set startAngle and endAngle!
This post has 2 examples using rotate.
http://forum.doom9.org/showthread.php?p=1146666#post1146666
mikeytown2
12th June 2008, 10:36
Added Source/Target PAR to both
Added the ability to not set x1 or y1; you still need 3 out of 4 points defined though in mode 1.
Also changed cubic option on KBE to an int. cubic=0 is the same as cubic=false; cubic=1 is the same as cubic=true. cubic's range is from 0-5 right now. Each option does something different, so play around with them! Set cubicX=4 and cubicY=5 to get an ugly Arc.
I attempted to make align work with XY inputs but the AR calculations became a nightmare. I also attempted to let less then 3 out of 4 inputs being defined, and the code started to really suck.
NerdWithNoLife
25th July 2008, 03:01
If possible, how would I use KenBurnsEffect/Zoombox to grow/shrink an image, (not just zoom it)? Enlarging an image without displacing it, if that makes sense.
mikeytown2
25th July 2008, 09:51
I think overlay would be the way to do it, here are 2 examples
r = BlankClip(120,color=$FF0000)
g = ColorBars(320,240).Trim(0,119).KenBurnsEffect(endZoomFactor=200)
Overlay(r,g,160,120).KenBurnsEffect(endZoomFactor=50,endFrame=119)
r = BlankClip(color=$FF0000)
g = ColorBars(320,240).Trim(0,119).KenBurnsEffect(endZoomFactor=200,startFrame=60)
last + Overlay(r,g,160,120).KenBurnsEffect(endZoomFactor=50,startFrame=120)
Let me know if its close to what your looking for.
NerdWithNoLife
25th July 2008, 18:39
Actually nevermind. What I'm seeking is a way to grow the alpha layer by a certain amount of pixels - not really the same thing as a zoom. It's more like "Grow Selection" in GIMP. But that's a thing for another thread.
The remove logo plugin seems to have that capability so I'll fiddle around with it.
mikeytown2
20th August 2008, 04:27
Added AvsP function Definitions for KenBurnsEffect and ZoomBox, Get them at the bottom of this post
http://forum.doom9.org/showthread.php?p=1112171#post1112171
tacman1123
4th October 2008, 16:22
I'm trying to upgrade to the latest KBE Script, June 12, 2008, and when I load it in my plugins directory, I get the not-too-helpful "Your computer is running low on Memory" error message. I've had this before, the problem isn't memory, but something wrong in the plugins directory.
Works fine with the June 7 release. I've done a compare, but nothing stands out as what the problem would be. I've simply taken the two scripts at the top of this page, combined them into a file called kbe.avsi and added it to my plugins directory, then tried to run the simple Version() script.
I'm using 2.58RC4, not sure if that's relevant.
Any ideas? Mike, this is such a great script, have you considered putting it into a zip file with some examples to show it off some more (and make for an easier download of these two scripts)? The other advantage would be not having to worry about the line endings issue, which I've had before when cutting and pasting scripts from the forum. I'm even wondering if that's the issue here.
Thx
Tac
mikeytown2
4th October 2008, 20:08
Here's a link to my KenBurnsEffect.avsi - There is nothing new, should be the same as the first 2 posts.
http://rapidshare.com/files/150926268/KenBurnsEffect.zip.html
There are a couple other scripts in there as well: ResizeKAR() (http://forum.doom9.org/showthread.php?t=135229), SplitScreen() (http://forum.doom9.org/showthread.php?t=137534), DissolveAGG() (http://forum.doom9.org/showthread.php?t=118016). Let me know if this one bombs out as well. How much ram do u have? Examples as well as AvsP stuff is located here (http://forum.doom9.org/showthread.php?p=1112171#post1112171). If you have some examples to share, please do so :)
tacman1123
4th October 2008, 21:58
Thanks! That worked, so it must be something to do with the cut-and-paste from Firefox into UltraEdit. Perhaps you could mofidy the message that started this thread to include either that link, or put it in the attachments field of the message.
Tac
jjones3535a
27th May 2009, 20:56
I'm trying to use the KenBurnsEffect function to first zoom in on a video and then zoom back to 100%. I get it to zoom in, but then it just stays zoomed in for the rest of the video.
Here's what I have.
##############
fr=5
clip = DirectShowSource("test.avi")
#this works fine, video is zoomed in for the first 3 seconds
clip.KenBurnsEffect(startFrame=0, endFrame=3*fr, startAlign=6, endAlign=4, endZoomFactor=150)
#this is where I'm stuck how to get the rest of the video to zoom back to 100% - my guess is something like this, but it is not working:
#clip.KenBurnsEffect(startFrame=16, endFrame=500, startAlign=5, endAlign=5, startZoomFactor=150, endZoomFactor=100)
############
Any help would be greatly appreciated. Great function by the way!
Thanks.
mikeytown2
27th May 2009, 21:35
It's been a little while since I've done some video work, but heres how I would do it
clip = ColorBars()
fr=30
clip.KenBurnsEffect(startFrame=0, endFrame=3*fr, endAlign=4, endZoomFactor=150).trim(0,3*fr)
last + clip.KenBurnsEffect(startFrame=3*fr, endFrame=6*fr, startAlign=4, startZoomFactor=150).trim(3*fr,0)
You do bring up an interesting point though, I might want to add a bool value that when set, returns the video back to its unmodified form after the effect is done. That would get rid of the trims at the end.
mikeytown2
27th May 2009, 22:12
Updated first post with a new version!
Now the above example can be done like this
fr=5
ColorBars()
KenBurnsEffect(startFrame=0, endFrame=3*fr, KeepState=false, endAlign=4, endZoomFactor=150)
KenBurnsEffect(startFrame=3*fr+1, endFrame=6*fr, KeepState=false, startAlign=4, startZoomFactor=150)
jjones3535a
27th May 2009, 23:20
Thanks for getting back to me and that is a great update. But I'm still having trouble accomplishing this:
I'd like to zoom in and then out at various points during a clip:
Something like this (pseudocode):
- Given a 1 minute clip:
- Start zooming in at 00:10 for 3 seconds (zoom to 150%)
- Play zoomed in for 10 seconds, then
- Zoom back down to 100%, and then
- Let the clip play till the end...
Is that possible?
I tried this:
clip = DirectShowSource("1278.avi")
fr=5
clip.KenBurnsEffect(startFrame=0, endFrame=3*fr, KeepState=false, endAlign=4, endZoomFactor=150)
last+ clip.KenBurnsEffect(startFrame=3*fr+1, endFrame=6*fr, KeepState=false, startAlign=4, startZoomFactor=150)
but, it doubles the length of my clip. Any ideas?
Thanks again.
mikeytown2
27th May 2009, 23:51
ah, r u a little green when it comes to avisynth syntax?
Anyway this will do your first request.
DirectShowSource("1278.avi")
fr=5
KenBurnsEffect(startFrame=0, endFrame=3*fr, KeepState=false, endAlign=4, endZoomFactor=150)
KenBurnsEffect(startFrame=3*fr+1, endFrame=6*fr, KeepState=false, startAlign=4, startZoomFactor=150)
Or if you like the clip value you can do it like this
Anyway this will do your first request.
clip = DirectShowSource("1278.avi")
fr=5
clip = clip.KenBurnsEffect(startFrame=0, endFrame=3*fr, KeepState=false, endAlign=4, endZoomFactor=150)
clip = clip.KenBurnsEffect(startFrame=3*fr+1, endFrame=6*fr, KeepState=false, startAlign=4, startZoomFactor=150)
clip
To do your second request I would do it this way
DirectShowSource("1278.avi")
fr=5
KenBurnsEffect(startFrame=10*fr , endFrame=13*fr, KeepState=false, endAlign=4, endZoomFactor=150)
KenBurnsEffect(startFrame=13*fr+1, endFrame=23*fr, KeepState=false, startAlign=4, startZoomFactor=150, endAlign=4, endZoomFactor=150)
KenBurnsEffect(startFrame=23*fr+1, endFrame=26*fr, KeepState=false, startAlign=4, startZoomFactor=150)
jjones3535a
28th May 2009, 01:47
Yes, green indeed.
That worked perfectly.
Thank you very much.
jjones3535a
29th May 2009, 02:12
I think I've pretty much got Mode 2 usage down, but am try to figure out how to zoom a particular area using Mode 1.
For example, if I have a 640x480 clip and I want to zoom in to an area that has these coordinates:
x coordinate: 100 (down 100 pixels)
y coordinate: 250 (over to the left 250 pixels)
width: 176 pixels
height: 144 pixels
After zooming into this area, I'd like to zoom back out to the regular video size.
Basically, I want to just zoom into a small boxed area with the main video. I can think of it in terms of x,y and width, height, but am having trouble translating that into the 8 parameters of the KenBurnsEffect function.
Any help would be greatly appreciated. Thanks.
mikeytown2
29th May 2009, 02:25
ColorBars().trim(0,99)
KenBurnsEffect(startframe=0, endframe=20, keepstate=false, endY1=250, endX1=100, endX2=276)
KenBurnsEffect(startframe=21, endframe=50, keepstate=false, endY1=250, endX1=100, endX2=276, startY1=250, startX1=100, startX2=276)
KenBurnsEffect(startframe=51, endframe=70, keepstate=false, startY1=250, startX1=100, startX2=276)
276 = 100+176
Only 3 out of the 4 points are needed.
mikeytown2
29th May 2009, 02:39
You can also use mode 2 and the startPanX, startPanY, endPanX, endPanY if align is close but not perfect. Takes a float btw so you can do stuff like endPanX=15.5
Gavino
29th May 2009, 10:02
x coordinate: 100 (down 100 pixels)
y coordinate: 250 (over to the left 250 pixels)
Is this really what you mean?
You've got your x and y mixed up - x is across and y is down.
jjones3535a
29th May 2009, 14:43
@Gavino - yes, that is exactly what I meant, sorry about that.
@mikeytown2 - thank you very much (again)! I'm still trying to wrap my head around zooming in/out on various areas of my video, but I think this will get me started.
Ultimately, I'm trying to accomplish this within a single video clip:
1) zoom in to a smaller area (a small box -> x, y, width, height)
2) hold the zoom for a while, then
3) zoom back out to normal size.
4) Then repeat steps 1-3 (zoom in/hold/zoom back out) with another small boxed area in the same video
I think I can do it with what mikeytown2 provided, I'll continue testing - thanks so such for the assistance.
Gavino
29th May 2009, 16:36
4) Then repeat steps 1-3 (zoom in/hold/zoom back out) with another small boxed area in the same video
I think I can do it with what mikeytown2 provided
Yes, mikeytown2's example gives you steps 1-3, and you can simply repeat them (with different frame numbers and co-ordinates) as often as you like to repeat the process on the same video.
cweb
20th December 2009, 16:54
SplineCalc seems to be missing... I get the error that the function is missing when I try any example above.
cweb
20th December 2009, 18:48
I found SplineCalc on the Internet. It works if I add it.
It's the following:
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
}
mikeytown2
20th December 2009, 20:07
thanks for pointing that out; updated second post with the missing function.
cweb
21st December 2009, 10:54
You're welcome...
bigboss97
2nd April 2010, 14:09
Great script! Thank you.
A question, I want to pan first and then zoom out. Do I have to do it in 2 calls of the function? which is very difficult for the second call because I've to make sure the start match the end of the first call.
or there's something in the parameter which I haven't found yet?
thanks in advance
Phuoc
cludos
24th November 2010, 14:38
Thanks for this wonderful script. :)
t_2
8th December 2011, 04:56
(Nice to be back again after several years!
Greetings to moderators & power posters - some of whom are new to me. Thanks for all the hard work you've been doing over the years! I haven't stopped using AviSynth!)
Now, to matter at hand: Tried to use zoom plug-in in VirtualDub to pan & zoom in a HD res photo that I turned into video using Image Sequence. Alas, zoom there only supports 3 decimal digits or a max res of 999 pixels. I noticed that Ken Burns Effect didn't work either. (Someone asked in a post why his video output moved about wildly with this script. Didn't see an answer, but I suppose it's because this script relies on zoom.dll which seems to have the same limitation.) At least I couldn't get it to work for me.
Also, ZoomBox script author said at end of his thread that he had given up trying to use his clever script with animate because it's simply too troublesome to code.
My question: Does anyone know of zoom plugin or script that doesn't have the 3 digit limit on resolution? Or does ZoomBox work with animate? I couldn't get it to. Thanks in advance!
Gavino
8th December 2011, 10:58
Tried to use zoom plug-in in VirtualDub to pan & zoom in a HD res photo that I turned into video using Image Sequence. Alas, zoom there only supports 3 decimal digits or a max res of 999 pixels. I noticed that Ken Burns Effect didn't work either. (Someone asked in a post why his video output moved about wildly with this script. Didn't see an answer, but I suppose it's because this script relies on zoom.dll which seems to have the same limitation.)
Are you talking about the Zoom plugin from this thread?
I am not aware of any such limitation there.
t_2
9th December 2011, 20:06
Yes, I was. Thanks for tip. Will try again and repost.
mikeytown2
10th June 2012, 09:46
It's been a little while but I would play around with the useZoomBox parameter; I think you can disable the usage of zoom.dll if you set this to 2 (the default).
Yellow_
8th July 2012, 19:56
Trying to use KenBurnsEffect & Zoombox on 2.58, getting an error message:
"There is no function named Max" Line 60
http://avisynth.org/mediawiki/Internal_functions/Numeric_functions
Line 60 of ZoomBox script reads:
modzoom = Max(Float(c.width())/Float(width),Float(c.height())/Float(height))
This is the example script I'm trying from this thread:
Width=640
Height=480
Resize="BlackmanResize"
Align=-5
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
Any ideas?
I copy pasted the ZoomBox etc functions and saved into plugins folder, as an avsi file, like usual. Reopened the script, reopened avspmod too but same error.
StainlessS
8th July 2012, 20:23
I think Max may have been one of Stickboy's script/plugins.
EDIT, here: http://avisynth.org/stickboy/
Yellow_
8th July 2012, 20:51
Cheers, that's fixed the Max error, then had to change the BlackmanResize line and 'a' was missing for a+b+c+d+e, not bad for a 12 line script. :-)
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.