Perspective transformation using object

Updated:

Previously I wrote an article that discussed the perspective transformation of an image using Imagick API of php. If you didn't read that article, I recommend you should read it first here, as I am using code and idea from there.

This time we will be cutting and distorting image in an object oriented way. We'll be using the same image before.

Let's start by defining an object and load filename of the image in the directory.

new ImageDistort('public/cat.png');

and call the run() method

(new ImageDistort('public/cat.png'))->run();

But before this, let's define a blueprint or class of the ImageDistort so that we can create object based on that.

And as much as possible we will adhere to the PSR when writing php code.

class ImageDistort
{
private object $image;

public function __construct(string $filename="")
{
}
}

As shown here, we define a private property called $image and a constructor which is responsible for create an instance of an object.

If you see a class defined like this:

class ImageDistort
{
private object $image;
}

constructor is defined under the hood for you like

public function __construct()
{
}

Inside the constructor, add this

self::loadImage($filename);

I always use self when calling method inside the class so that easy for me to determine where the method belong

public function __construct()
{
self::loadImage($filename);
}

As shown here, we call loadImage() method. It accept argument filename. A file name of the image.

Let's define that method

private function loadImage(string $filename="")
{
$this->image = new Imagick($filename);
$this->image->setImageFormat('png');
$this->image->cropThumbnailImage(300, 200);
}

As shown here, the required parameter follows contravariant arguments concept. This kind is subject to another discussion.

Here we also defined it as private type method as it will be used inside a class. If needed to be call outside in the future, then change it to public type.

Next we pass filename as argument to Imagick class to create new Imagick object $this->image that contains the image from the file.

Then set the format as png and crop a thumbnail with width=300 and height=200.

Next let's define a public type run() method. Public because we will be calling this method after an object is created.

And call some other method.

public function run()
{
$cuttedImage = self::cutAndDistortImage(50, 150, 0, 25, [
0,0, 5,5,
50,0, 50,0,
0,150, 5,145,
50,150, 50,150
]);

self::saveImage($cuttedImage);
}

As shown here, we call cutAndDistortImage() and saveImage() method.

It accept arguments such as (width, height, x-coordinate, y-coordinate, control-points) a requirement to distort an image.

Let's define the cutAndDistortImage() method first.

private function cutAndDistortImage(
float $width,
float $height,
int $x,
int $y,
array $controlPoints = []
) {
$image = clone $this->image;
$image->cropImage($width, $height, $x, $y);
$image->setImageVirtualPixelMethod(Imagick::VIRTUALPIXELMETHOD_TRANSPARENT);
$image->setImageMatte(true);
$image->distortImage(Imagick::DISTORTION_BILINEAR, $controlPoints, true);
return $image;
}

As shown here, we clone the defined image source by using clone keyword.

Next we crop the image using the given width, height and the x and y coordinate. And the create a virtual pixel. I described Virtual Pixel in the previous article.

Then distort an image using control points and return a new image resource.

Next we will define saveImage()

private function saveImage(object $image, string $format="png")
{
$image->writeImage("image.{$format}");
}

As shown here, the method accept the image resource and format and then it will write it to local storage with given the default filename "image".

The final output

The whole Code

If we combine what is discussed above it will be look like this.


class ImageDistort
{
private object $image;

public function __construct(string $filename="")
{
self::loadImage($filename);
}

public function run()
{
$firstCut = self::cutAndDistortImage(50, 150, 0, 25, [
0,0, 5,5,
50,0, 50,0,
0,150, 5,145,
50,150, 50,150
]);

self::saveImage($firstCut);
}

private function saveImage(object $image, string $format="png")
{
$image->writeImage('cat.png');
}

private function displayImage(object $image, string $format="png")
{
header("Content-Type: image/{$format}");
echo $image;
}

private function cutAndDistortImage(
float $width,
float $height,
int $x,
int $y,
array $controlPoints = []
) {
$image = clone $this->image;
$image->cropImage($width, $height, $x, $y);
$image->setImageVirtualPixelMethod(Imagick::VIRTUALPIXELMETHOD_TRANSPARENT);
$image->setImageMatte(true);
$image->distortImage(Imagick::DISTORTION_BILINEAR, $controlPoints, true);
return $image;
}

private function loadImage(string $filename="")
{
$this->image = new Imagick($filename);
$this->image->setImageFormat('png');
$this->image->cropThumbnailImage(300, 200);
}
}

(new ImageDistort('public/cat.png'))->run();

....

What's next?

I'll be continuing to write more about image processing using Imagick in php. Make sure to have a visit from time to time to keep tune.