使用opencv将一个形状放在另一个形状内

Placing a shape inside another shape using opencv

我有两张图片,我需要将第二张图片放在第一张图片中。第二张图片可以调整大小、旋转或倾斜,使其尽可能覆盖其他图片的更大区域。例如,在下图中,绿色圆圈需要放在蓝色形状内:

此处绿色圆圈经过变换,覆盖了更大的区域。另一个例子如下所示:

请注意,可能会有多个结果。但是,如上例所示,任何类似的结果都是可以接受的。

如何解决这个问题? 提前致谢!

我测试了我之前在评论中提到的想法,输出几乎不错。它可能会更好,但需要时间。最终代码太多,依赖于我个人的一个旧项目,就不分享了。但我会一步一步解释我是如何编写这样一个算法的。请注意,我已经多次测试该算法。还不是 100% 准确。


for N times do this:
    1. Copy from shape
    2. Transform it randomly
    3. Put the shape on the background
    4-1. It is not acceptable if the shape exceeds the background. Go to 
         the first step.
    4.2. Otherwise we will continue to step 5.
    5. We calculate the length, width and number of shape pixels.
    6. We keep a list of the best candidates and compare these three 
       parameters (W, H, Pixels) with the members of the list. If we 
       find a better item, we will save it.
  • 我把N的值设为5000。数字越大,算法运行越慢,但结果越好。

  • 你可以为 Transform. Mirror, , Shear, Scale, 等使用任何东西。但是我用了 warpPerspective 这个。

im1 = cv2.imread(sys.path[0]+'/Back.png')
im2 = cv2.imread(sys.path[0]+'/Shape.png')
bH, bW = im1.shape[:2]
sH, sW = im2.shape[:2]


# TopLeft, TopRight, BottomRight, BottomLeft of the shape
_inp = np.float32([[0, 0], [sW, 0], [sW, sH], [0, sH]])
cx = random.randint(5, sW-5)
ch = random.randint(5, sH-5)
o = 0
# Random transformed output
_out = np.float32([
            [random.randint(-o, cx-1), random.randint(1-o, ch-1)],
            [random.randint(cx+1, sW+o), random.randint(1-o, ch-1)],
            [random.randint(cx+1, sW+o), random.randint(ch+1, sH+o)],
            [random.randint(-o, cx-1), random.randint(ch+1, sH+o)]
])

# Transformed output
M = cv2.getPerspectiveTransform(_inp, _out)
t = cv2.warpPerspective(shape, M, (bH, bW))
  • 您可以使用 countNonZero 来计算像素数,并使用 findContoursboundingRect 来计算找到形状大小。
def getSize(msk):
    cnts, _ = cv2.findContours(msk, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
    cnts.sort(key=lambda p: max(cv2.boundingRect(p)[2],cv2.boundingRect(p)[3]), reverse=True)
    w,h=0,0
    if(len(cnts)>0):
        _, _, w, h = cv2.boundingRect(cnts[0])
    pix = cv2.countNonZero(msk)
    return pix, w, h
  • 要找到背部和形状的重叠,您可以这样做: 从背面制作面具并塑造并使用按位方法;根据您编写的软件更改此部分。这只是一个例子:)
mskMix = cv2.bitwise_and(mskBack, mskShape)
mskMix = cv2.bitwise_xor(mskMix, mskShape)
isCandidate = not np.any(mskMix == 255)

例如,这不是候选答案;这是因为如果你仔细看右边的图片,你会发现形状已经超出了背景。


我刚刚测试了4个不同背景的圆圈;结果:
4879 次迭代后:

1587 次迭代后:

4621 次迭代后:

4574 次迭代后:


  • 补充几点。如果你使用像medianBlur这样的方法来覆盖Background mask和Shape mask中的噪点,你可能会找到更好的解决方案。

  • 我建议您阅读有关 Evolutionary Computation, Metaheuristic and Soft Computing 的算法,以便更好地理解该算法:)