SAについて

初めてのSA(学生の講義補佐)の業務が終わりました。
質問とかはあんまりなく終了。見回ってるだけの人。警備員か?
とはいえこれからのようです。課題内容が難化するに向けて質問が増えてくるとか。

ということで、これから迫る初めの課題に向けてなんか面白い豆知識みたいなのが披露できたらなとは思っていて。
ひとつ、イイのを思い出しました。

負の色情報

マイナスの色情報、ネガティブカラー。字面がイケてると思いませんか?めだかボックスとかあたりに出てそうな能力名。
そんな感じでなかなか面白い題材なんですが、説明するとなると24bitカラーデータの仕組みを知らないと良く分からないんですよね。というわけで思考整理ついでに書き留めておきます。

まずこちらの画像を見てください。綺麗ですね。
幾重にも重なった斜めのストロークが織りなすグラデーション。いい見た目だと思います。

そうです。この画像こそ、「負の色情報」を用いて制作されています。
えっ?負の色情報ってこんなの?もっとめちゃくちゃな色だったりしないの?と思うかもしれません。そうです。見た目は意外と普通の色なんです。優しいヤンキーみたいですね。優しいヤンキーって何だ。

しかしこんなんでも負の色情報。中身はちゃんとバグってます。
バグってるのは主に以下の要素。

  • どっから繰り下げてるんだお前。
  • モノクロ指定なのに24bitカラーが出てくる。

色情報の仕組み

まず、色の情報の仕組みについて。24bitカラーとは何でしょうか。

1bitは、「0と1」で表現される2進数の1桁のことです。一つのスイッチのON, OFFそのものです。
それが24桁集まることで、24bitカラーが表されています。
そしてその24桁は 8*3 となって、8桁が三つに分かれることでそれぞれ R, G, B の色情報として使用されているわけです。

この8桁ですが、個別に管理されているようにイメージしている人もいるかもしれません。青色の情報から緑色の情報にアクセスすることは出来ないだろうと。
なんと出来ます。と言うのも8bitごとに分けたというのは結果的にそのように使用されているだけで、実際の計算上は一体化した24桁の2進数なのです。

まずRGBそれぞれは24桁をこのように割り当てられています。
111100001010101001010101
分かりやすいように各色ごとに数字を変更しています。
この24桁の2進数を使って計算しているわけです。

さて、以下の画像を見てください。

白色と黄色が見えると思います。細かく画像を見てみると分かるのですが、白から黄に遷移するときは滑らかに色が変化していて、黄から白に変化するときはパッと瞬間的に変わっています。
何故この現象が起こるのかは、先ほどの24bit構造を考えると分かります。

白色はどういう値でしょう。 もちろん、255, 255, 255です。
では黄色はどうでしょうか? 答えは、255, 255, 0です。

おや、3つ目の値が減っていますね?そうです。白から青色が減っていったことで現れた色です。
そして、青色は24bitカラーの中で最も右側にあります。つまり小さい方の8桁で管理されているのです。
これが原因です。

0からさらに数値を引いたとき、色情報は「単なる数値」としての振舞いを表面化し始めます。
負の領域に入った色情報から真っ先に差し引かれていく数値の桁・・・それが「青色の桁」です。

そしてそのまま青色が差し引かれていくとある時、青色が0になります。そうなった際にはどこかから繰り下げをしてこないとそれ以上引くことが出来ません。あなたならそうなってしまったらどうしますか?
そうですね。一つ大きい桁から繰り下がりで持ってきましょう。

しかし悲しきかな、その一つ大きい桁は青色の桁ではないのです。それは「緑色の桁」です。緑色の桁から1を持ってくることによって、青色はまた引き算が出来るようになります。

つまり、画像の黄色→白で瞬間的に色が変わっているのは
  255, 255, 0:11111111, 11111111, 00000000 → 255, 254, 255:11111111, 11111110, 11111111
と緑色から繰り下がった結果です。画像からはよく見えないだけで、色からはほんの少しずつ緑色の情報が消えていっています。

そしてその過程がさらに進行した結果が分かりやすく表示されているのが、冒頭1枚目の画像です。
あの画像では繰り下がりは緑色どころか赤色にまで及んでいます。その証拠に右下では赤色が抜けてしまっているのが分かるでしょう。
右下に表示されている色は緑色と青色、というか黒色です。
緑色は0, 255, 0
青色は0, 0, 255
黒色は0, 0, 0
全て赤色が抜けた時に表示される色だったのです。

そして画像サイズを大きくするとこのように値の動きが戻って繰り返しているのが分かります。
繰り返してはいますが、ここではまだ画面内はずっと負の色情報のままです。正であれ負であれ、数値が増えすぎることである現象が起きます。

それが起きたのがこの画像です。このプログラムではマウス位置の画素から色の数値を取り出し、println()で出力するようプログラムしています。
マウスの位置を動かすと、画像の薄灰色っぽい場所で-21億から+21億に飛び越えているのが分かります。
これはオーバーフローと呼ばれる現象で、この場合、int型の数値としてコンピューターが計算できる最小値や最大値以上に数値が溢れてしまうことで発生します。よくファミコンなど昔のゲームで、オーバーフローしたHP回復効果が結果的にダメージとなることがありましたが、ちょうどそれです。
Minecraftでも即時回復Lv29のポーションがオーバーフローによって即死効果を獲得してたり。
即時回復の計算式は2^lv × 2なので、ちょうど2^30ですかね。わーお。

余談ですが、なぜ24bitを超えても負の値をとったままだったのでしょうか?
それは単純に、色の情報は32bitのint型から24bitの部分だけをRGBカラーとして読み込んでいるからです。
残った8bitの部分は場合によっては「アルファチャンネル」と呼ばれる、透明度やベクトルデータといった色以外に必要な情報を1枚の画像内に保存するために使われたりします。ゲームや3DCGでモーションブラーの効果は絶大ですが、それには画像内のアルファチャンネルが活用されています。
上の画像の場合はどう利用されているのか分かりませんが、画面上はオーバーフロー直前に色全体が抜けていってしまっているように見えます。しかし一旦pngとして出力されるとこの灰色は見えなくなってしまうので、もしかしたらデフォルト背景の薄灰色が透けてるのかも。
その場合は最上位8bitの数値が負の透明度として処理されていた可能性がありますね。

余談から話を戻して、極めつけにこの負の色情報はグレースケール設定であっても容赦しません。

左上だけ白黒です。これはcolorMode(GRAY, 255)によって明示的にグレースケールに指定し、255から色を減らしていくようにしました。

がっ・・・ダメッ・・・!!!!グレースケールにしろって言ったのに無断で色が復活しています。穢土転生の術か何かでしょうか。
色が復活している箇所はちょうどx座標とy座標の合計が255となって、計算の結果が255 – 255 = 0となる部分です。
おそらくグレースケールは何らかのアルゴリズムによって24bitカラーの色域を制限するなどし、無理やりグレースケールとして活用しているのだと思われます。内部的にはちゃんと24bitカラーを使っているんですね。

まとめ

さて、そんなこんなで負の色情報について書きました。
数値的にはint型に特有である性質に基づいているので、この現象を直すことはどれほどの凄腕エンジニアであろうがどうやっても出来ないです。
ProcessingはアーティストのためのJavaライブラリみたいなとこがあるので、作品に活用できるならどんな裏をかいた現象でも利用したほうがいいのかもしれません。とはいえあんまりプログラミングルールに違反しすぎるとどこかしらイカレたり、場合によってはイカレるはずのない場所がイカレたり、最終的にどこがぶっ壊れたのか分からなくなって没になったりする事も考えられます。
Processingで意図的に不具合を活用するときには「なぜ不具合が発生したのか」、「回避する手段はあるのか」を理解したうえで活用するとしましょう。幸いJavaベースなので、検索すれば大抵の不具合は特定できます。エラーも表示されますし。

そんな感じで、3か月間SAをやっていきます。2年下の学生ですし、その学生が支払った学費から私の時給は出ている・・・と考えると、なるべく良い補佐を心掛けたいところです。

今回のProcessingファイルは私のGithubからダウンロードできます。

URL : https://github.com/ryu-blacklight/processing_blog2023

フォルダは0413_color_fromPositionで、その中に入れてあります。
その時点での授業範囲におさえ、strokeとpointで動作するようにしたcolor_pointと、
pixels配列を使用することで負荷の少ない動作にしたcolor_pixelsの2つが入ってます。

マウスクリックで値のオーバーフローを観察できるcolor_overflowも入れておきますが、オーバーフローはあまり好ましい挙動ではないので実行は自己責任でお願いします。イマドキのPCでオーバーフローに対応してない事なんて、そっちの方が逆に危険だと思いますし十中八九問題ないとは思いますが。念のため。