Tob*_*s K 3 python opencv image-processing
我有两张图片
图像 1(对象):
] 3
没有标记关键点的原始图像:
image2 是一张白色图片 (500x500)
在 image1 和 image2 中,我标记了关键点。我想通过关键点在 image2 上对齐 image1。因此,两个关键点与拉伸、缩放和变换 image2 重叠的目标。
这是我的关键点(csv 文件)。image1 中的 image1 和 image2 中的 image2 的坐标是 x 和 y。
object1_x,object1_y,image_x,image_y
0,0,80,137
286,0,409,42
286,198,416,390
174,198,331,384
158,116,291,119
0,97,111,311
Run Code Online (Sandbox Code Playgroud)
我怎样才能用 opencv 和 python 做到这一点?所以结果图像应该是这样的(没有红点,红点仅用于演示关键点):
从第一组关键点中提取 3 个索引的集合,当从两组关键点进行索引时,这些索引将形成三角形。使用索引,我们可以从两组关键点获得相应的三角形,允许我们逐个构建扭曲的图像三角形(有关更多详细信息,请参阅使用 OpenCV 将一个三角形变形为另一个三角形):
image1.png (加分):
image2.png (加分):
结果(加分)
import cv2
import numpy as np
def triangles(points):
points = np.where(points, points, 1)
subdiv = cv2.Subdiv2D((*points.min(0), *points.max(0)))
subdiv.insert(list(points))
for pts in subdiv.getTriangleList().reshape(-1, 3, 2):
yield [np.where(np.all(points == pt, 1))[0][0] for pt in pts]
def crop(img, pts):
x, y, w, h = cv2.boundingRect(pts)
img_cropped = img[y: y + h, x: x + w]
pts[:, 0] -= x
pts[:, 1] -= y
return img_cropped, pts
def warp(img1, img2, pts1, pts2):
for indices in triangles(pts1):
img1_cropped, triangle1 = crop(img1, pts1[indices])
img2_cropped, triangle2 = crop(img2, pts2[indices])
transform = cv2.getAffineTransform(np.float32(triangle1), np.float32(triangle2))
img2_warped = cv2.warpAffine(img1_cropped, transform, img2_cropped.shape[:2][::-1], None, cv2.INTER_LINEAR, cv2.BORDER_REFLECT_101)
mask = np.zeros_like(img2_cropped)
cv2.fillConvexPoly(mask, np.int32(triangle2), (1, 1, 1), 16, 0)
img2_cropped *= 1 - mask
img2_cropped += img2_warped * mask
img1 = cv2.imread("image1.png")
img2 = cv2.imread("image2.png")
pts1 = np.array([[0, 0], [286, 0], [286, 198], [174, 198], [158, 116], [0, 97]])
pts2 = np.array([[80, 37], [409, 42], [416, 390], [331, 384], [291, 119], [111, 311]])
warp(img1, img2, pts1, pts2)
for pt in pts2:
cv2.circle(img2, tuple(pt), 15, (0, 0, 255), -1)
cv2.imshow("Original", img1)
cv2.imshow("Transformed", img2)
cv2.waitKey(0)
cv2.destroyAllWindows()
Run Code Online (Sandbox Code Playgroud)
import cv2
import numpy as np
Run Code Online (Sandbox Code Playgroud)
triangles, , , , , , points, 并产生三角形数组的 3 个索引的列表,三角形将覆盖原始坐标数组的区域:def triangles(points):
points = np.where(points, points, 1)
subdiv = cv2.Subdiv2D((*points.min(0), *points.max(0)))
subdiv.insert(list(points))
for pts in subdiv.getTriangleList().reshape(-1, 3, 2):
yield [np.where(np.all(points == pt, 1))[0][0] for pt in pts]
Run Code Online (Sandbox Code Playgroud)
crop,它将接受一个图像数组img, 和一个包含三个坐标的数组,pts。它将返回图像的一个矩形段,刚好适合三个点形成的三角形,并返回转移到图像左上角的三个坐标数组:def crop(img, pts):
x, y, w, h = cv2.boundingRect(pts)
img_cropped = img[y: y + h, x: x + w]
pts[:, 0] -= x
pts[:, 1] -= y
return img_cropped, pts
Run Code Online (Sandbox Code Playgroud)
warp, , 将接受 2 个图像数组, img1and img2, 和 2 个坐标数组, pts1and pts2. 它将利用triangles之前定义的函数遍历第一个坐标数组中的三角形,crop之前定义的函数在与三角形索引对应的坐标处裁剪两个图像,并使用该cv2.warpAffine()方法在迭代的当前三角形处扭曲图像:def warp(img1, img2, pts1, pts2):
for indices in triangles(pts1):
img1_cropped, triangle1 = crop(img1, pts1[indices])
img2_cropped, triangle2 = crop(img2, pts2[indices])
transform = cv2.getAffineTransform(np.float32(triangle1), np.float32(triangle2))
img2_warped = cv2.warpAffine(img1_cropped, transform, img2_cropped.shape[:2][::-1], None, cv2.INTER_LINEAR, cv2.BORDER_REFLECT_101)
mask = np.zeros_like(img2_cropped)
cv2.fillConvexPoly(mask, np.int32(triangle2), (1, 1, 1), 16, 0)
img2_cropped *= 1 - mask
img2_cropped += img2_warped * mask
Run Code Online (Sandbox Code Playgroud)
img1是我们想要扭曲的图像,img2是空白的 500 x 500 图像。此外,定义 2 个坐标数组作为图像的关键点:img1 = cv2.imread("image1.png")
img2 = cv2.imread("image2.png")
pts1 = np.array([[0, 0], [286, 0], [286, 198], [174, 198], [158, 116], [0, 97]])
pts2 = np.array([[80, 37], [409, 42], [416, 390], [331, 384], [291, 119], [111, 311]])
Run Code Online (Sandbox Code Playgroud)
warp之前定义的函数进行扭曲img1,使其关键点与 的关键点重叠img2并显示结果图像。我将第二个坐标数组中的点绘制到生成的扭曲图像上,以使扭曲过程更容易可视化:warp(img1, img2, pts1, pts2)
for pt in pts2:
cv2.circle(img2, tuple(pt), 15, (0, 0, 255), -1)
cv2.imshow("Original", img1)
cv2.imshow("Transformed", img2)
cv2.waitKey(0)
cv2.destroyAllWindows()
Run Code Online (Sandbox Code Playgroud)