在这篇文章中,我将描述将 RGB 缓冲区转换为灰度(灰度)的算法。
这样做非常简单,缓冲区的每个像素颜色通道都根据一定的公式进行转换,输出是灰度图像。
平均法:
red = average;
green = average;
blue = average;Складываем 3 цветовых канала и делим на 3.


Однако существует еще один метод – метод средневзвешенный, он учитывает цветовосприятие человека:
red = luminance;
green = luminance;
blue = luminance;

Какой метод лучше использовать? Да какой вам больше подходит для конкретной задачи. Далее сравнение методов с помощью тестовой цветовой сетки:



Пример реализации на JavaScript + HTML 5
    image,
    canvas,
    weightedAverage
) {
    const context = canvas.getContext('2d');
    const imageWeight = image.width;
    const imageHeight = image.height;
    canvas.width = imageWeight;
    canvas.height = imageHeight;
    context.drawImage(image, 0, 0);
    let pixels = context
        .getImageData(
            0,
            0,
            imageWeight,
            imageHeight
        );
    for (let y = 0; y & lt; pixels.height; y++) {
        for (let x = 0; x & lt; pixels.width; x++) {
            const i = (y * 4) * pixels.width + x * 4;
            let red = pixels.data[i];
            let green = pixels.data[i + 1];
            let blue = pixels.data[i + 2]
            const average = (red + green + blue) / 3;
            const luminance = 0.2126 * red +
                0.7152 * green +
                0.0722 * blue;
            red = weightedAverage ? luminance : average;
            green = weightedAverage ? luminance : average;
            blue = weightedAverage ? luminance : average;
            pixels.data[i] = red;
            pixels.data[i + 1] = green;
            pixels.data[i + 2] = blue;
        }
    }
    context
        .putImageData(
            pixels,
            0,
            0,
            0,
            0,
            pixels.width,
            pixels.height
        );
}Источники
https://www.baeldung.com/cs/convert-rgb-to-grayscale
https://twitter.com/mudasobwa/status/1528046455587495940
https://rosettacode.org/wiki/Grayscale_image
Ссылки
http://papugi.demensdeum.repl.co/
Благодарности
Спасибо Aleksei Matiushkin (https://twitter.com/mudasobwa) за наводку на Rosetta Code
如何在 Macbook M1 上运行 CSGO
爱情傻瓜:第一次约会–慢玩1
图灵计算机
我向您展示了艾伦·图灵文章《世界》第一页的翻译。 “关于可计算数字及其解决问题的应用” 1936年。第一章包含对计算机的描述,后来成为现代计算的基础。
文章的全文翻译和解释可以在美国普及者查尔斯·佩措尔德(Charles Petzold)所著的《读图灵》一书中阅读。浏览图灵关于可计算性和图灵机的里程碑式论文—— (ISBN 978-5-97060-231-7、978-0-470-22905-7)
原文:
https://www.astro.puc.cl/~rparra/tools/PAPERS/turing_1936.pdf
—
关于应用于解决问题的可计算数字
A. M·图灵
[1936 年 5 月 28 日收到 – 1936 年 11 月 12 日阅读]
可计算数可以简单地描述为实数,其小数形式的表达式可以通过有限多种方式计算。尽管乍一看本文将数字视为可计算的,但定义和探索整数变量、实数变量、可计算变量、可计算谓词等的可计算函数几乎同样容易。然而,与这些可计算对象相关的基本问题在每种情况下都是相同的。为了详细考虑,我选择可计算数字作为可计算对象,因为考虑它们的方法是最不麻烦的。我希望尽快描述可计算数与可计算函数的关系等等。同时,将在以可计算数表示的实变量函数理论领域进行研究。根据我的定义,如果机器可以写出小数形式的实数,那么该实数就是可计算的。
在第 9 段和第 10 段中,我给出了一些论据来表明可计算数包括所有自然被认为是可计算的数。特别是,我证明了一些大类数字是可计算的。例如,它们包括所有代数数的实部、贝塞尔函数零点的实部、数字 π、e 等。但是,可计算数并不包括所有可定义数,如以下不可计算的可定义数示例所示。
尽管可计算数的类别非常大,并且在许多方面与实数的类别相似,但它仍然是可枚举的。在第 8 节中,我考虑了某些看似相反的论点。当其中一个论证得到正确应用时,乍一看,得出的结论与哥德尔*的结论相似。这些结果具有极其重要的应用。特别是如下图(§11)所示,分辨率问题无法解决。
Alonzo Church**在他最近的文章中介绍了“有效可计算性”的想法,这与我的“可计算性”的想法相当,但定义完全不同。关于解决问题,丘奇也得出了类似的结论。本文附录中给出了“可计算性”和“有效计算能力”等价性的证明。
1.计算机
我们已经说过,可计算数是那些小数位数可以通过有限方式计算的数。这里需要一个更清晰的定义。在我们到达第 9 节之前,本文不会真正尝试证明此处给出的定义的合理性。现在,我只想指出(这样做的)(逻辑)基本原理是人类的记忆必然是有限的。
让我们将计算实数的过程中的人与只能满足有限数量的条件 q1, q2, …, qR; 的机器进行比较。我们将这些条件称为“m 配置”。这台(即如此定义的)机器配备有“胶带”(类似于纸)。穿过机器的皮带被分成几段。我们称它们为“正方形”。每个这样的方块都可以包含某种“符号”。在任何时刻,只有一个这样的正方形,比如第 r 个,包含“在这台机器中”的符号。我们将这样的正方形称为“扫描符号”。可以说,“扫描字符”是机器“直接感知”的唯一字符。然而,通过改变它的 m 配置,机器可以有效地记住它之前“看到”(扫描过)的一些字符。机器在任何时刻可能的行为由 m 配置 qn 和扫描的符号***决定。我们将这对符号称为 qn,“配置”。由此指定的配置决定了给定机器的可能行为。在其中所扫描的方块是空白的(即,不包含字符)的一些配置中,机器在所扫描的方块上写入新字符,而在这些配置中的其他配置中,机器擦除所扫描的字符。这台机器也能够移动来扫描另一个方格,但这样它只能移动到右侧或左侧的相邻方格。除了这些操作之外,还可以更改机器的 m 配置。在这种情况下,一些写入的字符将形成一个数字序列,这是正在计算的实数的小数部分。其余的无非是为了“帮助记忆”而做的不准确的标记。这种情况下,只能擦除上述不准确的标记。
我声称这里考虑的操作包括所有计算中使用的操作。对于了解机器理论的读者来说,这种说法的基本原理更容易理解。因此,在下一节中,我将在理解“机器”、“磁带”、“扫描”等术语的基础上继续发展相关理论。
*哥德尔“论数学原理中的形式上不可判定的句子(由怀特海和罗素于 1910 年、1912 年和 1913 年出版)和相关系统,第一部分”,《数学杂志》。物理学,德文月刊第 38 期(1931 年,第 173-198 页。
** Alonzo Church,“初等数论中的一个不可判定问题”,American J. of Math.,第 58 期 (1936),第 345-363 页。
*** Alonzo Church,“关于解决问题的注释”,J. of Symbolic Logic,第 1 期(1936 年),第 40-41 页
观察者:Redux –慢打
来自彼岸的欲望–慢打
图灵炸弹
1936 年,科学家艾伦·图灵在他的出版物《论可计算数,及其在解决问题中的应用》中描述了通用计算机的使用,它可以解决数学中的可解性问题。结果,他得出的结论是,如果这种机器的工作结果被颠倒并循环回自身,那么它就无法正确解决任何问题。事实证明,不可能创建一个“理想的”防病毒软件、一个“理想的”磁贴设置器、一个为您的崩溃建议理想短语的程序等等。悖论!
然而,这种通用计算机可以用来实现任何算法,英国情报部门利用了这一点,雇佣了图灵并允许创建“Bombe”机器来破译第二次世界大战期间的德国信息。
以下是基于原始文档,使用 Dart 语言对单磁带计算机进行 OOP 建模。
图灵机由分成多个部分的薄膜组成,每个部分包含一个符号,这些符号可以读取或写入。电影类示例:
final _map = Map<int, String>(); 
  String read({required int at}) { 
    return _map[at] ?? ""; 
  } 
  void write({required String symbol, required int at}) { 
    _map[at] = symbol; 
  } 
}
还有一个“扫描方块”,它可以在胶片上移动,读取或写入信息,用现代语言来说就是——磁头。磁头类示例:
  int _index = 0; 
  InfiniteTape _infiniteTape; 
  TapeHead(this._infiniteTape) {} 
  String next() { 
    _index += 1; 
    move(to: _index); 
    final output = read(); 
    return output; 
  } 
  String previous() { 
    _index -= 1; 
    move(to: _index); 
    final output = read(); 
    return output; 
  } 
  void move({required int to}) { 
    this._index = to; 
  } 
  String read() { 
    return _infiniteTape.read(at: this._index); 
  } 
  void write(String symbol) { 
    _infiniteTape.write(symbol: symbol, at: this._index); 
  } 
  int index() { 
    return _index; 
  } 
} 
机器包含“m-configurations”,通过它可以决定下一步做什么。用现代语言来说——状态和状态处理程序。状态处理程序示例:
  FiniteStateControlDelegate? delegate = null; 
  void handle({required String symbol}) { 
    if (symbol == OPCODE_PRINT) { 
      final argument = delegate?.nextSymbol(); 
      print(argument);
    } 
    else if (symbol == OPCODE_GENERATE_RANDOM_NUMBER_FROM_ZERO_TO_AND_WRITE_AFTER) { 
      final to = int.tryParse(delegate!.nextSymbol())!; 
      final value = new Random().nextInt(to); 
      delegate!.nextSymbol(); 
      delegate!.write(value.toString()); 
    } 
    else if (symbol == OPCODE_INPUT_TO_NEXT) { 
      final input = stdin.readLineSync()!; 
      delegate?.nextSymbol(); 
      delegate?.write(input); 
    } 
    else if (symbol == OPCODE_COPY_FROM_TO) { 
      final currentIndex = delegate!.index(); 
и т.д. 
之后,您需要创建“配置”,用现代语言来说,这些是操作代码(操作码)及其处理程序。操作码示例:
const OPCODE_PRINT = "print"; 
const OPCODE_INCREMENT_NEXT = "increment next"; 
const OPCODE_DECREMENT_NEXT = "decrement next"; 
const OPCODE_IF_PREVIOUS_NOT_EQUAL = "if previous not equal"; 
const OPCODE_MOVE_TO_INDEX = "move to index"; 
const OPCODE_COPY_FROM_TO = "copy from index to index"; 
const OPCODE_INPUT_TO_NEXT = "input to next"; 
const OPCODE_GENERATE_RANDOM_NUMBER_FROM_ZERO_TO_AND_WRITE_AFTER = "generate random number from zero to next and write after"; 
不要忘记创建操作码和停止处理程序,否则您将无法证明或无法证明(原文如此!)解决问题。
现在,使用“中介者”模式,我们连接图灵机类中的所有类,创建该类的实例,通过磁带录音机录制程序,加载磁带就可以使用它了!
对我个人来说,什么是主要的问题仍然很有趣——“什么是主要的”?创建通用计算器或“Entscheidungsproblem”的证明,作为副产品,计算器出现了。
盒式磁带
为了好玩,我为我的机器版本录制了几个盒式磁带节目。
你好世界
hello world 
stopСчитаем до 16-ти
0
if previous not equal
16
copy from index to index
1
8
print
?
move to index
0
else
copy from index to index
1
16
print
?
print
Finished!
stopСамой интересной задачей было написание Quine программы, которая печатает свой исходный код, для одноленточной машины. Первые 8 часов мне казалось что эта задача не решаема с таким малым количеством опкодов, однако всего через 16 часов оказалось что я был не прав.
Реализация и примеры кассет, источники ниже.
Ссылки
https://gitlab.com/demensdeum/turing-machine
Источники
https://www.astro.puc.cl/~rparra/tools/PAPERS/turing_1936.pdf
https://kpolyakov.spb.ru/prog/turing.htm
https://www.youtube.com/watch?v=dNRDvLACg5Q
https://www.youtube.com/watch?v=jP3ceURvIYc
https://www.youtube.com/watch?v=9QCJj5QzETI
https://www.youtube.com/watch?v=HeQX2HjkcNo&t=0s
为 Sega Genesis #5 编写汇编
在这篇文章中,我将描述读取操纵杆、更改精灵位置、水平翻转、Sega Genesis 模拟器以及可能的控制台本身的过程。
读取点击并处理将棋操纵杆的“事件”按照以下方案进行:
- 请求按下按钮的位组合
- 读取按下的按钮的位
- 游戏逻辑级别的处理
要移动骨架精灵,我们需要存储当前位置的变量。
内存
游戏逻辑变量存储在RAM中;到目前为止人们还没有想出更好的办法。让我们声明变量地址并更改渲染代码:
skeletonYpos = $FF0002 
frameCounter = $FF0004 
skeletonHorizontalFlip = $FF0006
    move.w #$0100,skeletonXpos 
    move.w #$0100,skeletonYpos 
    move.w #$0001,skeletonHorizontalFlip 
FillSpriteTable: 
    move.l #$70000003,vdp_control_port 
    move.w skeletonYpos,vdp_data_port  
    move.w #$0F00,vdp_data_port 
    move.w skeletonHorizontalFlip,vdp_data_port 
    move.w skeletonXpos,vdp_data_port 
如您所见,可用于工作的地址从 0xFF0000 开始,到 0xFFFFFF 结束,总共有 64 KB 的内存可供我们使用。骨架位置在 sculptureXpos、sculptureYpos 处声明,水平翻转在 sculptureHorizontalFlip 处声明。
手柄
与 VDP 类比,游戏手柄的工作分别通过两个端口进行:控制端口和数据端口,第一个为0xA10009和0xA10003共号。使用游戏手柄时有一个有趣的功能——首先,您需要请求用于轮询的按钮组合,然后在等待总线上的更新后,读取所需的按键。对于 C/B 和 D-pad 按钮,这是 0x40,示例如下:
  move.b #$40,joypad_one_control_port; C/B/Dpad 
  nop ; bus sync 
  nop ; bus sync 
  move.b joypad_one_data_port,d2 
  rts 
在寄存器 d2 中,按钮按下或未按下的状态将保留,一般来说,通过日期端口请求的内容将保留。之后,转到您最喜欢的模拟器的 Motorola 68000 寄存器查看器,根据击键查看 d2 寄存器等于什么。您可以通过聪明的方式在手册中找到答案,但我们并不相信他们的话。进一步处理 d2
寄存器中按下的按钮
    cmp #$FFFFFF7B,d2; handle left 
    beq MoveLeft  
    cmp #$FFFFFF77,d2; handle right  
    beq MoveRight  
    cmp #$FFFFFF7E,d2; handle up  
    beq MoveUp  
    cmp #$FFFFFF7D,d2; handle down  
    beq MoveDown  
    rtsПроверять нужно конечно отдельные биты, а не целыми словами, но пока и так сойдет. Теперь осталось самое простое – написать обработчики всех событий перемещения по 4-м направлениям. Для этого меняем переменные в RAM, и запускаем процедуру перерисовки.
Пример для перемещения влево + изменение горизонтального флипа:
    move.w skeletonXpos,d0 
    sub.w #1,d0 
    move.w d0,skeletonXpos 
    move.w #$0801,skeletonHorizontalFlip 
    jmp FillSpriteTableПосле добавления всех обработчиков и сборки, вы увидите как скелет перемещается и поворачивается по экрану, но слишком быстро, быстрее самого ежа Соника.
Не так быстро!
Чтобы замедлить скорость игрового цикла, существуют несколько техник, я выбрал самую простую и не затрагивающую работу с внешними портами – подсчет цифры через регистр пока она не станет равна нулю.
Пример замедляющего цикла и игрового цикла:
  move.w #512,frameCounter 
WaitFrame: 
  move.w frameCounter,d0 
  sub.w #1,d0 
  move.w d0,frameCounter 
  dbra d0,WaitFrame 
GameLoop: 
  jsr ReadJoypad 
  jsr HandleJoypad 
  jmp GameLoop 
此后,骨架运行速度变慢,这正是所需要的。据我所知,“放慢速度”的最常见选项是计算垂直同步标志;您可以计算屏幕被绘制的次数,从而与特定的 fps 相关联。
链接
https://gitlab .com/demensdeum/segagenesisamples/-/blob/main/8Joypad/vasm/main.asm
来源
https://www.chibiakumas.com/68000/platform2.php 
https://huguesjohnson.com/programming/genesis/tiles-sprites/
