こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

幾何学変換

Windowsアプリケーションでボタン一つで画像を45度回転させるプログラムを作りたいのですが、プログラムがよく分かりません。どなたか教えていただけないでしょうか。あと、回転変化後の画像には線形補間法(バイリニア法)を使っての補間処理をして表示させたいのですがよろしいでしょうか。言語はC#です。

自分で色々プログラム組んでるのですがなかなか出来ないです。今組んでるプログラムを実行すると変な風に実行されます。

組んでる途中のプログラム↓↓
private Color[,] SpinImage(Color[,] colImage)
{
int iHeight = colImage.GetLength(0);
int iWidth = colImage.GetLength(1);

//Console.WriteLine(iHeight + "\t" + iWidth);

double X = 45.0 * Math.PI / 180.0;
int iHeight2 = (int)(iWidth * Math.Cos(X) + iHeight * Math.Sin(X));
int iWidth2 = (int)(iWidth * Math.Sin(X) + iHeight * Math.Cos(X));
Color[,] colImage2 = new Color[iHeight2, iWidth2];
//Console.WriteLine(iHeight +"\t" +iWidth);

for (int j = 0; j < iHeight-1; j++)
{
for (int i = 0; i < iWidth-1; i++)
{
int m = (int)(i * Math.Cos(X) + j * Math.Sin(X));
int n = (int)(-1 * i * Math.Sin(X) + j * Math.Cos(X)) + 100;
int iRed = 0;
int iGreen = 0;
int iBlue = 0;

// Console.WriteLine("y:"+ j +"\t i:"+i+"\t m:" +m + "\tn:" + n);

iRed = colImage[j, i].R;
iGreen = colImage[j, i].G;
iBlue = colImage[j, i].B;

#region a
//if ((j >= 0) && (j < iWidth) && (i >= 0) && (i < iHeight))
//{
// iRed = colImage[i, j].R;
// iGreen = colImage[i, j].G;
// iBlue = colImage[i, j].B;

// colImage[m, n] = Color.FromArgb(iRed, iGreen, iBlue);
//}
//else
//{
// colImage[m, n] = Color.FromArgb(0, 0, 0);
//}
#endregion

if (m < iHeight && n >= 0)
{
colImage2[m, n] = Color.FromArgb(iRed, iGreen, iBlue);

}
}
}

return colImage2;
}

投稿日時 - 2010-02-06 21:18:32

QNo.5654648

すぐに回答ほしいです

質問者が選んだベストアンサー

「変な風に実行されます」というのだけでは、どういう状況下わからないのですが、
それは、所々に黒いポツポツが出るとか、そういった状況ですか?
そうだとしたら、この手のプログラムでの典型的なミスですね。

質問者さんのコードは、
「変換元の各画素」について、「変換後の座標」を算出して、「その座標位置に書き込む」
この方法では「変換後の画像の全ての画素に書き込まれるとはかぎりません」ので、結果として、所々書き込まれずに黒いままの画素が出てきたりします。


ループを逆にして、
「変換先の各画素」についてループ処理して、
「変換前の座標」を算出(変換が45度回転なら、-45度回転した座標を求める)して、
「その座標の画素を取ってきて書き込む」
ようにすれば、そういった歯抜けはなくなります。

動作確認はしてませんが、質問者さんのコードは修正すると
---
int iOffsetX1 = iWidth/2
int iOffsetY1 = iHeight/2;
int iOffsetX2 = iWidth2/2
int iOffsetY2 = iHeight2/2;

for (int m = 0; m < iHeight2; m++)
{
for (int n = 0; n < iWidth2; n++)
{
int i = (int)((n-iOffsetX2) * Math.Cos(X) - (m-iOffsetY2) * Math.Sin(X)) + iOffsetX1;
int j = (int)((n-iOffsetX2) * Math.Sin(X) + (m-iOffsetY2) * Math.Cos(X)) + iOffsetY1;
int iRed = colImage[j, i].R;
int iGreen = colImage[j, i].G;
int iBlue = colImage[j, i].B;
if (i >= 0 && i < iWidth && j > 0 && j < iHeight) {
colImage2[m, n] = Color.FromArgb(iRed, iGreen, iBlue);
}
}
}
---
こんな感じになるかと。

投稿日時 - 2010-02-06 22:50:45

補足

回答ありがとうございます。

>>「変な風に実行されます」というのだけでは、どういう状況下わからないのですが、それは、所々に黒いポツポツが出るとか、そういった状況ですか?
>>そうだとしたら、この手のプログラムでの典型的なミスですね。

これ何ですけど、実行すると画像に白い点が入り、画像の一部が欠けてしまいます。

それと自分の書いたプログラムのfor文から回答者様のプログラムを書き換えて実行してみたのですが、iRedの所で「インデックスが配列の境界外です」って表示されプログラムが停止しました。

投稿日時 - 2010-02-06 23:07:57

ANo.1

このQ&Aは役に立ちましたか?

2人が「このQ&Aが役に立った」と投票しています

回答(3)

ANo.3

> 回転した画像がPictureボックス内にキッチリと入らずハミ出て回転した画像が欠けてしまいます。

はみ出るのが1~2ドットだとしたら、
---
int iHeight2 = (int)(iWidth * Math.Cos(X) + iHeight * Math.Sin(X));
int iWidth2 = (int)(iWidth * Math.Sin(X) + iHeight * Math.Cos(X));
---
ここで、整数にしている(切り捨てている)から、結果の画像サイズが小さくなってしまっているからでしょう。切り上げる必要があります。

投稿日時 - 2010-02-07 01:55:34

ANo.2

> iRedの所で「インデックスが配列の境界外です」って表示されプログラムが停止しました。
すみません、ifの配置を間違えました。
iRed~iBlueの代入はifの中で、

---
if (i >= 0 && i < iWidth && j > 0 && j < iHeight) {
int iRed = colImage[j, i].R;
int iGreen = colImage[j, i].G;
int iBlue = colImage[j, i].B;
colImage2[m, n] = Color.FromArgb(iRed, iGreen, iBlue);
}
---

といった感じになります。
…ていうか、これは、
---
if (i >= 0 && i < iWidth && j > 0 && j < iHeight) {
colImage2[m, n] = colImage[j, i];
}
---
で十分ですね。

投稿日時 - 2010-02-06 23:41:43

補足

ありがとうございます。

何度も申し訳ありません。

実行できたのですが、回転した画像がPictureボックス内にキッチリと入らずハミ出て回転した画像が欠けてしまいます。どうすればよろしいでしょうか。

投稿日時 - 2010-02-06 23:54:06

あなたにオススメの質問