BogisW
BogisW

Reputation: 473

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

Problem

I have a qr code as existing svg image, let's say this one: https://editsvgcode.com/wamcmgdcp9lf8ru018

I use a javascript qr code reader, that works fine when the qr code is on a flat surface, but doesn't reliably read the code when I put the code on a round surface, eg. a bottle.

So my idea is to apply a Pincushion Distortion on the svg image, that makes the qr code look flat if scanned from a certain angle (straight in front) and distance.

Question

How can apply a pincushion distortion effect on an svg image? Of course, I searched on the internet, but I didn't find anything useful (either other svg filters or articles about removing distortion from raster graphics).

Upvotes: 1

Views: 257

Answers (1)

BogisW
BogisW

Reputation: 473

Disclaimer

Being the submitter of the question, I know that the following answer is a non-solution, as it doesn't filfull the requirement "by svg means" of the original question.

Nevertheless, I want to share my workaround with the community. Thus, I kindly ask you not to dovnvote this answer as "not answering the original question". I will not acceppt this answer as solution, but any other answers as solution, that solves the question with svg means.

Using PHP/Imagick

Here is my code that turns a svg image into php, and apply a 'cylinder to plane' effect on it (https://phpimagick.com/Imagick/distortImage?distortion_type=Cyclinder%20to%20plane&image_path=Lorikeet). I was happy with a width of 500px and with a distortImageAngle of 20, where the qr code looks flat from a distance of about 25 cm (depending on the size of the bottle/jar).

  public function svg2png(string $svg, int $width, int $distortImageAngle):string {
     $svg = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>'.$svg;
     $image = new \Imagick();
     $image->readImageBlob($svg);
     $height = $width * $image->getImageHeight() / $image->getImageWidth();
     $res = $image->getImageResolution(); // in pixels per centimeter
     $x_ratio = $res['x'] / $image->getImageWidth();
     $y_ratio = $res['y'] / $image->getImageHeight();
     $ratio = $x_ratio;

     // https://stackoverflow.com/a/13625767/13192551
     $image->removeImage();
     $image->setResolution($width * $ratio * 2.54, $height * $ratio * 2.54);
     $image->readImageBlob($svg);
     $image->setImageFormat("png64");

     // https://github.com/Imagick/ImagickDemos/blob/def2cedc27d74e9ddd4a638154651dd3924ade11/src/ImagickDemo/Imagick/distortImage.php
     $points = array(
        $distortImageAngle, //fov_angle,
        //center_x,y,
        //fov_output,
        //dest_center_x,y
     );
     $image->setImageBackgroundColor("#ffffff");
     $image->setImageVirtualPixelMethod(\Imagick::VIRTUALPIXELMETHOD_BACKGROUND);
     $image->distortImage(\Imagick::DISTORTION_CYLINDER2PLANE, $points, true);

     $png = $image->getImageBlob();
     $image->clear();
     $image->destroy();
     return($png);
  }

Non-programming solution

The reason for applying a pincushion distortion effect on a svg image was that I needed to read a qr code from bottle or (preserving) jar. My wife's solution: Simply put the qr code on the top (of the jar) or bottom (of the bottle). It had saved a lot of time if I had asked her before.

Upvotes: 1

Related Questions