2D画像配列をスケーリングするための最良の方法は何ですか?たとえば、1024 x 2048バイトの画像があり、各バイトがピクセルであるとします。各ピクセルは0から255までのグレースケールレベルです。この画像を任意の係数でスケーリングして、新しい画像を取得できるようにしたいと思います。したがって、画像を0.68倍に拡大縮小すると、サイズが0.68 * 1024 x 0.68 * 2048の新しい画像が得られるはずです。一部のピクセルは互いに折りたたまれます。また、たとえば3.15倍に拡大縮小すると、ピクセルが複製された大きな画像が得られます。それで、これを達成するための最良の方法は何ですか?
次に、0〜360度(0〜2Pi)の範囲で、画像を任意の角度で回転できるようにしたいと思います。回転後の画像のトリミングは問題ではありません。これを行うための最良の方法は何でしょうか?
それを実現する「簡単な」方法はありません。スケーリングと回転の両方が "trivial" procesis。 ではありません
2Dイメージングライブラリ用にGoogleで検索してください。 Magick ++ はdivideandconquer.seポイントとしてのアイデアですが、他にもあります。
画像を拡大縮小および回転する方法はたくさんあります。スケーリングする最も簡単な方法は次のとおりです。
dest[dx,dy] = src[dx*src_width/dest_width,dy*src_height/dest_height]
しかし、これはサイズを大きくするとブロック効果を生み出し、サイズを小さくすると細部が失われます。より見栄えの良い結果を生成する方法があります。たとえば、 双一次フィルタリング です。
回転の場合、srcピクセルの位置は 回転行列 を使用して計算できます。
sx,sy = M(dx,dy)
ここで、Mは、宛先ピクセルをソース画像にマップする行列です。繰り返しますが、ブロックのない結果を生成するには、補間を行う必要があります。
しかし、画像処理の数学に興味がない場合は、利用できるライブラリがたくさんあります。
あなたがしているのは、入力ポイントのセットを出力ポイントのセットにマッピングすることです。問題の最初の部分は、サイズ変更または回転のマッピングを決定することです。 2番目の部分は、ピクセル境界上に正確に存在しないポイントを処理することです。
サイズ変更のマッピングは簡単です。
x' = x * (width' / width)
y' = y * (height' / height)
回転のマッピングは少し難しいだけです。
x' = x * cos(a) + y * sin(a)
y' = y * cos(a) - x * sin(a)
グリッドから外れているピクセルの値を決定する手法は、補間と呼ばれます。そのようなアルゴリズムは数多くあり、速度と最終的な画質の範囲が広くなっています。品質/時間の昇順でそれらのいくつかは、最近傍、双一次、双三次、およびSincフィルターです。
あなたは自分で汚い仕事をしたいですか、それとも ImageMagick あなたのためにそれをすることができますか?
ピクセルの複製または破棄は、結果がピクセル化とギザギザを示すため、最良の方法または画像のサイズ変更ではありません。最良の結果を得るには、画像をリサンプルする必要があります。これにより、結果の画像の外観がはるかに滑らかになります。バイリニア、バイキュービック、ランツォなど、リサンプリングの方法はたくさんあります。
WxWidgetsの ResampleBicubic 関数を見てください。グレースケールだけでなく、あらゆる種類の画像で機能しますが、ニーズに合わせて調整できるはずです。次に、リサンプリングコード VirtualDubから もあります。 Google Codesearchは、より関連性の高いコードを明らかにする可能性があります。
編集:リンクはプレビューでは問題なく表示されますが、投稿すると壊れます。これは奇妙です。 Googleコード検索に移動し、「wxwidgetsresamplebicubic」と「virtualdubresample」をそれぞれクエリして、同じ結果を取得します。
まだ触れられていないので、OpenCVには画像の拡大縮小や回転の機能だけでなく、他にも膨大な数のユーティリティがあることを指摘しておきます。質問に関係のない多くの機能が含まれている可能性がありますが、この種のライブラリのセットアップと使用は非常に簡単です。
このような変換を手動で実装することもできますが、スケーリングと回転の単純なアプローチでは、通常、詳細が大幅に失われます。
OpenCVを使用すると、スケーリングは次のように実行できます。
float scaleFactor = 0.68f;
cv::Mat original = cv::imread(path);
cv::Mat scaled;
cv::resize(original, scaled, cv::Size(0, 0), scaleFactor, scaleFactor, cv::INTER_LANCZOS4);
cv::imwrite("new_image.jpg", scaled);
これにより、ランツォシュ補間を使用して画像が0.68分の1に縮小されます。
私はローテーションにあまり詳しくありませんが、OpenCV Webサイトのチュートリアルの1つから、関連する部分まで編集した例の一部を次に示します。 (オリジナルにはスキューと翻訳も含まれていました...)
/// Compute a rotation matrix with respect to the center of the image
Point center = Point(original.size().width / 2, original.size().height / 2);
double angle = -50.0;
double scale = 0.6;
/// Get the rotation matrix with the specifications above
Mat rot_mat( 2, 3, CV_32FC1 );
rot_mat = getRotationMatrix2D(center, angle, scale);
/// Rotate the image
Mat rotated_image;
warpAffine(src, rotated_image, rot_mat, src.size());
CxImageは、画像を処理するための無料のライブラリであり、必要な処理を実行できます。些細なこと以外は個人的に使ったことはありませんが、何度もお勧めしているのを見てきました。
Intel Performance Primitives をチェックしてください。以前に使用したことがありますが、x86でほぼ最適なパフォーマンスが得られます。さまざまなアルゴリズムで遊ぶことができるテストプログラムもあります。
point scaling(point p,float sx,float sy) {
point s;
int c[1][3];
int a[1][3]={p.x,p.y,1};
int b[3][3]={sx,0,0,0,sy,0,0,0,1};
multmat(a,b,c);
s.x=c[0][0];
s.y=c[0][1];
return s;
}
CxImageのサイズ変更メソッドは奇妙な結果を生成します。 Resample関数とResample2関数を使用して、使用可能なすべての内挿法のバリエーションを使用し、同じ結果を得ました。たとえば、白い色で塗りつぶされた1024 x768の画像のサイズを802x582に変更してみてください。画像に色の付いたピクセルがあることがわかります。 異なる 白に!これを確認できます。サイズ変更された画像をWindowsペイントで開き、黒い色で塗りつぶしてみます。結果はきっとあなたを楽しませるでしょう。