はじめに
デジタルカメラなどで写真を撮影するとき、誤って傾けてしまい、水平でなくなってしまうことがあります。そこで本稿では、補正画像を見ながら、0.5°刻みで画像を回転して補正する方法を紹介します。
- 完成版のアプレットを見る
対象読者
画像処理に興味を持ち、特に撮影した写真の補正に関心のある人。
必要な環境
J2SE 5.0を使っていますが、これより古いバージョンでも、本稿のコードをコンパイルし実行することができます。ただし、添付のコンパイル済みアプレットの実行には、J2SE Runtime Environment 5.0が必要です。
概要
デジタルカメラで写真を撮影するとき、液晶モニターが見にくくて、水平を十分確認できないことがあります。そのような状況下で撮影した写真に対して、傾斜を補正する方法を紹介します。有償無償の既存画像ソフトは、90、180、270度などの一定の角度しか回転できないものが多く、数度程度の補正が可能なソフトでも、周辺部の考慮がされていません。
本稿では、0.5度単位で左右に回転ができ、周辺効果を無くして、画像サイズを元のままに保てるように、自動的に原画像を拡大する機能を付加しました。
画像の回転と拡大
画像の回転や拡大縮小、平行移動などは「アフィン変換」と呼ばれ、Java APIにその処理を行うAffineTransform
クラスがあります。また、類似の機能がGraphics2D
クラスにもあります。しかし、実際に試してみたところ、回転に際してジャギーが発生し、写真画像への応用には不適と判断しました。
従って、既存のAPIを使用しないで、回転と拡大を同時に実行できるプログラムを作成しました。
画像の回転方法
原画像を回転させるには、回転後の補正画像の座標を想定してスキャンし、補正画像のそれぞれの座標が原画像のどの場所に相当するかを計算します。
図1に示すように、回転後の補正画像の座標(画像の中心から測った)から見たP点の位置を(i, j)とし、回転前の原画像の座標から見た位置を(xx, yy)とすると、図および式で示すような関係があります。図1の例では、回転前の画像から見て時計方向に角度θだけ画像を回転させていますが、θはマイナスをとることもできます。
画像の拡大方法
回転させた補正画像を、原画像と同じサイズそのまま表示すると、画像に欠陥部分が生じます。これを、図2を使用して説明します。
図2の左の図で、黒は回転後の補正画像の範囲、赤は回転する前の原画像を示します。分かりやすく説明すると、「原画像を回転する」ということは、「回転後の補正画像を正しく配置し」、「補正前の原画像をあらかじめ傾斜させて置き」、原画像を補正画像にそのままコピーすることと考えられます。
これによると、倍率を同じにして原画像をθだけ回転すると、回転後の画像には、原画像データのない部分が生じることが分かります。緑色で示した部分は、欠如がなく、かつ原画像のサイズと相似ですので、緑色の範囲を黒の範囲に拡大する操作を行えば、欠けが生じないことになります。
拡大倍率の計算は、図2の右の図を参照します。右の図は、左の図の一部分を取り出したもので、左の図の赤い画像の対角線の長さの半分を1とし、緑の画像範囲の対角線の半分をXとしています。このXを求めて、逆数を取れば、必要な拡大倍率zoomが得られます。
ただし、画像を拡大して表示することは、原画像の座標位置を縮小しながら描画することなので、原画像の座標位置計算に当たっては、zoomで割り算をします(Xで乗算することと同じです)。
回転角θには、正(時計方向)と負(反時計方向)がありますが、図2の左の図から想像できるように、左右を反転しただけですので、θの絶対値を取ればよく、式の形は変わりません。
最終的な座標変換の式
以上の結果から、最終的に使用する座標変換の式は、下記の通りになります。ただし、iとjは回転後の補正画像のピクセルの座標位置で、対応する原画像のピクセルの座標位置をxxとyy(一般には整数値とならない)、右下がり方向の回転角をθ、画像の縦横比で決まる角度をαとします。
画像データの補間
図3に示すように、座標変換の式により原画像の座標(xx, yy)を求めると、xx、yyは一般には整数ではなく実数となります。整数以外の座標には画像データ(ピクセル値)が存在ませんので、座標(xx, yy)の画像データを求めるには、data_0、data_1などの周辺データから補間によって求める必要があります。ただし、xはxxより負の無限大に近い整数、yはyyより負の無限大に近い整数とし、dx = xx - x、dy = yy - yとなります。dxとdyは1未満の実数値です。求める補間値をinter[k]とすると(kは色を表し、0は赤、1は緑、2は青を意味します)、まずAとBを線形補間で求め、AとBをさらに線形補間して求めます。