This is a simple example of how to cross fade between two images with a pre-computed gradient.

Input images

Output image

This is a simple example of how to cross fade between two images with a pre-computed gradient.
// Example 1
function imagickComposite()
{
    //Load the images
    $left = new \Imagick(realpath('images/im/holocaust_tn.gif'));
    $right = new \Imagick(realpath('images/im/spiral_stairs_tn.gif'));
    $gradient = new \Imagick(realpath('images/im/overlap_mask.png'));

    //The right bit will be offset by a certain amount - avoid recalculating.
    $offsetX = $gradient->getImageWidth() - $right->getImageWidth();


    //Fade out the left part - need to negate the mask to
    //make math correct
    $gradient2 = clone $gradient;
    $gradient2->negateimage(false);
    $left->compositeimage($gradient2, \Imagick::COMPOSITE_COPYOPACITY, 0, 0);

    //Fade out the right part
    $right->compositeimage($gradient, \Imagick::COMPOSITE_COPYOPACITY, -$offsetX, 0);

    //Create a new canvas to render everything in to.
    $canvas = new \Imagick();
    $canvas->newImage($gradient->getImageWidth(), $gradient->getImageHeight(), new \ImagickPixel('black'));

    //Blend left half into final image
    $canvas->compositeimage($left, \Imagick::COMPOSITE_BLEND, 0, 0);

    //Blend Right half into final image
    $canvas->compositeimage($right, \Imagick::COMPOSITE_BLEND, $offsetX, 0);

    //Output the final image
    $canvas->setImageFormat('png');

    header("Content-Type: image/png");
    echo $canvas->getImageBlob();
}
// Example 2 - Gen
function generateBlendImage($height, $overlap, $contrast = 10, $midpoint = 0.5)
{
    $imagick = new \Imagick();
    $imagick->newPseudoImage($height, $overlap, 'gradient:black-white');
    $quantum = $imagick->getQuantum();
    $imagick->sigmoidalContrastImage(true, $contrast, $midpoint * $quantum);

    return $imagick;
}


function mergeImages(
    array $srcImages,
    $outputSize,
    $overlap,
    $contrast = 10,
    $blendMidpoint = 0.5,
    $horizontal = true
) {

    $images = array();
    $newImageWidth = 0;
    $newImageHeight = 0;

    if ($horizontal == true) {
        $resizeWidth = 0;
        $resizeHeight = $outputSize;
    }
    else {
        $resizeWidth = $outputSize;
        $resizeHeight = 0;
    }

    $blendWidth = 0;

    foreach ($srcImages as $srcImage) {
        $nextImage = new \Imagick(realpath($srcImage));
        $nextImage->resizeImage($resizeWidth, $resizeHeight, \Imagick::FILTER_LANCZOS, 0.5);

        if ($horizontal == true) {
            $newImageWidth += $nextImage->getImageWidth();
            $blendWidth = $nextImage->getImageHeight();
        }
        else {
            //$newImageWidth = $nextImage->getImageWidth();
            $blendWidth = $nextImage->getImageWidth();
            $newImageHeight += $nextImage->getImageHeight();
        }

        $images[] = $nextImage;
    }

    if ($horizontal == true) {
        $newImageWidth -= $overlap * (count($srcImages) - 1);
        $newImageHeight = $outputSize;
    }
    else {
        $newImageWidth = $outputSize;
        $newImageHeight -= $overlap * (count($srcImages) - 1);
    }

    if ($blendWidth == 0) {
        throw new \Exception("Failed to read source images");
    }

    $fadeLeftSide = generateBlendImage($blendWidth, $overlap, $contrast, $blendMidpoint);

    if ($horizontal == true) {
        //We are placing the images horizontally.
        $fadeLeftSide->rotateImage('black', -90);
    }

    //Fade out the left part - need to negate the mask to
    //make math correct
    $fadeRightSide = clone $fadeLeftSide;
    $fadeRightSide->negateimage(false);

    //Create a new canvas to render everything in to.
    $canvas = new \Imagick();
    $canvas->newImage($newImageWidth, $newImageHeight, new \ImagickPixel('black'));

    $count = 0;

    $imagePositionX = 0;
    $imagePositionY = 0;

    /** @var $image \Imagick */
    foreach ($images as $image) {
        $finalBlending = new \Imagick();
        $finalBlending->newImage($image->getImageWidth(), $image->getImageHeight(), 'white');

        if ($count != 0) {
            $finalBlending->compositeImage($fadeLeftSide, \Imagick::COMPOSITE_ATOP, 0, 0);
        }

        $offsetX = 0;
        $offsetY = 0;

        if ($horizontal == true) {
            $offsetX = $image->getImageWidth() - $overlap;
        }
        else {
            $offsetY = $image->getImageHeight() - $overlap;
        }

        if ($count != count($images) - 1) {
            $finalBlending->compositeImage($fadeRightSide, \Imagick::COMPOSITE_ATOP, $offsetX, $offsetY);
        }

        $image->compositeImage($finalBlending, \Imagick::COMPOSITE_COPYOPACITY, 0, 0);
        $canvas->compositeimage($image, \Imagick::COMPOSITE_BLEND, $imagePositionX, $imagePositionY);

        if ($horizontal == true) {
            $imagePositionX = $imagePositionX + $image->getImageWidth() - $overlap;
        }
        else {
            $imagePositionY = $imagePositionY + $image->getImageHeight() - $overlap;
        }
        $count++;
    }

    return $canvas;
}

function imagickCompositeGen($contrast = 10, $blendMidpoint = 0.5)
{
    $size = 160;

    //Load the images
    $output = mergeImages(
        [
            'images/lories/6E6F9109_480.jpg',
            'images/lories/IMG_1599_480.jpg',
            'images/lories/IMG_2561_480.jpg',
            'images/lories/IMG_2837_480.jpg',
            //'images/lories/IMG_4023.jpg',
        ],
        $size,
        0.2 * $size, //overlap
        $contrast,
        $blendMidpoint,
        true
    );

    //$output = generateBlendImage(200, 200, 5, 0.5);
    $output->setImageFormat('png');

    header("Content-Type: image/png");
    echo $output->getImageBlob();
}