使用 OpenCV 重映射功能裁剪图像
Using OpenCV remap function crops image
我正在尝试通过 OpenCV 重映射函数(在 python 2.7 中)扭曲 640x360 图像。执行的步骤如下
生成一条曲线并将其 x 和 y 坐标存储在两个单独的数组中,curve_x 和 curve_y.I 将生成的曲线附加为图像(使用 pyplot):
通过opencv imread函数加载图片
original = cv2.imread('C:\Users\User\Desktop\alaskan-landscaps3.jpg')
执行一个嵌套的for循环,使每个像素与曲线的高度成比例向上移动point.For每个像素我通过除以曲线之间的距离来计算翘曲因子曲线的 y 坐标和图像高度的 "ceiling" (360)。然后将该因子乘以像素的 y 坐标和 "ceiling" 之间的距离,以便找到像素必须与 "ceiling" 之间的新距离(它会更短,因为我们有一个向上的转移)。最后,我从 "ceiling" 中减去这个新距离以获得像素的新 y 坐标。我想到这个公式是为了确保重映射函数中使用的 map_y 数组中的所有条目都在原始图像的区域内。
for i in range(0, y_size):
for j in range(0,x_size):
map_y[i][j]= y_size-((y_size - i) * ((y_size - curve_y[j]) / y_size))
map_x[i][j]=j`
然后使用重映射函数
warped=cv2.remap(original,map_x,map_y,cv2.INTER_LINEAR)
生成的图像似乎沿着曲线的路径有些扭曲,但它被裁剪了 - 我附上了原始图像和生成的图像
我知道我一定遗漏了一些东西,但我无法找出我的代码中的错误所在 - 我不明白为什么 map_y 中的所有 y 坐标都在 0-360 之间图像的前三分之一在重新映射后消失了
任何指点或帮助将不胜感激。谢谢
[编辑:]我已经按如下方式编辑了我的函数:
#array to store previous y-coordinate, used as a counter during mapping process
floor_y=np.zeros((x_size),np.float32)
#for each row and column of picture
for i in range(0, y_size):
for j in range(0,x_size):
#calculate distance between top of the curve at given x coordinate and top
height_above_curve = (y_size-1) - curve_y_points[j]
#calculated a mapping factor, using total height of picture and distance above curve
mapping_factor = (y_size-1)/height_above_curve
# if there was no curve at given x-coordinate then do not change the pixel coordinate
if(curve_y_points[j]==0):
map_y[i][j]=j
#if this is the first time the column is traversed, save the curve y-coordinate
elif (floor_y[j]==0):
#the pixel is translated upwards according to the height of the curve at that point
floor_y[j]=i+curve_y_points[j]
map_y[i][j]=i+curve_y_points[j] # new coordinate saved
# use a modulo operation to only translate each nth pixel where n is the mapping factor.
# the idea is that in order to fit all pixels from the original picture into a new smaller space
#(because the curve squashes the picture upwards) a number of pixels must be removed
elif ((math.floor(i % mapping_factor))==0):
#increment the "floor" counter so that the next group of pixels from the original image
#are mapped 1 pixel higher up than the previous group in the new picture
floor_y[j]=floor_y[j]+1
map_y[i][j]=floor_y[j]
else:
#for pixels that must be skipped map them all to the last pixel actually translated to the new image
map_y[i][j]=floor_y[j]
#all x-coordinates remain unchanges as we only translate pixels upwards
map_x[i][j] = j
#printout function to test mappings at x=383
for j in range(0, 360):
print('At x=383,y='+str(j)+'for curve_y_points[383]='+str(curve_y_points[383])+' and floor_y[383]='+str(floor_y[383])+' mapping is:'+str(map_y[j][383]))
最重要的是,现在图像的较高部分不应接收来自最低部分的映射,因此不应发生像素覆盖。然而,我仍然在图片中得到一种我无法解释的非常夸张的向上翘曲效果。 (见下面的新图片)。弯曲部分的顶部在原始图片中位于 y=140 左右,但现在非常接近顶部,即 y 大约 300。还有一个问题是为什么我没有得到空白 space 位于曲线下方像素的底部。
我在想 map_y 数组中的行和列的顺序可能也有问题?
我认为图片没有被裁剪。相反,这些值在顶部中间像素中为 "crowded",因此它们会被覆盖。考虑以下在棋盘上使用简单函数的示例。
import numpy as np
import cv2
import pickle
y_size=200
x_size=200
x=np.linspace(0,x_size,x_size+1)
y=(-(x-x_size/2)*(x-x_size/2))/x_size+x_size
plt.plot(x,y)
函数如下所示:
然后让我们生成一个具有规则图案的图像。
test=np.zeros((x_size,y_size),dtype=np.float32)
for i in range(0, y_size):
for j in range(0,x_size):
if i%2 and j%2:
test[i][j]=255
cv2.imwrite('checker.png',test)
现在让我们将您的移位函数应用于该模式:
map_y=np.zeros((x_size,y_size),dtype=np.float32)
map_x=np.zeros((x_size,y_size),dtype=np.float32)
for i in range(0, y_size):
for j in range(0,x_size):
map_y[i][j]= y_size-((y_size - i) * ((y_size - y[j]) / y_size))
map_x[i][j]=j
warped=cv2.remap(test,map_x,map_y,cv2.INTER_LINEAR)
cv2.imwrite('warped.png',warped)
如果您注意到,由于偏移,不止一个值对应于顶部中间区域,这使得它看起来像是被裁剪了。但是,如果您检查图像的左上角和右上角,请注意值比较稀疏,因此 "cropping" 效果不会出现太多。我希望这个简单的例子有助于更好地理解发生了什么。
我正在尝试通过 OpenCV 重映射函数(在 python 2.7 中)扭曲 640x360 图像。执行的步骤如下
生成一条曲线并将其 x 和 y 坐标存储在两个单独的数组中,curve_x 和 curve_y.I 将生成的曲线附加为图像(使用 pyplot):
通过opencv imread函数加载图片
original = cv2.imread('C:\Users\User\Desktop\alaskan-landscaps3.jpg')
执行一个嵌套的for循环,使每个像素与曲线的高度成比例向上移动point.For每个像素我通过除以曲线之间的距离来计算翘曲因子曲线的 y 坐标和图像高度的 "ceiling" (360)。然后将该因子乘以像素的 y 坐标和 "ceiling" 之间的距离,以便找到像素必须与 "ceiling" 之间的新距离(它会更短,因为我们有一个向上的转移)。最后,我从 "ceiling" 中减去这个新距离以获得像素的新 y 坐标。我想到这个公式是为了确保重映射函数中使用的 map_y 数组中的所有条目都在原始图像的区域内。
for i in range(0, y_size): for j in range(0,x_size): map_y[i][j]= y_size-((y_size - i) * ((y_size - curve_y[j]) / y_size)) map_x[i][j]=j`
然后使用重映射函数
warped=cv2.remap(original,map_x,map_y,cv2.INTER_LINEAR)
生成的图像似乎沿着曲线的路径有些扭曲,但它被裁剪了 - 我附上了原始图像和生成的图像
我知道我一定遗漏了一些东西,但我无法找出我的代码中的错误所在 - 我不明白为什么 map_y 中的所有 y 坐标都在 0-360 之间图像的前三分之一在重新映射后消失了
任何指点或帮助将不胜感激。谢谢
[编辑:]我已经按如下方式编辑了我的函数:
#array to store previous y-coordinate, used as a counter during mapping process
floor_y=np.zeros((x_size),np.float32)
#for each row and column of picture
for i in range(0, y_size):
for j in range(0,x_size):
#calculate distance between top of the curve at given x coordinate and top
height_above_curve = (y_size-1) - curve_y_points[j]
#calculated a mapping factor, using total height of picture and distance above curve
mapping_factor = (y_size-1)/height_above_curve
# if there was no curve at given x-coordinate then do not change the pixel coordinate
if(curve_y_points[j]==0):
map_y[i][j]=j
#if this is the first time the column is traversed, save the curve y-coordinate
elif (floor_y[j]==0):
#the pixel is translated upwards according to the height of the curve at that point
floor_y[j]=i+curve_y_points[j]
map_y[i][j]=i+curve_y_points[j] # new coordinate saved
# use a modulo operation to only translate each nth pixel where n is the mapping factor.
# the idea is that in order to fit all pixels from the original picture into a new smaller space
#(because the curve squashes the picture upwards) a number of pixels must be removed
elif ((math.floor(i % mapping_factor))==0):
#increment the "floor" counter so that the next group of pixels from the original image
#are mapped 1 pixel higher up than the previous group in the new picture
floor_y[j]=floor_y[j]+1
map_y[i][j]=floor_y[j]
else:
#for pixels that must be skipped map them all to the last pixel actually translated to the new image
map_y[i][j]=floor_y[j]
#all x-coordinates remain unchanges as we only translate pixels upwards
map_x[i][j] = j
#printout function to test mappings at x=383
for j in range(0, 360):
print('At x=383,y='+str(j)+'for curve_y_points[383]='+str(curve_y_points[383])+' and floor_y[383]='+str(floor_y[383])+' mapping is:'+str(map_y[j][383]))
最重要的是,现在图像的较高部分不应接收来自最低部分的映射,因此不应发生像素覆盖。然而,我仍然在图片中得到一种我无法解释的非常夸张的向上翘曲效果。 (见下面的新图片)。弯曲部分的顶部在原始图片中位于 y=140 左右,但现在非常接近顶部,即 y 大约 300。还有一个问题是为什么我没有得到空白 space 位于曲线下方像素的底部。
我在想 map_y 数组中的行和列的顺序可能也有问题?
我认为图片没有被裁剪。相反,这些值在顶部中间像素中为 "crowded",因此它们会被覆盖。考虑以下在棋盘上使用简单函数的示例。
import numpy as np
import cv2
import pickle
y_size=200
x_size=200
x=np.linspace(0,x_size,x_size+1)
y=(-(x-x_size/2)*(x-x_size/2))/x_size+x_size
plt.plot(x,y)
函数如下所示:
然后让我们生成一个具有规则图案的图像。
test=np.zeros((x_size,y_size),dtype=np.float32)
for i in range(0, y_size):
for j in range(0,x_size):
if i%2 and j%2:
test[i][j]=255
cv2.imwrite('checker.png',test)
现在让我们将您的移位函数应用于该模式:
map_y=np.zeros((x_size,y_size),dtype=np.float32)
map_x=np.zeros((x_size,y_size),dtype=np.float32)
for i in range(0, y_size):
for j in range(0,x_size):
map_y[i][j]= y_size-((y_size - i) * ((y_size - y[j]) / y_size))
map_x[i][j]=j
warped=cv2.remap(test,map_x,map_y,cv2.INTER_LINEAR)
cv2.imwrite('warped.png',warped)
如果您注意到,由于偏移,不止一个值对应于顶部中间区域,这使得它看起来像是被裁剪了。但是,如果您检查图像的左上角和右上角,请注意值比较稀疏,因此 "cropping" 效果不会出现太多。我希望这个简单的例子有助于更好地理解发生了什么。