大家好。上面的图像是两幅图像的总和,其中我做了特征匹配,并绘制了所有匹配点。我还在第一个图像中找到了pcb部件的轮廓(半左图像-3个等高线)。问题是,我怎么能只画出第一幅图像中的等高线内的匹配点,而不是这样的蓝色混乱呢?我使用python2.7和opencv 2.4.12。
我在opencv 2.4.12中为绘制匹配函数编写了一个函数,但没有实现任何方法。如果我没有包括一些东西请告诉我。提前谢谢你!
import numpy as np
import cv2
def drawMatches(img1, kp1, img2, kp2, matches):
# Create a new output image that concatenates the two images
# (a.k.a) a montage
rows1 = img1.shape[0]
cols1 = img1.shape[1]
rows2 = img2.shape[0]
cols2 = img2.shape[1]
# Create the output image
# The rows of the output are the largest between the two images
# and the columns are simply the sum of the two together
# The intent is to make this a colour image, so make this 3 channels
out = np.zeros((max([rows1,rows2]),cols1+cols2,3), dtype='uint8')
# Place the first image to the left
out[:rows1,:cols1] = np.dstack([img1, img1, img1])
# Place the next image to the right of it
out[:rows2,cols1:] = np.dstack([img2, img2, img2])
# For each pair of points we have between both images
# draw circles, then connect a line between them
for mat in matches:
# Get the matching keypoints for each of the images
img1_idx = mat.queryIdx
img2_idx = mat.trainIdx
# x - columns
# y - rows
(x1,y1) = kp1[img1_idx].pt
(x2,y2) = kp2[img2_idx].pt
# Draw a small circle at both co-ordinates
# radius 4
# colour blue
# thickness = 1
cv2.circle(out, (int(x1),int(y1)), 4, (255, 0, 0), 1)
cv2.circle(out, (int(x2)+cols1,int(y2)), 4, (255, 0, 0), 1)
# Draw a line in between the two points
# thickness = 1
# colour blue
cv2.line(out, (int(x1),int(y1)), (int(x2)+cols1,int(y2)), (255,0,0), 1)
# Show the image
cv2.imshow('Matched Features', out)
cv2.imwrite("shift_points.png", out)
cv2.waitKey(0)
cv2.destroyWindow('Matched Features')
# Also return the image if you'd like a copy
return out
img1 = cv2.imread('pic3.png', 0) # Original image - ensure grayscale
img2 = cv2.imread('pic1.png', 0) # Rotated image - ensure grayscale
sift = cv2.SIFT()
# find the keypoints and descriptors with SIFT
kp1, des1 = sift.detectAndCompute(img1,None)
kp2, des2 = sift.detectAndCompute(img2,None)
# Create matcher
bf = cv2.BFMatcher()
# Perform KNN matching
matches = bf.knnMatch(des1, des2, k=2)
# Apply ratio test
good = []
for m,n in matches:
if m.distance < 0.75*n.distance:
# Add first matched keypoint to list
# if ratio test passes
good.append(m)
# Show only the top 10 matches - also save a copy for use later
out = drawMatches(img1, kp1, img2, kp2, good)
发布于 2017-11-16 11:19:57
根据你的要求,我假设你的意思是你有某种封闭的轮廓,勾勒出你想要将你的数据点对绑定到的区域。
这是相当简单的多边形等高线和更多的数学是需要更复杂的曲线,但解决办法是一样的。
你画一条从所讨论的点到无穷远的线。大多数人把一条线画成+x无穷大,但是任何方向都是可行的。如果有一个奇数的线交点,点在轮廓内。
参见本文:http://www.geeksforgeeks.org/how-to-check-if-a-given-point-lies-inside-a-polygon/
对于点对,只有两个点都在等高线内的对才完全在等高线内。对于具有凹面段的复杂轮廓形状,如果还想测试点之间的直线路径不与轮廓交叉,则对两个点之间的线段执行类似的测试,如果存在任何直线交叉点,则点之间在等高线之外交叉。
编辑:
因为你的轮廓是矩形,一个简单的方法就足以确定你的点是否在矩形内。
如果你的矩形是轴对齐的(它们是直的,不是旋转的),那么你可以用你的值来检查上、左、下、右。
让点A=顶,左,点B=下,右,点C=你的测试点。
我假设一个基于图像的坐标系,0,0是图像的左上方,宽度、高度是右下角。(我是用C#写的)
bool PointIsInside(Point A, Point B, Point C)
{
if (A.X <= C.X && B.X >= C.X && A.Y <= C.Y && B.Y >= C.Y)
return true;
return false;
}
如果矩形未对齐,则可以执行四次半空间测试,以确定您的点是否位于矩形内。
设点A=顶,左,点B=下,右,双W=宽,双H=高,双N=旋转角,C点=测试点。
对于轴对齐的矩形,可以通过取矢量(1,0),乘以宽度,并将该向量添加到顶部,向左,来计算上、右。对于底部,我们取向量(0,1),乘以高度,然后加到顶部,对。
(1, 0 )等于角0处的单位向量(长度为1)。同样,(0,1)是一个90度角的单位向量。这些矢量也可以被认为是直线指向的方向。这也意味着这些相同的向量可以用于从底部,左到下,右,从上,左到下,左以及左。
我们需要使用不同的单位向量,在提供的角度。为此,我们只需取给定角度的余弦和正弦。
设向量X=从上到上,从左到顶,从右到右,向量Y=从上到下,从右到右。
我在这个例子中用角度表示。
Vector X = new Vector();
Vector Y = new Vector();
X.X = Math.Cos(R);
X.Y = Math.Sin(R);
Y.X = Math.Cos(R+90);
Y.Y = Math.Sin(R+90);
因为我们从Top开始,左边,我们可以找到底部,右边,只需简单地将两个向量添加到Top,左侧
Point B = new Point();
B = A + X + Y;
我们现在想用点积来做半空间测试。前两个测试将使用测试点,顶部,左边,其他两个将使用测试点,以及底部,右边。
半空间测试本质上是基于方向性的。点是在前面,后面,还是垂直于给定的方向?我们有我们需要的两个方向,但它们是基于矩形的顶部,左点,而不是图像的全部空间,所以我们需要得到一个向量,从上,左,到所讨论的点,另一个从底部,右边,因为这是我们测试的两个点。
这是很简单的计算,因为它只是目的地-起源。
设向量D=顶部,左到测试点C,向量E=底部,右到测试点。
Vector D = C - A;
Vector E = C - B;
点积是两个向量的x1 * x2 + y1*y2。如果结果是正的,则这两个方向的绝对角度小于90度,或者大致是沿着相同的方向运动,零的结果表示它们是垂直的。在我们的例子中,它意味着测试点直接位于我们要测试的矩形的一侧。小于零意味着一个大于90度的绝对角度,或者它们大致是相反的方向。
如果点位于矩形内,则左上角的点积将为>= 0,而右下角的点积将为<= 0。从本质上说,测试点在从左上角进行测试时更接近右下角,但是当我们已经在右下角时,当我们选择相同的方向时,测试点就会离开,向上,向左。
double DotProd(Vector V1, Vector V2)
{
return V1.X * V2.X + V1.Y * V2.Y;
}
所以我们的测试结果是:
if( DotProd(X, D) >= 0 && DotProd(Y, D) >= 0 && DotProd(X, E) <= 0 && DotProd(Y, E) <= 0)
然后点在矩形内。对这两个点执行此操作,如果两者都为真,则这条线位于矩形内。
https://stackoverflow.com/questions/47337200
复制