0

特定の画像に適用された変換行列は、同じ画像のスケーリングされたバージョンで再利用できますか?

説明するには:「cv::findHomography」を使用して、最初に両方の画像間の対応を収集することにより、正投影参照画像と歪み補正された写真の間の 3x3 ホモグラフィ行列「Href」を計算することに成功しています。

Href = findHomography(mpts_2,
mpts_1,
cv::RANSAC,
Settings::getHomography_ransacReprojThr(),
outlier_mask);

写真入力とオルソフォト参照のサンプルについては、以下を参照してください。これは、エジプトのテーベにあるラムセス 2 世によって建てられた神殿のすべての壁のエジプト学的リファレンスを作成する考古学的コンピューティング プロジェクトです。

入力写真(上)、オルソフォト参照(下)

上記のマトリックスを使用すると、「cv::warpPerspective」を使用して、オルソモザイク参照オブジェクトの姿勢を正しく模倣する補間画像を作成できます。下の右側の画像を参照してください。

以下のコードで正しい結果が得られると思いますが (コード セクション A を参照)、同じ 'Href' マトリックスを、上記の同じ入力画像 'src' のより大きなバージョンに適用したいと思います。

これは可能ですか?

プロキシ イメージの以前の変換からの結果を拡大縮小して、それを最大解像度の写真に適用しようとすると、下の左側に示すように歪みが発生し、右側の正しい結果とは対照的です。

誤った結果 (左)、参照用の望ましい結果 (右)

要約すると、小さいプロキシ イメージを変換することはできますが、イメージのより大きなフル解像度バージョンで同じマトリックスを使用できるかどうかはわかりません。

コード セクション A

これは正投影参照画像に従ってプロキシ画像を変換する作業コードです。ここにあるコードのほとんどは、出力画像のサイズ変更とオフセットに関連しています。「cv::warpPerspective」呼び出しはブロックの最後にあります。

// http://en.wikipedia.org/wiki/Transformation_matrix
cv::namedWindow(REMAP_WINDOW, CV_WINDOW_AUTOSIZE); // create homography display window
bool redraw = true;
// load image associated with current image
src = cv::imread("input.jpg", 1); 
dst.create(src.size(), src.type()); // create destination and the maps
// Identify source image corners
std::vector<cv::Point2f> obj_corners(4);
obj_corners[0] = cvPoint(0,0);
obj_corners[1] = cvPoint(src.cols, 0);
obj_corners[2] = cvPoint(src.cols, src.rows);
obj_corners[3] = cvPoint(0, src.rows);
std::vector<cv::Point2f> scene_corners(4);
cv::perspectiveTransform(obj_corners, scene_corners, Href); // Transform source image corners by Href to find transformed bounds
int minCols = 0, maxCols = 0, minRows = 0, maxRows = 0;
for(int i=0; i < scene_corners.size(); i++)
{
//cout << "scene_corners.at(i).y: " << scene_corners.at(i).y << "scene_corners.at(i).x: " << scene_corners.at(i).x << endl;
if(maxRows < scene_corners.at(i).y)
maxRows = scene_corners.at(i).y;
if(minRows > scene_corners.at(i).y)
minRows = scene_corners.at(i).y;
if(maxCols < scene_corners.at(i).x)
maxCols = scene_corners.at(i).x;
if(minCols > scene_corners.at(i).x)
minCols = scene_corners.at(i).x;
}

int imageWidth = (maxCols-minCols)+30;
int imageHeight = (maxRows-minRows)+30;
double w = (double)imageWidth, h = (double)imageHeight;
int f = 500;
int x = -minCols; // This is an approximation only!
int y = -minRows; // This is an approximation only!

// Projection 2D -> 3D matrix
cv::Mat A1 = (cv::Mat_<double>(4,3) <<
1, 0, -w/2,
0, 1, -h/2,
0, 0, 0,
0, 0, 1);

// Camera Intrinsics matrix 3D -> 2D
cv::Mat A2 = (cv::Mat_<double>(3,4) <<
f, 0, w/2, 0,
0, f, h/2, 0,
0, 0, 1, 0);

// Translation matrix on the X and Y axis
cv::Mat T = (cv::Mat_<double>(4, 4) <<
1, 0, 0, x,
0, 1, 0, y,
0, 0, 1, 500,
0, 0, 0, 1);

// Apply matrix transformation
cv::Mat transfo = A2 * (T * A1);

// Apply image interpolation
cv::warpPerspective(src, dst, Href * transfo, cv::Size(imageWidth, imageHeight), CV_INTER_CUBIC);

imshow(REMAP_WINDOW, dst);

コード セクション B

この 2 番目のセクションは、'Href' マトリックスを拡大縮小された画像 (つまり、小さいプロキシではなく、フル解像度の写真) に適用する試みを示しています。

src = cv::imread("C:\\Users\\insight\\Documents\\Visual Studio 2010\\Projects\\find-object\\bin\\Release\\genies\\Img4913_pt.jpg", 1);
dst.create(src.size(), src.type()); // create destination and the maps 
// Scale existing min/max cols/rows to fit larger image
int imageWidth = ((maxCols-minCols)*(src.cols/image.cols))+30; // Arbitrary border of 30 pixels
int imageHeight = ((maxRows-minRows)*(src.rows/image.rows))+30;
double w = (double)imageWidth, h = (double)imageHeight;
cout << "original image width: " << src.cols << ", original image height: " << src.rows << endl;
cout << "transformed image width: " << imageWidth << ", transformed image height: " << imageHeight << endl;
int f = 500;
int x = (minCols*(src.cols/image.cols))*2; // This is an approximation only!
int y = (minRows*(src.rows/image.rows))*2; // This is an approximation only!

vector<cv::Point2f> corners;
corners.push_back(cv::Point2f(0, 0));
corners.push_back(cv::Point2f(image.cols, 0));
corners.push_back(cv::Point2f(image.cols, image.rows));
corners.push_back(cv::Point2f(0, image.rows));

// Corners of the destination image
vector<cv::Point2f> output_corner;
output_corner.push_back(cv::Point2f(0, 0));
output_corner.push_back(cv::Point2f(dst.cols, 0));
output_corner.push_back(cv::Point2f(dst.cols, dst.rows));
output_corner.push_back(cv::Point2f(0, dst.rows));

// Get transformation matrix
cv::Mat Hscale = getPerspectiveTransform(corners, output_corner);

int j = 0;
x = -14500;
y = -9500;
int z = 4000;
int xfactor = 0;
int yfactor = 0;
int width = dst.cols;
int height = dst.rows;

// Projection 2D -> 3D matrix
cv::Mat A1 = (cv::Mat_<double>(4,3) <<
1, 0, -w/2,
0, 1, -h/2,
0, 0, 0,
0, 0, 1);

// Camera Intrinsics matrix 3D -> 2D
cv::Mat A2 = (cv::Mat_<double>(3,4) <<
f, 0, w/2, 0,
0, f, h/2, 0,
0, 0, 1, 0);

// Translation matrix on the X and Y axis
cv::Mat T = (cv::Mat_<double>(4, 4) <<
1, 0, 0, x,
0, 1, 0, y,
0, 0, 1, z,
0, 0, 0, 1);

// Apply matrix transformation
cv::Mat transfo = A2 * (T * A1);

warpPerspective(src, dst, Href * Hscale * transfo, cv::Size(imageWidth, imageHeight), CV_INTER_CUBIC, cv::BORDER_CONSTANT, 0);
cv::imwrite("C:\\Users\\Kevin\\Documents\\Find-Object\\image.png", dst);
4

1 に答える 1

0

あなたのコード サンプルは少し面倒なので、コメントしません。ただし、ホモグラフィはスカラー乗法定数までしか定義されないため、質問に対する答えは肯定的です。すべてのホモグラフィ H、同次の 2D 点 x およびスカラー s に対して、H * x および (s * H) * x は 3 番目で除算した後、同じ 2D ポイントを生成することに注意することで、これが実際に当てはまることを自分自身で納得させることができます。結果の座標 (もちろん、無限遠点は例外です)。

したがって、小さな画像で推定されたホモグラフィを大きな画像に変更せ​​ずに適用する必要があります。

ただし、注意点があります。アップスケーリングは推定誤差も拡大し、推定されたホモグラフィが特異点に近づくほど、許容できなくなる可能性があります。

まず、見積もりの​​基になっている一致を再確認することから始めることをお勧めします。

于 2013-09-26T12:31:57.383 に答える