5.7. 이미지 합성

이전 페이지의 그리기 프리미티브는 이미지 위에 기하학적 표시 – 선, 사각형, 텍스트 한 조각 – 를 그립니다. 이는 알고리즘이 시각화해야 하는 대부분의 주석을 다루지만, 전부는 아닙니다. 때로는 주석 자체가 이미지인 경우가 있습니다. 현재 프레임과 나란히 표시할 캡처된 참조 프레임, 미리보기 한 구석에 보여주는 이전 캡처의 썸네일, 보정을 위해 라이브 프레임 위에 시각화한 이전에 저장된 템플릿 등이 그렇습니다. 한 이미지를 다른 이미지 위에 그리는 메커니즘은 단일 메서드 – draw_image() – 이며, 실제 합성에 필요한 위치, 크기 조정, 색상 팔레트, 투명도를 처리할 수 있는 충분한 매개변수를 갖추고 있습니다.

5.7.1. 기본 호출

가장 단순한 형태에서 draw_image는 다른 Image와 그것을 그릴 위치를 받습니다:

reference = image.Image("/sdcard/reference.bmp")
img.draw_image(reference, x=10, y=10)

대상은 img이고 소스는 reference입니다. 소스의 좌상단 픽셀은 img(10, 10) 위치에 놓이며, 소스의 나머지 픽셀은 거기서부터 오른쪽과 아래쪽으로 이어집니다. 소스가 덮는 대상의 픽셀은 소스의 해당 픽셀로 덮어쓰여지고, 소스의 영역 밖에 있는 픽셀은 그대로 남습니다.

소스가 대상의 가장자리를 넘어가면 벗어난 부분은 조용히 잘립니다 – set_pixel이 범위를 벗어난 위치에 대해 보여주는 것과 같은 관대한 동작입니다. 애플리케이션 코드는 미리 위치를 이미지 크기에 맞춰 제한할 필요가 없으며, 원하는 위치를 전달하고 메서드가 클리핑을 처리하도록 맡기면 됩니다.

5.7.2. 파일을 인라인으로 로드하기

draw_imageImage 인자 대신 파일 경로를 받아들이고, 합성하기 전에 그 파일을 로드합니다:

img.draw_image("/sdcard/reference.bmp", x=10, y=10)

이는 편의 기능처럼 보이며 – 두 줄 대신 한 줄 – 실제로 그렇긴 하지만, 그 차이는 단순한 문법 이상입니다. 파일로부터 Image를 생성하면 디코딩된 픽셀을 담을 버퍼가 할당되고, 그 버퍼는 가비지 컬렉션이 해제할 때까지 유지됩니다. 경로를 draw_image에 직접 전달하면 모듈이 파일을 스크래치 버퍼로 디코딩하고, 거기서 합성한 다음, 호출이 반환될 때 버퍼를 해제할 수 있으므로, 애플리케이션 코드가 프레임 사이에 별도의 Image 참조를 유지할 필요가 없습니다.

5.7.3. 크기 조정

소스와 대상의 크기가 다를 때 – 저해상도 캡처를 고해상도 캔버스 위에 합성하거나, 프레임의 특정 비율 크기로 맞춰야 하는 썸네일 – 두 개의 스케일 매개변수가 그려지는 동안 소스의 크기 조정을 처리합니다:

img.draw_image(reference, x=10, y=10, x_scale=2.0, y_scale=2.0)

x_scaley_scale은 독립적인 float 값입니다. 둘 다 같은 값으로 전달하면 균일하게 크기가 조정되고, 다른 값으로 전달하면 한 축을 따라 소스를 늘리거나 줄입니다. 크기 조정은 그리는 시점에 일어나며, 소스 reference는 수정되지 않습니다.

힌트 플래그의 비트마스크가 크기 조정 시 픽셀 사이를 실제로 어떻게 보간할지 결정합니다. image.BILINEAR은 더 많은 연산을 대가로 더 매끄러운 결과를 만들고, image.BICUBIC은 더욱 매끄러운 결과를 만들지만 비용이 또 더 들며, 기본값은 최근접 이웃(nearest-neighbour)을 사용하는데 이는 가장 저렴하며 소스가 이미 대상의 픽셀 해상도에 있을 때 올바른 선택입니다. 종횡비 처리 플래그 – SCALE_ASPECT_KEEP, SCALE_ASPECT_EXPAND, SCALE_ASPECT_IGNORE – 는 소스의 종횡비가 그려지는 사각형과 맞지 않을 때 어떻게 할지 결정합니다.

5.7.4. 알파 블렌딩

기본적으로 draw_image는 대상 픽셀을 소스 픽셀로 대체합니다. 목표가 반투명 오버레이 – 그래서 대상이 소스를 통해 비쳐 보이는 것 – 일 때는 alpha 매개변수가 둘이 어떻게 섞일지 제어합니다. alpha=0은 대상만 보여주고(소스 없음), alpha=255는 기본값으로 소스만 보여주며(완전 대체), 중간 값은 둘을 비례하여 섞습니다:

img.draw_image(overlay, x=0, y=0, alpha=128)

별도의 alpha_palette 인자는 모듈의 유일한 픽셀별 알파 메커니즘입니다. 이는 GRAYSCALE 이미지를 받아 그 값들을 소스의 일치하는 위치에서 알파로 사용합니다 – 예를 들어 강도에 따라 알파가 달라지는 히트맵이 그렇습니다. 알파는 그 별도의 그레이스케일 인자로 제공되어야 합니다. 자체 알파 채널을 가진 소스 이미지(예: 투명도가 있는 PNG)는 그것을 자동으로 가져오지 않습니다.

5.7.5. 소스 ROI와 팔레트

두 개의 추가 매개변수가 합성 메커니즘을 완성합니다:

  • roi=(x, y, w, h)는 소스를 그 자신의 하위 사각형으로 제한하므로, 그 사각형만 대상 위에 합성됩니다. 잘라낸 중간 결과를 준비하지 않고도 같은 호출 안에서 크롭할 때 유용합니다.

  • color_palette는 그리기 전에 룩업 테이블을 통해 각 소스 픽셀의 값을 치환합니다 – to_rainbow()to_ironbow()가 사용하는 것과 동일한 메커니즘으로, 여기에 노출되어 별도의 변환 과정 없이 오버레이가 대상 위로 올라가는 과정에서 팔레트화될 수 있습니다.

둘 다 호출의 다른 모든 것과 함께 합성됩니다: 크기 조정, 알파, 대상 측 mask 인자, 그리고 쓰기를 대상의 한 사각형으로 범위를 지정하는 대상 측 roi 매개변수와 함께 말입니다.