Using Python and openCV to revive a dead Etsy product


[ambigram pic]

Here are some things I like: words, optical illusions, art. An [ambigram] is a clever combination of all three of these, so of course I like these too. There are a few different forms, and while they're all neat, I am particularly fond of the type that incorporates two wholly different words, with a 180-degree rotation separating the two:

[rotational trans-ambigram]

One day, I noticed one of those dishwasher clean/dirty magnets, and thought "Hey! that would be a perfect way to use an ambigram!" Then, realizing my limited artistic skill would prevent me from inventing it myself, I turned to the web. I found a handful of examples, and [one that I really liked on Etsy][] - this one was actually designed to be used as a dishwasher magnet (tag: no original ideas)! Unfortunately, the product was listed as unavailable, and with no other products in the shop, I was not hopeful about contacting the creator, [].

Well, that would be a dead end, except the [image][] was available in a halfway decent resolution. That means I should be able to hack it back into existence, so I set out to do just that.

570x443 pixels isn't great, but for a simple, monochrome image with sharp lines, it might just work.

Given a moderate-resolution photograph of a rectangular object at an oblique angle, extract the design on the rectangle, and reproduce it at higher quality.


  1. Undo the perspective projection (homography transform)
  2. Generate an SVG image (vectorize)
  3. Clean up the messy edges (manual work)

Normally, I'm happy to dive into coding this stuff from scratch, but in this case I was more interested in the destination than the journey, so I went for some proven solutions.

  1. Undoing the perspective projection

As part of my perpetual [matlab-to-python] transition, I decided to ignore some old matlab code I wrote to solve this problem, and redo it in Python. Turns out, with the openCV bindings available in Python, it's a trivial problem. All I had to do was manually pick a handful of keypoints, and pass to a single function to generate the required transformation.

h, status = cv2.findHomography(pin, pout) im_dst = cv2.warpPerspective(im_src, h, dim)

If I needed to do this for more than a few images, I would have wanted to automate the keypoint-picking step (do people still use, but I'll save that for a time when I need it.


  1. Generating an SVG image

Using Hugo and org-mode for a blog

Reviving a dead Etsy product