質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

13763閲覧

C++言語で画像回転を掛けたい

TEC_S

総合スコア79

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2016/05/14 08:17

編集2016/05/14 09:54

お世話になります。
C言語での画像回転を行おうと思いますが、うまく行きません。
アドバイスを宜しくお願いします。

Vectorへ画像を入力して来て、回転を掛け(取り合えず90°)書き込むプログラムです。
outBufferには、800x1000の画像が正常に入って来ている事は、出力して確認しています。

画像中心点を中心とした回転アルゴリズムとしてネット上から下記を
探してきたのですが、x2,y2が(0,0)の時は、(0,800)が入ってくると考えていますが、計算結果が違います。

C++

1x1 = (((x2 - outCenX) * iCos - (y2 - outCenY) * iSin) >> 10) + centerX; 2y1 = (((x2 - outCenX) * iSin + (y2 - outCenY) * iCos) >> 10) + centerY;

使用方法が違うのでしょうか・・・。
下記、コード抜粋します。

C++

1//image rotation. 2int centerX, centerY; //入力画像中心点 3int outCenX, outCenY; //出力画像中心点 4 5int inWidht, inHeight; //画像サイズ(入力画像). 6int otWidht, otHeight; //画像サイズ(出力画像). 7double A ; //回転角度 8double p = 3.14159265358979323846; //円周率 9 10int iSin, iCos; //Sin Cos 最適化. 11int x_in, y_in; //入力画像の座標. 12int x_ot, y_ot; //出力画像の座標. 13 14A = 90.0; //取り急ぎ90. 15 16//三角関数の最適化(事前計算しておく) 17double valSin = sin(A); 18double valCos = cos(A); 19iSin = (int)(valSin * 1024); 20iCos = (int)(valCos * 1024); 21 22//入力画像サイズ 23x_in = 800; 24y_in = 1000; 25 26//出力画像の大きさ計算 27x_ot = 1000; 28y_ot = 800; 29//x_ot = (int)( fabs(x_in * cos(A)) + fabs(y_in * sin(A)) + 0.5 ); 30//y_ot = (int)( fabs(x_in * sin(A)) + fabs(y_in * cos(A)) + 0.5 ); 31 32//中心位置 33centerX = x_in / 2; 34centerY = y_in / 2; 35outCenX = x_ot / 2; 36outCenY = y_ot / 2; 37 38// 回転処理 39std::vector<char> outRotatBuffer; 40int x1, y1; 41for(int y2 = 0; y2 < y_ot; y2++) 42{ 43 for(int x2 = 0; x2 < x_ot * 2; x2++) 44 { 45 // 回転位置計算(移動先の座標から元画像の座標計算) 46 x1 = (((x2 - outCenX) * iCos - (y2 - outCenY) * iSin) >> 10) + centerX; 47 y1 = (((x2 - outCenX) * iSin + (y2 - outCenY) * iCos) >> 10) + centerY; 48 49 50 51 try{ 52 outRotatBuffer.push_back( outBuffer.at( (x1 + y1 ) * 2 ) ); 53 }catch(std::exception e){ 54 error = true; 55 } 56 } 57}

宜しくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

こんにちは。

A = 90.0; //取り急ぎ90.

//三角関数の最適化(事前計算しておく)
double valSin = sin(A);
double valCos = cos(A);

三角関数に与える角度の単位はラジアンが多いです。
ここで使われているsin(), cos()がどのライブラリのものか分かりませんが、もし、math.hのものであればラジアンです。度をラジアンへ変換するにはrad=度*π/180;で計算できますので、

double valSin = sin(A*3.14/180);

のようにして計算すると、恐らく意図した結果になると思いますよ。

なお、回転の向きには注意下さい。角度正方向が時計回りか反時計周りにより、回転行列の式が多少変わります。

ところで、outBufferはどのような型でしょうか? プログラムを見ると1次元vectorのようですが、どのようにして「画像」を保存しているのでしょうか? x, y座標を平均してインデックスとしているので「画像」を保管できる形式ではない印象を受けます。

ところで、C言語でstd:vector<>は使えません。提示されているプログラムはC++言語です。


【追記】
TEC_SNさんはどのような形式で画像をメモリ上で表現するか決めることに失敗しているのだと思います。画像をメモリ中で表現する方法を明確にしましょう。

①2次元の情報を1次元配列で表現する方法はいくつか有ります。どのようにされていますか?
②また、画像1ピクセルを表現する方法も多数あります。どのようにされてますか?

①として良く用いられるのは、行の幅を固定し、次々と行をつなげていく方法です。
メモリ中では、[第1行のデータ列][第2行のデータ列]...[第Height行のデータ列]のように並ぶことになります。(第Height行→第1行の順にする場合とか、行と列を逆にすることも考えられます。)

②は色々ありますが、もし、0~255のグレイスケール画像でしたら、単純に1バイトで1ピクセルを表現する場合が多いです。(カラーの場合はRGBの3バイトを使うことが多いです。)

もし、outRotatBufferとoutBuffer、および、画像表示用のフリーソウトウェアが上記に記述した①②の方式を使っている場合であれば下記でできる筈です。

outRotatBuffer.push_back( outBuffer.at( x1 + y1*x_in );

しかし、

outRotatBuffer.push_back( outBuffer.at( (x1 + ( y1 * 800 ) ) * 2 ) );

で1ピクセル毎に縦線が入った画像にならないのでしたら、上記①②の想定とは異なっていると思います。
①②について明確にする必要が有ります。この式の * 2は何のために設けているのでしょうか? その辺にヒントがありそうな気がします。

投稿2016/05/14 08:44

編集2016/05/16 01:37
Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TEC_S

2016/05/14 10:15

ご指摘、ありがとうございます。 rad=度*π/180; にて意図したとおりの結果になりました。 また、C⇒C++へ修正させて頂きました。大変失礼しました。 vectorは、Bufferの代わりの様に扱っています。 ゆくゆくは、色々なサイズのイメージデータを扱いたい為です。 アドバイスを元に、修正しましたが、、画像が正常に出力されません。 vectorへの代入を下記に変えてみましたが・・・入れ方が悪いのでしょうか?? outRotatBuffer.push_back( outBuffer.at( (x1 + ( y1 * 800 ) ) * 2 ) ); 申し訳ありませんが、もう少し、アドバイスを頂ければと思います。
Chironian

2016/05/14 12:31

> 画像が正常に出力されません。 outRotatBufferもoutBufferも1次元データを記録しているようにしか見えません。 画像は2次元データですので、どのようにして画像が正常に出力されないことを確認されたのでしょうか? 私が画像を確認する際は、ビットマップ・ファイルへ出力して、paint.exe等で表示してみることが多いのです。TEC_SNさんはどのようにされてますか?
TEC_S

2016/05/16 01:03

入力は、ヘッダー無しのRawデータになります。 出力画像もRawデータになりますので、Rawデータを見る様のフリーソフト(ImageJ)にて、画像出力を確認しています。
Chironian

2016/05/16 01:24

なるほど。 ということは、outBufferはそのフリーソフトで画像として表示できるけど、outRotatBufferに対して同じことをしても崩れた画像しか表示されないということですね。 回答へ追記します。
TEC_S

2016/05/16 03:06

はい。そういうことです。 outRotatBufferへ入れ替えると、画像になって来ません。
TEC_S

2016/05/16 11:43 編集

追記に気づくのが遅れました。申し訳ありません。 unsigned shortにて、符号無し、8bitのvcctorに格納しています。 対象画像は、ヘッダーの無い、16bitグレースケールです。 2bitずつの書き込みになる為に、*2としています。 宜しくお願い致します。 >修正しました。 すみません。認識が間違っていました。 unsigned charにて、8bitのchar形vectorに格納しています。  ↓ unsigned short
TEC_S

2016/05/17 02:57 編集

取り急ぎ、配列を使っての回転にて解決とさせて頂きます。 ご指摘通り、バッファのデータ形式の違いが分かっていなかったのと、 回転時の自分の考え方が違っていたので迷走していました。。 一次元での計算も出来そうですので、回答とさせて頂きました。 お時間を頂き、ありがとうございました。
guest

0

ベストアンサー

std::vector<char> outRotatBuffer に点の座標(x,y) を複数格納し、それを描画したいのですか?
ならば何故、vectorの要素がcharなのですか?

投稿2016/05/14 23:33

episteme

総合スコア16614

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TEC_S

2016/05/16 10:12 編集

ご回答ありがとうございます。 unsigned charだと、書き込み時にエラーになってしまうので、charにしていました。 そこで、vectorをあきらめ、配列を使用しての回転に方向転換しましたが・・・ やはり、正常な画像が出ません。 対象のデータは、16bitグレースケールのヘッダーの無い画像ファイルになります。 ouBuffer/imBufferは「unsigned short」です。 int x1, y1; for(int y2 = 0; y2 < y_ot ; y2++) { for(int x2 = 0; x2 <= x_ot * 2; x2++) { //回転座標の計算. x1 = (((x2 - outCenX) * iCos - (y2 - outCenY) * iSin) >> 10) + centerX; y1 = (((x2 - outCenX) * iSin + (y2 - outCenY) * iCos) >> 10) + centerY; ouBuffer[y2][x2] = imBuffer[y1][x1]; } } y1 , x1 には意図した値が入って来ている為、何処が駄目なのかが、分かりません。 ご確認、宜しくお願いします。 【更新】 申し訳ありません。 ブレイクをかけるようの値を削除しました。 追加で、コードを修正しましたが、変わらずでした。 ouBuffer[y2][x2 * 2] = imBuffer[y1][x1 * 2];     ↓ ouBuffer[y2][x2] = imBuffer[y1][x1];
episteme

2016/05/17 01:11

座標回転せずに ouBuffer[y1][x1] = imBuffer[y1][x1]; ならちゃんと描画されます?
TEC_S

2016/05/17 02:49

回転を掛けなけば、ちゃんと表示されました。 また、下記にて、画像が表示されました。 ouBuffer[x2][y2] = imBuffer[y1][x1]; どうやら、配列に入れる順番に問題があったようです。 ouBuffer[1000][800] (y , x) imBuffer[800][1000] 後は、、一次元での計算で出せれば目的達成ですので、地道に行こうと思います。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問