Страница Ивана Рощина > Статьи > Вывод чёрно-белых изображений с градациями яркости >

Приложение 2

Здесь речь пойдёт о том, как определить величины a0—a7 (яркость цветов 0—7 при bright=0) и b0—b7 (яркость тех же цветов при bright=1), когда изображение выводится в чёрно-белом виде.

Очевидно, эти величины могут быть различны для разных моделей ZX Spectrum, для разных преобразователей цветного сигнала в чёрно-белый, а также для разных мониторов и телевизоров. Поэтому вместо того, чтобы привести готовый набор чисел, я расскажу о том, как вы сможете определить их именно для своей системы «компьютер-монитор», причём для этого вам не понадобятся какие-либо специальные приборы.

Что можно сказать сразу?

1. Самый тёмный цвет — чёрный:

a0 = 0, b0 = 0.

2. Самый яркий цвет — белый при bright=1:

b7 = 255.

3. Яркость всех остальных цветов принимает промежуточные значения:

0 < (а1—а7, b1—b6) < 255.

4. С увеличением номера цвета яркость возрастает:
a1 > a0, b1 > b0,
a2 > a1, b2 > b1,
....... .......
a7 > a6, b7 > b6.
5. Для каждого цвета, кроме чёрного, яркость при bright=1 больше, чем при bright=0:
b1 > a1,
b2 > a2,
.......
b7 > a7.

Итак, кое-что мы уже знаем. Основываясь на этой информации, можно предположить, что распределение яркостей будет примерно таким:

Рис. 18

Выше мы говорили «яркость», а каков физический смысл этого понятия? Определим его так: яркость некоторого цвета (точнее, яркость градации, соответствующей этому цвету при чёрно-белом режиме отображения) — это величина, пропорциональная количеству фотонов, испускаемому единичной областью данного цвета за единицу времени. Например, если яркость одного цвета вдвое больше яркости другого, это значит, что некоторая область этого цвета испускает за единицу времени вдвое больше фотонов, чем такая же область другого цвета.

Если вывести в одной половине экрана какой-либо цвет (далее — исходный цвет), а в другой половине — смесь пикселов двух цветов, темнее и светлее исходного (далее — соответственно тёмный цвет и светлый цвет), то, подбирая соотношение числа пикселов этих двух цветов, можно добиться равенства яркостей обеих половин экрана. Равенство яркостей означает, что обе половины экрана за единицу времени испускают одинаковое количество фотонов. Тогда справедлива следующая формула:

    x = k y + (1 – k) z, (1)
где  x — яркость исходного цвета,
y — яркость тёмного цвета,
z — яркость светлого цвета,
k — доля пикселов тёмного цвета,
1 – k — доля пикселов светлого цвета.

Например, если яркости уравнялись при заполнении второй половины экрана текстурой 4x4, в которой 3 пиксела тёмного цвета и 13 пикселов светлого цвета, это будет записано так:

x = 3/16 y + 13/16 z.

Используем вышеизложенное для вычисления искомых яркостей a0—a7 и b0—b7. Сначала выразим яркость каждого из цветов b1—b6 через яркость соседних с ним цветов:

          b1 = k1b0 + (1–k1)b2,       (2)
          b2 = k2b1 + (1–k2)b3,
          .....................
          b6 = k6b5 + (1–k6)b7.

Из (2) следует:

     b1–k1b0
b2 = -------.
      1–k1

И далее:

     b2–k2b1
b3 = -------,
      1–k2

     b3–k3b2
b4 = -------,
      1–k3

.............

     b6–k6b5
b7 = -------.
      1–k6

Таким образом, зная b0 и b1, а также k1—k6 (находимые опытным путём), можно последовательно вычислить b2—b7.

Значение b0 нам известно — это 0. Значение b1 неизвестно, зато мы знаем, что b7=255. Можно выразить b7 через b1, затем определить b1 и далее вычислить b2—b6. Но этот путь связан с громоздкими преобразованиями. Поступим проще. Заметим, что b2—b7 линейно зависят от b1. В этом нетрудно убедиться из вышеприведённых формул (не забывая, что b0=0). Примем b1=1 и вычислим b2—b7. Тогда достаточно определить, во сколько раз получившееся значение b7 оказалось меньше 255, и затем умножить каждое из вычисленных значений b1—b7 на эту величину, чтобы получить их истинные значения.

После того, как яркости цветов с bright=1 известны, остаётся определить яркости цветов с bright=0 (a1—a7). Для этого достаточно найти опытным путём для каждого из этих цветов эквивалентную по яркости смесь двух цветов с bright=1, после чего воспользоваться формулой (1).

Это была теория, а теперь перейдём к практике. Рассмотрим, как я определял уровни яркости на своём компьютере и что для этого использовал.

Сначала я написал процедуру, которая заполняет верхнюю часть экрана одним цветом, а нижнюю — смесью пикселов двух других цветов (с помощью текстуры 4x4). Вот она:

           LD   H,1 ;Исходный цвет.
           LD   D,0 ;Тёмный цвет.
           LD   E,2 ;Светлый цвет.
           LD   L,4 ;Номер текстуры (0-16).

;Заполняем верхнюю половину экрана:

           LD   A,H
           ADD  A,A
           ADD  A,A
           ADD  A,A
           ADD  A,H

;Если исходный цвет - с повышенной яркостью (bright=1), то
;следует команда ADD A,#40, иначе она не нужна (можно заменить
;на ADD A,0):

           ADD  A,#40

           EXX
           LD   HL,#5800
           LD   DE,#5801
           LD   BC,#180
           LD   (HL),A
           LDIR
           EXX

;Заполняем нижнюю половину экрана:

           LD   A,D
           ADD  A,A
           ADD  A,A
           ADD  A,A
           ADD  A,E
           ADD  A,#40

           EXX
           LD   BC,#17F
           LD   (HL),A
           LDIR
           EXX

;Заполнение текстурой:

           LD   H,0
           ADD  HL,HL
           ADD  HL,HL ;*4
           LD   DE,TEXTURES
           ADD  HL,DE
           EX   DE,HL

;DE указывает на первый байт текстуры.

           LD   B,24
           LD   HL,#4880

M2         PUSH DE
           PUSH BC
           LD   B,4
M1         LD   A,(DE)
           PUSH BC
           PUSH DE
           PUSH HL
           LD   D,H
           LD   E,L
           LD   (HL),A
           INC  DE
           LD   BC,#1F
           LDIR
           POP  HL
           POP  DE
           POP  BC
           CALL DOWN_HL
           INC  DE
           DJNZ M1
           POP  BC
           POP  DE
           DJNZ M2

           RET

DOWN_HL    INC  H
           LD   A,H
           AND  7
           RET  NZ
           LD   A,L
           ADD  A,#20
           LD   L,A
           RET  C
           LD   A,H
           SUB  8
           LD   H,A
           RET

TEXTURES   DB   %00000000
           DB   %00000000
           DB   %00000000
           DB   %00000000

           DB   %00000000
           DB   %01000100
           DB   %00000000
           DB   %00000000

           DB   %00000000
           DB   %01000100
           DB   %00000000
           DB   %00010001

           DB   %00000000
           DB   %01010101
           DB   %00000000
           DB   %00010001

           DB   %00000000
           DB   %01010101
           DB   %00000000
           DB   %01010101

           DB   %00000000
           DB   %01010101
           DB   %00100010
           DB   %01010101

           DB   %10001000
           DB   %01010101
           DB   %00100010
           DB   %01010101

           DB   %10101010
           DB   %01010101
           DB   %00100010
           DB   %01010101

           DB   %10101010
           DB   %01010101
           DB   %10101010
           DB   %01010101

           DB   %10101010
           DB   %01110111
           DB   %10101010
           DB   %01010101

           DB   %10101010
           DB   %01110111
           DB   %10101010
           DB   %11011101

           DB   %10101010
           DB   %01110111
           DB   %10101010
           DB   %11111111

           DB   %10101010
           DB   %11111111
           DB   %10101010
           DB   %11111111

           DB   %10101010
           DB   %11111111
           DB   %11101110
           DB   %11111111

           DB   %10111011
           DB   %11111111
           DB   %11101110
           DB   %11111111

           DB   %11111111
           DB   %11111111
           DB   %11101110
           DB   %11111111

           DB   %11111111
           DB   %11111111
           DB   %11111111
           DB   %11111111

Чтобы было удобнее сравнивать яркости половин экрана, когда на одной половине яркость равномерная, а на другой — текстура, я рассматривал изображение через полупрозрачную полиэтиленовую плёнку (для этого годится обычный пакет).

С помощью вышеприведённой процедуры были получены следующие соотношения:

b1 =  9/16 b0 + 7/16 b2,
b2 = 10/16 b1 + 6/16 b3,
b3 =  8/16 b2 + 8/16 b4,
b4 = 13/16 b3 + 3/16 b5,
b5 =  9/16 b4 + 7/16 b6,
b6 = 10/16 b5 + 6/16 b7,
(т.е. k1=9/16, k2=10/16, k3=8/16, k4=13/16, k5=9/16, k6=10/16),
a1 =  3/16 b0 + 13/16 b1,
a2 =  9/16 b1 +  7/16 b2,
a3 =  9/16 b2 +  7/16 b3,
a4 =       b3,
a5 =  9/16 b4 +  7/16 b5,
a6 = 11/16 b5 +  5/16 b6,
a7 = 11/16 b6 +  5/16 b7.

Затем я написал программу, вычисляющую на основе этих данных искомые значения a0—a7 и b0—b7:

      10 DIM k(6): DIM a(7): DIM b(7)
      20 LET k(1)=9/16: LET k(2)=10/16: LET k(3)=8/16: LET k(4)=
         13/16: LET k(5)=9/16: LET k(6)=10/16
      30 REM CALCULATE b(1)-b(7)
      40 LET b(1)=1
      50 LET b(2)=1/(1-k(1))
      60 FOR i=3 TO 7
      70 LET b(i)=(b(i-1)-k(i-1)*b(i-2))/(1-k(i-1))
      80 NEXT i
      90 LET n=255/b(7)
     100 FOR i=1 TO 7
     110 LET b(i)=b(i)*n
     120 NEXT i
     130 REM CALCULATE a(1)-a(7)
     140 LET a(1)=13/16*b(1)
     150 LET a(2)=9/16*b(1)+7/16*b(2)
     160 LET a(3)=9/16*b(2)+7/16*b(3)
     170 LET a(4)=b(3)
     180 LET a(5)=9/16*b(4)+7/16*b(5)
     190 LET a(6)=11/16*b(5)+5/16*b(6)
     200 LET a(7)=11/16*b(6)+5/16*b(7)
     210 REM PRINT RESULT
     220 PRINT "a0=0",0
     230 FOR i=1 TO 7
     240 PRINT "a";i;"=";a(i), INT (a(i)*256+0.5)
     250 NEXT i
     260 PRINT
     270 PRINT "b0=0",0
     280 FOR i=1 TO 7
     290 PRINT "b";i;"=";b(i), INT (b(i)*256+0.5)
     300 NEXT i

Результаты работы программы: в левом столбце — вычисленные значения яркостей, в правом — они же, но в 256-х долях — в таком формате они хранятся в процедурах вывода изображения (см. Приложение 3).

а0 = 0            0
а1 = 4,344111     1112
а2 = 8,3540597    2139
а3 = 17,233232    4412
а4 = 23,677792    6062
а5 = 56,855343    14555
а6 = 104,72922    26811
а7 = 181,85936    46556

b0 = 0            0
b1 = 5,3465982    1369
b2 = 12,220796    3129
b3 = 23,677792    6062
b4 = 35,134788    8995
b5 = 84,781772    21704
b6 = 148,61361    38045
b7 = 255          65280

А вот как это выглядит на графике:

Рис. 19

Как видите, это отличается от первоначальных предположений (рис. 18). Значения располагаются неравномерно: чем меньше яркость, тем ближе они друг к другу. Чем это можно объяснить? Очевидно, при преобразовании цветного изображения в чёрно-белое стремятся к тому, чтобы различные цвета превращались в хорошо отличающиеся друг от друга градации серого. А для этого яркости соседних градаций должны отличаться друг от друга не на одну и ту же величину, а в одно и то же количество раз — таковы особенности человеческого зрения.

Страница Ивана Рощина > Статьи > Вывод чёрно-белых изображений с градациями яркости >