当前位置:   article > 正文

Intel RealSense T265鱼眼相机图像获取并矫正畸变(Unity)_realsense相机畸形矫正

realsense相机畸形矫正

1.添加RsDevice:

2.设置开启鱼眼相机:

 

3.新建RsStreamTextureRendererFisheye.cs和Fisheye.shader

  1. using Intel.RealSense;
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using System.Runtime.InteropServices;
  6. using System.Threading;
  7. using UnityEngine;
  8. using UnityEngine.Events;
  9. public class RsStreamTextureRendererFisheye : MonoBehaviour
  10. {
  11. private static TextureFormat Convert(Format lrsFormat)
  12. {
  13. switch (lrsFormat)
  14. {
  15. case Format.Z16: return TextureFormat.R16;
  16. case Format.Disparity16: return TextureFormat.R16;
  17. case Format.Rgb8: return TextureFormat.RGB24;
  18. case Format.Rgba8: return TextureFormat.RGBA32;
  19. case Format.Bgra8: return TextureFormat.BGRA32;
  20. case Format.Y8: return TextureFormat.Alpha8;
  21. case Format.Y16: return TextureFormat.R16;
  22. case Format.Raw16: return TextureFormat.R16;
  23. case Format.Raw8: return TextureFormat.Alpha8;
  24. case Format.Disparity32: return TextureFormat.RFloat;
  25. case Format.Yuyv:
  26. case Format.Bgr8:
  27. case Format.Raw10:
  28. case Format.Xyz32f:
  29. case Format.Uyvy:
  30. case Format.MotionRaw:
  31. case Format.MotionXyz32f:
  32. case Format.GpioRaw:
  33. case Format.Any:
  34. default:
  35. throw new ArgumentException(string.Format("librealsense format: {0}, is not supported by Unity", lrsFormat));
  36. }
  37. }
  38. private static int BPP(TextureFormat format)
  39. {
  40. switch (format)
  41. {
  42. case TextureFormat.ARGB32:
  43. case TextureFormat.BGRA32:
  44. case TextureFormat.RGBA32:
  45. return 32;
  46. case TextureFormat.RGB24:
  47. return 24;
  48. case TextureFormat.R16:
  49. return 16;
  50. case TextureFormat.R8:
  51. case TextureFormat.Alpha8:
  52. return 8;
  53. default:
  54. throw new ArgumentException("unsupported format {0}", format.ToString());
  55. }
  56. }
  57. public RsFrameProvider Source;
  58. [System.Serializable]
  59. public class TextureEvent : UnityEvent<Texture> { }
  60. public Stream _stream;
  61. public Format _format;
  62. public int _streamIndex;
  63. public FilterMode filterMode = FilterMode.Point;
  64. protected Texture2D texture;
  65. public ComputeShader shader;
  66. public Texture2D uvmap;
  67. [Delayed]
  68. public float fov = 90;
  69. [Space]
  70. public TextureEvent textureBinding;
  71. FrameQueue q;
  72. Predicate<Frame> matcher;
  73. void Start()
  74. {
  75. Source.OnStart += OnStartStreaming;
  76. Source.OnStop += OnStopStreaming;
  77. }
  78. void OnDestroy()
  79. {
  80. if (texture != null)
  81. {
  82. Destroy(texture);
  83. texture = null;
  84. }
  85. if (q != null)
  86. {
  87. q.Dispose();
  88. }
  89. }
  90. protected void OnStopStreaming()
  91. {
  92. Source.OnNewSample -= OnNewSample;
  93. if (q != null)
  94. {
  95. q.Dispose();
  96. q = null;
  97. }
  98. }
  99. public void OnStartStreaming(PipelineProfile activeProfile)
  100. {
  101. q = new FrameQueue(1);
  102. matcher = new Predicate<Frame>(Matches);
  103. Source.OnNewSample += OnNewSample;
  104. }
  105. private bool Matches(Frame f)
  106. {
  107. using (var p = f.Profile)
  108. return p.Stream == _stream && p.Format == _format && p.Index == _streamIndex;
  109. }
  110. void OnNewSample(Frame frame)
  111. {
  112. try
  113. {
  114. if (frame.IsComposite)
  115. {
  116. using (var fs = frame.As<FrameSet>())
  117. using (var f = fs.FirstOrDefault(matcher))
  118. {
  119. if (f != null)
  120. q.Enqueue(f);
  121. return;
  122. }
  123. }
  124. if (!matcher(frame))
  125. return;
  126. using (frame)
  127. {
  128. q.Enqueue(frame);
  129. }
  130. }
  131. catch (Exception e)
  132. {
  133. Debug.LogException(e);
  134. // throw;
  135. }
  136. }
  137. bool HasTextureConflict(VideoFrame vf)
  138. {
  139. return !texture ||
  140. texture.width != vf.Width ||
  141. texture.height != vf.Height ||
  142. BPP(texture.format) != vf.BitsPerPixel;
  143. }
  144. protected void LateUpdate()
  145. {
  146. if (q != null)
  147. {
  148. VideoFrame frame;
  149. if (q.PollForFrame<VideoFrame>(out frame))
  150. using (frame)
  151. ProcessFrame(frame);
  152. }
  153. }
  154. private void ProcessFrame(VideoFrame frame)
  155. {
  156. if (HasTextureConflict(frame))
  157. {
  158. if (texture != null)
  159. {
  160. Destroy(texture);
  161. }
  162. using (var p = frame.Profile)
  163. {
  164. bool linear = (QualitySettings.activeColorSpace != ColorSpace.Linear)
  165. || (p.Stream != Stream.Color && p.Stream != Stream.Infrared);
  166. texture = new Texture2D(frame.Width, frame.Height, Convert(p.Format), false, linear)
  167. {
  168. wrapMode = TextureWrapMode.Clamp,
  169. filterMode = filterMode
  170. };
  171. }
  172. textureBinding.Invoke(texture);
  173. }
  174. texture.LoadRawTextureData(frame.Data, frame.Stride * frame.Height);
  175. texture.Apply();
  176. if (uvmap == null)
  177. {
  178. CreateUvMap(frame);
  179. Shader.SetGlobalTexture("_UVMap", uvmap);
  180. }
  181. }
  182. static Vector2Int Undistort(float x, float y, ref Intrinsics intrin, int W, int H, float fov)
  183. {
  184. var uv = new Vector2(x / W * intrin.width, y / H * intrin.height);
  185. // see https://github.com/IntelRealSense/librealsense/blob/master/include/librealsense2/rsutil.h
  186. uv.x = (uv.x - intrin.ppx) / intrin.fx;
  187. uv.y = (uv.y - intrin.ppy) / intrin.fy;
  188. float rd = uv.magnitude;
  189. float theta = rd;
  190. float theta2 = rd * rd;
  191. for (int i = 0; i < 4; i++)
  192. {
  193. float f = theta * (1 + theta2 * (intrin.coeffs[0] + theta2 * (intrin.coeffs[1] + theta2 * (intrin.coeffs[2] + theta2 * intrin.coeffs[3])))) - rd;
  194. float df = 1 + theta2 * (3 * intrin.coeffs[0] + theta2 * (5 * intrin.coeffs[1] + theta2 * (7 * intrin.coeffs[2] + 9 * theta2 * intrin.coeffs[3])));
  195. theta -= f / df;
  196. theta2 = theta * theta;
  197. }
  198. float r = Mathf.Tan(theta);
  199. uv *= r / rd;
  200. // see https://github.com/IntelRealSense/librealsense/blob/master/wrappers/python/examples/t265_stereo.py
  201. float stereo_fov_rad = fov * (Mathf.PI / 180);
  202. float stereo_height_px = H;
  203. float stereo_focal_px = stereo_height_px / 2 / Mathf.Tan(stereo_fov_rad / 2);
  204. uv = uv * stereo_focal_px + Vector2.one * (stereo_height_px - 1f) / 2f;
  205. uv += Vector2.one * 0.5f;
  206. return Vector2Int.RoundToInt(uv);
  207. }
  208. private void CreateUvMap(VideoFrame frame)
  209. {
  210. const int W = 848, H = 800;
  211. if (uvmap)
  212. DestroyImmediate(uvmap);
  213. uvmap = new Texture2D(W, H, TextureFormat.RGFloat, false, true)
  214. {
  215. filterMode = FilterMode.Point,
  216. wrapMode = TextureWrapMode.Clamp
  217. };
  218. using (var profile = frame.Profile.As<VideoStreamProfile>())
  219. {
  220. var intrinsics = profile.GetIntrinsics();
  221. Debug.Log(intrinsics);
  222. var uvs = new Vector2[H, W];
  223. // see https://github.com/IntelRealSense/librealsense/blob/master/src/proc/align.cpp
  224. for (int y = 0; y < H; ++y)
  225. {
  226. for (int x = 0; x < W; ++x)
  227. {
  228. var uv = Undistort(x - 0.5f, y - 0.5f, ref intrinsics, W, H, fov);
  229. var uv1 = Undistort(x + 0.5f, y + 0.5f, ref intrinsics, W, H, fov);
  230. if (uv.x < 0 || uv.y < 0 || uv1.x >= W || uv1.y >= H)
  231. continue;
  232. float u = (float)x / W;
  233. float v = (float)y / H;
  234. for (int j = uv.y; j <= uv1.y; ++j)
  235. {
  236. for (int i = uv.x; i <= uv1.x; ++i)
  237. {
  238. uvs[j, i].Set(u, v);
  239. }
  240. }
  241. }
  242. }
  243. var h = GCHandle.Alloc(uvs, GCHandleType.Pinned);
  244. uvmap.LoadRawTextureData(h.AddrOfPinnedObject(), W * H * 2 * sizeof(float));
  245. uvmap.Apply();
  246. h.Free();
  247. }
  248. }
  249. }

Fisheye.shader:

  1. Shader "Custom/Fisheye" {
  2. Properties {
  3. _MainTex ("MainTex", 2D) = "white" {}
  4. _Gamma ("Gamma", float) = 0.45
  5. }
  6. SubShader {
  7. Tags { "QUEUE"="Transparent" "IGNOREPROJECTOR"="true" "RenderType"="Transparent" "PreviewType"="Plane" }
  8. Pass {
  9. ZWrite Off
  10. Cull Off
  11. Fog { Mode Off }
  12. ColorMask RGB
  13. CGPROGRAM
  14. #pragma vertex vert_img
  15. #pragma fragment frag
  16. #pragma target 3.0
  17. #pragma glsl
  18. #include "UnityCG.cginc"
  19. sampler2D _MainTex;
  20. uniform sampler2D _UVMap;
  21. float _Gamma;
  22. half4 frag (v2f_img pix) : SV_Target
  23. {
  24. float2 uv = pix.uv;
  25. float2 uvmap = tex2D(_UVMap, uv).xy;
  26. float Y = pow(tex2D(_MainTex, uvmap).a, _Gamma);
  27. return float4(Y.rrr, 1);
  28. }
  29. ENDCG
  30. }
  31. }
  32. FallBack Off
  33. }

 4.新建Raw Image以便显示相机图像:

设置材质球和着色器:

5.绑定相机:

这样,就可以显示正常相机图像,下面看看矫正前后对比:

矫正前:

矫正后:

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/59606
推荐阅读
相关标签
  

闽ICP备14008679号