Pinch / Bulge-Verzerrung mit Python OpenCV
Ich möchte mit Python OpenCV einen Pinch / Bulge-Filter auf ein Bild anwenden. Das Ergebnis sollte eine Art Beispiel sein:
https://pixijs.io/pixi-filters/tools/screenshots/dist/bulge-pinch.gif
Ich habe den folgenden Stackoverflow-Beitrag gelesen, der die richtige Formel für den Filter sein sollte: Formeln für die Verzerrung von Fässern / Nadelkissen
Ich habe jedoch Probleme, dies in Python OpenCV zu implementieren.
Ich habe über Karten gelesen, um Filter auf ein Bild anzuwenden: Verzerrungseffekt mit OpenCv-Python
Nach meinem Verständnis könnte der Code ungefähr so aussehen:
import numpy as np
import cv2 as cv
f_img = 'example.jpg'
im_cv = cv.imread(f_img)
# grab the dimensions of the image
(h, w, _) = im_cv.shape
# 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 map with the barrel pincushion distortion formula
for y in range(h):
for x in range(w):
flex_x[y, x] = APPLY FORMULA TO X
flex_y[y, x] = APPLY FORMULA TO Y
# do the remap this is where the magic happens
dst = cv.remap(im_cv, flex_x, flex_y, cv.INTER_LINEAR)
cv.imshow('src', im_cv)
cv.imshow('dst', dst)
cv.waitKey(0)
cv.destroyAllWindows()
Ist dies der richtige Weg, um die im Beispielbild dargestellte Verzerrung zu erzielen? Jede Hilfe in Bezug auf nützliche Ressourcen oder vorzugsweise Beispiele wird sehr geschätzt.
Antworten
Sie können dies mit implodierenden und explodierenden Optionen in Python Wand tun, das ImageMagick verwendet.
Eingang:
from wand.image import Image
import numpy as np
import cv2
with Image(filename='zelda1.jpg') as img:
img.virtual_pixel = 'black'
img.implode(0.5)
img.save(filename='zelda1_implode.jpg')
# convert to opencv/numpy array format
img_implode_opencv = np.array(img)
img_implode_opencv = cv2.cvtColor(img_implode_opencv, cv2.COLOR_RGB2BGR)
with Image(filename='zelda1.jpg') as img:
img.virtual_pixel = 'black'
img.implode(-0.5 )
img.save(filename='zelda1_explode.jpg')
# convert to opencv/numpy array format
img_explode_opencv = np.array(img)
img_explode_opencv = cv2.cvtColor(img_explode_opencv, cv2.COLOR_RGB2BGR)
# display result with opencv
cv2.imshow("IMPLODE", img_implode_opencv)
cv2.imshow("EXPLODE", img_explode_opencv)
cv2.waitKey(0)
Implodieren:
Explodieren:
Nachdem ich mich mit dem ImageMagick-Quellcode vertraut gemacht habe, habe ich einen Weg gefunden, die Formel für Verzerrungen anzuwenden. Mit Hilfe der OpenCV-Remap- Funktion können Sie auf folgende Weise ein Bild verzerren:
import numpy as np
import cv2 as cv
f_img = 'example.jpg'
im_cv = cv.imread(f_img)
# grab the dimensions of the image
(h, w, _) = im_cv.shape
# 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 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):
flex_x[y, x] = x
flex_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)
flex_x[y, x] = factor * delta_x / scale_x + center_x
flex_y[y, x] = factor * delta_y / scale_y + center_y
# do the remap this is where the magic happens
dst = cv.remap(im_cv, flex_x, flex_y, cv.INTER_LINEAR)
cv.imshow('src', im_cv)
cv.imshow('dst', dst)
cv.waitKey(0)
cv.destroyAllWindows()
Dies hat den gleichen Effekt wie die Verwendung der Funktion convert -implode von ImageMagick.