WPFだけどRotateTransformを使わずに画像の回転表示をしてみた
処理2元のピクセル座標を回転行列で変換しただけ
処理3処理2の位置調整版
処理4回転後のピクセル座標を回転行列の逆行列で変換
処理5処理4+ピクセルの値を線形補間でギザギザをなくした
処理6処理5のカラー版
使う関数は
変換前座標が(x,y)のとき求める変換後座標を(x',y')とすると
x' = cos * x -sin * y
y' = sin * x +cos * y
らしい
回転行列の逆行列を使った関数は
x' = cos * x +sin * y
y' = -sin * x +cos * y
らしい
これらを使ってエクセルで見てみる
エクセルには三角関数のCOSとSINも用意されている
引数は角度じゃなくでラジアンってのを使う
これもRADIANSっていう関数で変換できる
だいたい(2.6,1.5)になったのを逆行列で30度回転してみたら
.NETにもCOSとSINの関数は用意されている、けど角度をラジアンにするのはなさそうなので用意
角度をラジアンに変換するのは
ラジアン = 角度/180*パイ
みたいなので
private double Radians角度をラジアン(float kakudo)
{
return kakudo / 180 * Math.PI;
}
を用意して
座標を指定角度で変換する関数
private Point GetRotate回転座標(Point p, float kakudo)
{
double radians = Radians角度をラジアン(kakudo);
return new Point(
Math.Cos(radians) * p.X - Math.Sin(radians) * p.Y,
Math.Sin(radians) * p.X + Math.Cos(radians) * p.Y);
}
↑の逆行列版が
private Point GetRotate逆回転座標(Point p, float kakudo)
{
double radians = Radians角度をラジアン(kakudo);
return new Point(
Math.Cos(radians) * p.X + Math.Sin(radians) * p.Y,
-Math.Sin(radians) * p.X + Math.Cos(radians) * p.Y);
}
これが最初の状態で
処理2で30度回転
変な模様ができているのはピクセルに色の値が入っていないからそう見えるだけ
半透明の部分が範囲外になるところ
処理2のコード
元画像座標を回転+位置調整なし
WriteableBitmapのCopyPixelsを使ってピクセルごとの色を指定していくいつもの方法
wbが元画像から作ったWriteableBitmap、nWbが変換後画像用のWriteableBitmap
変数の頭にnが付いているのが変換後画像用
351行目のRect.Containsは指定したPoint座標がRect内に入っていたらTrueを返すメソッド、これを使って範囲外になったピクセルは無視するようにしている
処理3は処理2の改変
穴開き状態はまだそのまま
全部表示されるように赤枠の四角形を取得する必要があるので
そのサイズと位置を取得して調整する必要があるので
それを取得するのを用意、JustぴったりサイズRect
その4点から上下左右を取得が317行目からの4行
上下左右から幅と高さを計算して
Rectを作成して返す
処理3のコード
278行目で回転後画像がぴったり収まるRectを取得、これからWriteableBitmapを作成、これで表示する場所は整った
変換後座標をそのままだとマイナスだったり大きすぎたりするので調整する
調整する値はぴったりRectの左上座標をマイナスにした値
処理4
処理3までは元画像のピクセルの座標を回転行列を使って回転後の座標を取得していた
元画像のピクセル座標→回転行列で変換→回転後の座標
これを逆にした感じで
回転後画像のピクセル座標→回転行列の逆行列で変換→元画像での座標
こうすると回転後の全てのピクセルを計算するから穴開きがなくなる
x,yのループ数が変換後のサイズ分になる
半透明赤の部分を変換しても元画像にはない座標になるので
それを弾いているのが249行目から252行目
この処理4で画像の回転は完成
処理5
回転とは関係ない
変換後座標が外周1ピクセルだった場合はめんどくさかったので補間なしにした
処理6
これも回転とは関係ない
ここまで来て気づいたのが画像の四角が削れているのは
変換後座標の小数点以下を切り捨てて処理をしているのと
ぴったりサイズがぴったりじゃないのかなあ
あとは線形補間でギザギザをなくしたけど最外周部のギザギザが目立つ
これは最外周部の補間をしなかったせいかな
なんにしてもきれいにするには丁寧に計算する必要があるみたい
処理5のコード
WPFならRotateTransformを使えばいいんだけど
実際にできると楽しい
この穴が空いて模様に見えるのも面白い
今回の行列もこのまえの分散、中央値に続いて理系の高校でしか教えていないものだった…とはいっても画像の回転だけなら行列はあんまり関係ない感じかなあ、理解はできなかったけど変換の関数があったからそれを使ってできた
今はインターネットがあるから簡単に調べることができるのが素晴らしい
情報を公開してくださっている方々も素晴らしい
コード全部
参照したところ
アフィン変換 画像処理ソリューション
http://imagingsolution.blog107.fc2.com/blog-entry-284.html
アフィン変換っていうのと回転行列はこちらから
逆行列を理解してみる - デジタル・デザイン・ラボラトリーな日々回転行列の逆行列はこちらから
http://yaju3d.hatenablog.jp/entry/2013/07/14/133031
逆行列を使わないと穴が空く説明もここがわかりやすかった
大学1年生と再履生のための線形代数入門行列についてはこちら
https://oguemon.com/topic/study/linear-algebra/
【すぐわかる線形代数】11.掃き出し法と逆行列 - YouTube動画
https://www.youtube.com/watch?v=tFKaHfSB5hM
関連記事
2018/4/17
線形補間(バイリニア法)
バイリニア法で画像の拡大縮小 ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/15464617.html