###前提・実現したいこと
Unityのポストエフェクトとして、レンダリングした結果に射影変換を適用させようとしています。
メインカメラにアタッチしたコンポーネントのOnRenderImage
にて下記のシェーダを適用させています。
###発生している問題・エラーメッセージ
上記の処理を行っても、変換結果がOpenCvのそれと異なってしまい、悩んでおります。
皆さまのお力をお借りしたく、どうぞよろしくお願いいたします。
###該当のソースコード
Shader "Hidden/MappingShader" { Properties { _MainTex ("Texture", 2D) = "white" {} _translate ("Translate", Float) = 0 } SubShader { // No culling or depth Cull Off ZWrite Off ZTest Always Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" uniform float4x4 _mv; struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; v2f vert (appdata v) { float4 vec = v.vertex; float x = vec.x; float y = vec.y; float z = vec.z; float w = vec.w; float px = x * _mv[0][0] + y * _mv[0][1] + z * _mv[0][2] + w * _mv[0][3]; float py = x * _mv[1][0] + y * _mv[1][1] + z * _mv[1][2] + w * _mv[1][3]; float pz = x * _mv[2][0] + y * _mv[2][1] + z * _mv[2][2] + w * _mv[2][3]; float pw = x * _mv[3][0] + y * _mv[3][1] + z * _mv[3][2] + w * _mv[3][3]; vec.x = px; vec.y = py; vec.z = pz; vec.w = pw; v2f o; // o.vertex = mul(_mv, v.vertex); o.vertex = vec; o.vertex = UnityObjectToClipPos(o.vertex); o.uv = v.uv; return o; } sampler2D _MainTex; fixed4 frag (v2f i) : SV_Target { fixed4 col = tex2D(_MainTex, i.uv); return col; } ENDCG } } }
private Material m_Material; private Matrix4x4 matrix; void Awake() { Shader shader = Shader.Find("Hidden/MappingShader"); m_Material = new Material(shader); } void OnRenderImage(RenderTexture source, RenderTexture destination) { Graphics.Blit(source, destination, m_Material); } void Update() { Material.SetMatrix("_mv", matrix); }
###試したこと
行列の転置を試したり計算式を一から書いてみましたが、もっと別なところに原因があるのではないかと考えています。
他に思い当たる原因などありましたら、ご教授いただければ幸いです。
###補足情報(言語/FW/ツール等のバージョンなど)
Unity 5.6.1
macOS Sierra
# 行列のサンプルです。この変換行列での実行結果の画像を添付します。 0.74035 0.16225 0.00000 0.00069 0.13807 0.89541 0.00000 0.00028 0.00000 0.00000 1.00000 0.00000 149.00000 105.00000 0.00000 1.00000
###追記
OpenCv版の座標変換は、下記のような処理を行っています。
この行列を4x4に変換したものが、最初のサンプルの行列になっています。
正確に言うと(すこしややこしいですが)openframeworks
の ofxQuadWarp
というアドオンを利用し、getMatrix()
にて得られる変換行列(4x4)を利用しています。
こちらは内部的には(精度の問題で)cvFindHomography
を利用しているようですが、転置行列になるだけで結果はほぼ変わりません。
// openframework上で動かしています。 ofImage image; image.load("in.jpg"); cv::Mat cvInImage = cv::Mat(image.getHeight(), image.getWidth(), CV_8UC3, image.getPixels().getData()); cv::Mat cvOutImage = cvInImage.clone(); vector<cv::Point2f> src; vector<cv::Point2f> dst; for(int i = 0; i < 4; i ++){ // 変換前の座標配列:入力画像の左上、右上、右下、左下の座標 src.push_back(cv::Point2f(warper.srcPoints[i].x, warper.srcPoints[i].y)); // 変換後の座標配列:最初の画像の左(OpenCvの表記)の白い四角の四隅にある黄色い点の座標(左上、右上、右下、左下の順) dst.push_back(cv::Point2f(warper.dstPoints[i].x, warper.dstPoints[i].y)); } cv::Mat warp_matrix = cv::getPerspectiveTransform(src, dst); cv::warpPerspective(cvInImage, cvOutImage, warp_matrix, cvInImage.size()); ofImage outImage; outImage.allocate(image.getHeight(), image.getWidth(), image.getImageType()); outImage.setFromPixels(cvOutImage.ptr(), cvOutImage.cols, cvOutImage.rows, image.getImageType(), false); outImage.save("out.jpg"); cout << warp_matrix << endl;
// OpenCv版の変換行列の出力結果 [0.7403473533105349, 0.1380676946623043, 148.9999999999996; 0.1622461658588558, 0.895410834059531, 104.9999999999999; 0.0006888663351174518, 0.0002752964241302562, 1]
###追記2
warperに設定している変換前座標と変換後座標です。これで得られる行列は先述と同値です。
// SourceRectの設定値:画面のフルスクリーンサイズを設定しています。 // setSourceRect(ofRectangle(0, 0, ofGetScreenWidth(), ofGetScreenHeight())); srcPoint[0] : 0, 0, 0 srcPoint[1] : 1440, 0, 0 srcPoint[2] : 1440, 900, 0 srcPoint[3] : 0, 900, 0 dstPoint[0] : 149, 105, 0 dstPoint[1] : 610, 170, 0 dstPoint[2] : 598, 511, 0 dstPoint[3] : 219, 730, 0
回答1件
あなたの回答
tips
プレビュー