4

I am trying to change the perspective of the Plane2Cylinder distortion in ImageMagick via PHP.

To help explain what I'm looking for, I've created this graphic:

Sample of perspective

You can see that the lower part of the red block has a greater radius than the top part, as if you were viewing this from above center.

I have tried the optional center_x/y fields:

$label->distortImage(\Imagick::DISTORTION_PLANE2CYLINDER, [28,0,100], true);

With various settings between 0 and 1000 on each x and y, with zero results.

Anyone have any insights or hints? I've search thoroughly, but can't find anything relevent.

Luke Pittman
  • 870
  • 4
  • 12
  • As far as I know, there is no tilt in the ImageMagick plane2cylinder function. See https://imagemagick.org/Usage/mapping/#displace_cylinder where he uses a polynomial equation to apply a pseudo tilt to the cylinder. You would have to use some kind of inverse to that. – fmw42 Sep 30 '20 at 18:35
  • @fmw42 Thanks, I'll check it out. (Yep I realize this was awhile ago) – Luke Pittman Dec 09 '20 at 15:21
  • It will be better if you give bigger part of your code - then more people will try to help now it's only theory with one line of code and one image. – GTsvetanov Jan 07 '21 at 08:48

3 Answers3

1

I haven't fount solution with the DISTORTION_PLANE2CYLINDER but just as an idea that a hardcore perspective may reduce the strength of difference and maybe become also a point for further distortions for eg. Circular and Radial Distortion Methods (Arc).

enter image description here

plus

convert img.png \
-matte \
-virtual-pixel transparent \
-distort Perspective '200,0,0,0 100,700,100,700 700,700,700,700 600,0,800,0 ' \
img1.png

enter image description here

May give you desired radius on top and bottom.

Jimmix
  • 5,644
  • 6
  • 44
  • 71
  • Try plan2cylinder, then make a binary mask. Then on the result of plane to cylinder apply -distort barrel. Then apply the mask to that to trim any horizontalbulging – fmw42 Jan 12 '21 at 03:41
  • Thanks. This isn't quite what I was after, but I do appreciate the idea! – Luke Pittman Feb 09 '21 at 18:30
1

So, after all this work trying to figure out how to do this using masks, filters, etc... the solution was actually dead simple.

I ended up just placing the main image over top of a taller transparent image (at the correct distance down from the top to create the perspective), then applying the plane2cylindar to that whole image.

So crazy I didn't see that to start. Thanks for the thoughts and help though.

Edit - more details on how to achieve this.

enter image description here

$finalimage = new Imagick ('flowers_with_perspective.jpg'); // The final image

// a canvas with no background that sets the foundation for the perspective I want.
$canvas = new Imagick (); 
$canvas ->newImage ($width, $height+200, 'none'); // $height should be the input file size plus a bunch of extra height (200px for example).

// the image I am want in perspective (the flowers in my example)
$image = new Imagick ('flowers.jpg');
$image->setImageBackgroundColor(new \ImagickPixel('transparent'));
$image->setImageVirtualPixelMethod(Imagick::VIRTUALPIXELMETHOD_TRANSPARENT); // make sure it's in transparent mode so when I overlay it on another image it doesn't have an odd background

// get vertical offset for $image on $canvans
$top = (($canvas->getImageHeight() - $image->getImageHeight())/2) +100; // should offset flower image 100px down from center

// apply $image to $canvas at 0px left and $top px down from top
$canvas->compositeImage ($image, Imagick::COMPOSITE_DEFAULT, 0, $top);

// at this point we just have the normal 'flowers.jpg' but displayed 100px down from center on a larger, transparent canvas.

// now apply plane2cylendar to create perspective on entire image
$canvas->distortImage(\Imagick::DISTORTION_PLANE2CYLINDER, [26], true);

// now you would apply the canvas to $finalimage along with other filters/overlays/etc you'd need and save!
Luke Pittman
  • 870
  • 4
  • 12
  • 2
    How about posting and input and output example. – fmw42 Feb 10 '21 at 00:55
  • Hi Luke, stackoverflow's primary intention is to let others, who have the same questions, find solutions by just looking it up. Helping the questioner is only a (useful, first moment) side effect. So please, be so kind to extend your answer with your code. Thanks! – BogisW Mar 20 '23 at 06:29
  • Yes you are both absolutely right! Thanks for the reminder. I intended on coming back to update this but totally forgot. – Luke Pittman Mar 21 '23 at 07:21
  • @fmw42 Over 2 years ago but thanks to the above reminder I got around to it. Sorry about that. – Luke Pittman Mar 21 '23 at 07:38
  • 1
    @BogisW I had fully intended on adding more information but moved on to other projects then eventually just forgot. Thank you for the reminder. I've added more info and code. – Luke Pittman Mar 21 '23 at 07:38
1

Programming solution

I solved this with the following code - works like a charm and delivers the right result. Be aware, the angle also depends on the distance of the viewer, not only on the eye level.

public function renderCyclinderToPlane()
{
    //http://www.imagemagick.org/Usage/distorts/#cylinder2plane
    $imagick = new \Imagick(realpath($this->distortImageControl->getImagePath()));
    $points = array(
        70, //fov_angle,
        //center_x,y,
        //fov_output,
        //dest_center_x,y
    );
    $imagick->setImageBackgroundColor("#fad888");
    $imagick->setImageVirtualPixelMethod(\Imagick::VIRTUALPIXELMETHOD_BACKGROUND);
    $imagick->distortImage(\Imagick::DISTORTION_CYLINDER2PLANE, $points, true);
    header("Content-Type: image/jpeg");
    echo $imagick;
}

References / Credits go to:

Also see: How can I apply a pincushion distortion effect on a svg image (in order to read a qr code on round surface reliably)?

Non-programming alternative

If you just want to put an qr code on a glass/jar/bottle, put it on the top or bottom.

BogisW
  • 401
  • 2
  • 16
  • I do recall trying this route but it would never work as intended for me - it's possible that the packages have been updated to fix the issues I was running into 2 years ago when working on it. If this does produce the desired result it certainly is a much more elegant solution. – Luke Pittman Mar 21 '23 at 07:41