요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. SPDX-License-Identifier: GPL-2.0
Cropping and Scaling algorithm, used in the sh_mobile_ceu_camera driver
=======================================================================
Author: Guennadi Liakhovetski <[email protected]>
Terminology
-----------
sensor scales: horizontal and vertical scales, configured by the sensor driver
host scales: -"- host driver
combined scales: sensor_scale * host_scale
Generic scaling / cropping scheme
---------------------------------
.. code-block:: none
-1--
|
-2-- -\
| --\
| --\
+-5-- . -- -3-- -\
| `... -\
| `... -4-- . - -7..
| `.
| `. .6--
|
| . .6'-
| .´
| ... -4'- .´
| ...´ - -7'.
+-5'- .´ -/
| -- -3'- -/
| --/
| --/
-2'- -/
|
|
-1'-
In the above chart minuses and slashes represent "real" data amounts, points and
accents represent "useful" data, basically, CEU scaled and cropped output,
mapped back onto the client's source plane.
Such a configuration can be produced by user requests:
S_CROP(left / top = (5) - (1), width / height = (5') - (5))
S_FMT(width / height = (6') - (6))
Here:
(1) to (1') - whole max width or height
(1) to (2) - sensor cropped left or top
(2) to (2') - sensor cropped width or height
(3) to (3') - sensor scale
(3) to (4) - CEU cropped left or top
(4) to (4') - CEU cropped width or height
(5) to (5') - reverse sensor scale applied to CEU cropped width or height
(2) to (5) - reverse sensor scale applied to CEU cropped left or top
(6) to (6') - CEU scale - user window
S_FMT
-----
Do not touch input rectangle - it is already optimal.
1. Calculate current sensor scales:
scale_s = ((2') - (2)) / ((3') - (3))
2. Calculate "effective" input crop (sensor subwindow) - CEU crop scaled back at
current sensor scales onto input window - this is user S_CROP:
width_u = (5') - (5) = ((4') - (4)) * scale_s
3. Calculate new combined scales from "effective" input window to requested user
window:
scale_comb = width_u / ((6') - (6))
4. Calculate sensor output window by applying combined scales to real input
window:
width_s_out = ((7') - (7)) = ((2') - (2)) / scale_comb
5. Apply iterative sensor S_FMT for sensor output window.
subdev->video_ops->s_fmt(.width = width_s_out)
6. Retrieve sensor output window (g_fmt)
7. Calculate new sensor scales:
scale_s_new = ((3')_new - (3)_new) / ((2') - (2))
8. Calculate new CEU crop - apply sensor scales to previously calculated
"effective" crop:
width_ceu = (4')_new - (4)_new = width_u / scale_s_new
left_ceu = (4)_new - (3)_new = ((5) - (2)) / scale_s_new
9. Use CEU cropping to crop to the new window:
ceu_crop(.width = width_ceu, .left = left_ceu)
10. Use CEU scaling to scale to the requested user window:
scale_ceu = width_ceu / width
S_CROP
------
The :ref:`V4L2 crop API <crop-scale>` says:
"...specification does not define an origin or units. However by convention
drivers should horizontally count unscaled samples relative to 0H."
We choose to follow the advise and interpret cropping units as client input
pixels.
Cropping is performed in the following 6 steps:
1. Request exactly user rectangle from the sensor.
2. If smaller - iterate until a larger one is obtained. Result: sensor cropped
to 2 : 2', target crop 5 : 5', current output format 6' - 6.
3. In the previous step the sensor has tried to preserve its output frame as
good as possible, but it could have changed. Retrieve it again.
4. Sensor scaled to 3 : 3'. Sensor's scale is (2' - 2) / (3' - 3). Calculate
intermediate window: 4' - 4 = (5' - 5) * (3' - 3) / (2' - 2)
5. Calculate and apply host scale = (6' - 6) / (4' - 4)
6. Calculate and apply host crop: 6 - 7 = (5 - 2) * (6' - 6) / (5' - 5)
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
문서 범위와 용어
1-14이 `GPL-2.0` 문서는 Guennadi Liakhovetski가 작성했으며, `sh_mobile_ceu_camera` driver에서 사용하는 cropping 및 scaling 알고리즘을 설명합니다.
`sensor scales`는 sensor driver가 설정한 수평·수직 배율이고, `host scales`는 host driver가 설정한 수평·수직 배율입니다. `combined scales`는 두 단계를 연속 적용한 전체 배율이며 `sensor_scale * host_scale`로 계산합니다.
.. SPDX-License-Identifier: GPL-2.0
Cropping and Scaling algorithm, used in the sh_mobile_ceu_camera driver
=======================================================================
Author: Guennadi Liakhovetski <[email protected]>
Terminology
-----------
sensor scales: horizontal and vertical scales, configured by the sensor driver
host scales: -"- host driver
combined scales: sensor_scale * host_scale
일반적인 scaling·cropping 좌표 체계
15-65원문의 ASCII 그림에서 빼기표와 사선은 실제 데이터의 양을 나타내고, 점과 악센트는 유효한 데이터의 양을 나타냅니다. 유효 데이터는 기본적으로 CEU가 scaling하고 cropping한 출력을 client의 source plane에 역으로 사상한 영역입니다.
사용자는 `S_CROP(left / top = (5) - (1), width / height = (5') - (5))`로 source plane의 crop rectangle을 요청하고, `S_FMT(width / height = (6') - (6))`로 최종 user window의 크기를 요청합니다.
좌표 `(1)`부터 `(1')`까지는 전체 최대 width 또는 height입니다. `(1)`부터 `(2)`까지는 sensor가 잘라낸 left 또는 top이고, `(2)`부터 `(2')`까지는 sensor crop의 width 또는 height입니다. 이 실제 입력 영역은 sensor scaling을 거쳐 `(3)`부터 `(3')`까지가 됩니다.
Sensor 출력에서 `(3)`부터 `(4)`까지는 CEU가 잘라낸 left 또는 top이고, `(4)`부터 `(4')`까지는 CEU crop의 width 또는 height입니다. 이를 sensor 배율의 역으로 source plane에 사상하면 `(2)`부터 `(5)`까지가 CEU crop offset, `(5)`부터 `(5')`까지가 CEU crop 크기에 대응합니다.
마지막으로 `(6)`부터 `(6')`까지는 CEU scaling 뒤 사용자가 받는 window입니다. 그림의 `(7)`과 `(7')`은 새 combined scale을 실제 sensor 입력 window에 적용해 얻는 sensor output window의 경계입니다.
ASCII 도식을 같은 의미의 처리 단계와 좌표 구간으로 재구성했습니다.
Generic scaling / cropping scheme
---------------------------------
.. code-block:: none
-1--
|
-2-- -\
| --\
| --\
+-5-- . -- -3-- -\
| `... -\
| `... -4-- . - -7..
| `.
| `. .6--
|
| . .6'-
| .´
| ... -4'- .´
| ...´ - -7'.
+-5'- .´ -/
| -- -3'- -/
| --/
| --/
-2'- -/
|
|
-1'-
In the above chart minuses and slashes represent "real" data amounts, points and
accents represent "useful" data, basically, CEU scaled and cropped output,
mapped back onto the client's source plane.
Such a configuration can be produced by user requests:
S_CROP(left / top = (5) - (1), width / height = (5') - (5))
S_FMT(width / height = (6') - (6))
Here:
(1) to (1') - whole max width or height
(1) to (2) - sensor cropped left or top
(2) to (2') - sensor cropped width or height
(3) to (3') - sensor scale
(3) to (4) - CEU cropped left or top
(4) to (4') - CEU cropped width or height
(5) to (5') - reverse sensor scale applied to CEU cropped width or height
(2) to (5) - reverse sensor scale applied to CEU cropped left or top
(6) to (6') - CEU scale - user window
S_FMT 알고리즘
66-115`S_FMT`는 이미 최적인 input rectangle을 건드리지 않습니다. 대신 현재 sensor 배율과 기존 `S_CROP`의 유효 입력 영역을 바탕으로 새 sensor output, CEU crop, CEU scale을 차례로 계산합니다.
1단계에서는 현재 sensor 배율 `scale_s = ((2') - (2)) / ((3') - (3))`를 계산합니다. 2단계에서는 현재 sensor 배율로 CEU crop을 input window에 역사상해 사용자의 `S_CROP`인 유효 input crop을 구합니다. 식은 `width_u = (5') - (5) = ((4') - (4)) * scale_s`입니다.
3단계에서는 유효 input window에서 요청한 user window까지의 새 combined scale을 `scale_comb = width_u / ((6') - (6))`으로 계산합니다. 4단계에서는 이 combined scale을 실제 input window에 적용해 sensor output을 `width_s_out = ((7') - (7)) = ((2') - (2)) / scale_comb`으로 계산합니다.
5단계에서는 sensor output window에 대해 `subdev->video_ops->s_fmt(.width = width_s_out)`를 반복 적용합니다. 6단계에서는 `g_fmt`로 sensor output window를 다시 가져옵니다. Sensor가 요청값을 그대로 수용하지 않을 수 있으므로 실제 결과를 기준으로 다음 계산을 계속해야 합니다.
7단계에서는 새 sensor 배율을 `scale_s_new = ((3')_new - (3)_new) / ((2') - (2))`로 계산합니다. 8단계에서는 앞서 구한 유효 crop에 이 배율을 적용해 새 CEU crop의 크기 `width_ceu = (4')_new - (4)_new = width_u / scale_s_new`와 offset `left_ceu = (4)_new - (3)_new = ((5) - (2)) / scale_s_new`를 구합니다.
9단계에서는 `ceu_crop(.width = width_ceu, .left = left_ceu)`로 새 window를 crop합니다. 10단계에서는 요청한 user window에 맞도록 CEU 배율 `scale_ceu = width_ceu / width`를 적용합니다. 같은 계산은 수평의 width·left와 수직의 height·top에 각각 대응합니다.
Input rectangle을 유지하면서 sensor와 CEU의 실제 결과를 반영합니다.
S_FMT
-----
Do not touch input rectangle - it is already optimal.
1. Calculate current sensor scales:
scale_s = ((2') - (2)) / ((3') - (3))
2. Calculate "effective" input crop (sensor subwindow) - CEU crop scaled back at
current sensor scales onto input window - this is user S_CROP:
width_u = (5') - (5) = ((4') - (4)) * scale_s
3. Calculate new combined scales from "effective" input window to requested user
window:
scale_comb = width_u / ((6') - (6))
4. Calculate sensor output window by applying combined scales to real input
window:
width_s_out = ((7') - (7)) = ((2') - (2)) / scale_comb
5. Apply iterative sensor S_FMT for sensor output window.
subdev->video_ops->s_fmt(.width = width_s_out)
6. Retrieve sensor output window (g_fmt)
7. Calculate new sensor scales:
scale_s_new = ((3')_new - (3)_new) / ((2') - (2))
8. Calculate new CEU crop - apply sensor scales to previously calculated
"effective" crop:
width_ceu = (4')_new - (4)_new = width_u / scale_s_new
left_ceu = (4)_new - (3)_new = ((5) - (2)) / scale_s_new
9. Use CEU cropping to crop to the new window:
ceu_crop(.width = width_ceu, .left = left_ceu)
10. Use CEU scaling to scale to the requested user window:
scale_ceu = width_ceu / width
S_CROP 알고리즘
116-142`V4L2 crop API <crop-scale>`는 crop의 origin이나 unit을 규정하지 않지만, 관례상 driver가 수평 방향의 unscaled sample을 `0H`를 기준으로 세도록 권고합니다. 이 driver는 그 조언을 따라 cropping unit을 client input pixel로 해석합니다.
Cropping은 6단계로 수행합니다. 1단계에서 sensor에 사용자가 지정한 rectangle을 정확히 요청합니다. 2단계에서 결과가 더 작으면 더 큰 rectangle을 얻을 때까지 반복합니다. 그 결과 sensor crop은 `(2):(2')`, 목표 crop은 `(5):(5')`, 현재 output format은 `(6') - (6)`이 됩니다.
3단계에서는 이전 협상에서 sensor가 output frame을 최대한 보존하려 했더라도 값이 달라졌을 수 있으므로 output을 다시 조회합니다. 4단계에서 sensor는 `(3):(3')`로 scale했고 sensor scale은 `(2' - 2) / (3' - 3)`입니다. 따라서 중간 window는 `4' - 4 = (5' - 5) * (3' - 3) / (2' - 2)`로 계산합니다.
5단계에서는 host scale `(6' - 6) / (4' - 4)`를 계산해 적용합니다. 6단계에서는 host crop offset `6 - 7 = (5 - 2) * (6' - 6) / (5' - 5)`를 계산해 적용합니다. 이 절차는 client input pixel로 표현된 목표 crop을 sensor와 host가 실제로 제공하는 window에 맞춰 나눠 적용합니다.
Sensor 협상 결과를 다시 읽은 뒤 host crop과 scale을 계산합니다.
S_CROP
------
The :ref:`V4L2 crop API <crop-scale>` says:
"...specification does not define an origin or units. However by convention
drivers should horizontally count unscaled samples relative to 0H."
We choose to follow the advise and interpret cropping units as client input
pixels.
Cropping is performed in the following 6 steps:
1. Request exactly user rectangle from the sensor.
2. If smaller - iterate until a larger one is obtained. Result: sensor cropped
to 2 : 2', target crop 5 : 5', current output format 6' - 6.
3. In the previous step the sensor has tried to preserve its output frame as
good as possible, but it could have changed. Retrieve it again.
4. Sensor scaled to 3 : 3'. Sensor's scale is (2' - 2) / (3' - 3). Calculate
intermediate window: 4' - 4 = (5' - 5) * (3' - 3) / (2' - 2)
5. Calculate and apply host scale = (6' - 6) / (4' - 4)
6. Calculate and apply host crop: 6 - 7 = (5 - 2) * (6' - 6) / (5' - 5)
요약과 해설
sh_mobile_ceu_camera.rst:1-142이 문서의 핵심은 사용자 crop rectangle을 한 장치의 고정 좌표로 취급하지 않고, sensor crop·sensor scale·CEU crop·CEU scale 사이에서 일관되게 변환하는 것입니다. Sensor format 협상 결과가 요청과 달라질 수 있으므로 `S_FMT`와 `S_CROP` 모두 실제 sensor output을 다시 읽어 후속 계산에 사용합니다.
원문의 `(1)`부터 `(7')` 좌표는 수평 width·left와 수직 height·top에 공통으로 적용됩니다. 구현을 검토할 때는 source plane의 `(5):(5')`, sensor input의 `(2):(2')`, CEU input의 `(4):(4')`, 최종 user window의 `(6):(6')`를 구분해야 반대 방향의 배율이나 offset을 잘못 적용하지 않습니다.