https://www.youtube.com/watch?v=rMHGSoXj4bw
BlinkScript를 사용하여 이미지 처리를 설정하고 접근하는 기본적인 방법에 대해 설명하는 내용입니다. 핵심 단계는 아래와 같습니다:
1. 이미지 접근 방식 설정
BlinkScript에서는 기본적으로 access_point 방식을 사용하여 픽셀 하나씩 접근하며 처리합니다. 하지만, 다양한 접근 방식이 필요할 수 있으며, 주요한 접근 방식은 다음과 같습니다:
- access_point: 현재 픽셀만 접근
- access_ranged: X 또는 Y 축에서 하나의 차원을 접근
- access_2D: 중심 픽셀에서부터 2D로 접근
- access_random: 특정 좌표의 픽셀에 직접 접근
이번 예제에서는 access_ranged 2D를 사용하여 중심 픽셀로부터 2D 범위를 처리합니다.
2. 초기화 및 범위 설정
access_ranged 2D를 사용할 때는 스크립트가 필요한 범위를 미리 설정해야 합니다. 이를 위해 init 섹션에서 source.setRange를 사용하여 접근할 범위를 정의합니다.
source.setRange(-defocus_size, -defocus_size, defocus_size, defocus_size);
- 여기서 defocus_size는 블러 정도를 조절하는 변수입니다.
3. 파라미터 생성
defocus_size라는 파라미터를 생성하여 블러의 크기를 조절할 수 있도록 설정합니다. 이 변수는 int형으로 선언되며 기본값으로 1을 지정합니다.
int defocus_size;
- 이후 define 섹션에서 defocus_size를 사용자 인터페이스에 추가하여 조절할 수 있게 만듭니다.
4. 좌표 설정
access_ranged를 사용할 때는 읽어올 픽셀의 좌표를 지정해주어야 합니다. 예를 들어, source.read(0, 0)는 중심 픽셀을 읽어옵니다.
5. 파라미터를 사용한 테스트
defocus_size의 값을 변경하면서 이미지가 블러링 되는 효과를 확인할 수 있습니다.
결과
- 이렇게 설정된 BlinkScript는 defocus_size 값을 조정하면서 중심 픽셀로부터 블러가 퍼져나가는 효과를 구현합니다.
1. Defocus 구현을 위한 준비
Defocus 효과를 BlinkScript에서 구현하기 전에, Nuke의 기본 노드를 통해 개념을 이해할 수 있습니다. Defocus는 이미지의 블러링을 위해 **컨볼루션(convolution)**이라는 기법을 사용하여 수행됩니다. 이를 위해 아래와 같은 절차를 따릅니다:
- Radial 노드 생성: 컨볼루션 필터로 사용할 Radial 이미지를 생성합니다. 이는 Defocus의 기본 형태가 됩니다.
- Reformat 노드 설정: Radial의 크기를 적절히 조정하기 위해 Reformat 노드를 추가하여 설정합니다.
- Convolve 노드 사용: Radial 이미지를 필터로 삼아 Convolve 노드를 사용하여 Defocus 효과를 적용합니다.
2. BlinkScript에서 Radial 생성
BlinkScript에서 Defocus 효과를 구현하기 위해 Radial 형태의 가상 원을 설정합니다. 이 가상 원은 중심 픽셀에서 바깥쪽으로 퍼지며, 주변 픽셀의 값을 평균하여 블러 효과를 만듭니다.
3. 컨볼루션 수행
각 픽셀에 대해, 중심 픽셀을 기준으로 Radial 영역 내의 모든 픽셀 값을 합산하고, 이를 해당 픽셀 수로 나눠서 평균을 구합니다. 이러한 방식으로 주변 픽셀의 색상을 평균 내어 흐릿한 효과를 냅니다.
- 중심 픽셀 기준: 중심 픽셀을 기준으로 Radial 범위 내의 모든 유효한 픽셀(검정색이 아닌 픽셀)을 합산합니다.
- 평균 계산: 합산된 값을 픽셀 수로 나누어 평균을 계산하고, 이 값을 중심 픽셀에 할당합니다.
4. 외곽 픽셀 처리
블러 효과로 인해 이미지 경계가 손상되지 않도록 추가적인 검은색 픽셀 레이어를 추가하여 테두리에서 발생할 수 있는 'smearing(번짐)' 효과를 방지합니다.
요약
Defocus를 적용하기 위해 Radial 형태의 가상 원을 사용하여 중심 픽셀 주변의 모든 픽셀을 합산하고, 평균값을 중심 픽셀에 할당하는 방식으로 구현됩니다. 이 과정은 Nuke의 기본 노드 및 BlinkScript에서 동일한 논리로 수행됩니다.
원형 형태의 Defocus 필터를 코드로 정의하는 방법에 대해 설명하고 있습니다. BlinkScript를 사용하기 전에 Nuke의 Expression 노드를 활용해 간단한 원형을 구현하는 과정입니다. 다음은 주요 단계입니다.
Expression 노드를 사용해 반지름(Radius) 정의하기
- 반지름 변수 설정: radius 변수를 만들고 반지름 값(예: 50)을 할당합니다. 이 변수는 원형의 크기를 조절하는 데 사용됩니다.
- Expression을 이용한 좌표 설정: X와 Y 좌표를 사용하여 이미지에서 각 픽셀의 위치를 정의합니다.
원 방정식 정의
원의 방정식을 사용하여 픽셀이 원의 내부에 있는지를 판별합니다.
- 좌표의 제곱 계산: pow(X, 2)와 pow(Y, 2)를 사용하여 각각 X와 Y 좌표의 제곱을 구합니다. BlinkScript와 호환을 위해 `` 대신 pow 함수를 사용합니다.
- 합산 및 비교: pow(X, 2) + pow(Y, 2) 값을 계산한 후 반지름과 비교하여 픽셀이 원 내부에 있는지 여부를 판별합니다.
- 결과를 이진 값으로 반환: 원 내부에 있으면 1, 외부에 있으면 0을 반환하여 결과를 표시합니다.
정확한 반지름 구현
현재 원의 크기는 지정한 반지름과 일치하지 않으므로 반지름을 정확히 반영하도록 추가 조정이 필요합니다.
- 제곱근 계산: sqrt(pow(X, 2) + pow(Y, 2)) 또는 pow((pow(X, 2) + pow(Y, 2)), 0.5)로 표현하여 원하는 반지름 값을 얻습니다.
- 결과 확인: 원의 반지름 값을 변경하면 그에 따라 원의 크기도 조정됩니다.
필요한 경우 중심 오프셋 추가
원의 중심을 원하는 위치로 조정할 수 있도록, center라는 2D 위치 조정 노브를 추가하고 X와 Y 좌표에서 center 값을 빼는 방식으로 조정할 수 있습니다.
요약
이 방식으로 X와 Y 좌표를 사용하여 코드로 원형 형태를 구현하고, 원하는 반지름을 설정할 수 있습니다. 이렇게 정의된 원형 필터는 Defocus 필터 구현 시 사용할 수 있습니다.
Defocus 필터를 구현하는 BlinkScript의 다음 단계는 각 픽셀에 필터를 적용하기 위해 반복문을 설정하는 것입니다. 아래는 그 과정을 단계별로 설명합니다.
1. 반복문(Loop) 설정
- Y 좌표부터 시작: BlinkScript는 Y 좌표를 먼저 순회하는 것이 더 효율적이므로, Y를 먼저 설정합니다.
- Y 반복문 초기화:여기서 defocusSize부터 +defocusSize까지 반복하며, <= 연산자를 사용하여 마지막 픽셀도 포함합니다.
- for (int Y = -defocusSize; Y <= defocusSize; Y++) { // Y 방향으로 반복 }
- X 반복문 추가: Y 반복문 안에 X 좌표를 위한 또 다른 반복문을 만듭니다.이중 반복문을 통해 X, Y 좌표를 모두 탐색하며, 각각의 픽셀에 필터를 적용합니다.
- for (int X = -defocusSize; X <= defocusSize; X++) { // X 방향으로 반복 }
2. 필터가 적용될 픽셀 결정
- 픽셀 범위 제한: Defocus 필터는 원형 형태의 범위에서만 적용되어야 합니다. 그렇지 않으면 사각형 형태의 Defocus가 생깁니다.
- 원형 필터를 구현하기 위해 X와 Y의 제곱을 합산하여 반지름을 초과하지 않는 픽셀만 포함합니다.이 조건을 사용하여 원 안에 있는 픽셀만 포함하여 Defocus를 적용할 수 있습니다.
- if (pow(X, 2) + pow(Y, 2) <= pow(defocusSize, 2)) { // 해당 픽셀만 작업 수행 }
3. 코드 정렬
- BlinkScript는 Python처럼 들여쓰기가 필수적이지는 않지만, 코드 가독성을 위해 들여쓰기를 통해 구조를 명확히 하는 것이 좋습니다.
- 각 반복문과 조건문에 대해 중괄호({})를 사용하여 코드 블록을 정의합니다.
코드 요약
이제 다음과 같은 코드 구조가 만들어졌습니다:
for (int Y = -defocusSize; Y <= defocusSize; Y++) {
for (int X = -defocusSize; X <= defocusSize; X++) {
if (pow(X, 2) + pow(Y, 2) <= pow(defocusSize, 2)) {
// 원 범위 내 픽셀에 대해서만 Defocus 처리
}
}
}
이 코드를 통해 각 픽셀에 대한 Defocus 처리를 반복적으로 적용하며, 사각형이 아닌 원형 필터 형태로 구현할 수 있습니다.
BlinkScript에서 원형 필터를 구현하기 위해 특정 픽셀 범위 내에서만 효과를 적용하도록 if 조건문을 사용하고, 그 결과를 float4 변수에 할당하여 RGB와 Alpha 값을 관리할 수 있습니다. 여기서는 해당 픽셀을 루프하면서 조건에 맞는 경우에만 output에 값을 추가하는 방법을 단계별로 설명합니다.
1. if 조건문으로 원 정의하기
- 우선 원의 반지름 조건을 설정합니다. BlinkScript에서는 반지름을 나타내는 변수를 defocusSize로 설정할 수 있습니다.
- 각 픽셀 좌표 X와 Y의 제곱을 더하고 반지름 제곱과 비교하여 원 범위 내에 있는지를 확인합니다.
if (defocusSize - sqrt(pow(X, 2) + pow(Y, 2)) > 0) {
// 조건을 만족하는 경우 실행될 코드
}
이 조건문은 반복문이 픽셀을 순회할 때마다 해당 픽셀이 원의 반지름 내에 있는지 확인합니다.
2. float4 변수로 출력 설정하기
- BlinkScript에서는 RGBA 값을 다루기 위해 float4 변수를 사용합니다. 이를 통해 각 색상과 알파 값을 제어할 수 있습니다.
- output이라는 float4 변수를 생성하고, 기본값으로 초기화합니다.
float4 output = float4(0, 0, 0, 0); // 초기 값 설정
- 이후에 output 변수에 색상 값을 누적할 수 있도록 설정합니다.
3. 루프 내에서 output 값 누적하기
- 조건문 내에서 output 값을 source 픽셀 값과 더해 누적합니다. 이때 source는 현재 픽셀의 RGB 값을 나타내는 함수입니다.
output += source(X, Y);
여기서 output 값이 원 내부의 픽셀 RGB 값을 누적하는 방식으로 설정됩니다.
4. output을 최종 픽셀 값으로 설정
- 모든 연산이 끝난 후, output 값을 현재 픽셀에 할당하여 최종 필터링된 값을 출력합니다.
dst() = output;
코드 전체
for (int Y = -defocusSize; Y <= defocusSize; Y++) {
for (int X = -defocusSize; X <= defocusSize; X++) {
if (defocusSize - sqrt(pow(X, 2) + pow(Y, 2)) > 0) {
float4 output = float4(0, 0, 0, 0);
output += source(X, Y);
dst() = output;
}
}
}
이 코드를 통해 BlinkScript에서 원형 영역 내에서만 Defocus 필터가 적용되도록 할 수 있습니다.
이미지의 밝기를 유지하려면 누적된 output 값을 정규화해야 합니다. 현재 output에 픽셀 값을 계속 더하는 과정에서 밝기가 증가하고 있으므로, 이 값을 픽셀 수로 나누어 평균값을 구하는 방법을 사용하여 이미지의 밝기를 유지할 수 있습니다.
정규화 과정
- 정규화 변수 추가:output 값에 더해지는 픽셀의 개수를 추적하는 normalizer 변수를 생성하여, 루프가 끝난 후 총 픽셀 수로 output 값을 나눌 수 있도록 합니다.
- float4 output = float4(0, 0, 0, 0); int normalizer = 0;
- 정규화 카운트 증가:각 픽셀을 output에 추가할 때마다 normalizer를 증가시킵니다. 조건문이 만족될 때마다 1씩 추가되도록 설정합니다.
- if (defocusSize - sqrt(pow(X, 2) + pow(Y, 2)) > 0) { output += source(X, Y); normalizer += 1; }
- 정규화 적용:모든 루프가 완료된 후 output을 normalizer로 나눠 평균을 계산합니다. 이 단계가 output을 밝기 변화 없이 부드러운 디포커스 효과로 유지합니다.
- if (normalizer > 0) { output /= normalizer; // output을 평균으로 나눔 } dst() = output;
전체 코드 예시
float4 output = float4(0, 0, 0, 0);
int normalizer = 0;
for (int Y = -defocusSize; Y <= defocusSize; Y++) {
for (int X = -defocusSize; X <= defocusSize; X++) {
if (defocusSize - sqrt(pow(X, 2) + pow(Y, 2)) > 0) {
output += source(X, Y);
normalizer += 1;
}
}
}
if (normalizer > 0) {
output /= normalizer;
}
dst() = output;
이제 이 코드로 defocusSize가 변경되더라도 평균 밝기가 유지된 채 부드러운 디포커스 필터가 적용됩니다.
매트 입력으로 샷에 깊이 추가하기
매트 이미지를 사용하여 샷에 깊이를 추가하는 방법은 각 픽셀에 대해 다른 블러 강도를 적용하여 깊이 효과를 조절하는 방식입니다. 이 방법을 통해 매트의 값에 따라 화면의 특정 영역에만 디포커스를 적용할 수 있습니다.
매트 입력을 사용하여 깊이 추가하는 방법
- 커널을 디포커스 커널로 승격:먼저 BlinkScript를 간단한 디포커스 커널로 승격시킵니다. 이렇게 하면 디포커스 관련 기능을 사용할 수 있지만, 현재는 간단한 방식으로 진행합니다.
- kenel defocusKernel { input float defocusSize; input float defocusMatte; output float4 output; }
- 매트 입력 추가:매트 입력을 추가하여 각 픽셀이 디포커스 강도를 제어하도록 합니다. 매트 이미지의 알파 채널(.w)을 사용해 디포커스를 적용할 양을 제어합니다.
- input float defocusMatte; // 매트 입력
- 커널에서 매트 처리:이제 매트 입력을 사용해 디포커스 크기를 동적으로 조절합니다. 매트 값에 따라 블러 강도를 변경할 수 있도록 합니다.
- defocusSize = defocusSize * defocusMatte.w;
- 디포커스 크기 조정:매트 값에 defocusSize를 곱하여 블러 강도를 조정합니다. 매트 값이 0이면 블러가 없고, 매트 값이 1이면 전체 블러가 적용됩니다. 또한, 매트 값이 0일 때 발생할 수 있는 오류(예: "NaN")를 방지하기 위해 이를 처리해야 합니다.
- int scaledDefocusSize = defocusSize * defocusMatte.w;
- if 문을 사용해 예외 처리:매트 값이 0보다 클 때만 디포커스를 적용하도록 if 문을 추가합니다. 매트 값이 0이면 해당 픽셀은 변경되지 않습니다.
- if (scaledDefocusSize > 0) { // 디포커스 처리 코드 } else { output = source; // 디포커스를 적용하지 않음 }
전체 과정 요약
- 매트 이미지: 매트 이미지는 각 픽셀마다 디포커스를 얼마나 적용할지 결정합니다. 이 이미지의 알파 채널이 디포커스 크기를 조정하는 데 사용됩니다.
- 디포커스 크기 조정: 매트의 값을 기반으로 디포커스 크기를 동적으로 조절하여 깊이감을 더할 수 있습니다.
- 조건 처리: 매트 값에 따라 디포커스 효과를 적용하거나 원본 값을 그대로 출력할 수 있도록 처리합니다.
이러한 방법을 통해 이미지의 특정 영역에만 디포커스를 적용하고, 이를 통해 장면에 깊이를 추가할 수 있습니다.
'Nuke > Blink Script' 카테고리의 다른 글
blink kernels (4) (0) | 2024.12.08 |
---|---|
blink kernels (3) (0) | 2024.12.08 |
blink kernels (2) (0) | 2024.12.08 |
blink kernels (1) (0) | 2024.12.08 |
Blink Script (1) (0) | 2024.12.08 |