Applying a logo to a tshirt using PHP Imagick

2019-07-21 13:24发布

I'm new to imagemagic aka imagick on php and im trying to follow this thread using php code. I have tried to apply this logo onto a tshirt but couldn't do so by following the threas becuase i cannot find most of the methods in php like using displacement map to start with. What i have tried is the following code:

$image = new Imagick($_SERVER['DOCUMENT_ROOT'] . '/images/VYLZsoD.jpg');    
$logo = new Imagick($_SERVER['DOCUMENT_ROOT'] . '/images/logo.png');
$logo->resizeImage(200, 200, imagick::FILTER_LANCZOS, 1, TRUE);    
header("Content-Type: image/jpg");

$image->compositeimage($logo, Imagick::COMPOSITE_DEFAULT, 400, 260); 
$image->flattenImages();

echo $image;

I would want to use the steps shown in the thread to create a mask and so on in order to apply the logo onto the tshirt using php code (not via command). I have even used "COMPOSITE_OVERLAY" to make the logo look like its part of the tshirt but it seems like the original color of the logo reduces because of the transparency, check here for my final tshirt http://i62.tinypic.com/2ahuw6h.png.

  1. Please tell me how i can archive a better result using imagick in php (without the color of the logo is being reduced)
  2. Can i mark a territory on the tshirt so that when i drag the logo around, it wouldn't show outside the tshirt border?

Source tshirt http://i58.tinypic.com/154j52b.jpg Source logo http://i59.tinypic.com/e02051.png

4条回答
做自己的国王
2楼-- · 2019-07-21 13:40

I hope, this effects will help you.

(this page has much effects, so you can search with F3 (tshirt) )

查看更多
乱世女痞
3楼-- · 2019-07-21 13:41

Here;s the final code for my 2nd question:

<?php

// Let's check whether we can perform the magick.
if (TRUE !== extension_loaded('imagick')) {
    throw new Exception('Imagick extension is not loaded.');
}

// This check is an alternative to the previous one.
// Use the one that suits you better.
if (TRUE !== class_exists('Imagick')) {
    throw new Exception('Imagick class does not exist.');
}

function getAverageColorString(\Imagick $imagick) {

    $max = $imagick->getquantumrange(); 
    $max = $max["quantumRangeLong"];

    $tshirtCrop = clone $imagick;
    $tshirtCrop->cropimage(100, 100, 90, 50);
    $stats = $tshirtCrop->getImageChannelStatistics();
    $averageRed = $stats[\Imagick::CHANNEL_RED]['mean'];
    $averageRed = intval(255 * $averageRed / $max);
    $averageGreen = $stats[\Imagick::CHANNEL_GREEN]['mean'];
    $averageGreen = intval(255 * $averageGreen / $max);
    $averageBlue = $stats[\Imagick::CHANNEL_BLUE]['mean'];
    $averageBlue = intval(255 * $averageBlue / $max);
    $colorString = "rgb($averageRed, $averageGreen, $averageBlue)";

    return $colorString;
}

//final product
$tshirt = new \Imagick($_SERVER['DOCUMENT_ROOT'] . '/images/VYLZsoD.jpg');
$logo = new \   Imagick($_SERVER['DOCUMENT_ROOT'] . '/logo.png');
$logo->resizeImage(100, 100, imagick::FILTER_LANCZOS, 1, TRUE);

$tshirt->setImageFormat('png');

//First lets find the creases
//Get the average color of the tshirt and make a new image from it.
$colorString = getAverageColorString($tshirt);
$creases = new \Imagick();
$creases->newpseudoimage(
   $tshirt->getImageWidth(),
   $tshirt->getImageHeight(), 
   "XC:".$colorString
);

//Composite difference finds the creases
$creases->compositeimage($tshirt, \Imagick::COMPOSITE_DIFFERENCE, 0, 0);
$creases->setImageFormat('png');
//We need the image negated for the maths to work later. 
$creases->negateimage(true);
//We also want "no crease" to equal 50% gray later
//$creases->brightnessContrastImage(-50, 0); //This isn't in Imagick head yet, but is more sensible than the modulate function.
$creases->modulateImage(50, 100, 100);

//Copy the logo into an image the same size as the shirt image
//to make life easier
$logoCentre = new \Imagick();
$logoCentre->newpseudoimage(
   $tshirt->getImageWidth(),
   $tshirt->getImageHeight(),
   "XC:none"
);
$logoCentre->setImageFormat('png');
$logoCentre->compositeimage($logo, \Imagick::COMPOSITE_SRCOVER, 110, 75);

//Save a copy of the tshirt sized logo
$logoCentreMask = clone $logoCentre;

//Blend the creases with the logo
$logoCentre->compositeimage($creases, \Imagick::COMPOSITE_MODULATE, 0, 0);

//Mask the logo so that only the pixels under the logo come through
$logoCentreMask->compositeimage($logoCentre, \Imagick::COMPOSITE_SRCIN, 0, 0);

//Composite the creased logo onto the shirt
$tshirt->compositeimage($logoCentreMask, \Imagick::COMPOSITE_DEFAULT, 0, 0);

//And Robert is your father's brother
header("Content-Type: image/png");
echo $tshirt->getImageBlob();
?>

Output Output http://i59.tinypic.com/23h7nzs.png

查看更多
兄弟一词,经得起流年.
4楼-- · 2019-07-21 13:55

The second part of your question, how to get the creases to show through 'nicely' is possibly a bad idea. There are two problems with attempting it:

i) The distortions in the tshirt are physical displacements. Although you can get the crease lighting to show through, it's really hard to get the logo to look realistic without also having the same physical displacement.

ii) Colors really don't behave consistently. Just having the logo be lighter/darker by the same amount as the tshirt crease may produce unrealistic effects. e.g. dark tshirt + crease = 50% brighter background. Bright blue logo + 50% brighter crease effect = unrealistic looking blue highlight.

I would recommend having a flat tshirt as the background as unrealistic effects tend to distract people. But you could do it like this:

function getAverageColorString(\Imagick $imagick) {

    $tshirtCrop = clone $imagick;
    $tshirtCrop->cropimage(100, 100, 90, 50);
    $stats = $tshirtCrop->getImageChannelStatistics();
    $averageRed = $stats[\Imagick::CHANNEL_RED]['mean'];
    $averageRed = intval(255 * $averageRed / \Imagick::getQuantum());
    $averageGreen = $stats[\Imagick::CHANNEL_GREEN]['mean'];
    $averageGreen = intval(255 * $averageGreen / \Imagick::getQuantum());
    $averageBlue = $stats[\Imagick::CHANNEL_BLUE]['mean'];
    $averageBlue = intval(255 * $averageBlue / \Imagick::getQuantum());
    $colorString = "rgb($averageRed, $averageGreen, $averageBlue)";

    return $colorString;
}


$tshirt = new \Imagick(realpath("../images/tshirt/tshirt.jpg"));
$logo = new \Imagick(realpath("../images/tshirt/Logo.png"));
$logo->resizeImage(100, 100, \Imagick::FILTER_LANCZOS, 1, TRUE);

$tshirt->setImageFormat('png');

//First lets find the creases
//Get the average color of the tshirt and make a new image from it.
$colorString = getAverageColorString($tshirt);
$creases = new \Imagick();
$creases->newpseudoimage(
   $tshirt->getImageWidth(),
   $tshirt->getImageHeight(), 
   "XC:".$colorString
);

//Composite difference finds the creases
$creases->compositeimage($tshirt, \Imagick::COMPOSITE_DIFFERENCE, 0, 0);
$creases->setImageFormat('png');
//We need the image negated for the maths to work later. 
$creases->negateimage(true);
//We also want "no crease" to equal 50% gray later
//$creases->brightnessContrastImage(-50, 0); //This isn't in Imagick head yet, but is more sensible than the modulate function.
$creases->modulateImage(50, 100, 100);

//Copy the logo into an image the same size as the shirt image
//to make life easier
$logoCentre = new \Imagick();
$logoCentre->newpseudoimage(
   $tshirt->getImageWidth(),
   $tshirt->getImageHeight(),
   "XC:none"
);
$logoCentre->setImageFormat('png');
$logoCentre->compositeimage($logo, \Imagick::COMPOSITE_SRCOVER, 110, 75);

//Save a copy of the tshirt sized logo
$logoCentreMask = clone $logoCentre;

//Blend the creases with the logo
$logoCentre->compositeimage($creases, \Imagick::COMPOSITE_MODULATE, 0, 0);

//Mask the logo so that only the pixels under the logo come through
$logoCentreMask->compositeimage($logoCentre, \Imagick::COMPOSITE_SRCIN, 0, 0);

//Composite the creased logo onto the shirt
$tshirt->compositeimage($logoCentreMask, \Imagick::COMPOSITE_DEFAULT, 0, 0);

//And Robert is your father's brother
header("Content-Type: image/png");
echo $tshirt->getImageBlob();

Produces an image like:

enter image description here

查看更多
走好不送
5楼-- · 2019-07-21 13:57

The output image you posted doesn't look like the output image I see when running your code. Obviously adjusting the position a little, the output image I see doesn't have the color reduced.

enter image description here

If you don't see see the same thing, it may be a bug in your version of ImageMagick. You could try using the composite method COMPOSITE_ATOP, which should produce the same result, via a different blend method.

For your second question, how to limit the logo overlay to the edge of the Tshirt, you can do it by creating a mask out of the tshirt, painting the logo onto that mask with COMPOSITE_SRCIN and then painting the result of that onto the tshirt:

    $tshirt = new \Imagick(realpath("../images/tshirt/tshirt.jpg"));
    $logo = new \Imagick(realpath("../images/tshirt/Logo.png"));
    $logo->resizeImage(100, 100, \Imagick::FILTER_LANCZOS, 1, TRUE);

    $tshirt->setImageFormat('png');

    $max = $image->getQuantumRange();
    $max = $max["quantumRangeLong"];

    //Create a mask by cloning the shirt,
    $mask = clone $tshirt;
    //Negating the image,
    $mask->negateimage(true);
    //Make it transparent everywhere that it is now white.
    $mask->transparentPaintImage(
        'black', 
        0, 
        0.1 * $max, 
        false
    );

    //Paint the logo onto the mask, SRCIN just uses the logo's color
    $mask->compositeimage($logo, \Imagick::COMPOSITE_SRCIN, 210, 75);
    //Paint the result of the logo + mask onto the tshirt.
    $tshirt->compositeimage($mask, \Imagick::COMPOSITE_DEFAULT, 0, 0);
    //Merge the image with a non-deprecated function.
    $tshirt->mergeimagelayers(\Imagick::LAYERMETHOD_COALESCE);

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

Which produces something like:

enter image description here

Whether that's a good idea or not is another matter.

查看更多
登录 后发表回答