OpenCV 中的“逆映射”函数有哪些不准确之处?

问题描述 投票:0回答:2

我正在尝试以一种非常具体的方式水平拉伸图像。每个 x 素数坐标应遵循相对于原始 x 坐标的切线路径。我相信有两种方法可以做到这一点:

  1. 反转正切函数并正常映射
  2. 映射正切函数,然后反转映射

使用this答案进行地图反演,我试图找出为什么两个图像不相同。我知道第一种方法可以为我提供所需的正确图像,那么为什么第二种方法不起作用呢?是因为@ChristophRackwitz 对答案的评论“精度有限”吗?

import cv2
import glob
import numpy as np
import math

A = -1010
B = -3.931
C = 5.258
D = 978.3

M = -193.8
N = 1740

def get_tan_func_value(x):
    return A * math.tan((((x-N)/M)+B)/C) + D

def get_inverse_tan_func_value(x):
    return M * (C*math.atan((x-D)/A) - B) + N

# answer from linked post
def invert_map(F, shape):
    I = np.zeros_like(F)
    I[:,:,1], I[:,:,0] = np.indices(shape)
    P = np.copy(I)
    for i in range(10):
        P += I - cv2.remap(F, P, None, interpolation=cv2.INTER_LINEAR)
    return P

# import image
images = glob.glob('*.jpg')
img = cv2.imread(images[0])
h,  w = img.shape[:2]

map_x_tan = np.zeros((img.shape[0], img.shape[1]), dtype=np.float32)
map_x_inverse_tan = np.zeros((img.shape[0], img.shape[1]), dtype=np.float32)
map_y = np.zeros((img.shape[0], img.shape[1]), dtype=np.float32)

# x tan function map
for i in range(map_x_tan.shape[0]):
    map_x_tan[i,:] = [get_tan_func_value(x) for x in range(map_x_tan.shape[1])]

# x inverse tan function map
for i in range(map_x_inverse_tan.shape[0]):
    map_x_inverse_tan[i,:] = [get_inverse_tan_func_value(x) for x in range(map_x_inverse_tan.shape[1])]

# default y map
for j in range(map_y.shape[1]):              
    map_y[:,j] = [y for y in range(map_y.shape[0])]

# convert x tan map to 2 channel (x,y) map
(xymap_tan, _) = cv2.convertMaps(map1=map_x_tan, map2=map_y, dstmap1type=cv2.CV_32FC2)

# invert the 2 channel x tan map
xymap_inverted = invert_map(xymap_tan, (h,w))

# remap and write the target image (inverse tan function with normal map)
target = cv2.remap(img, map_x_inverse_tan, map_y, cv2.INTER_LINEAR)
cv2.imwrite("target.jpg", target)

# remap and write the attempted image (normal tan function with inverted map) 
attempt = cv2.remap(img, xymap_inverted, None, cv2.INTER_LINEAR)
cv2.imwrite("attempt.jpg", attempt)

方法一:目标图像

方法2:尝试图像

结果表明,尝试(带有倒置贴图的正常 tan 函数)在图像边缘附近的拉伸比预期要小。除了边缘之外,图像上几乎所有其他地方都是相同的。为了节省空间我没有贴原图

python opencv image-processing
2个回答
3
投票

我已经尝试过那个

invert_map
程序。似乎有点容易振荡。

用这个代替:

def invert_map(F):
    (h, w) = F.shape[:2] # (h, w, 2), "xymap"
    I = np.zeros_like(F)
    I[:,:,1], I[:,:,0] = np.indices((h,w)) # identity map
    P = np.copy(I)
    for i in range(10):
        correction = I - cv2.remap(F, P, None, interpolation=cv2.INTER_LINEAR)
        P += correction * 0.5
    return P

我只是将修正值阻尼 0.5,这使得定点迭代更加温和,收敛速度也更快。

在我对你的 tan 贴图的实验中,我发现 5-10 次迭代已经足够好了,并且在进一步的迭代中没有进一步的进展。

我的探索的整个笔记本:https://gist.github.com/crackwitz/67f76f8a9eff21476b080c06d20660d0

功能请求:https://github.com/opencv/opencv/issues/22120


0
投票

干得好!我添加了一些额外的改进:

  • 交替阻尼(根据我的经验结果,步骤更少,更干净)
  • 使未映射的区域无效(否则包含细化迭代产生的工件)
  • 小幅重构以略微加快速度

代码:

# invert remapping for cv2.remap (hwc order c0 == u, c1 == v)
def invert_remap(m0, steps_refine=8, dampening=[1.0,0.49], thr_inv=0.5):
    ident0 = np.float32(np.dstack(np.indices((m0.shape[0], m0.shape[1]))[:,:,::-1])
    m1 = np.copy(ident0)
    for i in range(steps_refine):
        diff0 = ident0 - cv2.remap(m0[:,:,:2], m1, None, interpolation=cv2.INTER_LINEAR)
        if i>0 and i == steps_refine-1 and thr_inv >= 0: #deactivate invalids
            m1[np.abs(diff0)>thr_inv] = -1.0
        else:
            m1 += diff0 * dampening[i%len(dampening)]
    return m1

这应该与原始解决方案相同:

def invert_map(F):
    return invert_remap(F, steps_refine=10, dampening=[0.5], thr_inv=-1)
© www.soinside.com 2019 - 2024. All rights reserved.