Final Project: Image Quilting

In this project, we implement the "image quilting" and "texture transfer" algorithms described in "Image Quilting for Texture Synthesis and Transfer" (Efros, Freeman).

Randomly Sampled Textures

Texture synthesis is the creation of a similar but different version of a "texture image", or an image with repeated patterns. We begin with a highly naive approach to texture synthesis: we fill the patches of an output image by repeatedly sampling random patches from an input image.

img

Input (from the paper)

img

Random sampling output (patch_size=15)

The resulting output is poor because it is clearly "blocky". Note that the output (300x300) is larger than the input (192x192).

Overlapping Patches

A better approach to texture synthesis is to overlap the output patches and fill them in raster-scan order. To fill an output patch, we compute how well each input patch overlaps with the already-filled portion of the output patch. (This is measured as the SSD (sum of square differences) between the already-filled portion of the output patch and the corresponding portion of the input patch.) We set tol=5; in other words, one of the five best input patches is chosen at random to fill the output patch.

img

Overlapping patches output (patch_size=25, overlap=11, tol=5)

Seam Finding

The official image quilting algorithm eliminates "blocky" results by establishing curved boundaries between output patches. Once we have chosen an input patch to fill an output patch, we compute a curved cut along the output patch's overlapping portion. In particular, we compute the cut that minimizes the difference between existing pixels and new pixels along the path of the cut. (To do this, we compute the optimal horizontal and vertical cuts separately and combine them.)

img

Image quilting output (patch_size=25, overlap=11, tol=5)

We display the seam-finding process for a single output patch below.

img

Existing pixels in output patch.

img

The chosen input patch.

img

Squared error between existing pixels and input patch.

img

Optimal horizontal cut.

img

Optimal vertical cut.

img

Combined cut.

Additional Quilting Results

img

Input (my photo)

img

Image quilting output (patch_size=25, overlap=11, tol=5)

img

Input (my photo)

img

Image quilting output (patch_size=25, overlap=11, tol=5)

Texture Transfer

We can repurpose the image quilting algorithm to perform "texture transfer". During texture transfer, we reconstruct a guidance image by sampling patches from a different image, which we call the texture image.

To produce an output that resembles the guidance image, we introduce a "correspondence cost". For any output patch and candidate input patch, the correspondence cost of choosing the input patch is the SSD between the input patch and the patch in the guidance image that is being reconstructed. (Before computing SSD, we apply several transformations to the texture and guidance images: smoothing the images, converting the images to grayscale, and normalizing pixel values.)

The overall cost of selecting an input patch is the weighted average alpha * overlap_cost + (1-alpha) * correspondence_cost for some weight alpha. Note that overlap_cost is the existing cost that is computed from patch overlap. Once the overall cost of each input patch is known, we randomly select an input patch according to tol and proceed with seam-finding.

img

Texture input (from the paper)

img

Guidance input (from the paper)

img

Texture transfer output (patch_size=11, overlap=4, tol=3, alpha=0.5)

img

Texture input (from wallpapers.com)

img

Guidance input (my photo)

img

Texture transfer output (patch_size=11, overlap=4, tol=3, alpha=0.5)

B&W: Iterative Texture Transfer

We improve texture transfer by turning it into an iterative process: we perform several raster scans with decreasing values of patch_size and overlap, and increasing values of alpha. Starting from the second iteration, we compute "overlap cost" using the entire input patch and all existing pixels in the output patch.

img

Non-iterative output from before

img

Iterative output (patch_sizes=[67, 43, 27, 17, 11], overlaps=[32, 20, 12, 7, 4], tol=3, alphas=[0.1, 0.3, 0.5, 0.7, 0.9])

img

Non-iterative output from before

img

Iterative output (patch_sizes=[67, 43, 27, 17, 11], overlaps=[32, 20, 12, 7, 4], tol=3, alphas=[0.1, 0.3, 0.5, 0.7, 0.9])

In both examples of texture transfer, the iterative outputs fix minor issues in the non-iterative outputs. In the first example, the left half of the non-iterative output contains a region of highly-uniform, "rectangular" patches; the iterative output makes these patches less uniform. In the second example, the left half of the non-iterative output has a lot of colorful noise; the iterative output somewhat dims the noise.