Remap()の可能な限り簡単なテストケースを次に示します。
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
出力は次のとおりです。
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を生成しますが、正しい形状ではありません。範囲0〜3の値が補間された20x20または10x10の画像が必要です。
すべてのドキュメントを読みました。それとSOでは、開始点の配列(マップ)、終了点のマップを入力すると、remap()はimgのすべての値を新しい位置に配置し、私はそれをやっていますが、それはちょうど動作しませんなぜ?ほとんどの例はC++のためです。Pythonで壊れていますか?
これはドキュメントの単なる誤解であり、私はあなたを責めることはできません。それを理解するのに手間がかかりました。ドキュメントは明確ですが、この関数はおそらく期待どおりに機能しません。実際、最初に期待していたものとは反対のopposite方向で動作します。
remap()
does n'tは、ソースイメージの座標を取得し、ポイントを変換してから補間します。 remap()
doesが行うことは、destination画像内のすべてのピクセルについて、それがどこから来るかを検索ソース画像に挿入し、補間値を割り当てます。補間するためには、各ピクセルでソース画像の周囲の値を見る必要があるため、この方法で動作する必要があります。拡大させてください(少し繰り返すかもしれませんが、間違ったやり方をしないでください)。
remap()
docs から:
map1–
(x,y)
ポイント、またはCV_16SC2
、CV_32FC1
、またはCV_32FC2
タイプを持つx
値の最初のマップ。速度のために浮動小数点表現を固定小数点に変換する方法の詳細については、convertMaps()
を参照してください。map2–タイプ
CV_16UC1
、CV_32FC1
、またはnone(map1
が(x,y)
ポイントの場合は空のマップ)を持つy
値の2番目のマップ、それぞれ。
「firstmap of ...」というmap1
の言葉遣いは、やや誤解を招く恐れがあります。覚えておいてください、これらは厳密にあなたのイメージがマップされる場所の座標ですfrom...ポイントがマップされていますfromsrc
map_x(x, y), map_y(x, y)
のvar] _を使用し、x, y
のdst
に配置します。そして、それらはあなたがそれらをワープしたい画像の同じ形状でなければなりませんto。ドキュメントに示されている式に注意してください。
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_x
およびmap_y
を確認し、次に、宛先イメージの(0, 0)
で補間値を割り当てます。ソース。これは、remap()
がこのように機能する基本的な理由の一種です。ピクセルがどこから来たのかを知る必要があるため、補間する隣接ピクセルを見ることができます。
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)
ここで何が起きているのでしょうか?これらはimg
のインデックスであり、それらが位置する行と列にマッピングされることを忘れないでください。この場合、マトリックスを調べるのが最も簡単です。
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
tosrc
を変換することに注意してください。したがって、必要なポイントをいくつでも作成し、それらのポイントがホモグラフィで変換することでソースイメージ内のどこにあるかを計算します。次に、remap()
を使用して、ソースイメージ内のそれらのポイントを検索し、それらを宛先イメージにマップします。
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()
オックスフォードのビジュアルジオメトリグループ の画像とグラウンドトゥルースのホモグラフィ。