Question

How can I repeat an image along a circle? Note that it should also get distorted a bit. What I'm trying to get to is this: I've been working on a POV LED design that takes an image and flashes it along a string of LEDs while the whole thing is spinning. When you look at the display, the image is distorted a little bit, squished in along the inner part of the circle and stretched a bit on the outer. I want to recreate that.

The red circle is for reference only and will always be the same size. I will probably leave it in the resulting composite as well. How often the image gets repeated along the circle path should be adjustable based on the actual width of the original image (and whether I'm adding a break between each copy.) For example, there are images that tile right next to each other, no break, and others that will need a break. So I need a way to define that.

With the yellow diagonal lines, I don't want a break between the image as it repeats. I left the white edges on the top one to show how it's distorted.

How can I accomplish this using Magick++? Ultimately I will take the code and incorporate it into a much large application that used Magick++ to manipulate the images that the user imports for the POV LED display.

Thanks!

Repeating Image

Was it helpful?

Solution 2

I think I figured it out. So here's the snippet of code that I am now working with:

Magick::Image srcImage;
srcImage.read("001.png");
srcImage.resize("x100");      // I want images at least 100 pixels high
Magick::Color color(0, 0, 0); // images should always be on a black background

// to add space beween a repeating image, add a value to .columns()
// for example:
// srcImage.extent(Magick::Geometry(srcImage.columns() + 10, 100), color);
// will add 10 pixels of space or padding after each image repeat
srcImage.extent(Magick::Geometry(srcImage.columns(), 100), color);

// preprocess
// .columns() is multiplied by the amount of times the image repeats in the circle
// for example, this repeats the image 8 times:
// srcImage.size(Magick::Geometry(srcImage.columns() * 8, 100));
srcImage.size(Magick::Geometry(srcImage.columns() * 8, 100));
srcImage.virtualPixelMethod(Magick::HorizontalTileEdgeVirtualPixelMethod);
const double tileArgs[1] = {0};
srcImage.distort(Magick::ScaleRotateTranslateDistortion, 1, tileArgs, Magick::MagickTrue);

// distort
srcImage.virtualPixelMethod(Magick::BlackVirtualPixelMethod);
const double arcArgs[4] = {360, 0, 98, 30};
srcImage.distort(Magick::ArcDistortion, 4, arcArgs, Magick::MagickTrue);
srcImage.write("001-out.png");

OTHER TIPS

Yes, you can accomplish tiling images around a circle with Magick::Image.distort. Although some trial & error would be expected as you have very localized requirements for your POV project.

Repeat Image Along Circle

ArcDistortion examples apply, just the same, in Magick++. Ensure you enable a virtual pixel method, and distort a given image with an 360 degree Arc. I'm using image "pattern:CHECKERBOARD", but you would use "tile:image_source.png".

Magick::Image MyArc;
MyArc.read("pattern:CHECKERBOARD");
MyArc.size("600x45");
MyArc.virtualPixelMethod(Magick::WhiteVirtualPixelMethod);
const double arcArgs[1] = {360};
MyArc.distort(Magick::ArcDistortion,1, arcArgs,Magick::MagickTrue);
MyArc.write("out.png");

This will give you a repeating image along a circle.

Example arc distortion

Preserver Inner Circle

To control the size of the inner & outer circle. Apply the 3rd & 4th arguments to the distortion method.

const double arcArgs[4] = {360,0,200,100};
MyArc.distort(Magick::ArcDistortion,4, arcArgs,Magick::MagickTrue);

Example arc distortion around given circle

Custom Image with Pre-Processing

As far as adding whitespace, padding, bleeding, and adjust image repetition. Those will all require pre-processing before arc distortion.

Magick::Image SourceImage;
SourceImage.read("me.png");
SourceImage.resize("45x45");
// Add whitespace between repeating image
SourceImage.extent(Magick::Geometry(100,45));

// Resize image to be "long" enough to bend around arc.
SourceImage.size("600x45");
// PrePrecess image to tile horizontally with Edge Virtual Pixel
SourceImage.virtualPixelMethod(Magick::HorizontalTileEdgeVirtualPixelMethod);
const double tileArgs[1] = {0};
SourceImage.distort(Magick::ScaleRotateTranslateDistortion,1,tileArgs,Magick::MagickTrue);

// Distort around circle
SourceImage.virtualPixelMethod(Magick::WhiteVirtualPixelMethod);
const double arcArgs[4] = {360,0,200,100};
SourceImage.distort(Magick::ArcDistortion,4, arcArgs,Magick::MagickTrue);
SourceImage.write("out.png");

Arc distortion with custom image frequency

Just remember a lot if POV issues can be resolved with fun math.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top