这是答案的一半。 cv2.remap 函数使用映射从源中为目标中的每个像素选择一个像素。 alkasm 对此的回答:How do I use OpenCV's remap function?
在定义流程方面做得很好,但掩盖了这些地图的用处。如果您可以在地图中发挥创意,您可以制作任何您想要的效果。这是我想出的。
程序首先加载图像并调整其大小。这对于较小的屏幕来说是一种便利。然后创建空地图。
地图需要与正在处理的图像具有相同的尺寸,但深度为 1。如果调整后的原始尺寸为 633 x 400 x 3,则地图都需要为 633 x 400。
重新映射完成后,cv2.remap 将使用地图中每个坐标处的值来确定要在目标中使用原始像素中的哪个像素。对于目标中的每个 x,y,dest[x,y] = src[map1[x,y],map2[x,y]]。
最简单的映射是如果对于每个 (x,y),map1(x,y)=x 和 map2(x,y)=y。这将创建一个 1 对 1 的映射,并且目标将与源匹配。在此示例中,为每个值添加了一个小偏移量。偏移中的余弦函数会产生正负偏移,从而在最终图像中产生波浪。
请注意,创建地图很慢,但 cv2.remap 很快。创建地图后,cv2.remap 的速度足以应用于视频帧。
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()