imagejes

How do you add a swirl to an image (image distortion)?


I was trying to figure out how to make a swirl in the photo, tried looking everywhere for what exactly you do to the pixels. I was talking with a friend and we kinda talked about using sine functions for the redirection of pixels?


Solution

  • Let's say you define your swirl using 4 parameters:

    Start with a source image and create a destination image with the swirl applied. For each pixel (in the destination image), you need to adjust the pixel co-ordinates based on the swirl and then read a pixel from the source image. To apply the swirl, figure out the distance of the pixel from the center of the swirl and it's angle. Then adjust the angle by an amount based on the number of twists that fades out the further you get from the center until it gets to zero when you get to the swirl radius. Use the new angle to compute the adjusted pixel co-ordinates to read from. In pseudo code it's something like this:

    Image src, dest
    float swirlX, swirlY, swirlRadius, swirlTwists
    for(int y = 0; y < dest.height; y++)
    {
        for(int x = 0; x < dest.width; x++)
        {
            // compute the distance and angle from the swirl center:
            float pixelX = (float)x - swirlX;
            float pixelY = (float)y - swirlY;
            float pixelDistance = sqrt((pixelX * pixelX) + (pixelY * pixelY));
            float pixelAngle = arc2(pixelY, pixelX);
    
            // work out how much of a swirl to apply (1.0 in the center fading out to 0.0 at the radius):
            float swirlAmount = 1.0f - (pixelDistance / swirlRadius);
            if(swirlAmount > 0.0f)
            {
                float twistAngle = swirlTwists * swirlAmount * PI * 2.0;
    
                // adjust the pixel angle and compute the adjusted pixel co-ordinates:
                pixelAngle += twistAngle;
                pixelX = cos(pixelAngle) * pixelDistance;
                pixelY = sin(pixelAngle) * pixelDistance;
            }
            // read and write the pixel
            dest.setPixel(x, y, src.getPixel(swirlX + pixelX, swirlY + pixelY));
        }
    }