A lot of questions about removing radial (or barrel) distortion, but how would I add it?
Visually, I want to take my input, which is presumed to be image (a), and distort it, to be like image (b):

And ideally I'd like a tunable parameter of some "radius" to control "how much distortion" I get. Based on what I want to do, it looks like I'd just need one parameter to control the 'radius of distortion' or whatever it would be called (correct me if I'm wrong).
How can I achieve this with OpenCV? I figure it must be possible because a lot of people try going the other way for things like this. I'm just not as familiar with the proper math operations and library calls to do it.
Any help much appreciated, cheers.
The program below creates barrel distortion
from wand.image import Image
import numpy as np
import cv2
with Image(filename='Path/to/Img/') as img:
print(img.size)
img.virtual_pixel = 'transparent'
img.distort('barrel', (0.1, 0.0, 0.0, 1.0)) # play around these values to create distortion
img.save(filename='filname.png')
# convert to opencv/numpy array format
img_opencv = np.array(img)
# display result with opencv
cv2.imshow("BARREL", img_opencv)
cv2.waitKey(0)
cv2.destroyAllWindows()
Here is one way to produce barrel or pincushion distortion in Python/OpenCV by creating the X and Y distortion maps and then using cv.remap() to do the warping.
Input:

import numpy as np
import cv2 as cv
import math
img = cv.imread('lena.jpg')
# grab the dimensions of the image
(h, w, _) = img.shape
# set up the x and y maps as float32
map_x = np.zeros((h, w), np.float32)
map_y = np.zeros((h, w), np.float32)
scale_x = 1
scale_y = 1
center_x = w/2
center_y = h/2
radius = w/2
#amount = -0.75 # negative values produce pincushion
amount = 0.75 # positive values produce barrel
# create map with the barrel pincushion distortion formula
for y in range(h):
delta_y = scale_y * (y - center_y)
for x in range(w):
# determine if pixel is within an ellipse
delta_x = scale_x * (x - center_x)
distance = delta_x * delta_x + delta_y * delta_y
if distance >= (radius * radius):
map_x[y, x] = x
map_y[y, x] = y
else:
factor = 1.0
if distance > 0.0:
factor = math.pow(math.sin(math.pi * math.sqrt(distance) / radius / 2), amount)
map_x[y, x] = factor * delta_x / scale_x + center_x
map_y[y, x] = factor * delta_y / scale_y + center_y
# do the remap
dst = cv.remap(img, map_x, map_y, cv.INTER_LINEAR)
# save the result
#cv.imwrite('lena_pincushion.jpg',dst)
cv.imwrite('lena_barrel.jpg',dst)
# show the result
cv.imshow('src', img)
cv.imshow('dst', dst)
cv.waitKey(0)
cv.destroyAllWindows()
Barrel (positive amount):

Pincushion (negative amount):

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With