Tilt Shift Effects

김성빈·2024년 5월 7일
0

Modern Computer Vision

목록 보기
32/117

두 개의 이미지를 섞어서 새로운 이미지를 생성하는 이미지 블렌딩 기술을 구현

이미지에 강조하고싶은 부분을 강조하기 위해 특정 위치를 제외한 나머지 부분을 블러 처리한다.




def main():
    """Given the two images, blend them according to the mask."""

    sourcefolder = 'images/original'
    outfolder = 'images/output'

    if os.path.isdir(outfolder):
        shutil.rmtree(outfolder)
    os.mkdir(outfolder)

    for photo, white_img, black_img, mask_img in get_images(sourcefolder):
        imshow("Original Image", black_img)
        print("...applying blending")
        black_img = black_img.astype(float)
        white_img = white_img.astype(float)
        mask_img = mask_img.astype(float) / 255

        out_layers = []
        for channel in range(3):
            outimg = run_blend(black_img[:, :, channel],
                               white_img[:, :, channel],
                               mask_img[:, :, channel])
            out_layers.append(outimg)

        outimg = cv2.merge(out_layers)
        cv2.imwrite(os.path.join(outfolder, photo), outimg)
        imshow("Tilt Shift Effect", outimg)
        print('...[DONE]')

if __name__ == "__main__":
    main()
def generating_kernel(parameter):
    """ 입력 파라미터를 기반으로 5x5 생성 커널을 반환한다.

참고: 이 기능은 사용자에게 제공되는 것이므로 변경하지 마십시오.

Args:
parameter(float): 값의 범위: [0, 1].

반환:
numpy.ndarray: 5x5 커널.

    """
    kernel = np.array([0.25 - parameter / 2.0, 0.25, parameter,
                       0.25, 0.25 - parameter / 2.0])
    return np.outer(kernel, kernel)


def reduce_img(image):
    """ 입력 영상을 0.4 파라미터의 생성 커널로 컨볼루션합니다
그리고 폭과 높이를 두 개 줄인다.

모든 기능을 사용하여 이미지를 변환하고 축소할 수 있지만
강의에는 많은 것들이 있기 때문에 우리가 조언하는 추천 방법들이 있다
'딱 알맞게' 일을 해야 하는 이 과제의 조각들.

Args:
image(numpy.ndarray): 형상(r, c)의 그레이스케일 이미지

반환:
출력(numpy.ndarray): 형상 이미지(ceil(r/2), ceil(c/2))
예를 들어, 입력이 5x7이면 출력은 3x4가 됩니다.

    """
    # per the instructions, use 0.4 for the kernel generation
    kernel = generating_kernel(0.4)

    # use convolve2d with the image and kernel sent in
    output = scipy.signal.convolve2d(image, kernel, 'same')

    # return every other line and row
    return output[:output.shape[0]:2, :output.shape[1]:2]


def expand(image):
    """이미지를 확장하여 크기를 두 배로 늘린 다음 a로 컨벌루션합니다
매개 변수가 0.4인 커널을 생성합니다.

이미지를 업샘플링한 다음 생성으로 변환해야 합니다
= 0.4의 커널.

마지막으로 출력 이미지에 4배를 곱하여 확장합니다
백업. 이렇게 하지 않으면(그리고 나는 당신이 그것을 사용하지 않고 사용해 보는 것을 추천합니다)
(that) 컨볼루션을 적용하면 이미지가 어두워지는 것을 볼 수 있습니다.
제출하신 PDF에서 왜 이런 일이 발생하는지 설명 부탁드립니다.

강의를 듣고 좀 더 깊이 있는 토론을 위해 저를 읽어주세요
확장 기능에 대처하는 방법.

모든 기능을 사용하여 이미지를 변환하고 축소할 수 있지만
강의에는 많은 것들이 있기 때문에 우리가 조언하는 추천 방법들이 있다
'딱 알맞게' 일을 해야 하는 이 과제의 조각들.

Args:
image(numpy.ndarray): 형상(r, c)의 그레이스케일 이미지

반환:
출력(numpy.ndarray): 모양의 이미지(2*r, 2*c)
    """
    # per the instructions, use 0.4 for the kernel generation
    kernel = generating_kernel(0.4)

    # make a new array double the size, assign initial values
    output = np.zeros((image.shape[0] * 2, image.shape[1] * 2))
    output[:output.shape[0]:2, :output.shape[1]:2] = image

    # use convolve2d to fill in rest
    # multiply by 4 per instructions to scale back up
    output = scipy.signal.convolve2d(output, kernel, 'same') * 4
    return output


def gauss_pyramid(image, levels):
    """ 이미지에서 피라미드의 수를 줄여 피라미드를 구성한다
입력에 의해 통과된 레벨입니다.

참고: 이 함수에서 축소 함수를 사용하여 다음 함수를 생성해야 합니다
산출량.

Args:
image(numpy.ndarray): 차원(r,c) 및 dtype의 그레이스케일 이미지
흘러가다.
levels (uint8): 다음의 수를 지정하는 양의 정수
줄여야 한다. 따라서 레벨 = 0이면 해야 한다
입력된 이미지만 포함된 목록을 반환합니다. 만약
레벨 = 1, 하나의 축소를 수행해야 합니다.
len(출력) = 레벨 + 1

반환:
출력(목록): dtype np.float의 배열 목록. 의 첫 번째 요소
목록(출력[0])은 피라미드의 레이어 0(이미지)입니다
그 자체). 출력[1]은 피라미드의 계층 1(이미지 축소)이다
일단) 등. 원본 이미지를 이미 포함했습니다
당신을 위한 출력 배열입니다. 배열은 numpy.ndarray 유형입니다.

    """
    output = [image]
    for level in range(levels):
        output.append(reduce_img(output[level]))

    return output


def lapl_pyramid(gauss_pyr):
    """ 높이의 가우스 피라미드로부터 라플라시안 피라미드를 구축한다
레벨.

참고: 이 함수에서 확장 함수를 사용하여 다음 함수를 생성해야 합니다
출력. 가우시안 피라미드는 당신의 출력입니다
gauss_pyramid 함수.

Args:
gauss_pyr (목록): 당신의 gauss_pyramid가 반환한 가우스 피라미드
function. numpy.ndarray 항목 목록입니다.

반환:
출력(목록) : gauss_pyr와 같은 크기의 라플라시안 피라미드. 이
피라미드는 guassPyr와 같은 방식으로 표현되어야 한다,
배열 목록으로 말이지 지금 목록의 모든 요소가
라플라시안 피라미드의 층에 해당하며, 다음을 포함한다
가우스 피라미드의 두 층 사이의 차이.

출력[k] = gauss_pyr[k] - expand(gauss_pyr[k + 1])

참고: 마지막 출력 요소는 마지막 출력 요소와 동일해야 합니다
더 이상 뺄 수 없기 때문에 입력 피라미드의 레이어입니다.

참고: 확장된 이미지의 크기가 확장된 이미지보다 클 수 있습니다
주어진 레이어. 확장된 이미지를 자르면 모양이 일치합니다
주어진 층.

예를 들어, 내 레이어의 크기가 5x7인 경우 축소 및 확장이 발생합니다
6x8 크기의 이미지에서 이 경우 확장된 레이어를 5x7로 자릅니다.
    """
    output = []
    # look over the lists, but ignore the last element since it cannot be
    # subtracted
    for image1, image2 in zip(gauss_pyr[:-1], gauss_pyr[1:]):
        # add in the subtracted difference
        # expand and bind the 2nd image based on the dimentions of the first
        output.append(
            image1 - expand(image2)[:image1.shape[0], :image1.shape[1]])

    # now add the last item back in
    output.append(gauss_pyr[-1])

    return output


def blend(lapl_pyr_white, lapl_pyr_black, gauss_pyr_mask):
    """ 라플라시안 피라미드 두 개를 각각 무게를 두어 섞어라
가우시안 마스크.

Args:
lapl_pyr_white (목록): 하나의 이미지로 구성된 라플라시안 피라미드
당신의 lapl_pyramid 함수에 의해서요.

lapl_pyr_black (목록) : 다른 이미지의 라플라시안 피라미드, 다음과 같이
당신의 lapl_pyramid 함수에 의해 구성됩니다.

gauss_pyr_mask(리스트): 마스크의 가우시안 피라미드. 각 값은 다음과 같습니다
[0, 1]의 범위.

피라미드는 같은 수의 층을 가질 것입니다. 게다가, 각각의 층은
이전 레벨과 동일한 모양을 보장합니다.

당신은 다음과 같은 차원의 라플라시안 피라미드를 반환해야 한다
입력 피라미드. 모든 레이어는 해당 레이어의 알파 블렌드여야 합니다
가우시안 마스크로 가중치를 부여한 입력 피라미드의 층. 이것은 다음을 의미한다
피라미드의 각 레이어에 대한 다음 계산:
output[i, j] = current_mask[i, j] * white_image[i, j] +
(1 - current_mask[i, j]) * black_image[i, j]
따라서:
current_mask == 1인 픽셀은 흰색에서 완전히 가져와야 합니다
이미지.
current_mask == 0인 픽셀은 완전히 검은색에서 가져와야 합니다
이미지.

참고: current_mask, white_image, black_image는 다음과 같은 변수입니다
우리가 지금 보고 있는 레이어의 이미지로. 네가 이렇게 해
피라미드의 모든 층에 대한 계산.
    """
    blended_pyr = []
    for lapl_white, lapl_black, gauss_mask in \
            zip(lapl_pyr_white, lapl_pyr_black, gauss_pyr_mask):
        blended_pyr.append(gauss_mask * lapl_white +
                           (1 - gauss_mask) * lapl_black)

    return blended_pyr


def collapse(pyramid):
    """입력 피라미드를 붕괴시킵니다.

Args:
pyramid (list): numpy.ndarray 이미지 목록입니다. 입력을 가정할 수 있습니다
블렌드 () 또는 lapl_pyramid().에서 가져온 것입니다.

반환:
출력(numpy.ndarray) : 의 기본 레이어와 동일한 모양의 이미지
피라미드와 d형이 떠다닌다.

다음과 같이 이 문제에 접근하고, 가장 작은 레이어에서 시작합니다
가장 작은 층을 확장하고 두 번째 층부터 가장 작은 층까지 추가합니다
layer. 그런 다음 두 번째 레이어에서 가장 작은 레이어로 확장하고 프로세스를 계속 진행합니다
가장 큰 이미지가 될 때까지. 이것이 당신의 결과입니다.

참고: 때때로 확장하면 다음 이미지보다 큰 이미지가 반환됩니다
layer. 이 경우 확장된 이미지를 다음 크기로 잘라야 합니다
다음 레이어. 눔피 슬라이싱을 조사해보세요./이 작업을 하려면 리드미를 읽어보세요
쉽게.

예를 들어, 3x4 크기의 레이어를 확장하면 크기의 이미지가 생성됩니다
6x8. 다음 레이어가 5x7 크기이면 확장된 이미지를 5x7 크기로 잘라냅니다.
    """
    output = pyramid[-1]
    for image in reversed(pyramid[:-1]):
        output = image + expand(output)[:image.shape[0], :image.shape[1]]
    return output


def run_blend(black_image, white_image, mask):
    """ 이 기능은 다음에 따라 두 이미지의 혼합을 관리합니다
가면을 쓰다.

모든 영상이 플로팅 타입이라고 가정하고, 플로팅 타입을 반환합니다.
    """

    # Automatically figure out the size
    min_size = min(black_image.shape)
    # at least 16x16 at the highest level.
    depth = int(math.floor(math.log(min_size, 2))) - 4

    gauss_pyr_mask = gauss_pyramid(mask, depth)
    gauss_pyr_black = gauss_pyramid(black_image, depth)
    gauss_pyr_white = gauss_pyramid(white_image, depth)

    lapl_pyr_black = lapl_pyramid(gauss_pyr_black)
    lapl_pyr_white = lapl_pyramid(gauss_pyr_white)

    outpyr = blend(lapl_pyr_white, lapl_pyr_black, gauss_pyr_mask)
    outimg = collapse(outpyr)

    # blending sometimes results in slightly out of bound numbers.
    outimg[outimg < 0] = 0
    outimg[outimg > 255] = 255
    outimg = outimg.astype(np.uint8)

    return outimg


def get_images(sourcefolder):
    """Rewritten function to collect the three images from three folders."""
    filenames = os.listdir(sourcefolder)
    for photo in filenames:
        black_img = cv2.imread('images/original/' + photo)
        white_img = cv2.imread('images/blur/' + photo)
        mask_img = cv2.imread('images/mask/' + photo)

        if mask_img is None:
            print('Oops! There is no mask of image: ', photo)
            continue
        if white_img is None:
            print('Oops! There is no blurred version of image: ', photo)
            continue

        assert black_img.shape == white_img.shape, \
            "Error - the sizes of orignal and blur are not equal"

        assert black_img.shape == mask_img.shape, \
            "Error - the sizes of the original and the mask are not equal"

        print(photo)
        yield photo, white_img, black_img, mask_img
profile
감사합니다. https://www.youtube.com/channel/UCxlkiu9_aWijoD7BannNM7w

0개의 댓글