1. ホーム
  2. python

[解決済み] OpenCVのリマップ機能はどのように使うのですか?

2022-02-06 03:16:40

質問

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の画像を期待しています。

ドキュメントをすべて読みました。そして、remap() は img のすべての値を新しい位置に配置し、空いたスペースは補間するとあります。 私はそれをやっているのですが、うまくいきません。 なぜでしょうか? ほとんどの例はC++のためのものです。 Pythonでは壊れているのでしょうか?

どのように解決するのですか?

これは単純にドキュメントを誤解しているだけで、あなたを責めるつもりはありません---私も理解するのに何度か失敗しました。ドキュメントは明確ですが、この関数はおそらくあなたが期待するような働きはしません。 反対 最初に予想した方向と違う。

remap() はありません。 は、ソース画像の座標を取得し、ポイントを変換し、そして補間します。何 remap() が行います。 は,出力画像の各画素について,以下のようなルックアップを行います. どこから来たか を元画像に挿入し、補間した値を割り当てる。補間するためには、各ピクセルで元画像の周辺の値を見る必要があるので、このように動作させる必要があります。拡大します(少し繰り返すかもしれませんが、誤解のないようにお願いします)。

からの remap() ドキュメント :

マップ1 - のどちらかの最初のマップは (x,y) 点または単に x という型を持つ値です。 CV_16SC2 , CV_32FC1 または CV_32FC2 . 参照 convertMaps() は、浮動小数点表現を固定小数点に変換して高速化する方法の詳細について説明します。

マップ2 - の2番目のマップは y という型を持つ値です。 CV_16UC1 , CV_32FC1 またはなし(空のマップの場合 map1(x,y) ポイント)にそれぞれ対応しています。

に関するこちらの文言は map1 を使用しています。 第一 の地図..." は、混乱することがあります。これらは、あなたの画像がマッピングされる場所の座標であることを忘れないでください。 から ...点がマッピングされている から srcmap_x(x, y), map_y(x, y) に配置し、さらに dstx, y . そして、それらはワープさせたい画像と同じ形であるべきです。 . ドキュメントに示されている式に注意してください。

dst(x,y) =  src(map_x(x,y),map_y(x,y))

ここで map_x(x, y) は上を見ている map_x で与えられる行と列で x, y . そして、その画素で画像値が評価される。のマッピングされた座標を調べているのです。 x, ysrc に代入し、その値を x, ydst . これをじっと見ていると、何となく分かってくる。ピクセルで (0, 0) を見ると、新しい目的地の画像では map_xmap_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)

では、ここで何が起こっているのか?この場合、行列を調べるのが一番簡単です。

map_y
=====
0  1
2  3

map_x
=====
5  6
7  10

つまり、(0, 0)にある出力画像は、(1, 2)にある入力画像と同じ値を持つことになります。 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() を使い、元画像からそれらの点を探し出し、目的画像にマッピングする。

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()

の画像とグランドトゥルースホモグラフィ。 オックスフォード大学 視覚幾何学研究室 .