我想将图像从球形投影到立方体贴图。根据我学习数学的理解,我需要为每个像素创建一个 theta、phi 分布,然后将其转换为笛卡尔系统以获得标准化像素图。
我使用以下代码来做到这一点
theta = 0
phi = np.pi/2
squareLength = 2048
# theta phi distribution for X-positive face
t = np.linspace(theta + np.pi/4, theta - np.pi/4, squareLength)
p = np.linspace(phi + np.pi/4, phi - np.pi/4, squareLength)
x, y = np.meshgrid(t, p)
# converting into cartesion sytem for X-positive face (where r is the distance from sphere center to cube plane and X is constantly 0.5 in cartesian system)
X = np.zeros_like(y)
X[:,:] = 0.5
r = X / (np.cos(x) * np.sin(y))
Y = r * np.sin(x) * np.sin(y)
Z = r * np.cos(y)
XYZ = np.stack((X, Y, Z), axis=2)
# shifting pixels from the negative side
XYZ = XYZ + [0, 0.5, 0.5]
# since i want to project on X-positive face my map should be
x_map = -XYZ[:, :, 1] * squareLength
y_map = XYZ[:,:, 2] * squareLength
上面创建的地图应该给我带来我想要的结果
cv2.remap()
但事实并非如此。然后我尝试循环像素并实现我自己的重新映射,而无需插值或外推。经过一番尝试,我推导出以下公式,给出了正确的结果
for i in range(2048):
for j in range(2048):
try:
image[int(y_map[i,j]), int(x_map[i,j])] = im[i, j]
except:
pass
与实际的 cv2 重新映射相反,它表示
dst(x,y)=src(mapx(x,y),mapy(x,y))
我不明白数学是否全部错误,或者是否有办法隐藏
x_map
和 y_map
来纠正形式,以便 cv2.remap()
给出所需的结果。
当前结果(使用
cv2.remap()
)
我对
opencv
很陌生,之前我没有使用过如此困难的数学算法,但我尝试这样做。我重写了你的代码,如下:
import numpy as np
import cv2
src = cv2.imread("data/pink_sq.png")
def make_map():
theta = 0
phi = np.pi / 2
squareLength = 4000
# theta phi distribution for X-positive face
t = np.linspace((theta - np.pi / 4), (theta + np.pi / 4), squareLength)
p = np.linspace((phi + np.pi / 4), (phi - np.pi / 4), squareLength)
x, y = np.meshgrid(t, p)
x_res = np.zeros_like(y)
x_res[:, :] = 0.5
r = x_res * (np.cos(x))
r /= np.amax(r)
y_res = r * x
z_res = r * np.cos(y)
xyz = np.stack((x_res, y_res, z_res), axis=2)
# shifting pixels from the negative side
xyz = xyz + [0, 0.5, 0.5]
# since i want to project on X-positive face my map should be
x_map = xyz[:, :, 1] * squareLength
y_map = xyz[:, :, 2] * squareLength
map_x = y_map.astype("float32")
map_y = x_map.astype("float32")
return map_x, map_y
map_x, map_y = make_map()
dst = cv2.remap(src, map_y, map_x, cv2.INTER_LINEAR)
cv2.imwrite("res.png", dst)
我根本不理解这段代码中的数学,但我重写了一点,我应该说它工作得很好。这是结果图像:
是的,我的结果图片和你的结果图片之间有一点差异,但我希望没关系:)如果我在某个地方不正确,当然会否决这个答案,因为我不确定它是否正确。
我几乎可以肯定这个问题与参考系在空间中的方向有关。也许如果您稍微澄清一下数学,我们可以提供帮助。
我制作了一个适合您情况的
cv2.remap
用法示例。您可以更改弯曲比例的conf
参数。
# Load an image
img = cv2.imread('/content/doc.png')
# To RGB
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
[enter image description here][1]
# Create depth map
h, w = img.shape[:2]
x_axis = np.linspace(-1, 1, w)
y_axis = np.linspace(-1, 1, h)
xx, yy = np.meshgrid(x_axis, y_axis)
arr = np.sqrt(xx ** 2 + yy ** 2)
inner = 0
outer = 1
arr /= arr.max()
arr = arr * outer + (1 - arr) * inner
# map1 and map2 for cv2.remap function
rows, cols = img.shape[:2]
conf =.2
map1 = np.arange(cols) - arr * (np.arange(cols) - cols / 2) * conf
map2 = np.arange(rows) - arr.T * (np.arange(rows) - rows / 2) * conf
map2 = map2.T
map1 = map1.astype(np.float32)
map2 = map2.astype(np.float32)
img_remapped = cv2.remap(
src=img,
map1=map1,
map2=map2,
interpolation=cv2.INTER_NEAREST,
borderMode=cv2.BORDER_CONSTANT
)