2次元画像処理
言語と開発環境へ戻る。
概要
画像処理には、大きく分けて2種類の分野について理解が必要となると思います。
- 画像種類別によるエンコードおよびデコード技術の理解
- RGB表示系での画像描画処理および編集技術の理解
文章で表現するとすごく短い言葉ですが、この2つを理解することがいかに困難で高い壁であるかということは想像に絶するところがあると思います。エンコードデコードについてはBMP形式だけを理解するのであれば、ちょっとしたコンピュータ処理技術を理解していれば、なんとか理解できなくもないレベルですが、JPEGやPNGあるいはGIFのような画像圧縮と呼ばれる技術を利用している場合は大学レベルを超えて、博士号取得レベルの数学知識が必要になってきます。個々の数学的要素は大学で習得できるレベルですが応用していくという点においては誰も教えてくれない、研究の上に研究を重ねなければならないものです。
うまくエンコード・デコードをブラックボックス技術として理解し、活用するだけに専念するにしても、どういう圧縮方式があるのか?ということぐらいは理解しなければならないので、それだけでもかなり難しいと感じる人もいるかもしれません。
エンコード・デコードはとにかくコツコツと理解し、普段なにげなく使っている画像ファイルの構造をバイナリ形式の目線で眺め、紐解いていく作業になります。
エンコードやデコードの技術の理解を乗り越えたとして、RGB形式のようなR赤8ビット、G緑8ビット、B青8ビットの合計24bitで1ピクセルを表示する方式によるカラー画像表示のある大きさnピクセル×mピクセルの2次元配列で管理された画像を編集する技術やその領域をデカルト座標系のような幾何学を利用した線や円、微分、積分による線、面、空間における計算。線形代数のような学問とも触れ合いながら、ち密に表示画像を編集したり、配列に格納された値を書き換えたりしながら画面表示を制御しなければなりません。
ここでは、TIFF・BMP・JPEG・GIF・PNG・RAW形式のエンコード・デコードに関する考え方や具体的な手法を記述したり、2次元の範囲の幾何学を利用した図形描画や図形操作・画像処理について記述したいと思います。たぶんJPEGあたりの記事を書き始めたら終わらないと思うので、せいぜい頑張ってもそのあたりで右往左往していることでしょう。
画像処理のTop記事として、かるくJPEGの技術に触れておきましょう。こういう記事を読まれている人ならBMP形式くらいは、なんとなく理解されていると思っています。で、JPEGなんですけど、画像を開くだけでもかなりすごい計算がされています。なんつうか、数学のすごさ、美しさ、コンピュータの計算の速さ、すべてがあいまって、私たちは日々、エロ画像いや画像を閲覧することができています。SNSなんかに画像を気軽にアップロードできます。BMP形式のままだとファイルサイズはJPEGのおよそ20倍くらいになると思います。ちなみにBMPの画像の横と縦のピクセル数の限界値は16ビットの2進数で表せる最大値に1を加えた65536ピクセルあたりが制限にあったりします。十分おおきくみたこともない大きさの画像だと思います。近頃よく流通している画素数の大きいPCの画面の大きさはFullHDで1920x1080ですから、Retinaディスプレイとか4Kディスプレイでも、その倍くらいのピクセルなんで65535は相当大きいですよね。ちなみに縦65535x横65535xRGB3バイトで12884508675バイトつまり1枚あたり12GByteだったり…
ちなみにJPEGでもファイルを開いたときは、メモリ上ではBMPの形式のような状態に戻して表示されています。実はメモリ負荷的にはやばいっす。それはおいておいても、ハードディスク上に保存する際は圧縮されて保存できるというわけです。
したがって
JPEG(保存形式) → デコード → BMP RGB系(表示・画像処理) → エンコード → JPEG(保存形式)
こういうイメージが必要です。
で、JPEGエンコードとかデコードって何やってんの?ってことなんですけど、BMPのようなRGB系で管理された画像配列をエンコードしてJPEGの形式にするには以下のような処理を実施しています。何をやっているかの説明はしないのでここでは理解しなくてよいと思います。どんな感じのことをやっているかをなんとなしにしってもらえればと思っています。ここではよくやられているJPEGの書き込み時の圧縮方法についての流れを少しふれます。最近はよくやられていないJPEG圧縮手法もあと何個かくらいあります。プログレッシブとかSpatialとかロスレスとか算術符号化とかですかね。要するに以下の方法だけではないですが、と付け加えたいということです。まぁでもおおまかには以下のようなことをやっています。
- RGB系からYUV系(輝度・色差UとV)へ変換
- 16ピクセルx16ピクセルのブロックごとにYUV1~YUV12という構成要素の配列に変換する。YUV1~4が輝度情報Yに関する演算、5~8が色差Uに関する演算、9~12が色差Vに関する演算。間引きという手法で考えれば、YUV4:1:1間引きでは情報は8ピクセルx8ピクセルに集約されます。輝度情報が大事で色さ情報が間引かれても人間にはわからない。そういうことらしいです。間引きしない場合は8ピクセルx8ピクセルのブロックごとに画像全体に対して、以降の処理が逐次処理されます。
- DCT(離散コサイン変換)YUV1~12をDCT1~12という構成要素に変換。間引いている場合は要素数は12→6にまで減ります。以下同じです。
- DCT1~12を量子化してDCT_量子化1~12という構成要素に変換。このときY輝度変換テーブル64要素とUV色差変換テーブル64要素を利用。StepSizeつまりは量子化の分解能の係数をあたえるのですが、これが次の符号化で圧縮率を変化させます。
- DCT_量子化1~12という構成要素をハフマン符号化という処理を行う。これがBitStreamを生成する。このとき輝度・色差のそれぞれに対してのDC差分エンコードであるとか、AC成分エンコードを先に実施することになっている。
- ビットストリームへの各種情報付加(こんな一言でごまかすな的な内容の処理ですが…)
というような処理をしています。それで、読み込むときのデコードでは、おおよそ逆の順番でもとに戻そうとする処理をします。元のBMP情報とまったく同じ表示にはなりません。情報は欠落して人間にはあまりわからないような、ある程度似た値にごまかされて復元されます。各変換時における係数があって、その係数で圧縮率をあげると人間でも劣化がわかります。あと目の肥えた人は少しでもJPEG化されていると圧縮されているかどうかが判別できるそうです。ほんとか?
おおまかにかきましたが、項目の2つめ以降は何を言っているかさっぱりわからない人がほとんどだったかもしれません。構成要素ってDCTって?量子化とは?ハフマン符号化?まぁまぁあせらずに、そういうことは時間をかけて文章にしていかなければならないと思ってはいます。キーワードだけでも書いておけば各々で個別に調べることもできるわけで、急いでいる人はそうやって紐解いていってほしいですね。
そんなわけで、すこしづつですが、ここに書いていく予定です。
言語と開発環境へ戻る。