使用OpenCV重映射函数裁剪图像

时间:2017-01-06 14:32:24

标签: python opencv remap

我试图通过OpenCV重映射功能(在python 2.7中)扭曲640x360图像。执行的步骤如下

  1. 生成一条曲线并将其x和y坐标存储在两个单独的数组中,即curve_x和curve_y。我将生成的曲线作为图像附加(使用pyplot):Curve

  2. 通过opencv imread函数

    加载图像
    original = cv2.imread('C:\\Users\\User\\Desktop\\alaskan-landscaps3.jpg')
    
  3. 执行嵌套的for循环,使每个像素与该点处曲线的高度成比例向上移动。对于每个像素,我通过除以曲线之间的距离来计算变形因子。和#34;天花板" (360)按图像的高度。然后将该因子乘以像素的y坐标和"上限之间的距离。为了找到像素必须具有的新距离"天花板" (由于我们有向上的转变,它会更短)。最后,我从"天花板"中减去这个新的距离。获得像素的新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`
    
  4. 然后使用重映射功能

    warped=cv2.remap(original,map_x,map_y,cv2.INTER_LINEAR)
    
  5. 生成的图像在曲线的路径上看起来有点弯曲,但它被裁剪 - 我附加了原始图像和结果图像

    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,但现在非常接近顶部,即大约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数组中的行和列的顺序也会发生变化?

1 个答案:

答案 0 :(得分:0)

我不认为图像正在裁剪。相反,价值观是拥挤的#34;在中上像素,以便它们被覆盖。请考虑以下示例,在棋盘上使用简单的函数。

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)

该功能如下所示: The curve

然后让我们生成一个规则模式的图像。

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

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