Python和OpenCV,用于查找和覆盖/替换图像的一部分

时间:2018-11-05 09:05:57

标签: python image opencv

需要查找图像中的某些部分并将其替换为其他图像。

原始图像如下所示。我要查找并替换:

blue squares to blue triangles
orange squares to orange octagons

enter image description here

图像文件的位置为:

original.jpg, blue square.jpg, orange square.jpg, blue triangle.jpg, orange octagon.jpg

enter image description here enter image description here enter image description here enter image description here

使用cv2,我可以找到目标图像的位置。

import cv2
import numpy as np

img_original = cv2.imread("C:\\original.jpg")

img_to_replace_0 = cv2.imread("C:\\blue square.jpg")
img_to_replace_1 = cv2.imread("C:\\orange square.jpg")

img_overlay_0 = cv2.imread("C:\\blue triangle.jpg")
img_overlay_1 = cv2.imread("C:\\orange octagon.jpg")

res_0 = cv2.matchTemplate(img_original, img_to_replace_0, cv2.TM_CCOEFF_NORMED)
res_1 = cv2.matchTemplate(img_original, img_to_replace_1, cv2.TM_CCOEFF_NORMED)

threshold = 0.80
loc_0 = np.where (res_0 >= threshold)
loc_1 = np.where (res_1 >= threshold)

bl_0 = list(loc_0)
bl_1 = list(loc_1)

print bl_0
print bl_1

输出为:

[array([106, 294, 477]), array([17, 18, 21])]
[array([ 22, 210, 393]), array([16, 17, 20])]

进一步进行下去的最好方法是什么? CV2是针对这种情况的最佳工具吗?谢谢。

1 个答案:

答案 0 :(得分:1)

是的,可以从这一点继续。然后,您将获得每个位置,第一个数组是y轴,第二个数组是x轴。此位置是对象的左上角。

这里可能的问题是模板的大小不同。因此它可能与原始图像中未发生的图像其他部分重叠,并且我不知道这是否是一个问题。因此,如果出现问题,您可能必须确保它们都相等,或者它们具有足够的空间。可以解决此问题,例如将图像缩放到相同大小。

无论如何,您可以这样实现替换:

import cv2
import numpy as np

# load the data
img = cv2.imread('scene.jpg')
blueTri = cv2.imread('blueTri.jpg')
blueSq = cv2.imread('blueSq.jpg')
bgColor = (255,255,255)

# find the matching rectangles
res = cv2.matchTemplate(img, blueSq, cv2.TM_CCOEFF_NORMED)
threshold = 0.98 # I used a higher threshold, because it was giving several "good" locations that are next to each other
loc = np.where (res >= threshold)

# process the positions
for i in range(len(loc[0])):
  # it is given as (y,x)
  pos = (loc[0][i], loc[1][i])
  # delete the blue squares
  img[pos[0]:pos[0]+blueSq.shape[0] , pos[1]:pos[1]+blueSq.shape[1] ] = bgColor
  # put the new blue triangle
  img[pos[0]:pos[0]+blueTri.shape[0] , pos[1]:pos[1]+blueTri.shape[1] ] = blueTri


cv2.imshow("Frame", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

这是蓝色正方形到蓝色三角形的结果:

enter image description here

对于这两个更改,例如您的示例:

enter image description here

如果两个模板的大小相等(即您要查找的图像和将要替换的图像),则可以减少一级并将for循环更改为:

# process the positions
for i in range(len(loc[0])):
  # it is given as (y,x)
  pos = (loc[0][i], loc[1][i])
  # put the new blue triangle
  img[pos[0]:pos[0]+blueTri.shape[0] , pos[1]:pos[1]+blueTri.shape[1] ] = blueTri

更新

要移动要复制的形状,可以移动整个ROI,无论如何,您已经删除了旧的ROI,就可以了。只是不要忘记检查图像的界限。为此,您可以执行以下操作:

for i in range(len(loc[0])):
  posToDelete = (loc[0][i], loc[1][i])
  posToAdd = (loc[0][i] -10, loc[1][i]+15) # 10 pixels up and 15 to the right
  posToAdd = (max(0, min(posToAdd[0],img.shape[0]-1 -blueTri.shape[0] )) , max(0, min(posToAdd[1],img.shape[1]-1-blueTri.shape[1]))) # sanity check to make sure it is inside the borders
  img[posToDelete[0]:posToDelete[0]+blueSq.shape[0] , posToDelete[1]:posToDelete[1]+blueSq.shape[1] ] = bgColor
  img[posToAdd[0]:posToAdd[0]+blueTri.shape[0] , posToAdd[1]:posToAdd[1]+blueTri.shape[1] ] = blueTri