【C++】OpenCVによる画像幾何変換:リサイズ、回転、平行移動の実装テクニック
C++とOpenCVを用いることで、画像のリサイズ、回転、平行移動、反転、アフィン変換、射影変換など多彩な幾何変換が可能です。
直感的な関数呼び出しで処理が行えるため、画像の位置調整や補正がシンプルに実装でき、プロジェクトの効率向上につながります。
リサイズ
変更目的と利用シーン
画像サイズの調整意図
画像サイズの調整は、さまざまなデバイスや処理環境に適したサイズに変更するために行います。
たとえば、ディスプレイの解像度に合わせる場合や、ネットワークを介して素早く画像を転送する場合、さらに画像処理アルゴリズムの計算負荷を軽減するために調整することが挙げられます。
また、ディープラーニングの入力サイズに合わせる際など、用途に合わせた画像の大きさが求められるケースが多数存在します。
用途別のリサイズケース
用途に応じた調整例として、下記のケースが考えられます。
- ウェブ表示:読み込み速度の向上と帯域幅削減のため、画像サイズの縮小を行います
- スマートフォンアプリ:各デバイスの画面サイズに合わせた画像サイズを用意する必要があります
- 機械学習:モデル入力用として、固定サイズに合わせるためリサイズ処理を実施します
OpenCVのresize関数活用法
cv::resize
関数は、画像サイズの変更をシンプルに実装できる便利な関数です。
引数に元画像、出力先の画像、目標サイズを指定するだけで、簡単にリサイズ処理を実現できます。
補間方式の選択(最近傍補間、線形補間、立体補間)
リサイズ時に最も影響を及ぼす要因のひとつが補間方式です。
以下の方式が一般的に使用されます。
INTER_NEAREST
:計算が非常に高速ですが、画像がギザギザになることがありますINTER_LINEAR
:標準的な補間方式で、スムーズな見た目が得られますINTER_CUBIC
:高品質な補間が求められる場合に使用しますが、計算負荷が大きめです
用途に合わせた補間方式の選択が、見た目のクオリティや処理速度に大きく影響します。
アスペクト比維持の工夫
アスペクト比を維持したままリサイズする場合、元画像の幅と高さの比率を計算し、どちらかの辺を目標サイズに合わせた上で、もう一方を連動して変更する必要があります。
たとえば、元画像の幅がW
、高さがH
の場合、目標の幅をW_target
に合わせるなら、
という計算で新しい高さを求めることができます。
調整パラメータの設定
目標サイズの算出方法
リサイズ処理では、目標サイズの算出が大切です。
画像の比率や用途に応じて、適切な幅と高さを決めます。
計算例としては、固定のスケール係数を掛ける方法や、指定した1辺の値からもう1辺を算出する方法が挙げられます。
画質劣化防止のポイント
リサイズに伴い、画質の劣化が発生する可能性があります。
これを防ぐためには、
- 適切な補間方式の選定
- アスペクト比を維持する計算
- 過度なリサイズを避けること
などに注意します。
上記のポイントを意識することで、元画像に近い品質の画像を維持できます。
画像の回転
回転処理の基礎
回転行列の構造と役割
画像の回転処理は、回転行列と呼ばれる数学的なツールを利用します。
回転行列は、
という形を持ち、角度
これにより、指定した角度だけ画像を回転させることが可能となります。
回転行列には、通常の回転に加えて平行移動を組み合わせることができ、画像の中心を基準に回転させるための補正も行います。
中心点設定の重要性
画像回転の際、中心点の設定が非常に重要です。
中心点を画像の中心に設定することで、バランス良く回転処理が適用され、画像の一部が切れたり、予期せぬ黒枠が生じたりする可能性が低くなります。
適切な中心点の設定は、操作性の向上に寄与します。
cv::getRotationMatrix2Dの利用
OpenCVのcv::getRotationMatrix2D
関数を使うと、指定した中心点、角度、スケールパラメータで簡単に回転行列が作成できます。
下記のサンプルコードは、画像を45度回転させる例です。
#include <opencv2/opencv.hpp>
#include <iostream>
int main() {
// 画像の読み込み
cv::Mat image = cv::imread("image.jpg");
if (image.empty()) {
std::cerr << "画像の読み込みに失敗しました" << std::endl;
return -1;
}
// 画像の中心を計算
cv::Point2f center(image.cols / 2.0, image.rows / 2.0);
// 回転角度と拡大率を設定
double angle = 45.0; // 45度回転
double scale = 1.0; // 拡大率1.0(サイズ変更なし)
// 回転行列を作成
cv::Mat rotationMatrix = cv::getRotationMatrix2D(center, angle, scale);
// 回転適用後の画像保存用Matを作成
cv::Mat rotatedImage;
// 画像サイズは元画像に合わせるが、場合によりサイズを調整する必要があります
cv::warpAffine(image, rotatedImage, rotationMatrix, image.size());
// 画像を表示
cv::imshow("Rotated Image", rotatedImage);
cv::waitKey(0);
return 0;
}
(ウィンドウに45度回転した画像が表示されます)

上記のコードでは、cv::getRotationMatrix2D
関数を利用して回転行列を作成し、cv::warpAffine
関数で回転処理を実施しています。
コード内のコメントにもある通り、中心点の設定、角度、スケール設定など、パラメータの調整が大切です。
パラメータ(角度・スケール)の調整方法
角度とスケールは、ユーザーが自由に設定できます。
角度を正の値に設定すると反時計回りに回転し、負の値にすると時計回りに回転します。
また、スケールパラメータは、画像の大きさを拡大または縮小する際に活用され、1.0を基準に変更可能です。
好きな効果を出すために、これらのパラメータを柔軟に調整すると良いです。
数学的背景の理解
回転行列の数学的背景を理解することで、回転処理の動作をより深く把握できます。
具体的には、
数学的な知識があると、処理結果のトラブルシューティングや、カスタム変換の実装が容易になります。
cv::warpAffineによる回転適用
出力画像サイズの決定
cv::warpAffine
を利用する場合、出力画像のサイズを適切に設定する必要があります。
基本的には元画像のcv::Size
を指定しますが、回転により画像が枠からはみ出してしまう場合は、出力サイズを十分に確保するか、ROI(Region Of Interest)を用いることで対処できます。
補間処理のポイント
補間方式は、回転後の画像の品質に大きく影響します。
cv::warpAffine
では、前述のINTER_LINEAR
やINTER_CUBIC
などの補間方式を指定することができます。
適切な補間モードを選択することで、画像のギザギザや不自然さを軽減できるため、目的に合わせた設定が推奨されます。
回転処理の実装上の注意事項
誤差発生の防止策
回転処理では、整数と浮動小数点演算の相互変換に起因する誤差が発生することがあります。
数値の丸めや補間処理に注意しながら実装することで、予期せぬアーティファクトが現れるのを抑えられるため、処理前後の画像サイズやピクセル位置の確認を行うと良いです。
高速処理への工夫
多くの画像をリアルタイムで処理する場合、回転演算の高速化が求められます。
- ROIを利用して必要な部分のみ処理する
- ハードウェアアクセラレーションを活用する
- マルチスレッド処理の実装を検討する
などの工夫により、パフォーマンス向上が期待できます。
平行移動
平行移動の理論と意義
行列表現による変換原理
平行移動は、画像全体または一部の座標に一定の値を加えることで実現します。
行列表現では、変換行列は下記の形を取ります。
ここで、
シンプルな行列計算で平行移動を実現できるため、処理負荷が低いのが魅力です。
移動量計算の基本
平行移動で重要なのは、どの方向にどれだけ移動させるかを正確に計算することです。
たとえば、画像の中心を基準として移動する場合や、特定のオブジェクトの位置合わせを行う場合、移動量の計算を正確にすることで、スムーズな変換が可能になります。
平行移動行列の設定手法
cv::Matを用いた行列生成
cv::Mat
を利用して、平行移動行列を簡単に作成できます。
下記のコードは、水平方向に100ピクセル、垂直方向に50ピクセル移動させる例です。
#include <opencv2/opencv.hpp>
#include <iostream>
int main() {
// 画像の読み込み
cv::Mat image = cv::imread("image.jpg");
if (image.empty()) {
std::cerr << "画像の読み込みに失敗しました" << std::endl;
return -1;
}
// 平行移動行列の作成(100px右、50px下に移動)
cv::Mat translationMatrix = (cv::Mat_<double>(2, 3) << 1, 0, 100,
0, 1, 50);
// 変換後の画像
cv::Mat translatedImage;
cv::warpAffine(image, translatedImage, translationMatrix, image.size());
// 結果の表示
cv::imshow("Translated Image", translatedImage);
cv::waitKey(0);
return 0;
}
(ウィンドウに平行移動後の画像が表示されます)

このサンプルコードでは、簡単な行列生成の方法と、cv::warpAffine
による平行移動の手順を示しています。
簡潔ながら、平行移動の基本的な実装方法が理解しやすくなっています。
方向性と距離の調整
移動量として設定する
たとえば、特定のオブジェクトの位置を中央に寄せたい場合、オブジェクトの位置を検出して適切な移動量を計算し、行列に反映する工夫が求められます。
実際のアプリケーションでは、ユーザー入力や自動検出のアルゴリズムと連携させることで、柔軟に移動量を調整することが可能です。
cv::warpAffineによる平行移動適用
画像境界の取り扱い
平行移動を行うと、画像の一部が表示領域から外れてしまう場合があります。
こうしたとき、背景色や透過処理で隙間を補完する方法が考えられます。
詳細は、cv::warpAffine
のパラメータにおける境界補完方法(BORDER_CONSTANTやBORDER_REPLICATEなど)を試すことで、対応可能です。
連続処理時の注意点
平行移動が連続して適用される場合、各処理間での座標の累積計算に注意が必要です。
連続処理を行う際は、各変換後の画像の位置情報を確認しながら実装すると、変換後に不自然な位置ずれが発生するのを防げます。
その他の幾何変換
アフィン変換
3点選択による変換行列作成
アフィン変換は、平行移動、回転、スケーリングを同時に行う変換手法です。
基本的には、元画像から任意の3点と、変換後の画像上で対応する3点を選び、その対応関係から変換行列を計算します。
この方法は、手動による画像補正や、簡易的な透視補正など、柔軟な変換処理が必要な場合に便利です。
利用シーンと調整方法
アフィン変換は、たとえば傾いた画像の補正や、特定の領域を抜き出す際に利用されます。
用途に合わせて、
- 選択する3点の位置
- 変換後の画像サイズ
などを調整する必要があります。
ユーザーの操作に応じたインタラクティブな調整も可能なため、デジタル画像編集の現場でよく利用されます。
射影変換
四隅座標設定の考え方
射影変換(透視変換)は、より複雑な変換が求められる場合に利用できます。
画像の4隅の座標を指定することで、元画像と変換後の画像間の対応関係を定めることができます。
計算では、行列の解を求める必要があるため、4点の正確な位置設定が重要です。
たとえば、建物の写真で遠近法を補正する際などに活用できます。
高度な位置補正の活用
複数の視点から撮影された画像や、自然現象を撮影した画像の補正において、射影変換の活用が進んでいます。
幾何学的な理解に基づいた各点の設定と、最適化手法を組み合わせることで、高度な位置補正が実現され、歪みなく画像を再構成することが可能です。
各変換手法の比較検討
利用目的別の適用基準
リサイズ、回転、平行移動、アフィン変換、射影変換など、各幾何変換手法にはそれぞれ特性があり、利用目的によって適用基準が異なります。
例えば、単純なサイズ調整はリサイズ処理で十分ですが、複数の変換を連続して適用する場合はアフィン変換や射影変換が有効です。
用途ごとに処理内容や計算負荷、精度などを比較検討することで、最適な変換手法を選べます。
処理パフォーマンスの検証
画像処理の現場では、変換処理における計算負荷も考慮が必要です。
各手法ごとに、処理時間やメモリ使用量を計測し、パフォーマンスと品質のバランスを検証することが推奨されます。
特にリアルタイム処理が求められるアプリケーションでは、この検証が非常に重要なポイントとなります。
まとめ
ここまで、リサイズ、画像の回転、平行移動、さらにその他の幾何変換に関する各処理手法や実装の注意点についてお伝えしました。
それぞれの変換技法は、目的や用途に応じた柔軟な対応が可能で、適切なパラメータ設定やアルゴリズムの選択が品質向上とパフォーマンス最適化に寄与します。
読者の環境や利用シーンに合わせた実装方法を検討していただく参考になれば幸いです。