OpenCV\'s remap() uses a real-valued index grid to sample a grid of values from an image using bilinear interpolation, and returns the grid of samples as a new image.
<
If you map is derived from a homography H you could invert H and directly create the inverse maps with cv::initUndistortRectifyMap().
e.g. in Python:
import numpy as np.
map_size = () # fill in your map size
H_inv = np.linalg.inv(H)
map1, map2 = cv2.initUndistortRectifyMap(cameraMatrix=np.eye(3), distCoeffs=np.zeros(5), R=H_inv, newCameraMatrix=np.eye(3), size=map_size, m1type=cv2.CV_32FC1)
The OpenCV documentation states about initUndistortRectifyMap():
The function actually builds the maps for the inverse mapping algorithm that is used by
remap(). That is, for each pixel (u, v) in the destination image, the function computes the corresponding coordinates in the source image.
In the case you have just given the maps, you have to do it by yourself. Hoewever, interpolation of the new maps' coordinates is not trivial, because the support region for one pixel could be very large.
Here is a simple Python solution which inverts the maps by doing point-to-point mapping. This will probably leave some coordinates unassigned, while others will be updated several times. So there may be holes in the map.
Here is a small Python program demonstrating both approaches:
import cv2
import numpy as np
def invert_maps(map_x, map_y):
assert(map_x.shape == map_y.shape)
rows = map_x.shape[0]
cols = map_x.shape[1]
m_x = np.ones(map_x.shape, dtype=map_x.dtype) * -1
m_y = np.ones(map_y.shape, dtype=map_y.dtype) * -1
for i in range(rows):
for j in range(cols):
i_ = round(map_y[i, j])
j_ = round(map_x[i, j])
if 0 <= i_ < rows and 0 <= j_ < cols:
m_x[i_, j_] = j
m_y[i_, j_] = i
return m_x, m_y
def main():
img = cv2.imread("pigeon.png", cv2.IMREAD_GRAYSCALE)
# a simply rotation by 45 degrees
H = np.array([np.sin(np.pi/4), -np.cos(np.pi/4), 0, np.cos(np.pi/4), np.sin(np.pi/4), 0, 0, 0, 1]).reshape((3,3))
H_inv = np.linalg.inv(H)
map_size = (img.shape[1], img.shape[0])
map1, map2 = cv2.initUndistortRectifyMap(cameraMatrix=np.eye(3), distCoeffs=np.zeros(5), R=H, newCameraMatrix=np.eye(3), size=map_size, m1type=cv2.CV_32FC1)
map1_inv, map2_inv = cv2.initUndistortRectifyMap(cameraMatrix=np.eye(3), distCoeffs=np.zeros(5), R=H_inv, newCameraMatrix=np.eye(3), size=map_size, m1type=cv2.CV_32FC1)
map1_simple_inv, map2_simple_inv = invert_maps(map1, map2)
img1 = cv2.remap(src=img, map1=map1, map2=map2, interpolation=cv2.INTER_LINEAR)
img2 = cv2.remap(src=img1, map1=map1_inv, map2=map2_inv, interpolation=cv2.INTER_LINEAR)
img3 = cv2.remap(src=img1, map1=map1_simple_inv, map2=map2_simple_inv,
interpolation=cv2.INTER_LINEAR)
cv2.imshow("Original image", img)
cv2.imshow("Mapped image", img1)
cv2.imshow("Mapping forth and back with H_inv", img2)
cv2.imshow("Mapping forth and back with invert_maps()", img3)
cv2.waitKey(0)
if __name__ == '__main__':
main()