简体   繁体   English

如何使用变形网格扭曲图像

[英]How to warp an image using deformed mesh

I'm trying to generate "crumpled" images using images obtained from a flatbed bed scanner.我正在尝试使用从平板扫描仪获得的图像生成“皱巴巴”的图像。

By following the method described in the paper [Link] in the section 3.1.按照3.1节中论文[链接]中描述的方法。 I've written the code generate the perturbed mesh but I don't know how to map this pixels from source image onto this mesh to form the perturbed image.我已经编写了生成扰动网格的代码,但我不知道如何将源图像中的 map 这个像素添加到该网格上以形成扰动图像。

This is the code to generate the perturbed mesh.这是生成扰动网格的代码。

import numpy as np
import matplotlib.pyplot as plt

mr = 88
mc = 68

xx = np.arange(mr-1, -1, -1)
yy = np.arange(0, mc, 1)
[Y, X] = np.meshgrid(xx, yy)
ms = np.transpose(np.asarray([X.flatten('F'), Y.flatten('F')]), (1,0))

perturbed_mesh = ms
nv = np.random.randint(20) - 1
for k in range(nv):
    #Choosing one vertex randomly
    vidx = np.random.randint(np.shape(ms)[0])
    vtex = ms[vidx, :]
    #Vector between all vertices and the selected one
    xv  = perturbed_mesh - vtex
    #Random movement 
    mv = (np.random.rand(1,2) - 0.5)*20
    hxv = np.zeros((np.shape(xv)[0], np.shape(xv)[1] +1) )
    hxv[:, :-1] = xv
    hmv = np.tile(np.append(mv, 0), (np.shape(xv)[0],1))
    d = np.cross(hxv, hmv)
    d = np.absolute(d[:, 2])
    d = d / (np.linalg.norm(mv, ord=2))
    wt = d
    
    curve_type = np.random.rand(1)
    if curve_type > 0.3:
        alpha = np.random.rand(1) * 50 + 50
        wt = alpha / (wt + alpha)
    else:
        alpha = np.random.rand(1) + 1
        wt = 1 - (wt / 100 )**alpha
    msmv = mv * np.expand_dims(wt, axis=1)
    perturbed_mesh = perturbed_mesh + msmv

plt.scatter(perturbed_mesh[:, 0], perturbed_mesh[:, 1], c=np.arange(0, mr*mc))
plt.show()

This is how the perturbed mesh looks like:这是扰动网格的样子: 在此处输入图像描述

This is the screenshot from the paper illustrating the synthetic image generation:这是说明合成图像生成的论文的屏幕截图: 在此处输入图像描述

Sample source image for testing: https://i.stack.imgur.com/26KN4.jpg用于测试的示例源图像: https://i.stack.imgur.com/26KN4.jpg

I'm stuck with mapping the source image pixels onto the mesh.我坚持将源图像像素映射到网格上。 I'll be grateful if someone can help.如果有人可以提供帮助,我将不胜感激。

(1) Use cv2.copyMakeBorder to enlarge the image, to avoid the warpped points going out of range of the original image size. (1) 使用cv2.copyMakeBorder放大图像,避免扭曲点超出原始图像尺寸范围。

cv2.copyMakeBorder(...)
    copyMakeBorder(src, top, bottom, left, right, borderType[, dst[, value]]) -> dst
    .   @brief Forms a border around an image.
    .
    .   The function copies the source image into the middle of the destination image. The areas to the
    .   left, to the right, above and below the copied source image will be filled with extrapolated
    .   pixels. This is not what filtering functions based on it do (they extrapolate pixels on-fly), but
    .   what other more complex functions, including your own, may do to simplify image boundary handling.

useage:用途:

img = cv2.copyMakeBorder(img, dh, dh, dw, dw, borderType=cv2.BORDER_CONSTANT, value=(0,0,0))

Set dw=nw//2, dh=nh//2 maybe ok, adjust if necessary.设置dw=nw//2, dh=nh//2可能没问题,必要时调整。 The nh, nw is the height and width of the source image. nh, nw是源图像的高度和宽度。

(2) Create perturbed mesh grid using the method from the paper (2) 使用论文中的方法创建扰动网格

xs, ys = create_grid() # the result is like np.meshgrid

Notice make sure the type and the size.注意确定类型和尺寸。

# xs = xs.reshape(nh, nw).astype(np.float32)
# nh, nw is the height and width of the coppied image

(3) Use cv2.remap to remap: (3) 使用cv2.remap重新映射:

cv2.remap(...)
    remap(src, map1, map2, interpolation[, dst[, borderMode[, borderValue]]]) -> dst
    .   @brief Applies a generic geometrical transformation to an image.
    .
    .   The function remap transforms the source image using the specified map:
    .   \f[\texttt{dst} (x,y) =  \texttt{src} (map_x(x,y),map_y(x,y))\f]

usage:用法:

dst= cv2.remap(img, xs, ys, cv2.INTER_CUBIC)

This is a demo result:这是一个演示结果:

在此处输入图片说明

(4) Crop the nonzero region and resize if necessary: (4) 裁剪非零区域并在必要时调整大小:

在此处输入图片说明


Related:有关的:

  1. Converting opencv remap code from c++ to python 将opencv重映射代码从c++转换为python

  2. Split text lines in scanned document 分割扫描文档中的文本行

I'm leaving a minimum working demo for other readers.我要为其他读者留下一个最低限度的工作演示。

Currently, trying to figure out in which condition perturbed_mesh becomes None .目前,试图找出在哪种情况下perturbed_mesh变为None

def deform(img, perturbed_mesh):
    h,w = img.shape[:2]

    perturbed_mesh_x = perturbed_mesh[:,0]
    perturbed_mesh_y = perturbed_mesh[:,1]
    
    perturbed_mesh_x =perturbed_mesh_x.reshape((h,w))
    perturbed_mesh_y =perturbed_mesh_y.reshape((h,w))

    remapped = cv2.remap(img, perturbed_mesh_x, perturbed_mesh_y, cv2.INTER_LINEAR) 

    return remapped

def get_perturbed_mesh(img):
    """
        Author: papabiceps
        https://stackoverflow.com/q/53907633
    """

    # mesh row & col
    mr,mc = img.shape[:2]

    xx = np.arange(0, mr, 1)
    yy = np.arange(mc-1, -1, -1)

    # yy = np.arange(0, mc, 1)
    [Y, X] = np.meshgrid(xx, yy)

    ms = np.transpose(np.asarray([X.flatten('F'), Y.flatten('F')]), (1,0))
 
    perturbed_mesh = ms
    nv = np.random.randint(20) - 1

    for k in range(nv):
        #Choosing one vertex randomly
        vidx = np.random.randint(np.shape(ms)[0])
        vtex = ms[vidx, :]
        #Vector between all vertices and the selected one
        xv  = perturbed_mesh - vtex
        #Random movement 
        mv = (np.random.rand(1,2) - 0.5)*20
        hxv = np.zeros((np.shape(xv)[0], np.shape(xv)[1] +1) )
        hxv[:, :-1] = xv
        hmv = np.tile(np.append(mv, 0), (np.shape(xv)[0],1))
        d = np.cross(hxv, hmv)
        d = np.absolute(d[:, 2])
        d = d / (np.linalg.norm(mv, ord=2))
        wt = d
        
        curve_type = np.random.rand(1)
        if curve_type > 0.3:
            alpha = np.random.rand(1) * 50 + 50
            wt = alpha / (wt + alpha)
        else:
            alpha = np.random.rand(1) + 1
            wt = 1 - (wt / 100 )**alpha
        msmv = mv * np.expand_dims(wt, axis=1)

        perturbed_mesh = perturbed_mesh + msmv

        perturbed_mesh = perturbed_mesh.astype(np.float32)

        if perturbed_mesh is not None:
            result = deform(img, perturbed_mesh)

            flipped = cv2.flip(result,1)

            cv2.imshow("before",result)
            cv2.imshow("after",flipped)
            cv2.waitKey(0)
 

def main():
    img = cv2.imread("./sample.png")

    get_perturbed_mesh(img)


声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM