スタンフォード/CS131/宿題4-4 画像の拡大・縮小

前回のStanford University/CS131/宿題4-3 画像拡大の続きをやる。今回の宿題は、Other experiments on the image(同じ画像によるさまざまな実験的試み)、Reducing and enlarging on another image(別の画像を使用した画像の縮小・拡大)をカバーする。

スポンサーリンク

Other experiments on the image

Feel free to experiment more on this image, try different sizes to enlarge or reduce, or check what seams are chosen…
この画像を使って、さまざまなサイズに画像を拡大・縮小したり、あるいは、どのシームが選択されたかをチェックしてみたりと、色々と自由に実験してみよう。

Reducing by a 2x factor often leads to weird patterns.
Enlarging by more than 2x is impossible since we only duplicate seams. One solution is to enlarge in mutliple steps (enlarge x1.4, enlarge again x1.4…)
2倍率での画像縮小は変なパターンを生成しやすい。2倍以上の画像の拡大については、ただ単にシームを複製しているだけなので不可能だ。1つの解決方法が、複数ステップ(x1.4拡大した後で再びx1.4拡大する)を使って画像を拡大することだ。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import rc
from skimage import color,io, util
from time import time
from IPython.display import HTML
from __future__ import print_function
from seam_carving import compute_cost,energy_function,enlarge
from seam_carving import backtrack_seam,reduce,remove_seam

%matplotlib inline
plt.rcParams['figure.figsize'] = (15.0, 12.0) # set default size of plots
plt.rcParams["font.size"] = "17"
plt.rcParams['image.interpolation'] = 'nearest'
plt.rcParams['image.cmap'] = 'gray'
img = io.imread('imgs/broadway_tower.jpg')
img = util.img_as_float(img)
# Reduce image width
H, W, _ = img.shape
W_new = 200

start = time()
out = reduce(img, W_new)
end = time()

print("Reducing width from %d to %d: %f seconds." % (W, W_new, end - start))

plt.subplot(2, 1, 1)
plt.title('Original')
plt.imshow(img)

plt.subplot(2, 1, 2)
plt.title('Resized')
plt.imshow(out)
plt.show()
Reducing width from 640 to 200: 22.203419 seconds.

Faster reduce

Implement a faster version of reduce called reduce_fast in the file seam_carving.py.
seam_carving.pyreduce高速版reduce_fastを実装する。

def reduce_fast(image, size, axis=1, efunc=energy_function, cfunc=compute_cost):
    """Reduces the size of the image using the seam carving process. Faster than `reduce`.
    Use your own implementation (you can use auxiliary functions if it helps like `energy_fast`)
    to implement a faster version of `reduce`.
    Hint: do we really need to compute the whole cost map again at each iteration?
    Args:
        image: numpy array of shape (H, W, C)
        size: size to reduce height or width to (depending on axis)
        axis: reduce in width (axis=1) or height (axis=0)
        efunc: energy function to use
        cfunc: cost function to use
    Returns:
        out: numpy array of shape (size, W, C) if axis=0, or (H, size, C) if axis=1
    """
    out = np.copy(image)
    if axis == 0:
        out = np.transpose(out, (1, 0, 2))
    H = out.shape[0]
    W = out.shape[1]
    assert W > size, "Size must be smaller than %d" % W
    assert size > 0, "Size must be greater than zero"
    ### YOUR CODE HERE
    energy = efunc(out)
    for i in range(W-size):
        cost,path = cfunc(out,energy)
        seam = backtrack_seam(path,np.argmin(cost[-1]))
        out = remove_seam(out,seam)
        i = np.min(seam)
        j = np.max(seam) 
        if i <= 3:
            energy = np.c_[efunc(out[:,0:j+2])[:,:-1],\
                           energy[:,j+2:]]
        elif j >= i-3:
            energy = np.c_[energy[:,0:i-1],\
                           efunc(out[:,i-3:])[:,2:]]
        else:
            energy = np.c_[energy[:,0:i-1], \
             efunc(out[:,i-3:j+2])[:,2:-1],energy[:,j+2:]]
    ### END YOUR CODE
    assert out.shape[1] == size, "Output doesn't have the right shape"
    if axis == 0:
        out = np.transpose(out, (1, 0, 2))
    return out
# Reduce image width
H, W, _ = img.shape
W_new = 400

start = time()
out = reduce(img, W_new)
end = time()

print("Normal reduce width from %d to %d: %f seconds." % (W, W_new, end - start))

start = time()
out_fast = reduce_fast(img, W_new)
end = time()

print("Faster reduce width from %d to %d: %f seconds." % (W, W_new, end - start))

assert np.allclose(out, out_fast), "Outputs don't match."

plt.subplot(3, 3, 1)
plt.title('Original')
plt.imshow(img)

plt.subplot(3, 3, 2)
plt.title('Resized')
plt.imshow(out)

plt.subplot(3, 3, 3)
plt.title('Faster resized')
plt.imshow(out)
plt.show()
Normal reduce width from 640 to 400: 12.342480 seconds.
Faster reduce width from 640 to 400: 11.610037 seconds.

Reducing and enlarging on another image

Also check these outputs with another image.
別の画像を使ってこれらの出力のチェックもしておく。

# Load image
img2 = io.imread('imgs/wave.jpg')
img2 = util.img_as_float(img2)

plt.title('Original Image')
plt.imshow(img2)
plt.show()
out = reduce(img2, 300)
plt.imshow(out)
plt.show()
out = enlarge(img2, 800)
plt.imshow(out)
plt.show()