Opencv 将点从贴图a转换为贴图B

Opencv 将点从贴图a转换为贴图B,opencv,math,geometry,Opencv,Math,Geometry,我试图将一个点从一张地图转换到另一张地图。我曾尝试为getAffineTransform()、getPerspectiveTransform()、warpAffine()和findHomography()使用一些OpenCV示例代码,但在我的转换网格中总是有一些空白。特征点通常在非常不同的位置检测,所以我想我需要一个好的插值方法 关于地图: 这两张地图都是包含人体部位和人体皮肤的图像。我正在使用OpenCV特征检测/匹配算法在两张地图中获得两个相等的点。棘手的是,它们也有胳膊和脚。手臂/触角上的

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

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

目标是: 我想把地图A上的任意点尽可能地变换到地图B上的等效位置

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

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

谢谢你的建议

转换的简单草图(我试图从右图的左图中找到点X1到X3):

单应性样本(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);
Mat imgA=new Mat(@“d:\Mesh\Left2.jpg”,ImreadModes.Color);
Mat imgB=新Mat(@“d:\Mesh\Right2.jpg”,ImreadModes.Color);
调整大小(imgA,imgA,新大小(512341));
调整大小(imgB,imgB,新大小(512341));
冲浪探测器=冲浪创建(500.0);
KeyPoint[]keypointsA=检测器。检测(imgA);
KeyPoint[]keypointsB=检测器检测(imgB);
SIFT提取器=SIFT.Create();
Mat描述符RSA=新Mat();
Mat描述符SB=新Mat();
Compute(imgA,ref keypointsA,descriptor rsa);
Compute(imgB,ref keypointsB,descriptorsB);
BFMatcher matcher=新的BFMatcher(NormTypes.L2,true);
DMatch[]matches=matcher.Match(描述符RSA,描述符SB);
双心距=10000.0;
双最大距离=0.0;
for(int i=0;i最大距离)
{
最大距离=距离;
}
}
List goodMatches=新列表();
for(int i=0;i如果(匹配[i].距离你有任何代码示例吗?谢谢。添加了一些单应性的示例代码。你想要什么样的变换?你在这里使用透视变换,但这合理吗?听起来你可能需要一个一般的非线性变换。也许,光流的向量场?我添加了一个变换的示例草图我希望它能比我的描述文本更好地解释它。谢谢尼科,我会研究你关于OpenCV中光流的注释。
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];