Search code examples
phpimagemathzoomingexponential

PHP Image Zoom - Exponential scale


Iam trying to calculate a zoom Effect beetween 12 Images. Every Image is 100% larger then the one before. Its geting near to perfect, but there is only a issue at the transition beetween the images. It isn't fluid zoom beetween each image. Please see the video: http://youtu.be/dUBbDjewpO0

I think the Exponential expression pow() isnt coorect for some reason. Here is the PHP script, but i cant find the issue:

 <?php
    $imageFiles=array(
     '1.jpg',
     '2.jpg',
     '3.jpg',        
     '4.jpg');
 $targetFrameRate=$targetDuration='18';
 $imageCount = count($imageFiles);
 $totalFrames        = ($targetFrameRate*$targetDuration);
 $sourceIndex  = 0;
 $firstIndex   = 1;
 $lastIndex    = $totalFrames; //==total frames
 $currentScale = 1;//image scaling for first scale 
 $deltaScale   = ((($imageCount-1)*($scaleFactor-$currentScale))/$totalFrames);

  for ($i=$firstIndex; $i<=$lastIndex; $i++) {

// prepare filename

$filename = createImageFilename($i, $imageType);

// determine source..
if ($i == $firstIndex) {
    $newSourceIndex = 0;
}
else if ($i == $lastIndex) {
    $newSourceIndex = ($imageCount-1);
}
else {
     $newSourceIndex = intval(($i*($imageCount-1))/$totalFrames);

}
// create frame..
if ($newSourceIndex != $sourceIndex) {
    $sourceIndex  = $newSourceIndex;
    $currentScale = pow($scaleFactor, $sourceIndex);
    $nextScale    = pow($scaleFactor, ($sourceIndex+1));
    $deltaScale   = ((($imageCount-1)*($nextScale-$currentScale))/$totalFrames);

    copyImage($imageFiles[$sourceIndex], 
              sprintf('%s/%s', $outputDir, $filename), 
              $imageWidth, 
              $imageHeight, 
              $imageType);
}
else {
    createImage($imageFiles[$sourceIndex], 
                sprintf('%s/%s', $outputDir, $filename), 
                ($currentScale/pow($scaleFactor, $sourceIndex)),
                $imageWidth, 
                $imageHeight, 
                $imageType);
}

//DEBUG: buffer some values for optional debug-output
if (isDebugOutputEnabled()) {
    $debug_idx[$i] = $filename;
    $debug_inf[$i] = sprintf('sourceIndex=%d , scale=%01.2f<br />', $sourceIndex, $currentScale);
}
// advance..
$currentScale += $deltaScale;
 }


 ?>

rendering is well

  shell_exec('ffmpeg -f image2 -i /var/www/htdocs/image2/i%d.jpg -s 1280x720 -movflags faststart -b:v 5500k -r 18 output.flv');

Solution

  • The problem comes from the fact that you are adding a delta to your scale instead of multiplying it by a constant amount each frame:

    $currentScale += $deltaScale;
    

    An exponential zoom means you increase the zoom by a constant factor (not difference) for a given constant amount of time, so you need to change that line to:

    $currentScale *= $deltaScale;
    

    and also calculate $deltaScale differently:

    $deltaScale = pow($nextScale / $currentScale, ($imageCount-1) / $totalFrames);
    

    This will compute a fractional power of the scale difference between the images, so that when you multiply it with the $currentScale value $totalFrames / ($imageCount-1) times (the number of frame you render between the current scale and next scale), the result will be an increase by a factor of $nextScale / $currentScale.

    Simplification:

    Because the zoom is at a constant rate for the whole animation, $deltaScale is constant the whole time, so you can compute it outside the loop like this:

    $deltaScale = pow($scaleFactor, ($imageCount-1) / $totalFrames);