将图像色块插入子像素位置的另一个图像

时间:2017-01-27 16:48:44

标签: python opencv image-processing graphics computer-vision

我有一个图像补丁,我想在浮点位置插入另一个图像。事实上,我需要的是与opencv getRectSubPix 函数相反的东西。

我想我可以通过将补丁的子像素转换到另一个补丁并将其他补丁插入到整个位置的目标图像中来实现它。但是,我不知道如何处理变形补丁中像素的空白部分,或者如何将新补丁的边框与目标图像混合。

我宁愿使用库函数而不是自己实现这个操作。有人知道在opencv或任何其他图像处理库中是否有可以执行此类操作的库函数吗?

更新

我发现opencv warpPerspective 可以与 borderMode = BORDER_TRANSPARENT 一起使用,这意味着目标图像中与源图像中的“异常值”对应的像素是没有被功能修改。所以我认为我可以用 warpPerspective 和足够的转换矩阵来实现这个子像素补丁插入。所以我在python中编写了这个函数来执行操作:

def insert_patch_subpixel(im, patch, p):
    """
    im: numpy array with source image.
    patch: numpy array with patch to be inserted into the source image
    p: tuple with the center of the position (can be float) where the patch is to be inserted.
    """
    ths = patch.shape[0]/2
    xpmin = p[0] - ths
    ypmin = p[1] - ths
    Ho = np.array([[1, 0, xpmin],
                   [0, 1, ypmin],
                   [0, 0,     1]], dtype=float)

    h,w = im.shape
    im2 = cv2.warpPerspective(patch, Ho, (w,h), dst=im,
                        flags=cv2.INTER_LINEAR,
                        borderMode=cv2.BORDER_TRANSPARENT)
    return im2

不幸的是,如果使用 BORDER_TRANSPARENT ,插值似乎不适用于异常像素。我用一个小的10x10图像(填充值30)测试了这个函数,并在p =(5,5)处插入了一个4x4补丁(填充值100)(左图)和p =(5.5,5.5)(中图)我们可以在下图中看到边界没有插值。但是,如果我将boderMode更改为 BORDER_CONSTANT ,则插值可以正常工作(右图),但是也可以使用0来填充目标图像的异常值。 enter image description here

令人遗憾的是,插值不适用于 BORDER_TRANSPARENT 。我建议将其作为opencv项目的改进。

3 个答案:

答案 0 :(得分:2)

将修补程序图像的大小调整为目标中所需的大小。然后根据边缘设置alpha - 左边缘的分数,右边缘的分数。然后混合。

它并不完美,因为您没有正确重新取样所有像素,但这也会损害分辨率。这可能是你最好的妥协。

答案 1 :(得分:1)

实际上你应该使用getRectSubPix()。 使用它从源图像中提取补丁,使用所需偏移的小数部分,然后使用简单副本(或根据需要混合)将其设置为目标图像。

您可能希望在补丁周围添加1像素边框,您可以在其中进行混合。

此函数基本上只进行平移(子像素)扭曲。

答案 2 :(得分:1)

我找到了一个基于我在更新问题中找到的解决方案。 我可以看到在 warpPerspective 函数中使用 boderMode = BORDER_CONSTANT 时发生插值我认为我可以将其用作原始图像和子像素之间混合的加权掩码在黑色背景上插入的补丁。请参阅新功能和测试代码:

 import numpy as np
 import matplotlib.pyplot as plt

 def insert_patch_subpixel2(im, patch, p):
    """
    im: numpy array with source image.
    patch: numpy array with patch to be inserted into the source image
    p: tuple with the center of the position (can be float) where the patch is to be inserted.
    """
    ths = patch.shape[0]/2
    xpmin = p[0] - ths
    ypmin = p[1] - ths
    Ho = np.array([[1, 0, xpmin],
                   [0, 1, ypmin],
                   [0, 0,     1]], dtype=float)

    h,w = im.shape
    im2 = cv2.warpPerspective(patch, Ho, (w,h),
                        flags=cv2.INTER_LINEAR,
                        borderMode=cv2.BORDER_CONSTANT)

    patch_mask = np.ones_like(patch,dtype=float)
    blend_mask = cv2.warpPerspective(patch_mask, Ho, (w,h),
                        flags=cv2.INTER_LINEAR,
                        borderMode=cv2.BORDER_CONSTANT)

    #I don't multiply im2 by blend_mask because im2 has already
    #been interpolated with a zero background.
    im3 = im*(1-blend_mask)+im2
    im4 = cv2.convertScaleAbs(im3)
    return im4

if __name__ == "__main__":
    x,y = np.mgrid[0:10:1, 0:10:1]
    im =(x+y).astype('uint8')*5
    #im = np.ones((10,10), dtype='uint8')*30
    patch = np.ones((4,4), dtype='uint8')*100
    p=(5.5,5.5)
    im = insert_patch_subpixel2(im, patch, p)
    plt.gray()
    plt.imshow(im, interpolation='none',  extent = (0, 10, 10, 0))
    ax=plt.gca()
    ax.grid(color='r', linestyle='-', linewidth=1)
    ax.set_xticks(np.arange(0, 10, 1));
    ax.set_yticks(np.arange(0, 10, 1));
    def format_coord(x, y):
        col = int(x)
        row = int(y)
        z = im[row,col]
        return 'x=%1.4f, y=%1.4f %s'%(x, y, z)
    ax.format_coord = format_coord
    plt.show()

在下面的图像中,我们可以看到一个小的10x10图像(填充值30)并在p =(5,5)处插入4x4补丁(填充值100)的测试结果(左图)和p =(5.5,5.5)(中图)现在我们可以在下图中看到边界中有双线性插值。为了表明插值适用于任意背景,我还展示了一个带有渐变10x10图像背景的测试(右图)。测试脚本创建一个图形,使您可以检查像素值并验证是否在每个边框像素处完成了正确的插值。 enter image description here