使用OpenCV remap功能裁剪图像

3
我正在尝试通过OpenCV remap函数(在Python 2.7中)对640x360的图像进行扭曲。执行的步骤如下:
  1. Generate a curve and store its x and y coordinates in two seperate arrays, curve_x and curve_y.I am attaching the generated curve as an image(using pyplot): Curve

  2. Load image via the opencv imread function

    original = cv2.imread('C:\\Users\\User\\Desktop\\alaskan-landscaps3.jpg')
    
  3. Execute a nested for loop so that each pixel is shifted upwards in proportion to the height of the curve at that point.For each pixel I calculate a warping factor by dividing the distance between the curve's y coordinate and the "ceiling" (360) by the height of the image. The factor is then multiplied with the distance between the pixel's y-coordinate and the "ceiling" in order to find the new distance that the pixel must have from the "ceiling" (it will be shorter since we have an upward shift). Finally I subtract this new distance from the "ceiling" to obtain the new y-coordinate for the pixel. I thought of this formula in order to ensure that all entries in the map_y array used in the remap function will be within the area of the original image.

    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`
    
  4. Then using the remap function

    warped=cv2.remap(original,map_x,map_y,cv2.INTER_LINEAR)
    
生成的图像沿着曲线路径似乎有些扭曲,但它已经被裁剪了 - 我将原始图像和生成的图像都附在此处。

Images

我知道我一定漏掉了什么,但我找不到代码错误在哪里——我不明白为什么由于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。还有一个问题是,为什么我没有在曲线以下的像素处得到一个空白空间。

The top of the curved part is at around y=140 in the original picture yet now is very close to the top i.e y around 300

我在思考地图数组map_y的行列顺序是否也存在问题?


{}按钮没有格式化我发布的代码示例,我不知道为什么。我正在尝试格式化代码以使其易读 - 如果您在我完成之前阅读了帖子,请原谅。 - Socrats
使用四个空格进行缩进没有起作用,但使用反引号似乎可以。 - Socrats
从编辑器的帮助中得知:"如果你想在列表中有一个预格式化的块,缩进八个空格"。更多细节请参考高级帮助 - Dan Mašek
1个回答

2
我认为这个图像并没有被裁剪。相反,值是“拥挤”在顶部中间的像素上,以至于它们被覆盖掉了。考虑下面这个例子,在棋盘上应用一个简单的函数。
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)

regular pattern

现在让我们将您的移位函数应用于该模式:
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)

enter image description here

如果你注意到了,由于移位的原因,多个值对应于图像的顶部中间区域,这使得它看起来像是被裁剪了。但是,如果你检查图像的左上角和右上角,会发现数值更稀疏,因此“裁剪”效果不太明显。我希望这个简单的例子能够更好地帮助理解正在发生的事情。

确实有帮助,谢谢。所以我猜我需要一个更复杂的函数来扭曲图像的那一部分。基本上,我想要的效果是由于向上移动而使图像的顶部部分出现“压缩”。是否有任何Python/OpenCV实现可以产生类似的效果? - Socrats
嗨,我已经根据你的描述修正了我的映射函数,但我仍然遇到了一种奇怪的效果,无法解释。 [已使用新代码更新问题] - Socrats
嗨,当我输入: y_size=50 x_size=200时,结果显示底部是黑色的。请问哪个变量是长度和高度? - yw173
对于i在范围(0,y_size)内: #我认为y将从1循环到y的最大尺寸,也许它可以是map_y[j][i] 对于j在范围(0,x_size)内: map_y[i][j]= y_size-((y_size - i) * ((y_size - y[j]) / y_size)) map_x[i][j]=j - yw173

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接