Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python OpenCV How to Apply Radial/Barrel Distortion?

Tags:

python

opencv

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):

enter image description here

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.

like image 846
JDS Avatar asked Oct 30 '25 06:10

JDS


2 Answers

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()
like image 193
Teddy 1993 Avatar answered Nov 01 '25 18:11

Teddy 1993


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:

enter image description here

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):

enter image description here

Pincushion (negative amount):

enter image description here

like image 20
fmw42 Avatar answered Nov 01 '25 20:11

fmw42