DOBON.NET DOBON.NETプログラミング掲示板過去ログ

BMPファイルの画像を回転して保存する方法

環境/言語:[WinXP、VB.NET]
分類:[.NET]

bmpファイルの画像を、
任意の点を中心に、任意の角度回転し、
元のbmpファイルの大きさで,
bmpファイルとして保存したいのですが,
どのようにすればよいでしょうか。

ポイントとして、
image、bitmapクラスの使用方法と
回転について、
があると思いますが、どうもよくわかりません。

関連の疑問点で、
・ピクチャーボックスに表示する必要があるか。
・各点座標計算をする必要があるのか。
(photshopなどでは任意角度の場合時間かかっているよう)
・角度が90度、180などの場合は、速い方法があるのでしょうか。
(ビットマップオブジェクトのRotateFilipメソッドなどの利用で)

http://dobon.net/vb/dotnet/graphics/transform.htmlを参考に
グローバル座標の変換でピクチャーボックスに表示させたものを保存しようとしたがうまくいきません。

'(10,10)を中心に30度回転する
Dim Fname1 As String="D:\test1.bmp"
Dim Fname2 As String="D:\test2.bmp"

Dim g As Graphics = PictureBox1.CreateGraphics()
Dim img As Image = Image.FromFile(Fname1)

g.ResetTransform()
g.TranslateTransform(10, 10)
g.ResetTransform()
g.RotateTransform(30.0F)
g.ResetTransform()
g.TranslateTransform(-10, -10)

g.DrawImage(img, 0, 0)
PictureBox1.Image.Save(Fname2)

g.Dispose()
img.Dispose()

また、http://dobon.net/vb/dotnet/graphics/skewing.htmlを参考に
表示位置を傾けたものを保存しようとしたがこれもうまくいきません。

グラフィックでは初歩的なことかと大変恐縮ですが、
どなたか御教唆頂けますでしょうか。
■No3062に返信(C_tenさんの記事)
> bmpファイルの画像を、
> 任意の点を中心に、任意の角度回転し、
> 元のbmpファイルの大きさで,
> bmpファイルとして保存したいのですが,
> どのようにすればよいでしょうか。
>
> ポイントとして、
> image、bitmapクラスの使用方法と
> 回転について、
> があると思いますが、どうもよくわかりません。
>
> 関連の疑問点で、
> ・ピクチャーボックスに表示する必要があるか。
> ・各点座標計算をする必要があるのか。
> (photshopなどでは任意角度の場合時間かかっているよう)
> ・角度が90度、180などの場合は、速い方法があるのでしょうか。
> (ビットマップオブジェクトのRotateFilipメソッドなどの利用で)
>
> http://dobon.net/vb/dotnet/graphics/transform.htmlを参考に
> グローバル座標の変換でピクチャーボックスに表示させたものを保存しようとしたがうまくいきません。
>
> '(10,10)を中心に30度回転する
> Dim Fname1 As String="D:\test1.bmp"
> Dim Fname2 As String="D:\test2.bmp"
>
> Dim g As Graphics = PictureBox1.CreateGraphics()
> Dim img As Image = Image.FromFile(Fname1)
>
> g.ResetTransform()
> g.TranslateTransform(10, 10)
> g.ResetTransform()
> g.RotateTransform(30.0F)
> g.ResetTransform()
> g.TranslateTransform(-10, -10)
>
> g.DrawImage(img, 0, 0)
> PictureBox1.Image.Save(Fname2)
>
> g.Dispose()
> img.Dispose()
>
> また、http://dobon.net/vb/dotnet/graphics/skewing.htmlを参考に
> 表示位置を傾けたものを保存しようとしたがこれもうまくいきません。
>
> グラフィックでは初歩的なことかと大変恐縮ですが、
> どなたか御教唆頂けますでしょうか。

グラフィックについて詳しくありませんが、とりあえずお答えします。
座標とカラーを保持する構造体を作って、
ビットマップ上のすべての座標とそれぞれのカラーを取得して、
先の構造体に配列として保持しますよね。
そうしたら、それぞれの構造体の座標を回転した位置に書き換える
という方法がいいと思います。
P.S. 値を保持するだけなら、クラスより断然構造体です。
   構造体は値型で、参照型ではないので、オーバーヘッドがかかりません。
補足しておきます。
たとえば、四角いものを、斜めに回転させると、
高さや横幅の最大値が大きくなりますよね、
ですから、先の構造体すべてを調べて、一番外側のポイントを取得して、
そのサイズの画像として保存する必要がありますね。
最大値を取得するほうほうは簡単です。
たとえばGazou構造体で、Tateプロパティ(int)とYokoプロパティ(int)
があるとします、

int tate_saidai = Gazou[0].Tate;
int yoko_saidai = Gazou[0].Tate;

for(int i = 0; i < Gazou.Length; i++)
{
if(Gazou[i].Tate < Gazou[i + 1].Tate)
{
tate_saidai = Gazou[i + 1].Tate;
}
if(Gazou[i].Yoko < Gazou[i + 1].Yoko)
{
yoko_saidai = Gazou[i + 1].Yoko;
}
}

こんな感じでどうでしょう。
■No3062に返信(C_tenさんの記事)
コードを拝見させていただくと、PictureBoxのGraphicsに描画したものが、PictureBox.Imageプロパティの画像に描画されると勘違いされているようですが、これは間違いです。ですので、
PictureBox1.Image.Save
としても意味がありません。

・画像を動的に作成する
http://dobon.net/vb/dotnet/graphics/createimage.html

を参考にして、新しく作成したBitmapオブジェクトなどに描画して保存したらどうでしょうか。

> 関連の疑問点で、
> ・ピクチャーボックスに表示する必要があるか。
> ・各点座標計算をする必要があるのか。
> (photshopなどでは任意角度の場合時間かかっているよう)
> ・角度が90度、180などの場合は、速い方法があるのでしょうか。
> (ビットマップオブジェクトのRotateFilipメソッドなどの利用で)

これらの問題に関しては、私のサイトが参考になると思います。
C_tenです.
りょうさん,管理人さん早速の回答ありがとうございます.

まず,bmpデータの座標計算を行って,できることを確認しました.
あとは,りょうさんのいわれるように,データの構造体化,画像領域拡大などですね.
以下の方法だとやはり荒くなるので,補完等をする必要があると思いますが,
これもコード書き込まないといけないですよね.
用途として,計算時間はかかっても良いが,高精度でコードが簡単なもの,
ということで,もう一度Tipsの方を参考にさせて頂きます.

以下冗長ですが,書いてみたコードです.----------------------
 '画像の中心周りに,30度回転する

Dim Fname1, Fname2 As String
Fname1 = "C:\test1.bmp"
Fname2 = "C:\test2.bmp"
'元の画像--------------------------------------------------
Dim bmp1 As Bitmap = Image.FromFile(Fname1)
Dim nx, ny As Integer
nx = bmp1.Width
ny = bmp1.Height
'処理画像--------------------------------------------------
Dim bmp2 As Bitmap = Image.FromFile(Fname1)
Dim c1, c2, c3 As Integer
Dim x, y, tmpX, tmpY, newX, newY As Integer
'並進移動量--------------------------------------------------
Dim movX, movY As Integer
movX = Int(bmp1.Width / 2)
movY = Int(bmp1.Height / 2)
'回転量--------------------------------------------------
Dim dAngle, dDegree, dCos, dSin As Double
dDegree = 30
dAngle = dDegree * Math.PI / 180
dCos = Math.Cos(dAngle)
dSin = Math.Sin(dAngle)
'--------------------------------------------------
For y = 0 To ny - 1
For x = 0 To nx - 1
'代入
tmpX = x
tmpY = y
'並進移動(回転中心移動)
tmpX = tmpX - movX
tmpY = tmpY - movY
'回転
newX = tmpX * dCos - tmpY * dSin
newY = tmpX * dSin + tmpY * dCos
'並進移動(元に戻す)
newX = newX + movX
newY = newY + movY
'量子化
newX = Int(newX)
newY = Int(newY)
If 0 < newX And newX < nx - 1 then
If 0 < newY And newY < ny - 1 Then
c1 = bmp1.GetPixel(newX, newY).R
c2 = bmp1.GetPixel(newX, newY).G
c3 = bmp1.GetPixel(newX, newY).B
bmp2.SetPixel(x, y, Color.FromArgb(c1, c2, c3))
Else
bmp2.SetPixel(x, y, Color.FromArgb(0, 0, 0))
End If
End If
Next
Next
'処理画像の保存--------------------------------------------------
bmp2.Save(Fname2)

以上
下記のコードで、とりあえず目的を達成しましたので報告します。
(でも、image,Graphicsなどの違いがわかりにくいです。。)

角度が90,180,270度の場合
Dim bmp As Bitmap = New Bitmap(Image.FromFile(Fname1))
bmp.RotateFlip(RotateFlipType.Rotate90FlipNone) bmp.Save(Fname2, System.Drawing.Imaging.ImageFormat.Bmp)
bmp.Dispose()

任意角度の場合((10,20)を中心に30度回転して保存)

Dim myAngle As Single = 30
Dim myX As Integer = 10
Dim myY As Integer = 20

'元の画像
Dim img As Bitmap = New Bitmap(Image.FromFile(Fname1))

'ベースのビットマップ作成
Dim d_img As New Bitmap(img.Width, img.Height)
Dim d_g As Graphics = Graphics.FromImage(d_img)
d_g.FillRectangle(Brushes.Black, d_g.VisibleClipBounds)

'Graphicsオブジェクトの作成
Dim DD As Image = d_img
Dim g As Graphics = Graphics.FromImage(DD)

'回転操作
g.ResetTransform()
g.TranslateTransform(myX, myY)
g.RotateTransform(myAngle)
g.TranslateTransform(-myX, -myY)
g.DrawImage(img, 0, 0)

DD.Save(Fname2)

'オブジェクトの破棄------------------------------------
d_g.Dispose()
img.Dispose()
g.Dispose()
以上
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板