2

I want to create distortion effect like Spiral, stretch, fisheye, Wedge and other effect like underwater and snow like this website using cv2 library in python.

gauravd2196
  • 185
  • 1
  • 11
  • Imagemagick has many effects. You can use Python Wand, which is based upon Imagemagick to do quite a lot of things. https://imagemagick.org/Usage/ – fmw42 Apr 17 '20 at 17:34

3 Answers3

0

I figured out fisheye distortion.

In OpenCV version 3.0 and above it is possible to perform it using cv2.fisheye.undistortImage(). I have the code in python if you need.

This is what I got for the following input image:

Input Image:

enter image description here

Distorted image:

enter image description here

The function accepts a matrix, which upon modification yield different distortions of the image.

UPDATE

In order to add a snowfall effect you can add some noise like Poisson noise.

Community
  • 1
  • 1
Jeru Luke
  • 20,118
  • 13
  • 80
  • 87
  • 1
    Thank you Jeru Luke. But I think it is used for correcting fisheye effect. I want to create fisheye effect from normal image. – gauravd2196 Mar 12 '17 at 14:34
0

Here is half of an answer. The cv2.remap function uses maps to choose a pixel from the source for each pixel in the destination. alkasm's answer to this: How do I use OpenCV's remap function? does a great job of defining the process, but glosses over the usefulness of those maps. If you can get creative in the maps, you can make any effect you want. Here is what I came up with.

The program starts by loading the image and resizing it. This is a convenience for a smaller screen. Then the empty maps are created.

The maps need to be the same dimensions as the image that is being processed, but with a depth of 1. If the resized original is 633 x 400 x 3, the maps both need to be 633 x 400.

When the remapping is done, cv2.remap will used the value at each coordinate in the maps to determine which pixel in the original to use in the destination. For each x,y in the destination, dest[x,y] = src[map1[x,y],map2[x,y]].

The simplest mapping would be if for every (x,y), map1(x,y)=x and map2(x,y)=y. This creates a 1-to-1 map, and the destination would match the source. In this example, a small offset is added to each value. The cosine function in the offset creates both positive and negative shifts, creating waves in the final image.

Note that creating the maps is slow, but the cv2.remap is fast. Once you have created the map, the cv2.remap is fast enough to be applied to frames of video.

    import numpy as np            #create waves
    import cv2
    import math

    # read in image and resize down to width of 400
    # load your image file here
    image = cv2.imread("20191114_154534.jpg")

    r = 400.0 / image.shape[1]
    dim = (400, int(image.shape[0] * r))

    # Perform the resizing of the image
    resized = cv2.resize(image, dim, interpolation = cv2.INTER_AREA)

    # Grab the dimensions of the image and calculate the center
    # of the image  (center not needed at this time)
    (h, w, c) = resized.shape
    center = (w // 2, h // 2)

    # set up the x and y maps as float32
    flex_x = np.zeros((h,w),np.float32)
    flex_y = np.zeros((h,w),np.float32)

    # create simple maps with a modified assignment
    # the math modifier creates ripples.  increase the divisor for less waves, 
    # increase the multiplier for greater movement
    # this is where the magic is assembled
    for y in range(h):
        for x in range(w):
            flex_x[y,x] = x + math.cos(x/15) * 15
            flex_y[y,x] = y + math.cos(y/30) * 25


    # do the remap  this is where the magic happens      
    dst = cv2.remap(resized,flex_x,flex_y,cv2.INTER_LINEAR)


    #show the results and wait for a key
    cv2.imshow("Resized",resized)
    cv2.imshow("Flexed",dst)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
jpmutant
  • 3
  • 1
0

Here is a replacement block to map out a fisheye in the middle of the image. Please look elsewhere for details on the math. Use this in place of the 2 for loops in the previous code.

As stated in the first half of my answer (see previous answer), the purpose of this block is to create 2 maps that work together to remap the source image into the destination image.

To create the two maps, this block sweeps through 2 for loops with the dimensions of the image. Values are calculated for the X and y maps (flex_x and flex_y). It starts with assigning each to simply x and y for a 1-to-1 replacement map. Then, if the radius (r) is between 0 and 1, the map for the tangential slide for the fisheye is applied and new flex_x and flex_y values are mapped.

Please see my other answer for more details.

    # create simple maps with a modified assignment
    # outside the bulge is normal, inside is modified
    # this is where the magic is assembled
    for y in range(h):
        ny = ((2*y-250)/(h-250))-1     #play with the 250's to move the y
        ny2 = ny*ny
        for x in range(w):
            nx = ((2*x-50)/(w-50))-1   #play with the 50's to move the x
            nx2 = nx*nx
            r = math.sqrt(nx2+ny2)
            flex_x[y,x] = x
            flex_y[y,x] = y
            if r>0 and r<1:
                nr1 = 1 - r**2
                nr2 = math.sqrt(nr1)
                nr = (r + (1.0-nr2)) / 2.0
                theta = math.atan2(ny,nx)
                nxn = nr*math.cos(theta)
                nyn = nr*math.sin(theta)
                flex_x[y,x] = (((nxn+1)*w)/2.0)
                flex_y[y,x] = (((nyn+1)*h)/2.0)
jpmutant
  • 3
  • 1
  • 2
    While this code may solve the question, [including an explanation](https://meta.stackexchange.com/q/114762) of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please [edit] your answer to add explanations and give an indication of what limitations and assumptions apply. – Brian61354270 Apr 17 '20 at 17:36