Python 在子像素位置将图像面片插入到另一个图像中
我有一个图像补丁,我想插入到另一个图像的浮点位置。事实上,我需要的是与opencvgetRectSubPix函数功能相反的东西 我想我可以通过将补丁的子像素扭曲到另一个补丁中,然后将另一个补丁插入到目标图像的整数位置来实现它。但是,我不清楚如何处理扭曲面片中的空像素部分,或者如何将新面片的边界与目标图像中的像素混合 我宁愿使用库函数,也不愿自己实现这个操作。有人知道opencv或任何其他图像处理库中是否有任何库函数可以执行这种类型的操作吗 更新: 我发现opencvwarpPerspective可以与borderMode=BORDER_TRANSPARENT一起使用,这意味着目标图像中与源图像中的“异常值”对应的像素不会被函数修改。所以我想我可以用一个透视图和一个适当的变换矩阵来实现这个亚像素面片插入。所以我用python编写了这个函数来执行这个操作:Python 在子像素位置将图像面片插入到另一个图像中,python,opencv,image-processing,graphics,computer-vision,Python,Opencv,Image Processing,Graphics,Computer Vision,我有一个图像补丁,我想插入到另一个图像的浮点位置。事实上,我需要的是与opencvgetRectSubPix函数功能相反的东西 我想我可以通过将补丁的子像素扭曲到另一个补丁中,然后将另一个补丁插入到目标图像的整数位置来实现它。但是,我不清楚如何处理扭曲面片中的空像素部分,或者如何将新面片的边界与目标图像中的像素混合 我宁愿使用库函数,也不愿自己实现这个操作。有人知道opencv或任何其他图像处理库中是否有任何库函数可以执行这种类型的操作吗 更新: 我发现opencvwarpPerspective
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)(左图)和p=(5.5,5.5)(中间图)插入了一个4x4面片(填充值100),我们可以在下图中看到边界中没有插值。但是,如果我将boderMode更改为BORDER_CONSTANT,则插值可以工作(右图),但这也会用0填充目标图像中的异常值。
很遗憾,插值不能与BORDER\u TRANSPARENT一起使用。我建议这是对opencv项目的改进。将补丁图像调整为目标中所需的大小。然后根据1.0设置沿边的alpha-左边为分数,右边为分数。然后混合
这不是很完美,因为没有正确地对所有像素进行重新采样,但这也会损害分辨率。这可能是您最好的折衷办法。将修补程序图像的大小调整为目标中所需的大小。然后根据1.0设置沿边的alpha-左边为分数,右边为分数。然后混合
这不是很完美,因为没有正确地对所有像素进行重新采样,但这也会损害分辨率。这可能是您最好的折衷办法。实际上,您应该使用
getRectSubPix()
。
使用它从源图像中提取具有所需偏移的分数部分的面片,然后使用简单副本(或根据需要混合)将其设置到目标图像中
您可能需要在面片周围添加一个1像素的边框,以便进行混合
此函数本质上只执行平移(子像素)扭曲。实际上,您应该使用
getRectSubPix()
。
使用它从源图像中提取具有所需偏移的分数部分的面片,然后使用简单副本(或根据需要混合)将其设置到目标图像中
您可能需要在面片周围添加一个1像素的边框,以便进行混合
这个函数基本上只执行翻译(亚像素)扭曲。我根据我在问题更新中找到的内容找到了一个解决方案。 正如我在warpPerspective函数中使用boderMode=BORDER_常量时看到的插值,我想我可以将其用作原始图像和黑色背景上插入的子像素面片之间混合的加权遮罩。请参阅新功能和测试代码:
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)(左图)和p=(5.5,5.5)(中间图)插入一个4x4面片(填充值100),现在我们可以在下图中看到边界中存在双线性插值。为了显示插值在任意背景下工作,我还显示了一个梯度为10x10图像背景的测试(右图)。测试脚本将创建一个图形,用于检查像素值并验证在每个边界像素处是否执行了正确的插值。
根据我在问题更新中找到的内容,我找到了一个解决方案。 正如我在warpPerspective函数中使用boderMode=BORDER_常量时看到的插值,我想我可以将其用作原始图像和黑色背景上插入的子像素面片之间混合的加权遮罩。请参阅新功能和测试代码:
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)(左图)和p=(5.5,5.5)(中间图)插入一个4x4面片(填充值100),现在我们可以在下图中看到边界中存在双线性插值。为了显示插值在任意背景下工作,我还显示了一个梯度为10x10图像背景的测试(右图)。测试脚本将创建一个图形,用于检查像素值并验证在每个边界像素处是否执行了正确的插值。
可以使用
cv2.findHomography()
将子图像扭曲到另一个图像,这可能会对您的问题造成过度伤害,但您可以在傅里叶空间域扭曲面片,然后反向变换并将其合并到目标图像中。如果执行正确,该操作将产生亚像素accuracy@Matt-麦克·马芬:你能详细介绍一下这种方法吗?图像中的空间偏移是频域中的相位差。你