You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ImageProcessor.cs 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using OpenCvSharp;
  5. using System.Threading.Tasks;
  6. public class ImageProcessor : MonoBehaviour
  7. {
  8. [Header("RenderTexture")]
  9. [Tooltip("RenderTexture that will be passed to the LearningBrain.")]
  10. public RenderTexture renderTextureCropped;
  11. [Header("Debug Helper")]
  12. //[Tooltip("Reference to the MeshRenderer that will show the processed Image from Cozmo")]
  13. //public MeshRenderer processedImageRenderer;
  14. [Tooltip("Reference to the MeshRenderer that will show the processed and cropped Image from Cozmo")]
  15. public MeshRenderer processedImageRendererCropped;
  16. /// <summary>
  17. /// Center of Gravity in the cropped canny image
  18. /// </summary>
  19. public Point CenterOfGravity { get; private set; }
  20. // OpenCVSharp parameters
  21. private Mat videoSourceImage;
  22. private Mat cannyImage;
  23. private Texture2D processedTexture;
  24. private Vec3b[] videoSourceImageData;
  25. private byte[] cannyImageData;
  26. private int imWidth = 320; // Width of the camera image from the virtual cozmo
  27. private int imHeight = 240; // Height of the camera image from the virtual cozmo
  28. private int croppedImHeight = 120; // Height of the cropped camera image from the virtual cozmo
  29. private Camera textureCamera; // Virtual Cozmo camera
  30. private void Start()
  31. {
  32. // Get reference to the cozmo camera
  33. textureCamera = GetComponent<Camera>();
  34. // Set image widths and heights based on the given RenderTextures
  35. imWidth = textureCamera.targetTexture.width;
  36. imHeight = textureCamera.targetTexture.height;
  37. croppedImHeight = renderTextureCropped.height;
  38. //assign the processed targetTexture to the renderer to display the image
  39. //processedImageRenderer.material.mainTexture = textureCamera.targetTexture;
  40. processedImageRendererCropped.material.mainTexture = renderTextureCropped;
  41. // initialize video / image with given size
  42. videoSourceImage = new Mat(imHeight, imWidth, MatType.CV_8UC3);
  43. videoSourceImageData = new Vec3b[imHeight * imWidth];
  44. cannyImage = new Mat(imHeight, imWidth, MatType.CV_8UC1);
  45. cannyImageData = new byte[croppedImHeight * imWidth];
  46. }
  47. /// <summary>
  48. /// Gets called when a new image arrives from the camera this script lies on
  49. /// </summary>
  50. /// <param name="source"></param>
  51. /// <param name="destination"></param>
  52. private void OnRenderImage(RenderTexture source, RenderTexture destination)
  53. {
  54. Texture2D tex = RenderTextureToTexture2D(source);
  55. videoSourceImage = TextureToMat(tex);
  56. cannyImage = ProcessImage(videoSourceImage);
  57. cannyImage = CropImage(cannyImage);
  58. CenterOfGravityTest(cannyImage);
  59. processedTexture = MatToTexture(cannyImage);
  60. //Graphics.Blit(processedTexture, destination);
  61. Graphics.Blit(processedTexture, renderTextureCropped);
  62. }
  63. // Crop image to just see the middle of the original image
  64. private Mat CropImage(Mat image)
  65. {
  66. //cut a fourth out of the top and bottom of the image
  67. OpenCvSharp.Rect rectCroped = new OpenCvSharp.Rect(0, image.Height / 4, image.Width, image.Height / 2);
  68. Mat croppedImage = new Mat(image, rectCroped);
  69. return croppedImage;
  70. }
  71. private Texture2D RenderTextureToTexture2D(RenderTexture rTex)
  72. {
  73. Texture2D tex = new Texture2D(imWidth, imHeight, TextureFormat.RGBA32, true, true);
  74. RenderTexture.active = rTex;
  75. tex.ReadPixels(new UnityEngine.Rect(0, 0, rTex.width, rTex.height), 0, 0);
  76. tex.Apply();
  77. return tex;
  78. }
  79. // Convert Unity Texture2D object to OpenCVSharp Mat object
  80. private Mat TextureToMat(Texture2D source)
  81. {
  82. // Color32 array : r, g, b, a
  83. Color32[] c = source.GetPixels32();
  84. // Parallel for loop
  85. // convert Color32 object to Vec3b object
  86. // Vec3b is the representation of pixel for Mat
  87. Parallel.For(0, imHeight, i =>
  88. {
  89. for (var j = 0; j < imWidth; j++)
  90. {
  91. var col = c[j + i * imWidth];
  92. var vec3 = new Vec3b
  93. {
  94. Item0 = col.b,
  95. Item1 = col.g,
  96. Item2 = col.r
  97. };
  98. // set pixel to an array
  99. videoSourceImageData[j + i * imWidth] = vec3;
  100. }
  101. });
  102. // assign the Vec3b array to Mat
  103. Mat tmpMat = new Mat(imHeight, imWidth, MatType.CV_8UC3);
  104. tmpMat.SetArray(0, 0, videoSourceImageData);
  105. return tmpMat;
  106. }
  107. // Simple example of canny edge detect
  108. private Mat ProcessImage(Mat _image)
  109. {
  110. Mat cannyImg = new Mat();
  111. Cv2.Canny(_image, cannyImg, 100, 100);
  112. return cannyImg;
  113. }
  114. // Convert OpenCVSharp Mat object to Unity Texture2D object
  115. private Texture2D MatToTexture(Mat mat)
  116. {
  117. // cannyImageData is byte array, because canny image is grayscale
  118. mat.GetArray(0, 0, cannyImageData);
  119. // create Color32 array that can be assigned to Texture2D directly
  120. Color32[] c = new Color32[croppedImHeight * imWidth];
  121. // parallel for loop
  122. Parallel.For(0, croppedImHeight, i =>
  123. {
  124. for (var j = 0; j < imWidth; j++)
  125. {
  126. byte vec = cannyImageData[j + i * imWidth];
  127. var color32 = new Color32
  128. {
  129. r = vec,
  130. g = vec,
  131. b = vec,
  132. a = 0
  133. };
  134. c[j + i * imWidth] = color32;
  135. }
  136. });
  137. Texture2D texture = new Texture2D(imWidth, croppedImHeight, TextureFormat.RGBA32, true, true);
  138. texture.SetPixels32(c);
  139. // to update the texture, OpenGL manner
  140. texture.Apply();
  141. return texture;
  142. }
  143. private void CenterOfGravityTest(Mat processedImage)
  144. {
  145. // find moments of the image
  146. Moments m = new Moments(processedImage, true);
  147. CenterOfGravity = new Point(m.M10 / m.M00, m.M01 / m.M00);
  148. #if UNITY_EDITOR
  149. // show the image with a point mark at the centroid
  150. Cv2.Circle(processedImage, CenterOfGravity, 5, new Scalar(128, 0, 0), -1);
  151. Cv2.Flip(processedImage, processedImage, FlipMode.X);
  152. Cv2.ImShow("Image with center", processedImage);
  153. #endif
  154. }
  155. }