我目前正在使用 opencv (CV2) 和 Python Pillow 图像库来尝试拍摄任意手机的图像并用新图像替换屏幕。我已经到了可以拍摄图像并识别手机屏幕并获取角落所有坐标的地步,但我真的很难用新图像替换图像中的那个区域。
我目前的代码:
import cv2
from PIL import Image
image = cv2.imread('mockup.png')
edged_image = cv2.Canny(image, 30, 200)
(contours, _) = cv2.findContours(edged_image.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours = sorted(contours, key = cv2.contourArea, reverse = True)[:10]
screenCnt = None
for contour in contours:
peri = cv2.arcLength(contour, True)
approx = cv2.approxPolyDP(contour, 0.02 * peri, True)
# if our approximated contour has four points, then
# we can assume that we have found our screen
if len(approx) == 4:
screenCnt = approx
break
cv2.drawContours(image, [screenCnt], -1, (0, 255, 0), 3)
cv2.imshow("Screen Location", image)
cv2.waitKey(0)
我还可以使用这行代码获取屏幕角的坐标:
screenCoords = [x[0].tolist() for x in screenCnt]
// [[398, 139], [245, 258], [474, 487], [628, 358]]
但是我终究无法弄清楚如何拍摄新图像并将其缩放为我找到的坐标空间的形状并将图像叠加在上面。
我的猜测是,我可以使用 Pillow 中的图像变换来执行此操作,使用我改编自 this stackoverflow question 的函数:
def find_transform_coefficients(pa, pb):
"""Return the coefficients required for a transform from start_points to end_points.
args:
start_points -> Tuple of 4 values for start coordinates
end_points --> Tuple of 4 values for end coordinates
"""
matrix = []
for p1, p2 in zip(pa, pb):
matrix.append([p1[0], p1[1], 1, 0, 0, 0, -p2[0]*p1[0], -p2[0]*p1[1]])
matrix.append([0, 0, 0, p1[0], p1[1], 1, -p2[1]*p1[0], -p2[1]*p1[1]])
A = numpy.matrix(matrix, dtype=numpy.float)
B = numpy.array(pb).reshape(8)
res = numpy.dot(numpy.linalg.inv(A.T * A) * A.T, B)
return numpy.array(res).reshape(8)
但是我有点头昏脑胀,无法准确了解细节。有人可以帮我吗?
编辑
好的,现在我正在使用 getPerspectiveTransform 和 warpPerspective 函数,我得到了以下附加代码:
screenCoords = numpy.asarray(
[numpy.asarray(x[0], dtype=numpy.float32) for x in screenCnt],
dtype=numpy.float32
)
overlay_image = cv2.imread('123.png')
overlay_height, overlay_width = image.shape[:2]
input_coordinates = numpy.asarray(
[
numpy.asarray([0, 0], dtype=numpy.float32),
numpy.asarray([overlay_width, 0], dtype=numpy.float32),
numpy.asarray([overlay_width, overlay_height], dtype=numpy.float32),
numpy.asarray([0, overlay_height], dtype=numpy.float32)
],
dtype=numpy.float32,
)
transformation_matrix = cv2.getPerspectiveTransform(
numpy.asarray(input_coordinates),
numpy.asarray(screenCoords),
)
warped_image = cv2.warpPerspective(
overlay_image,
transformation_matrix,
(background_width, background_height),
)
cv2.imshow("Overlay image", warped_image)
cv2.waitKey(0)
图像正在正确旋转和倾斜(我认为),但它与屏幕的尺寸不一样。它的“更短”:
如果我使用另一个垂直方向非常高的图像,我最终会得到太“长”的图像:
我是否需要应用额外的转换来缩放图像?不确定这里发生了什么,我认为透视变换会使图像自动扩展到提供的坐标。
最佳答案
我下载了你的图像数据,并在我的本地机器上重现了这个问题,以找出解决方案。还下载了 lenna.png
以适合手机屏幕。
import cv2
import numpy as np
# Template image of iPhone
img1 = cv2.imread("/Users/anmoluppal/Downloads/46F1U.jpg")
# Sample image to be used for fitting into white cavity
img2 = cv2.imread("/Users/anmoluppal/Downloads/Lenna.png")
rows,cols,ch = img1.shape
# Hard coded the 3 corner points of white cavity labelled with green rect.
pts1 = np.float32([[201, 561], [455, 279], [742, 985]])
# Hard coded the same points on the reference image to be fitted.
pts2 = np.float32([[0, 0], [512, 0], [0, 512]])
# Getting affine transformation form sample image to template.
M = cv2.getAffineTransform(pts2,pts1)
# Applying the transformation, mind the (cols,rows) passed, these define the final dimensions of output after Transformation.
dst = cv2.warpAffine(img2,M,(cols,rows))
# Just for Debugging the output.
final = cv2.addWeighted(dst, 0.5, img1, 0.5, 1)
cv2.imwrite("./garbage.png", final)
关于python - 如何使用 Python 用新图像替换图像中的轮廓(矩形)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38320865/