首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用OpenCV的remap功能?

如何使用OpenCV的remap功能?
EN

Stack Overflow用户
提问于 2017-10-02 13:50:10
回答 2查看 31.2K关注 0票数 21

下面是remap()最简单的测试用例:

代码语言:javascript
复制
import cv2
import numpy as np
inimg = np.arange(2*2).reshape(2,2).astype(np.float32)
inmap = np.array([[0,0],[0,1],[1,0],[1,1]]).astype(np.float32)
outmap = np.array([[10,10],[10,20],[20,10],[20,20]]).astype(np.float32)
outimg = cv2.remap(inimg,inmap,outmap,cv2.INTER_LINEAR)
print "inimg:",inimg
print "inmap:",inmap
print "outmap:",outmap
print "outimg:", outimg

下面是输出:

代码语言:javascript
复制
inimg: [[ 0.  1.]
 [ 2.  3.]]
inmap: [[ 0.  0.]
 [ 0.  1.]
 [ 1.  0.]
 [ 1.  1.]]
outmap: [[ 10.  10.]
 [ 10.  20.]
 [ 20.  10.]
 [ 20.  20.]]
outimg: [[ 0.  0.]
 [ 0.  0.]
 [ 0.  0.]
 [ 0.  0.]]

如您所见,outimg生成0,0,它甚至不是正确的形状。我希望得到一个20x20或10x10的图像,内插值范围从0到3。

我已经阅读了所有的文档。它和每个人都声明你输入一个开始点的数组(一个映射),一个结束点的映射,然后remap()将把img中的所有值放到它们的新位置,插入任何空格。我正在这么做,但它就是不起作用。为什么?大多数示例都是针对C++的。它在python中是不是坏了?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-10-02 19:24:04

这只是对文档的一个简单的误解,我不会责怪你-我也花了一些时间才理解它。文档很清楚,但是这个函数可能不会以您期望的方式工作;实际上,它的工作方向与我一开始所期望的相反。

remap()不做的是获取源图像的坐标,转换点,然后进行插值。remap()所做的是,对于目标图像中的每个像素,查找它在源图像中的位置,然后分配一个插值值。它需要这样工作,因为为了插值,它需要在每个像素上查看源图像周围的值。让我来扩展一下(可能会重复一下,但不要误会)。

remap() docs

map1 - (x,y)点或仅具有CV_16SC2CV_32FC1CV_32FC2类型的x值的第一个映射。有关将浮点表示转化为固定点以提高速度的详细信息,请参见convertMaps()

map2 - y值的第二个映射,其类型分别为CV_16UC1CV_32FC1或none (如果map1(x,y) points,则为空映射)。

map1上的长篇大论是“第一张地图……”可能会让人感到困惑。请记住,这些是图像映射位置的严格坐标,这些点是从map_x(x, y), map_y(x, y)src映射到x, ydst中的。它们应该与你想要扭曲的图像的形状相同。请注意文档中显示的等式:

代码语言:javascript
复制
dst(x,y) =  src(map_x(x,y),map_y(x,y))

在这里,map_x(x, y)map_x中查找x, y给出的行和列。然后在这些像素处计算图像值。它在src中查找x, y的映射坐标,然后将该值赋给dst中的x, y。如果你盯着它看足够长的时间,它就开始变得有意义了。在新目标图像中的像素(0, 0)处,我查看map_xmap_y,它们告诉我源图像中相应像素的位置,然后我可以通过查看源图像中的近似值,在目标图像中的(0, 0)处分配插值值。这在某种程度上是remap()以这种方式工作的基本原因;它需要知道像素来自哪里,以便让相邻像素进行插值。

小的、人为的例子

代码语言:javascript
复制
img = np.uint8(np.random.rand(8, 8)*255)
#array([[230,  45, 153, 233, 172, 153,  46,  29],
#       [172, 209, 186,  30, 197,  30, 251, 200],
#       [175, 253, 207,  71, 252,  60, 155, 124],
#       [114, 154, 121, 153, 159, 224, 146,  61],
#       [  6, 251, 253, 123, 200, 230,  36,  85],
#       [ 10, 215,  38,   5, 119,  87,   8, 249],
#       [  2,   2, 242, 119, 114,  98, 182, 219],
#       [168,  91, 224,  73, 159,  55, 254, 214]], dtype=uint8)

map_y = np.array([[0, 1], [2, 3]], dtype=np.float32)
map_x = np.array([[5, 6], [7, 10]], dtype=np.float32)
mapped_img = cv2.remap(img, map_x, map_y, cv2.INTER_LINEAR)
#array([[153, 251],
#       [124,   0]], dtype=uint8)

那么这里发生了什么呢?在这种情况下,最简单的方法是检查矩阵:

代码语言:javascript
复制
map_y
=====
0  1
2  3

map_x
=====
5  6
7  10

因此,(0,0)处的目标映像与map_y(0, 0), map_x(0, 0) = 0, 5处的源映像具有相同的值,而第0行和第5列的源映像为153。请注意,在目标图像mapped_img[0, 0] = 153中。这里没有发生插值,因为我的地图坐标是精确的整数。此外,我还包含了一个越界索引(map_x[1, 1] = 10,它大于图像宽度),请注意,当它超出边界时,它只是被赋值为0

完整的用例示例

这里是一个完整的代码示例,使用地面真实单应性,手动扭曲像素位置,然后使用remap()从变换点映射图像。这里请注意,我的单应性将true_dst转换为src。因此,我制作了一组我想要的任意多个点,然后通过单应变换计算这些点在源图像中的位置。然后使用remap()查找源图像中的这些点,并将它们映射到目标图像中。

代码语言:javascript
复制
import numpy as np
import cv2

# read images
true_dst = cv2.imread("img1.png")
src = cv2.imread("img2.png")

# ground truth homography from true_dst to src
H = np.array([
    [8.7976964e-01,   3.1245438e-01,  -3.9430589e+01],
    [-1.8389418e-01,   9.3847198e-01,   1.5315784e+02],
    [1.9641425e-04,  -1.6015275e-05,   1.0000000e+00]])

# create indices of the destination image and linearize them
h, w = true_dst.shape[:2]
indy, indx = np.indices((h, w), dtype=np.float32)
lin_homg_ind = np.array([indx.ravel(), indy.ravel(), np.ones_like(indx).ravel()])

# warp the coordinates of src to those of true_dst
map_ind = H.dot(lin_homg_ind)
map_x, map_y = map_ind[:-1]/map_ind[-1]  # ensure homogeneity
map_x = map_x.reshape(h, w).astype(np.float32)
map_y = map_y.reshape(h, w).astype(np.float32)

# remap!
dst = cv2.remap(src, map_x, map_y, cv2.INTER_LINEAR)
blended = cv2.addWeighted(true_dst, 0.5, dst, 0.5, 0)
cv2.imshow('blended.png', blended)
cv2.waitKey()

来自Visual Geometry Group at Oxford的图像和地面真实单应性。

票数 75
EN

Stack Overflow用户

发布于 2020-12-09 02:54:05

代码语言:javascript
复制
warped = cv.warpPerspective(img, H, (width, height))

等同于

代码语言:javascript
复制
idx_pts = np.mgrid[0:width, 0:height].reshape(2, -1).T
map_pts = transform(idx_pts, np.linalg.inv(H))
map_pts = map_pts.reshape(width, height, 2).astype(np.float32)
warped = cv.remap(img, map_pts, None, cv.INTER_CUBIC).transpose(1, 0, 2)

transform函数的位置

代码语言:javascript
复制
def transform(src_pts, H):
    # src = [src_pts 1]
    src = np.pad(src_pts, [(0, 0), (0, 1)], constant_values=1)
    # pts = H * src
    pts = np.dot(H, src.T).T
    # normalize and throw z=1
    pts = (pts / pts[:, 2].reshape(-1, 1))[:, 0:2]
    return pts

src_pts[[x0, y0], [x1, y1], [x2, y2], ...] (每行是一个点)

H, status = cv.findHomography(src_pts, dst_pts)

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46520123

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档