将点从地图A转换为地图B

时间:2018-08-06 18:36:30

标签: opencv math geometry

我正在尝试将一个点从一张地图转换为另一张地图。我曾尝试对getAffineTransform(),getPerspectiveTransform(),warpAffine()和findHomography()使用一些OpenCV示例代码,但是我的转换网格中总是存在一些空白。通常,特征点通常是在非常不同的位置上检测到的,因此,我认为我需要一种好的插值方法。

关于地图: 这两个地图都是包含人体部位和人体皮肤的图像。我正在使用OpenCV特征检测/匹配算法在两个地图中获得两个相等的点。棘手的是它们也包含着手臂和脚。手臂/脚上的特征点可能比躯干上的特征点具有更大的偏移量。

目标: 我想将地图A上的任意点尽可能地变换为地图B上的等效位置。

我目前的方法是在地图A上找到我最原始的三个最闭合的点,并构造一个三角形。然后,将这个三角形转换为地图B上相同的三个特征点。如果我在原始点周围有很多闭合特征点,那就很好用了。但是在没有特征点的较大区域,插值会遇到一些问题。

这是这样做的好方法吗?还是有更好的解决方案? 我最喜欢的一个是为两个图像构建完整的变换图,但是我不确定如何做到这一点。可能吗?

非常感谢您的任何建议!

转换的简单草图(我正在尝试从右侧图像中的左侧图像中找到点X1至X3): Sketch of a sample transformation

单应性示例(OpenCVSharp):

Mat imgA = new Mat(@"d:\Mesh\Left2.jpg", ImreadModes.Color);
Mat imgB = new Mat(@"d:\Mesh\Right2.jpg", ImreadModes.Color);

Cv2.Resize(imgA, imgA, new Size(512, 341));
Cv2.Resize(imgB, imgB, new Size(512, 341));

SURF detector = SURF.Create(500.0);
KeyPoint[] keypointsA = detector.Detect(imgA);
KeyPoint[] keypointsB = detector.Detect(imgB);

SIFT extractor = SIFT.Create();
Mat descriptorsA = new Mat();
Mat descriptorsB = new Mat();
extractor.Compute(imgA, ref keypointsA, descriptorsA);
extractor.Compute(imgB, ref keypointsB, descriptorsB);

BFMatcher matcher = new BFMatcher(NormTypes.L2, true);
DMatch[] matches = matcher.Match(descriptorsA, descriptorsB);

double minDistance = 10000.0;
double maxDistance = 0.0;
for (int i = 0; i < matches.Length; ++i)
{
    double distance = matches[i].Distance;
    if (distance < minDistance)
    {
        minDistance = distance;
    }
    if (distance > maxDistance)
    {
        maxDistance = distance;
    }
}

List<DMatch> goodMatches = new List<DMatch>();
for (int i = 0; i < matches.Length; ++i)
{
    if (matches[i].Distance <= 3.0 * minDistance &&
        Math.Abs(keypointsA[matches[i].QueryIdx].Pt.Y - keypointsB[matches[i].TrainIdx].Pt.Y) < 30)
    {
        goodMatches.Add(matches[i]);
    }
}

Mat output = new Mat();
Cv2.DrawMatches(imgA, keypointsA, imgB, keypointsB, goodMatches.ToArray(), output);

List<Point2f> goodA = new List<Point2f>();
List<Point2f> goodB = new List<Point2f>();
for (int i = 0; i < goodMatches.Count; i++)
{
    goodA.Add(keypointsA[goodMatches[i].QueryIdx].Pt);
    goodB.Add(keypointsB[goodMatches[i].TrainIdx].Pt);
}

InputArray goodInputA = InputArray.Create<Point2f>(goodA);
InputArray goodInputB = InputArray.Create<Point2f>(goodB);

Mat h = Cv2.FindHomography(goodInputA, goodInputB);

Point2f centerA = new Point2f(imgA.Cols / 2.0f, imgA.Rows / 2.0f);
output.DrawMarker((int)centerA.X, (int)centerA.Y, Scalar.Red, MarkerStyle.Cross, 50, LineTypes.Link8, 5);

Point2f[] transformedPoints = Cv2.PerspectiveTransform(new Point2f[] { centerA }, h);
output.DrawMarker((int)transformedPoints[0].X + imgA.Cols, (int)transformedPoints[0].Y, Scalar.Red, MarkerStyle.Cross, 50, LineTypes.Link8, 5);

透视变换的代码段(不同的方法,OpenCVSharp):

pointsA[0] = new Point(trisA[i].Item0, trisA[i].Item1);
pointsA[1] = new Point(trisA[i].Item2, trisA[i].Item3);
pointsA[2] = new Point(trisA[i].Item4, trisA[i].Item5);

pointsB[0] = new Point(trisB[i].Item0, trisB[i].Item1);
pointsB[1] = new Point(trisB[i].Item2, trisB[i].Item3);
pointsB[2] = new Point(trisB[i].Item4, trisB[i].Item5);

Mat transformation = Cv2.GetAffineTransform(pointsA, pointsB);

InputArray inputSource = InputArray.Create<Point2f>(new Point2f[] { new Point2f(10f, 50f) });
Mat outputMat = new Mat();
Cv2.PerspectiveTransform(inputSource, outputMat, transformation);
Mat.Indexer<Point2f> indexer = outputMat.GetGenericIndexer<Point2f>();
var target = indexer[0, 0];

0 个答案:

没有答案