├── AllowUnsafeCode.png ├── Assets ├── NatDeviceWithOpenCVForUnityExample.meta └── NatDeviceWithOpenCVForUnityExample │ ├── IntegrationWithNatShareExample.meta │ ├── IntegrationWithNatShareExample │ ├── ComicFilter.cs │ ├── ComicFilter.cs.meta │ ├── IntegrationWithNatShareExample.cs │ ├── IntegrationWithNatShareExample.cs.meta │ ├── IntegrationWithNatShareExample.unity │ └── IntegrationWithNatShareExample.unity.meta │ ├── NatDeviceCamPreviewOnlyExample.meta │ ├── NatDeviceCamPreviewOnlyExample │ ├── NatDeviceCamPreviewOnlyExample.cs │ ├── NatDeviceCamPreviewOnlyExample.cs.meta │ ├── NatDeviceCamPreviewOnlyExample.unity │ └── NatDeviceCamPreviewOnlyExample.unity.meta │ ├── NatDeviceCamPreviewToMatExample.meta │ ├── NatDeviceCamPreviewToMatExample │ ├── NatDeviceCamPreviewToMatExample.cs │ ├── NatDeviceCamPreviewToMatExample.cs.meta │ ├── NatDeviceCamPreviewToMatExample.unity │ └── NatDeviceCamPreviewToMatExample.unity.meta │ ├── NatDeviceCamPreviewToMatHelperExample.meta │ ├── NatDeviceCamPreviewToMatHelperExample │ ├── ExampleMaterial.mat │ ├── ExampleMaterial.mat.meta │ ├── NatDeviceCamPreviewToMatHelperExample.cs │ ├── NatDeviceCamPreviewToMatHelperExample.cs.meta │ ├── NatDeviceCamPreviewToMatHelperExample.unity │ └── NatDeviceCamPreviewToMatHelperExample.unity.meta │ ├── NatDeviceWithOpenCVForUnityExample.cs │ ├── NatDeviceWithOpenCVForUnityExample.cs.meta │ ├── NatDeviceWithOpenCVForUnityExample.unity │ ├── NatDeviceWithOpenCVForUnityExample.unity.meta │ ├── Scripts.meta │ ├── Scripts │ ├── ExampleBase.cs │ ├── ExampleBase.cs.meta │ ├── ICameraSource.cs │ ├── ICameraSource.cs.meta │ ├── NatDeviceCamSource.cs │ ├── NatDeviceCamSource.cs.meta │ ├── Utils.meta │ ├── Utils │ │ ├── FpsMonitor.cs │ │ ├── FpsMonitor.cs.meta │ │ ├── NatDeviceCamPreviewToMatHelper.cs │ │ ├── NatDeviceCamPreviewToMatHelper.cs.meta │ │ ├── RuntimePermissionHelper.cs │ │ └── RuntimePermissionHelper.cs.meta │ ├── WebCamMatSource.cs │ ├── WebCamMatSource.cs.meta │ ├── WebCamSource.cs │ └── WebCamSource.cs.meta │ ├── ShowLicense.cs │ ├── ShowLicense.cs.meta │ ├── ShowLicense.unity │ ├── ShowLicense.unity.meta │ ├── ShowSystemInfo.cs │ ├── ShowSystemInfo.cs.meta │ ├── ShowSystemInfo.unity │ ├── ShowSystemInfo.unity.meta │ ├── WebCamTextureOnlyExample.meta │ ├── WebCamTextureOnlyExample │ ├── WebCamTextureOnlyExample.cs │ ├── WebCamTextureOnlyExample.cs.meta │ ├── WebCamTextureOnlyExample.unity │ └── WebCamTextureOnlyExample.unity.meta │ ├── WebCamTextureToMatExample.meta │ ├── WebCamTextureToMatExample │ ├── WebCamTextureToMatExample.cs │ ├── WebCamTextureToMatExample.cs.meta │ ├── WebCamTextureToMatExample.unity │ └── WebCamTextureToMatExample.unity.meta │ ├── link.xml │ └── link.xml.meta ├── README.md ├── Use_UnsafeCode.png ├── screenshot01.jpg ├── screenshot02.jpg └── screenshot03.jpg /AllowUnsafeCode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnoxSoftware/NatDeviceWithOpenCVForUnityExample/4bf5536abc1a2088686e63e375128af84d8454d9/AllowUnsafeCode.png -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 66597862d10556b4096fef8f3680a3ab 3 | folderAsset: yes 4 | timeCreated: 1521821567 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/IntegrationWithNatShareExample.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a394dc9ddb1871f46991ea89223c9b72 3 | folderAsset: yes 4 | timeCreated: 1524389028 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/IntegrationWithNatShareExample/ComicFilter.cs: -------------------------------------------------------------------------------- 1 | using OpenCVForUnity.CoreModule; 2 | using OpenCVForUnity.ImgprocModule; 3 | using OpenCVForUnity.UtilsModule; 4 | using System; 5 | 6 | namespace NatDeviceWithOpenCVForUnityExample 7 | { 8 | 9 | public class ComicFilter 10 | { 11 | 12 | Mat grayMat; 13 | Mat maskMat; 14 | Mat screentoneMat; 15 | Mat grayDstMat; 16 | 17 | Mat grayLUT; 18 | Mat contrastAdjustmentsLUT; 19 | Mat kernel_dilate; 20 | Mat kernel_erode; 21 | Size blurSize; 22 | int blackThresh; 23 | bool drawMainLine; 24 | bool useNoiseFilter; 25 | 26 | 27 | public ComicFilter(int blackThresh = 60, int grayThresh = 120, int thickness = 5, bool useNoiseFilter = true) 28 | { 29 | this.blackThresh = blackThresh; 30 | this.drawMainLine = (thickness != 0); 31 | this.useNoiseFilter = useNoiseFilter; 32 | 33 | grayLUT = new Mat(1, 256, CvType.CV_8UC1); 34 | byte[] lutArray = new byte[256]; 35 | for (int i = 0; i < lutArray.Length; i++) 36 | { 37 | if (blackThresh <= i && i < grayThresh) 38 | lutArray[i] = 255; 39 | } 40 | MatUtils.copyToMat(lutArray, grayLUT); 41 | 42 | if (drawMainLine) 43 | { 44 | kernel_dilate = new Mat(thickness, thickness, CvType.CV_8UC1, new Scalar(1)); 45 | 46 | int erode = (thickness >= 5) ? 2 : 1; 47 | kernel_erode = new Mat(erode, erode, CvType.CV_8UC1, new Scalar(1)); 48 | 49 | int blur = (thickness >= 4) ? thickness - 1 : 3; 50 | blurSize = new Size(blur, blur); 51 | 52 | contrastAdjustmentsLUT = new Mat(1, 256, CvType.CV_8UC1); 53 | byte[] contrastAdjustmentsLUTArray = new byte[256]; 54 | for (int i = 0; i < contrastAdjustmentsLUTArray.Length; i++) 55 | { 56 | int a = (int)(i * 1.5f); 57 | contrastAdjustmentsLUTArray[i] = (a > byte.MaxValue) ? (byte)255 : (byte)a; 58 | 59 | } 60 | MatUtils.copyToMat(contrastAdjustmentsLUTArray, contrastAdjustmentsLUT); 61 | } 62 | } 63 | 64 | public void Process(Mat src, Mat dst, bool isBGR = false) 65 | { 66 | if (src == null) 67 | throw new ArgumentNullException("src == null"); 68 | if (dst == null) 69 | throw new ArgumentNullException("dst == null"); 70 | 71 | if (grayMat != null && (grayMat.width() != src.width() || grayMat.height() != src.height())) 72 | { 73 | grayMat.Dispose(); 74 | grayMat = null; 75 | maskMat.Dispose(); 76 | maskMat = null; 77 | screentoneMat.Dispose(); 78 | screentoneMat = null; 79 | grayDstMat.Dispose(); 80 | grayDstMat = null; 81 | } 82 | grayMat = grayMat ?? new Mat(src.height(), src.width(), CvType.CV_8UC1); 83 | maskMat = maskMat ?? new Mat(src.height(), src.width(), CvType.CV_8UC1); 84 | grayDstMat = grayDstMat ?? new Mat(src.height(), src.width(), CvType.CV_8UC1); 85 | 86 | if (screentoneMat == null) 87 | { 88 | // create a striped screentone. 89 | screentoneMat = new Mat(src.height(), src.width(), CvType.CV_8UC1, new Scalar(255)); 90 | for (int i = 0; i < screentoneMat.rows() * 2.5f; i = i + 4) 91 | { 92 | Imgproc.line(screentoneMat, new Point(0, 0 + i), new Point(screentoneMat.cols(), -screentoneMat.cols() + i), new Scalar(0), 1); 93 | } 94 | } 95 | 96 | if (src.type() == CvType.CV_8UC1) 97 | { 98 | src.copyTo(grayMat); 99 | } 100 | else if (dst.type() == CvType.CV_8UC3) 101 | { 102 | Imgproc.cvtColor(src, grayMat, (isBGR) ? Imgproc.COLOR_BGR2GRAY : Imgproc.COLOR_RGB2GRAY); 103 | } 104 | else 105 | { 106 | Imgproc.cvtColor(src, grayMat, (isBGR) ? Imgproc.COLOR_BGRA2GRAY : Imgproc.COLOR_RGBA2GRAY); 107 | } 108 | 109 | 110 | // binarize. 111 | Imgproc.threshold(grayMat, grayDstMat, blackThresh, 255.0, Imgproc.THRESH_BINARY); 112 | 113 | // draw striped screentone. 114 | Core.LUT(grayMat, grayLUT, maskMat); 115 | screentoneMat.copyTo(grayDstMat, maskMat); 116 | 117 | // draw main line. 118 | if (drawMainLine) 119 | { 120 | Core.LUT(grayMat, contrastAdjustmentsLUT, maskMat); // = grayMat.convertTo(maskMat, -1, 1.5, 0); 121 | 122 | if (useNoiseFilter) 123 | { 124 | Imgproc.blur(maskMat, grayMat, blurSize); 125 | Imgproc.dilate(grayMat, maskMat, kernel_dilate); 126 | } 127 | else 128 | { 129 | Imgproc.dilate(maskMat, grayMat, kernel_dilate); 130 | } 131 | Core.absdiff(grayMat, maskMat, grayMat); 132 | Imgproc.threshold(grayMat, maskMat, 25, 255.0, Imgproc.THRESH_BINARY); 133 | if (useNoiseFilter) 134 | { 135 | Imgproc.erode(maskMat, grayMat, kernel_erode); 136 | Core.bitwise_not(grayMat, maskMat); 137 | maskMat.copyTo(grayDstMat, grayMat); 138 | } 139 | else 140 | { 141 | Core.bitwise_not(maskMat, grayMat); 142 | grayMat.copyTo(grayDstMat, maskMat); 143 | } 144 | } 145 | 146 | 147 | if (dst.type() == CvType.CV_8UC1) 148 | { 149 | grayDstMat.copyTo(dst); 150 | } 151 | else if (dst.type() == CvType.CV_8UC3) 152 | { 153 | Imgproc.cvtColor(grayDstMat, dst, (isBGR) ? Imgproc.COLOR_GRAY2BGR : Imgproc.COLOR_GRAY2RGB); 154 | } 155 | else 156 | { 157 | Imgproc.cvtColor(grayDstMat, dst, (isBGR) ? Imgproc.COLOR_GRAY2BGRA : Imgproc.COLOR_GRAY2RGBA); 158 | } 159 | } 160 | 161 | public void Dispose() 162 | { 163 | foreach (var mat in new[] { grayMat, maskMat, screentoneMat, grayDstMat, grayLUT, kernel_dilate, kernel_erode, contrastAdjustmentsLUT }) 164 | if (mat != null) mat.Dispose(); 165 | 166 | grayDstMat = 167 | screentoneMat = 168 | maskMat = 169 | grayMat = 170 | grayLUT = 171 | kernel_dilate = 172 | kernel_erode = 173 | contrastAdjustmentsLUT = null; 174 | } 175 | } 176 | } -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/IntegrationWithNatShareExample/ComicFilter.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 08d77cc1cacdd0f42b35833496299c75 3 | timeCreated: 1524599498 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/IntegrationWithNatShareExample/IntegrationWithNatShareExample.cs: -------------------------------------------------------------------------------- 1 | using NatSuite.Devices; 2 | using NatSuite.Sharing; 3 | using OpenCVForUnity.CoreModule; 4 | using OpenCVForUnity.ImgprocModule; 5 | using OpenCVForUnity.UnityUtils; 6 | using System; 7 | using System.Threading.Tasks; 8 | using UnityEngine; 9 | using UnityEngine.UI; 10 | 11 | namespace NatDeviceWithOpenCVForUnityExample 12 | { 13 | 14 | /// 15 | /// Integration With NatShare Example 16 | /// An example of the native sharing and save to the camera roll using NatShare. 17 | /// 18 | public class IntegrationWithNatShareExample : ExampleBase 19 | { 20 | public bool applyComicFilter; 21 | public Toggle applyComicFilterToggle; 22 | 23 | Mat frameMatrix; 24 | Texture2D texture; 25 | ComicFilter comicFilter; 26 | 27 | FpsMonitor fpsMonitor; 28 | 29 | string exampleTitle = ""; 30 | string exampleSceneTitle = ""; 31 | string settingInfo1 = ""; 32 | Scalar textColor = new Scalar(255, 255, 255, 255); 33 | Point textPos = new Point(); 34 | 35 | protected override async void Start() 36 | { 37 | base.Start(); 38 | 39 | fpsMonitor = GetComponent(); 40 | if (fpsMonitor != null) 41 | { 42 | fpsMonitor.Add("Name", "IntegrationWithNatShareExample"); 43 | fpsMonitor.Add("onFrameFPS", onFrameFPS.ToString("F1")); 44 | fpsMonitor.Add("drawFPS", drawFPS.ToString("F1")); 45 | fpsMonitor.Add("width", ""); 46 | fpsMonitor.Add("height", ""); 47 | fpsMonitor.Add("isFrontFacing", ""); 48 | fpsMonitor.Add("orientation", ""); 49 | } 50 | 51 | // Request camera permissions 52 | var permissionStatus = await MediaDeviceQuery.RequestPermissions(); 53 | if (permissionStatus != PermissionStatus.Authorized) 54 | { 55 | Debug.LogError("User did not grant camera permissions"); 56 | return; 57 | } 58 | 59 | // Load global camera benchmark settings. 60 | int width, height, framerate; 61 | NatDeviceWithOpenCVForUnityExample.CameraConfiguration(out width, out height, out framerate); 62 | // Create camera source 63 | cameraSource = new NatDeviceCamSource(width, height, framerate, useFrontCamera); 64 | if (cameraSource.activeCamera == null) 65 | cameraSource = new NatDeviceCamSource(width, height, framerate, !useFrontCamera); 66 | await cameraSource.StartRunning(OnStart, OnFrame); 67 | 68 | // Update GUI state 69 | applyComicFilterToggle.isOn = applyComicFilter; 70 | 71 | // Create comic filter 72 | comicFilter = new ComicFilter(); 73 | 74 | exampleTitle = "[NatDeviceWithOpenCVForUnity Example] (" + NatDeviceWithOpenCVForUnityExample.GetNatDeviceVersion() + ")"; 75 | exampleSceneTitle = "- Integration With NatShare Example"; 76 | } 77 | 78 | protected override void OnStart() 79 | { 80 | base.OnStart(); 81 | 82 | settingInfo1 = "- resolution: " + cameraSource.width + "x" + cameraSource.height; 83 | 84 | // Create matrices 85 | if (frameMatrix != null) 86 | frameMatrix.Dispose(); 87 | frameMatrix = new Mat(cameraSource.height, cameraSource.width, CvType.CV_8UC4); 88 | // Create texture 89 | if (texture != null) 90 | Texture2D.Destroy(texture); 91 | texture = new Texture2D( 92 | cameraSource.width, 93 | cameraSource.height, 94 | TextureFormat.RGBA32, 95 | false, 96 | false 97 | ); 98 | // Display preview 99 | rawImage.texture = texture; 100 | aspectFitter.aspectRatio = cameraSource.width / (float)cameraSource.height; 101 | Debug.Log("NatDevice camera source started with resolution: " + cameraSource.width + "x" + cameraSource.height + " isFrontFacing: " + cameraSource.isFrontFacing); 102 | 103 | if (fpsMonitor != null) 104 | { 105 | fpsMonitor.Add("width", cameraSource.width.ToString()); 106 | fpsMonitor.Add("height", cameraSource.height.ToString()); 107 | fpsMonitor.Add("isFrontFacing", cameraSource.isFrontFacing.ToString()); 108 | fpsMonitor.Add("orientation", Screen.orientation.ToString()); 109 | } 110 | } 111 | 112 | protected override void Update() 113 | { 114 | base.Update(); 115 | 116 | if (updateCount == 0) 117 | { 118 | if (fpsMonitor != null) 119 | { 120 | fpsMonitor.Add("onFrameFPS", onFrameFPS.ToString("F1")); 121 | fpsMonitor.Add("drawFPS", drawFPS.ToString("F1")); 122 | fpsMonitor.Add("orientation", Screen.orientation.ToString()); 123 | } 124 | } 125 | } 126 | 127 | protected override void UpdateTexture() 128 | { 129 | cameraSource.CaptureFrame(frameMatrix); 130 | 131 | if (applyComicFilter) 132 | comicFilter.Process(frameMatrix, frameMatrix); 133 | 134 | textPos.x = 5; 135 | textPos.y = frameMatrix.rows() - 50; 136 | Imgproc.putText(frameMatrix, exampleTitle, textPos, Imgproc.FONT_HERSHEY_SIMPLEX, 0.5, textColor, 1, Imgproc.LINE_AA, false); 137 | textPos.y = frameMatrix.rows() - 30; 138 | Imgproc.putText(frameMatrix, exampleSceneTitle, textPos, Imgproc.FONT_HERSHEY_SIMPLEX, 0.5, textColor, 1, Imgproc.LINE_AA, false); 139 | textPos.y = frameMatrix.rows() - 10; 140 | Imgproc.putText(frameMatrix, settingInfo1, textPos, Imgproc.FONT_HERSHEY_SIMPLEX, 0.5, textColor, 1, Imgproc.LINE_AA, false); 141 | 142 | // Convert to Texture2D 143 | Utils.fastMatToTexture2D(frameMatrix, texture, true, 0, false); 144 | } 145 | 146 | protected override void OnDestroy() 147 | { 148 | base.OnDestroy(); 149 | 150 | if (frameMatrix != null) 151 | frameMatrix.Dispose(); 152 | frameMatrix = null; 153 | Texture2D.Destroy(texture); 154 | texture = null; 155 | comicFilter.Dispose(); 156 | comicFilter = null; 157 | } 158 | 159 | protected virtual async void OnApplicationPause(bool pauseStatus) 160 | { 161 | if (cameraSource == null || cameraSource.activeCamera == null) 162 | return; 163 | 164 | // The developer needs to do the camera suspend process oneself so that it is synchronized with the app suspend. 165 | if (pauseStatus) 166 | { 167 | if (cameraSource.isRunning) 168 | cameraSource.StopRunning(); 169 | } 170 | else 171 | { 172 | if (!cameraSource.isRunning) 173 | await cameraSource.StartRunning(OnStart, OnFrame); 174 | } 175 | } 176 | 177 | public void OnApplyComicFilterToggleValueChanged() 178 | { 179 | if (applyComicFilter != applyComicFilterToggle.isOn) 180 | { 181 | applyComicFilter = applyComicFilterToggle.isOn; 182 | } 183 | } 184 | 185 | public async void OnShareButtonClick() 186 | { 187 | var mes = ""; 188 | 189 | #if (UNITY_IOS || UNITY_ANDROID) && !UNITY_EDITOR 190 | try 191 | { 192 | SharePayload payload = new SharePayload(); 193 | payload.AddText("User shared image! [NatDeviceWithOpenCVForUnity Example](" + NatDeviceWithOpenCVForUnityExample.GetNatDeviceVersion() + ")"); 194 | payload.AddImage(texture); 195 | var success = await payload.Commit(); 196 | 197 | mes = $"Successfully shared items: {success}"; 198 | } 199 | catch (ApplicationException e) 200 | { 201 | mes = e.Message; 202 | } 203 | #else 204 | mes = "NatShare Error: SharePayload is not supported on this platform"; 205 | await Task.Delay(100); 206 | #endif 207 | 208 | Debug.Log(mes); 209 | if (fpsMonitor != null) fpsMonitor.Toast(mes); 210 | } 211 | 212 | public async void OnSaveToCameraRollButtonClick() 213 | { 214 | var mes = ""; 215 | 216 | #if (UNITY_IOS || UNITY_ANDROID) && !UNITY_EDITOR 217 | try 218 | { 219 | SavePayload payload = new SavePayload("NatDeviceWithOpenCVForUnityExample"); 220 | payload.AddImage(texture); 221 | var success = await payload.Commit(); 222 | 223 | mes = $"Successfully saved items: {success}"; 224 | } 225 | catch (ApplicationException e) 226 | { 227 | mes = e.Message; 228 | } 229 | #else 230 | mes = "NatShare Error: SavePayload is not supported on this platform"; 231 | await Task.Delay(100); 232 | #endif 233 | 234 | Debug.Log(mes); 235 | if (fpsMonitor != null) fpsMonitor.Toast(mes); 236 | } 237 | } 238 | } -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/IntegrationWithNatShareExample/IntegrationWithNatShareExample.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f5ca190fc54d25e4a80601d2e5f9c573 3 | timeCreated: 1524389028 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/IntegrationWithNatShareExample/IntegrationWithNatShareExample.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f78ae37dff926a641be7ee414fcc2798 3 | timeCreated: 1524389028 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/NatDeviceCamPreviewOnlyExample.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7a91cc898012624429966da3089ef8fb 3 | folderAsset: yes 4 | timeCreated: 1522155379 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/NatDeviceCamPreviewOnlyExample/NatDeviceCamPreviewOnlyExample.cs: -------------------------------------------------------------------------------- 1 | using NatSuite.Devices; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEngine.EventSystems; 5 | 6 | namespace NatDeviceWithOpenCVForUnityExample 7 | { 8 | 9 | /// 10 | /// NatDeviceCamPreview Only Example 11 | /// An example of displaying the preview frame of camera only using NatDevice. 12 | /// 13 | public class NatDeviceCamPreviewOnlyExample : ExampleBase 14 | { 15 | 16 | Texture2D texture; 17 | byte[] pixelBuffer; 18 | 19 | FpsMonitor fpsMonitor; 20 | 21 | #region --ExampleBase-- 22 | 23 | protected override async void Start() 24 | { 25 | base.Start(); 26 | 27 | fpsMonitor = GetComponent(); 28 | if (fpsMonitor != null) 29 | { 30 | fpsMonitor.Add("Name", "NatDeviceCamPreviewOnlyExample"); 31 | fpsMonitor.Add("onFrameFPS", onFrameFPS.ToString("F1")); 32 | fpsMonitor.Add("drawFPS", drawFPS.ToString("F1")); 33 | fpsMonitor.Add("width", ""); 34 | fpsMonitor.Add("height", ""); 35 | fpsMonitor.Add("isFrontFacing", ""); 36 | fpsMonitor.Add("orientation", ""); 37 | } 38 | 39 | // Request camera permissions 40 | var permissionStatus = await MediaDeviceQuery.RequestPermissions(); 41 | if (permissionStatus != PermissionStatus.Authorized) 42 | { 43 | Debug.LogError("User did not grant camera permissions"); 44 | return; 45 | } 46 | 47 | // Load global camera benchmark settings. 48 | int width, height, framerate; 49 | NatDeviceWithOpenCVForUnityExample.CameraConfiguration(out width, out height, out framerate); 50 | // Create camera source 51 | cameraSource = new NatDeviceCamSource(width, height, framerate, useFrontCamera); 52 | if (cameraSource.activeCamera == null) 53 | cameraSource = new NatDeviceCamSource(width, height, framerate, !useFrontCamera); 54 | await cameraSource.StartRunning(OnStart, OnFrame); 55 | } 56 | 57 | protected override void OnStart() 58 | { 59 | base.OnStart(); 60 | 61 | // Create pixel buffer 62 | pixelBuffer = new byte[cameraSource.width * cameraSource.height * 4]; 63 | // Create texture 64 | if (texture != null) 65 | Texture2D.Destroy(texture); 66 | texture = new Texture2D( 67 | cameraSource.width, 68 | cameraSource.height, 69 | TextureFormat.RGBA32, 70 | false, 71 | false 72 | ); 73 | // Display preview 74 | rawImage.texture = texture; 75 | aspectFitter.aspectRatio = cameraSource.width / (float)cameraSource.height; 76 | Debug.Log("NatDevice camera source started with resolution: " + cameraSource.width + "x" + cameraSource.height + " isFrontFacing: " + cameraSource.isFrontFacing); 77 | 78 | // Log camera properties 79 | var cameraProps = new Dictionary(); 80 | var camera = cameraSource.activeCamera; 81 | if (camera != null) 82 | { 83 | cameraProps.Add("defaultForMediaType", camera.defaultForMediaType.ToString()); 84 | cameraProps.Add("exposureBias", camera.exposureBias.ToString()); 85 | cameraProps.Add("exposureBiasRange", camera.exposureBiasRange.min + "x" + camera.exposureBiasRange.max); 86 | cameraProps.Add("exposureDurationRange", camera.exposureDurationRange.min + "x" + camera.exposureDurationRange.max); 87 | cameraProps.Add("exposureMode", camera.exposureMode.ToString()); 88 | cameraProps.Add("ExposureModeSupported:Continuous", camera.ExposureModeSupported(CameraDevice.ExposureMode.Continuous).ToString()); 89 | cameraProps.Add("ExposureModeSupported:Locked", camera.ExposureModeSupported(CameraDevice.ExposureMode.Locked).ToString()); 90 | cameraProps.Add("ExposureModeSupported:Manual", camera.ExposureModeSupported(CameraDevice.ExposureMode.Manual).ToString()); 91 | cameraProps.Add("exposurePointSupported", camera.exposurePointSupported.ToString()); 92 | cameraProps.Add("fieldOfView", camera.fieldOfView.width + "x" + camera.fieldOfView.height); 93 | cameraProps.Add("flashMode", camera.flashMode.ToString()); 94 | cameraProps.Add("flashSupported", camera.flashSupported.ToString()); 95 | cameraProps.Add("focusMode", camera.focusMode.ToString()); 96 | cameraProps.Add("FocusModeSupported:Continuous", camera.FocusModeSupported(CameraDevice.FocusMode.Continuous).ToString()); 97 | cameraProps.Add("FocusModeSupported:Locked", camera.FocusModeSupported(CameraDevice.FocusMode.Locked).ToString()); 98 | cameraProps.Add("focusPointSupported", camera.focusPointSupported.ToString()); 99 | cameraProps.Add("frameRate", camera.frameRate.ToString()); 100 | cameraProps.Add("frontFacing", camera.frontFacing.ToString()); 101 | cameraProps.Add("ISORange", camera.ISORange.min + "x" + camera.ISORange.max); 102 | cameraProps.Add("location", camera.location.ToString()); 103 | cameraProps.Add("name", camera.name.ToString()); 104 | cameraProps.Add("photoResolution", camera.photoResolution.width + "x" + camera.photoResolution.height); 105 | cameraProps.Add("previewResolution", camera.previewResolution.width + "x" + camera.previewResolution.height); 106 | cameraProps.Add("running", camera.running.ToString()); 107 | cameraProps.Add("torchEnabled", camera.torchEnabled.ToString()); 108 | cameraProps.Add("torchSupported", camera.torchSupported.ToString()); 109 | cameraProps.Add("uniqueID", camera.uniqueID.ToString()); 110 | cameraProps.Add("whiteBalanceLock", camera.whiteBalanceLock.ToString()); 111 | cameraProps.Add("whiteBalanceLockSupported", camera.whiteBalanceLockSupported.ToString()); 112 | cameraProps.Add("zoomRange", camera.zoomRange.max + "x" + camera.zoomRange.min); 113 | cameraProps.Add("zoomRatio", camera.zoomRatio.ToString()); 114 | } 115 | 116 | Debug.Log("# Active Camera Properties #####################"); 117 | foreach (string key in cameraProps.Keys) 118 | Debug.Log(key + ": " + cameraProps[key]); 119 | Debug.Log("#######################################"); 120 | 121 | if (fpsMonitor != null) 122 | { 123 | fpsMonitor.Add("width", cameraSource.width.ToString()); 124 | fpsMonitor.Add("height", cameraSource.height.ToString()); 125 | fpsMonitor.Add("isFrontFacing", cameraSource.isFrontFacing.ToString()); 126 | fpsMonitor.Add("orientation", Screen.orientation.ToString()); 127 | 128 | fpsMonitor.boxWidth = 280; 129 | fpsMonitor.boxHeight = 1030; 130 | fpsMonitor.LocateGUI(); 131 | 132 | foreach (string key in cameraProps.Keys) 133 | fpsMonitor.Add(key, cameraProps[key]); 134 | } 135 | 136 | // Add camera device disconnection event 137 | camera.onDisconnected += () => 138 | { 139 | if (fpsMonitor != null) 140 | fpsMonitor.consoleText = "the camera device is disconnected."; 141 | }; 142 | } 143 | 144 | protected override void Update() 145 | { 146 | base.Update(); 147 | 148 | if (updateCount == 0) 149 | { 150 | if (fpsMonitor != null) 151 | { 152 | fpsMonitor.Add("onFrameFPS", onFrameFPS.ToString("F1")); 153 | fpsMonitor.Add("drawFPS", drawFPS.ToString("F1")); 154 | fpsMonitor.Add("orientation", Screen.orientation.ToString()); 155 | } 156 | } 157 | } 158 | 159 | protected override void UpdateTexture() 160 | { 161 | cameraSource.CaptureFrame(pixelBuffer); 162 | ProcessImage(pixelBuffer, texture.width, texture.height, imageProcessingType); 163 | texture.LoadRawTextureData(pixelBuffer); 164 | texture.Apply(); 165 | } 166 | 167 | protected override void OnDestroy() 168 | { 169 | base.OnDestroy(); 170 | 171 | Texture2D.Destroy(texture); 172 | texture = null; 173 | pixelBuffer = null; 174 | } 175 | 176 | #endregion 177 | 178 | protected virtual async void OnApplicationPause(bool pauseStatus) 179 | { 180 | if (cameraSource == null || cameraSource.activeCamera == null) 181 | return; 182 | 183 | // The developer needs to do the camera suspend process oneself so that it is synchronized with the app suspend. 184 | if (pauseStatus) 185 | { 186 | if (cameraSource.isRunning) 187 | cameraSource.StopRunning(); 188 | } 189 | else 190 | { 191 | if (!cameraSource.isRunning) 192 | await cameraSource.StartRunning(OnStart, OnFrame); 193 | } 194 | } 195 | 196 | public void FocusCamera(BaseEventData e) 197 | { 198 | if (cameraSource == null || cameraSource.activeCamera == null) 199 | return; 200 | 201 | var cameraDevice = cameraSource.activeCamera; 202 | 203 | // Check if focus is supported 204 | if (!cameraDevice.focusPointSupported) 205 | return; 206 | // Get the touch position in viewport coordinates 207 | var eventData = e as PointerEventData; 208 | var transform = eventData.pointerPress.GetComponent(); 209 | if (!RectTransformUtility.ScreenPointToWorldPointInRectangle( 210 | transform, 211 | eventData.pressPosition, 212 | eventData.pressEventCamera, 213 | out var worldPoint 214 | )) 215 | return; 216 | var corners = new Vector3[4]; 217 | transform.GetWorldCorners(corners); 218 | var point = worldPoint - corners[0]; 219 | var size = new Vector2(corners[3].x, corners[1].y) - (Vector2)corners[0]; 220 | // Focus camera at point 221 | cameraDevice.SetFocusPoint(point.x / size.x, point.y / size.y); 222 | 223 | if (fpsMonitor != null) 224 | fpsMonitor.Toast("Set Focus Point: " + point.x / size.x + " x " + point.y / size.y); 225 | } 226 | } 227 | } -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/NatDeviceCamPreviewOnlyExample/NatDeviceCamPreviewOnlyExample.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7de64702992c67842b18b623410d3b42 3 | timeCreated: 1484195860 4 | licenseType: Store 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/NatDeviceCamPreviewOnlyExample/NatDeviceCamPreviewOnlyExample.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 45d5c81453669024799a34ff7a3d5b51 3 | timeCreated: 1477101412 4 | licenseType: Store 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/NatDeviceCamPreviewToMatExample.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 96db6872c06c0dd43b5374295f5c6c53 3 | folderAsset: yes 4 | timeCreated: 1522155392 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/NatDeviceCamPreviewToMatExample/NatDeviceCamPreviewToMatExample.cs: -------------------------------------------------------------------------------- 1 | using NatSuite.Devices; 2 | using OpenCVForUnity.CoreModule; 3 | using OpenCVForUnity.UnityUtils; 4 | using System.Collections.Generic; 5 | using UnityEngine; 6 | using UnityEngine.EventSystems; 7 | 8 | namespace NatDeviceWithOpenCVForUnityExample 9 | { 10 | 11 | /// 12 | /// NatDeviceCamPreview To Mat Example 13 | /// An example of converting a NatDevice camera preview image to OpenCV's Mat format. 14 | /// 15 | public class NatDeviceCamPreviewToMatExample : ExampleBase 16 | { 17 | 18 | Mat frameMatrix; 19 | Mat grayMatrix; 20 | Texture2D texture; 21 | 22 | FpsMonitor fpsMonitor; 23 | 24 | #region --ExampleBase-- 25 | 26 | protected override async void Start() 27 | { 28 | base.Start(); 29 | 30 | fpsMonitor = GetComponent(); 31 | if (fpsMonitor != null) 32 | { 33 | fpsMonitor.Add("Name", "NatDeviceCamPreviewToMatExample"); 34 | fpsMonitor.Add("onFrameFPS", onFrameFPS.ToString("F1")); 35 | fpsMonitor.Add("drawFPS", drawFPS.ToString("F1")); 36 | fpsMonitor.Add("width", ""); 37 | fpsMonitor.Add("height", ""); 38 | fpsMonitor.Add("isFrontFacing", ""); 39 | fpsMonitor.Add("orientation", ""); 40 | } 41 | 42 | // Request camera permissions 43 | var permissionStatus = await MediaDeviceQuery.RequestPermissions(); 44 | if (permissionStatus != PermissionStatus.Authorized) 45 | { 46 | Debug.LogError("User did not grant camera permissions"); 47 | return; 48 | } 49 | 50 | // Load global camera benchmark settings. 51 | int width, height, framerate; 52 | NatDeviceWithOpenCVForUnityExample.CameraConfiguration(out width, out height, out framerate); 53 | // Create camera source 54 | cameraSource = new NatDeviceCamSource(width, height, framerate, useFrontCamera); 55 | if (cameraSource.activeCamera == null) 56 | cameraSource = new NatDeviceCamSource(width, height, framerate, !useFrontCamera); 57 | await cameraSource.StartRunning(OnStart, OnFrame); 58 | } 59 | 60 | protected override void OnStart() 61 | { 62 | base.OnStart(); 63 | 64 | // Create matrices 65 | if (frameMatrix != null) 66 | frameMatrix.Dispose(); 67 | frameMatrix = new Mat(cameraSource.height, cameraSource.width, CvType.CV_8UC4); 68 | if (grayMatrix != null) 69 | grayMatrix.Dispose(); 70 | grayMatrix = new Mat(cameraSource.height, cameraSource.width, CvType.CV_8UC1); 71 | // Create texture 72 | if (texture != null) 73 | Texture2D.Destroy(texture); 74 | texture = new Texture2D( 75 | cameraSource.width, 76 | cameraSource.height, 77 | TextureFormat.RGBA32, 78 | false, 79 | false 80 | ); 81 | // Display preview 82 | rawImage.texture = texture; 83 | aspectFitter.aspectRatio = cameraSource.width / (float)cameraSource.height; 84 | Debug.Log("NatDevice camera source started with resolution: " + cameraSource.width + "x" + cameraSource.height + " isFrontFacing: " + cameraSource.isFrontFacing); 85 | 86 | // Log camera properties 87 | var cameraProps = new Dictionary(); 88 | var camera = cameraSource.activeCamera as CameraDevice; 89 | if (camera != null) 90 | { 91 | cameraProps.Add("defaultForMediaType", camera.defaultForMediaType.ToString()); 92 | cameraProps.Add("exposureBias", camera.exposureBias.ToString()); 93 | cameraProps.Add("exposureBiasRange", camera.exposureBiasRange.min + "x" + camera.exposureBiasRange.max); 94 | cameraProps.Add("exposureDurationRange", camera.exposureDurationRange.min + "x" + camera.exposureDurationRange.max); 95 | cameraProps.Add("exposureMode", camera.exposureMode.ToString()); 96 | cameraProps.Add("ExposureModeSupported:Continuous", camera.ExposureModeSupported(CameraDevice.ExposureMode.Continuous).ToString()); 97 | cameraProps.Add("ExposureModeSupported:Locked", camera.ExposureModeSupported(CameraDevice.ExposureMode.Locked).ToString()); 98 | cameraProps.Add("ExposureModeSupported:Manual", camera.ExposureModeSupported(CameraDevice.ExposureMode.Manual).ToString()); 99 | cameraProps.Add("exposurePointSupported", camera.exposurePointSupported.ToString()); 100 | cameraProps.Add("fieldOfView", camera.fieldOfView.width + "x" + camera.fieldOfView.height); 101 | cameraProps.Add("flashMode", camera.flashMode.ToString()); 102 | cameraProps.Add("flashSupported", camera.flashSupported.ToString()); 103 | cameraProps.Add("focusMode", camera.focusMode.ToString()); 104 | cameraProps.Add("FocusModeSupported:Continuous", camera.FocusModeSupported(CameraDevice.FocusMode.Continuous).ToString()); 105 | cameraProps.Add("FocusModeSupported:Locked", camera.FocusModeSupported(CameraDevice.FocusMode.Locked).ToString()); 106 | cameraProps.Add("focusPointSupported", camera.focusPointSupported.ToString()); 107 | cameraProps.Add("frameRate", camera.frameRate.ToString()); 108 | cameraProps.Add("frontFacing", camera.frontFacing.ToString()); 109 | cameraProps.Add("ISORange", camera.ISORange.min + "x" + camera.ISORange.max); 110 | cameraProps.Add("location", camera.location.ToString()); 111 | cameraProps.Add("name", camera.name.ToString()); 112 | cameraProps.Add("photoResolution", camera.photoResolution.width + "x" + camera.photoResolution.height); 113 | cameraProps.Add("previewResolution", camera.previewResolution.width + "x" + camera.previewResolution.height); 114 | cameraProps.Add("running", camera.running.ToString()); 115 | cameraProps.Add("torchEnabled", camera.torchEnabled.ToString()); 116 | cameraProps.Add("torchSupported", camera.torchSupported.ToString()); 117 | cameraProps.Add("uniqueID", camera.uniqueID.ToString()); 118 | cameraProps.Add("whiteBalanceLock", camera.whiteBalanceLock.ToString()); 119 | cameraProps.Add("whiteBalanceLockSupported", camera.whiteBalanceLockSupported.ToString()); 120 | cameraProps.Add("zoomRange", camera.zoomRange.max + "x" + camera.zoomRange.min); 121 | cameraProps.Add("zoomRatio", camera.zoomRatio.ToString()); 122 | } 123 | 124 | Debug.Log("# Active Camera Properties #####################"); 125 | foreach (string key in cameraProps.Keys) 126 | Debug.Log(key + ": " + cameraProps[key]); 127 | Debug.Log("#######################################"); 128 | 129 | if (fpsMonitor != null) 130 | { 131 | fpsMonitor.Add("width", cameraSource.width.ToString()); 132 | fpsMonitor.Add("height", cameraSource.height.ToString()); 133 | fpsMonitor.Add("isFrontFacing", cameraSource.isFrontFacing.ToString()); 134 | fpsMonitor.Add("orientation", Screen.orientation.ToString()); 135 | 136 | fpsMonitor.boxWidth = 280; 137 | fpsMonitor.boxHeight = 1030; 138 | fpsMonitor.LocateGUI(); 139 | 140 | //foreach (string key in cameraProps.Keys) 141 | // fpsMonitor.Add(key, cameraProps[key]); 142 | } 143 | 144 | // Add camera device disconnection event 145 | camera.onDisconnected += () => 146 | { 147 | if (fpsMonitor != null) 148 | fpsMonitor.consoleText = "the camera device is disconnected."; 149 | }; 150 | } 151 | 152 | protected override void Update() 153 | { 154 | base.Update(); 155 | 156 | if (updateCount == 0) 157 | { 158 | if (fpsMonitor != null) 159 | { 160 | fpsMonitor.Add("onFrameFPS", onFrameFPS.ToString("F1")); 161 | fpsMonitor.Add("drawFPS", drawFPS.ToString("F1")); 162 | fpsMonitor.Add("orientation", Screen.orientation.ToString()); 163 | } 164 | } 165 | 166 | // Update display of camera image metadata every frame. 167 | if (cameraSource.isRunning && fpsMonitor != null) 168 | { 169 | fpsMonitor.Add("timestamp", cameraSource.timestamp.ToString()); 170 | fpsMonitor.Add("verticallyMirrored", cameraSource.verticallyMirrored.ToString()); 171 | fpsMonitor.Add("intrinsics", "\n" + cameraSource.intrinsics.ToString()); 172 | fpsMonitor.Add("exposureBias", cameraSource.exposureBias.ToString()); 173 | fpsMonitor.Add("exposureDuration", cameraSource.exposureDuration.ToString()); 174 | fpsMonitor.Add("ISO", cameraSource.ISO.ToString()); 175 | fpsMonitor.Add("focalLength", cameraSource.focalLength.ToString()); 176 | fpsMonitor.Add("fNumber", cameraSource.fNumber.ToString()); 177 | fpsMonitor.Add("brightness", cameraSource.brightness.ToString()); 178 | } 179 | } 180 | 181 | protected override void UpdateTexture() 182 | { 183 | // Get the matrix 184 | cameraSource.CaptureFrame(frameMatrix); 185 | 186 | ProcessImage(frameMatrix, grayMatrix, imageProcessingType); 187 | 188 | // Convert to Texture2D 189 | Utils.fastMatToTexture2D(frameMatrix, texture); 190 | } 191 | 192 | protected override void OnDestroy() 193 | { 194 | base.OnDestroy(); 195 | 196 | if (frameMatrix != null) 197 | frameMatrix.Dispose(); 198 | if (grayMatrix != null) 199 | grayMatrix.Dispose(); 200 | frameMatrix = 201 | grayMatrix = null; 202 | Texture2D.Destroy(texture); 203 | texture = null; 204 | } 205 | 206 | #endregion 207 | 208 | protected virtual async void OnApplicationPause(bool pauseStatus) 209 | { 210 | if (cameraSource == null || cameraSource.activeCamera == null) 211 | return; 212 | 213 | // The developer needs to do the camera suspend process oneself so that it is synchronized with the app suspend. 214 | if (pauseStatus) 215 | { 216 | if (cameraSource.isRunning) 217 | cameraSource.StopRunning(); 218 | } 219 | else 220 | { 221 | if (!cameraSource.isRunning) 222 | await cameraSource.StartRunning(OnStart, OnFrame); 223 | } 224 | } 225 | 226 | public void FocusCamera(BaseEventData e) 227 | { 228 | if (cameraSource == null || cameraSource.activeCamera == null) 229 | return; 230 | 231 | var cameraDevice = cameraSource.activeCamera; 232 | 233 | // Check if focus is supported 234 | if (!cameraDevice.focusPointSupported) 235 | return; 236 | // Get the touch position in viewport coordinates 237 | var eventData = e as PointerEventData; 238 | var transform = eventData.pointerPress.GetComponent(); 239 | if (!RectTransformUtility.ScreenPointToWorldPointInRectangle( 240 | transform, 241 | eventData.pressPosition, 242 | eventData.pressEventCamera, 243 | out var worldPoint 244 | )) 245 | return; 246 | var corners = new Vector3[4]; 247 | transform.GetWorldCorners(corners); 248 | var point = worldPoint - corners[0]; 249 | var size = new Vector2(corners[3].x, corners[1].y) - (Vector2)corners[0]; 250 | // Focus camera at point 251 | cameraDevice.SetFocusPoint(point.x / size.x, point.y / size.y); 252 | 253 | if (fpsMonitor != null) 254 | fpsMonitor.Toast("Set Focus Point: " + point.x / size.x + " x " + point.y / size.y); 255 | } 256 | } 257 | } -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/NatDeviceCamPreviewToMatExample/NatDeviceCamPreviewToMatExample.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8ee1737701661f640b54a64e60ee8de5 3 | timeCreated: 1522098564 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/NatDeviceCamPreviewToMatExample/NatDeviceCamPreviewToMatExample.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b7a31f20bafa7a14997597b75d05ea78 3 | timeCreated: 1482683808 4 | licenseType: Store 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/NatDeviceCamPreviewToMatHelperExample.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fc933a03de5fd314bac0848335d7ca1c 3 | folderAsset: yes 4 | timeCreated: 1524603639 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/NatDeviceCamPreviewToMatHelperExample/ExampleMaterial.mat: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!21 &2100000 4 | Material: 5 | serializedVersion: 6 6 | m_ObjectHideFlags: 0 7 | m_PrefabParentObject: {fileID: 0} 8 | m_PrefabInternal: {fileID: 0} 9 | m_Name: ExampleMaterial 10 | m_Shader: {fileID: 10750, guid: 0000000000000000f000000000000000, type: 0} 11 | m_ShaderKeywords: 12 | m_LightmapFlags: 5 13 | m_EnableInstancingVariants: 0 14 | m_CustomRenderQueue: -1 15 | stringTagMap: {} 16 | disabledShaderPasses: [] 17 | m_SavedProperties: 18 | serializedVersion: 3 19 | m_TexEnvs: 20 | - _MainTex: 21 | m_Texture: {fileID: 2800000, guid: 9a89f0244015e104fb922e309d53caf1, type: 3} 22 | m_Scale: {x: 1, y: 1} 23 | m_Offset: {x: 0, y: 0} 24 | m_Floats: [] 25 | m_Colors: 26 | - _Color: {r: 1, g: 1, b: 1, a: 1} 27 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/NatDeviceCamPreviewToMatHelperExample/ExampleMaterial.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6c6c3f29578c5fc438256e239d0e7273 3 | NativeFormatImporter: 4 | userData: 5 | assetBundleName: 6 | assetBundleVariant: 7 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/NatDeviceCamPreviewToMatHelperExample/NatDeviceCamPreviewToMatHelperExample.cs: -------------------------------------------------------------------------------- 1 | using NatDeviceWithOpenCVForUnity.UnityUtils.Helper; 2 | using NatSuite.Devices; 3 | using OpenCVForUnity.CoreModule; 4 | using OpenCVForUnity.ImgprocModule; 5 | using OpenCVForUnity.UnityUtils; 6 | using OpenCVForUnity.UnityUtils.Helper; 7 | using System; 8 | using System.Collections.Generic; 9 | using UnityEngine; 10 | using UnityEngine.SceneManagement; 11 | using UnityEngine.UI; 12 | 13 | namespace NatDeviceWithOpenCVForUnityExample 14 | { 15 | /// 16 | /// NatDeviceCamPreviewToMatHelper Example 17 | /// 18 | [RequireComponent(typeof(NatDeviceCamPreviewToMatHelper))] 19 | public class NatDeviceCamPreviewToMatHelperExample : MonoBehaviour 20 | { 21 | /// 22 | /// The requested resolution dropdown. 23 | /// 24 | public Dropdown requestedResolutionDropdown; 25 | 26 | /// 27 | /// The requested resolution. 28 | /// 29 | public ResolutionPreset requestedResolution = ResolutionPreset._1280x720; 30 | 31 | /// 32 | /// The requestedFPS dropdown. 33 | /// 34 | public Dropdown requestedFPSDropdown; 35 | 36 | /// 37 | /// The requestedFPS. 38 | /// 39 | public FPSPreset requestedFPS = FPSPreset._30; 40 | 41 | /// 42 | /// The rotate 90 degree toggle. 43 | /// 44 | public Toggle rotate90DegreeToggle; 45 | 46 | /// 47 | /// The flip vertical toggle. 48 | /// 49 | public Toggle flipVerticalToggle; 50 | 51 | /// 52 | /// The flip horizontal toggle. 53 | /// 54 | public Toggle flipHorizontalToggle; 55 | 56 | /// 57 | /// The texture. 58 | /// 59 | Texture2D texture; 60 | 61 | /// 62 | /// The webcam texture to mat helper. 63 | /// 64 | NatDeviceCamPreviewToMatHelper webCamTextureToMatHelper; 65 | 66 | /// 67 | /// The FPS monitor. 68 | /// 69 | FpsMonitor fpsMonitor; 70 | 71 | // Use this for initialization 72 | void Start() 73 | { 74 | fpsMonitor = GetComponent(); 75 | if (fpsMonitor != null) 76 | { 77 | fpsMonitor.Add("deviceName", ""); 78 | fpsMonitor.Add("width", ""); 79 | fpsMonitor.Add("height", ""); 80 | fpsMonitor.Add("camera fps", ""); 81 | fpsMonitor.Add("isFrontFacing", ""); 82 | fpsMonitor.Add("rotate90Degree", ""); 83 | fpsMonitor.Add("flipVertical", ""); 84 | fpsMonitor.Add("flipHorizontal", ""); 85 | fpsMonitor.Add("orientation", ""); 86 | } 87 | 88 | webCamTextureToMatHelper = gameObject.GetComponent(); 89 | int width, height; 90 | Dimensions(requestedResolution, out width, out height); 91 | webCamTextureToMatHelper.requestedWidth = width; 92 | webCamTextureToMatHelper.requestedHeight = height; 93 | webCamTextureToMatHelper.requestedFPS = (int)requestedFPS; 94 | webCamTextureToMatHelper.Initialize(); 95 | 96 | // Update GUI state 97 | requestedResolutionDropdown.value = (int)requestedResolution; 98 | string[] enumNames = System.Enum.GetNames(typeof(FPSPreset)); 99 | int index = Array.IndexOf(enumNames, requestedFPS.ToString()); 100 | requestedFPSDropdown.value = index; 101 | rotate90DegreeToggle.isOn = webCamTextureToMatHelper.rotate90Degree; 102 | flipVerticalToggle.isOn = webCamTextureToMatHelper.flipVertical; 103 | flipHorizontalToggle.isOn = webCamTextureToMatHelper.flipHorizontal; 104 | } 105 | 106 | /// 107 | /// Raises the webcam texture to mat helper initialized event. 108 | /// 109 | public void OnWebCamTextureToMatHelperInitialized() 110 | { 111 | Debug.Log("OnWebCamTextureToMatHelperInitialized"); 112 | 113 | Mat webCamTextureMat = webCamTextureToMatHelper.GetMat(); 114 | 115 | texture = new Texture2D(webCamTextureMat.cols(), webCamTextureMat.rows(), TextureFormat.RGBA32, false); 116 | Utils.fastMatToTexture2D(webCamTextureMat, texture); 117 | 118 | gameObject.GetComponent().material.mainTexture = texture; 119 | 120 | gameObject.transform.localScale = new Vector3(webCamTextureMat.cols(), webCamTextureMat.rows(), 1); 121 | Debug.Log("Screen.width " + Screen.width + " Screen.height " + Screen.height + " Screen.orientation " + Screen.orientation); 122 | 123 | if (fpsMonitor != null) 124 | { 125 | fpsMonitor.Add("deviceName", webCamTextureToMatHelper.GetDeviceName().ToString()); 126 | fpsMonitor.Add("width", webCamTextureToMatHelper.GetWidth().ToString()); 127 | fpsMonitor.Add("height", webCamTextureToMatHelper.GetHeight().ToString()); 128 | fpsMonitor.Add("camera fps", webCamTextureToMatHelper.GetFPS().ToString()); 129 | fpsMonitor.Add("isFrontFacing", webCamTextureToMatHelper.IsFrontFacing().ToString()); 130 | fpsMonitor.Add("rotate90Degree", webCamTextureToMatHelper.rotate90Degree.ToString()); 131 | fpsMonitor.Add("flipVertical", webCamTextureToMatHelper.flipVertical.ToString()); 132 | fpsMonitor.Add("flipHorizontal", webCamTextureToMatHelper.flipHorizontal.ToString()); 133 | fpsMonitor.Add("orientation", Screen.orientation.ToString()); 134 | } 135 | 136 | 137 | float width = webCamTextureMat.width(); 138 | float height = webCamTextureMat.height(); 139 | 140 | float widthScale = (float)Screen.width / width; 141 | float heightScale = (float)Screen.height / height; 142 | if (widthScale < heightScale) 143 | { 144 | Camera.main.orthographicSize = (width * (float)Screen.height / (float)Screen.width) / 2; 145 | } 146 | else 147 | { 148 | Camera.main.orthographicSize = height / 2; 149 | } 150 | 151 | UpdateNatDeviceCameraProps(webCamTextureToMatHelper); 152 | } 153 | 154 | /// 155 | /// Raises the webcam texture to mat helper disposed event. 156 | /// 157 | public void OnWebCamTextureToMatHelperDisposed() 158 | { 159 | Debug.Log("OnWebCamTextureToMatHelperDisposed"); 160 | 161 | if (texture != null) 162 | { 163 | Texture2D.Destroy(texture); 164 | texture = null; 165 | } 166 | } 167 | 168 | /// 169 | /// Raises the webcam texture to mat helper error occurred event. 170 | /// 171 | /// Error code. 172 | public void OnWebCamTextureToMatHelperErrorOccurred(WebCamTextureToMatHelper.ErrorCode errorCode) 173 | { 174 | Debug.Log("OnWebCamTextureToMatHelperErrorOccurred " + errorCode); 175 | } 176 | 177 | // Update is called once per frame 178 | void Update() 179 | { 180 | if (webCamTextureToMatHelper.IsPlaying() && webCamTextureToMatHelper.DidUpdateThisFrame()) 181 | { 182 | Mat rgbaMat = webCamTextureToMatHelper.GetMat(); 183 | 184 | //Imgproc.putText (rgbaMat, "W:" + rgbaMat.width () + " H:" + rgbaMat.height () + " SO:" + Screen.orientation, new Point (5, rgbaMat.rows () - 10), Imgproc.FONT_HERSHEY_SIMPLEX, 1.0, new Scalar (255, 255, 255, 255), 2, Imgproc.LINE_AA, false); 185 | 186 | // Restore the coordinate system of the image by OpenCV's Flip function. 187 | Utils.fastMatToTexture2D(rgbaMat, texture); 188 | } 189 | } 190 | 191 | private void UpdateNatDeviceCameraProps(NatDeviceCamPreviewToMatHelper helper) 192 | { 193 | var cameraProps = new Dictionary(); 194 | cameraProps.Add("defaultForMediaType", helper.defaultForMediaType.ToString()); 195 | cameraProps.Add("exposureBias", helper.exposureBias_device.ToString()); 196 | cameraProps.Add("exposureBiasRange", helper.exposureBiasRange.min + "x" + helper.exposureBiasRange.max); 197 | cameraProps.Add("exposureDurationRange", helper.exposureDurationRange.min + "x" + helper.exposureDurationRange.max); 198 | cameraProps.Add("exposureMode", helper.exposureMode.ToString()); 199 | cameraProps.Add("ExposureModeSupported:Continuous", helper.ExposureModeSupported(CameraDevice.ExposureMode.Continuous).ToString()); 200 | cameraProps.Add("ExposureModeSupported:Locked", helper.ExposureModeSupported(CameraDevice.ExposureMode.Locked).ToString()); 201 | cameraProps.Add("ExposureModeSupported:Manual", helper.ExposureModeSupported(CameraDevice.ExposureMode.Manual).ToString()); 202 | cameraProps.Add("exposurePointSupported", helper.exposurePointSupported.ToString()); 203 | cameraProps.Add("fieldOfView", helper.fieldOfView.width + "x" + helper.fieldOfView.height); 204 | cameraProps.Add("flashMode", helper.flashMode.ToString()); 205 | cameraProps.Add("flashSupported", helper.flashSupported.ToString()); 206 | cameraProps.Add("focusMode", helper.focusMode.ToString()); 207 | cameraProps.Add("FocusModeSupported:Continuous", helper.FocusModeSupported(CameraDevice.FocusMode.Continuous).ToString()); 208 | cameraProps.Add("FocusModeSupported:Locked", helper.FocusModeSupported(CameraDevice.FocusMode.Locked).ToString()); 209 | cameraProps.Add("focusPointSupported", helper.focusPointSupported.ToString()); 210 | cameraProps.Add("frameRate", helper.frameRate.ToString()); 211 | cameraProps.Add("frontFacing", helper.frontFacing.ToString()); 212 | cameraProps.Add("ISORange", helper.ISORange.min + "x" + helper.ISORange.max); 213 | cameraProps.Add("location", helper.location.ToString()); 214 | cameraProps.Add("name", helper.name_device); 215 | cameraProps.Add("photoResolution", helper.photoResolution.width + "x" + helper.photoResolution.height); 216 | cameraProps.Add("previewResolution", helper.previewResolution.width + "x" + helper.previewResolution.height); 217 | cameraProps.Add("running", helper.running.ToString()); 218 | cameraProps.Add("torchEnabled", helper.torchEnabled.ToString()); 219 | cameraProps.Add("torchSupported", helper.torchSupported.ToString()); 220 | cameraProps.Add("uniqueID", helper.uniqueID.ToString()); 221 | cameraProps.Add("whiteBalanceLock", helper.whiteBalanceLock.ToString()); 222 | cameraProps.Add("whiteBalanceLockSupported", helper.whiteBalanceLockSupported.ToString()); 223 | cameraProps.Add("zoomRange", helper.zoomRange.max + "x" + helper.zoomRange.min); 224 | cameraProps.Add("zoomRatio", helper.zoomRatio.ToString()); 225 | 226 | if (fpsMonitor != null) 227 | { 228 | fpsMonitor.boxWidth = 280; 229 | fpsMonitor.boxHeight = 1080; 230 | fpsMonitor.LocateGUI(); 231 | 232 | foreach (string key in cameraProps.Keys) 233 | fpsMonitor.Add(key, cameraProps[key]); 234 | } 235 | } 236 | 237 | /// 238 | /// Raises the destroy event. 239 | /// 240 | void OnDestroy() 241 | { 242 | webCamTextureToMatHelper.Dispose(); 243 | } 244 | 245 | /// 246 | /// Raises the back button click event. 247 | /// 248 | public void OnBackButtonClick() 249 | { 250 | SceneManager.LoadScene("NatDeviceWithOpenCVForUnityExample"); 251 | } 252 | 253 | /// 254 | /// Raises the play button click event. 255 | /// 256 | public void OnPlayButtonClick() 257 | { 258 | webCamTextureToMatHelper.Play(); 259 | } 260 | 261 | /// 262 | /// Raises the pause button click event. 263 | /// 264 | public void OnPauseButtonClick() 265 | { 266 | webCamTextureToMatHelper.Pause(); 267 | } 268 | 269 | /// 270 | /// Raises the stop button click event. 271 | /// 272 | public void OnStopButtonClick() 273 | { 274 | webCamTextureToMatHelper.Stop(); 275 | } 276 | 277 | /// 278 | /// Raises the change camera button click event. 279 | /// 280 | public void OnChangeCameraButtonClick() 281 | { 282 | webCamTextureToMatHelper.requestedIsFrontFacing = !webCamTextureToMatHelper.requestedIsFrontFacing; 283 | } 284 | 285 | /// 286 | /// Raises the requested resolution dropdown value changed event. 287 | /// 288 | public void OnRequestedResolutionDropdownValueChanged(int result) 289 | { 290 | if ((int)requestedResolution != result) 291 | { 292 | requestedResolution = (ResolutionPreset)result; 293 | 294 | int width, height; 295 | Dimensions(requestedResolution, out width, out height); 296 | 297 | webCamTextureToMatHelper.Initialize(width, height); 298 | } 299 | } 300 | 301 | /// 302 | /// Raises the requestedFPS dropdown value changed event. 303 | /// 304 | public void OnRequestedFPSDropdownValueChanged(int result) 305 | { 306 | string[] enumNames = Enum.GetNames(typeof(FPSPreset)); 307 | int value = (int)System.Enum.Parse(typeof(FPSPreset), enumNames[result], true); 308 | 309 | if ((int)requestedFPS != value) 310 | { 311 | requestedFPS = (FPSPreset)value; 312 | 313 | webCamTextureToMatHelper.requestedFPS = (int)requestedFPS; 314 | } 315 | } 316 | 317 | /// 318 | /// Raises the rotate 90 degree toggle value changed event. 319 | /// 320 | public void OnRotate90DegreeToggleValueChanged() 321 | { 322 | if (rotate90DegreeToggle.isOn != webCamTextureToMatHelper.rotate90Degree) 323 | { 324 | webCamTextureToMatHelper.rotate90Degree = rotate90DegreeToggle.isOn; 325 | } 326 | 327 | if (fpsMonitor != null) 328 | fpsMonitor.Add("rotate90Degree", webCamTextureToMatHelper.rotate90Degree.ToString()); 329 | } 330 | 331 | /// 332 | /// Raises the flip vertical toggle value changed event. 333 | /// 334 | public void OnFlipVerticalToggleValueChanged() 335 | { 336 | if (flipVerticalToggle.isOn != webCamTextureToMatHelper.flipVertical) 337 | { 338 | webCamTextureToMatHelper.flipVertical = flipVerticalToggle.isOn; 339 | } 340 | 341 | if (fpsMonitor != null) 342 | fpsMonitor.Add("flipVertical", webCamTextureToMatHelper.flipVertical.ToString()); 343 | } 344 | 345 | /// 346 | /// Raises the flip horizontal toggle value changed event. 347 | /// 348 | public void OnFlipHorizontalToggleValueChanged() 349 | { 350 | if (flipHorizontalToggle.isOn != webCamTextureToMatHelper.flipHorizontal) 351 | { 352 | webCamTextureToMatHelper.flipHorizontal = flipHorizontalToggle.isOn; 353 | } 354 | 355 | if (fpsMonitor != null) 356 | fpsMonitor.Add("flipHorizontal", webCamTextureToMatHelper.flipHorizontal.ToString()); 357 | } 358 | 359 | public enum FPSPreset : int 360 | { 361 | _0 = 0, 362 | _1 = 1, 363 | _5 = 5, 364 | _10 = 10, 365 | _15 = 15, 366 | _30 = 30, 367 | _60 = 60, 368 | } 369 | 370 | public enum ResolutionPreset 371 | { 372 | Lowest, 373 | _640x480, 374 | _1280x720, 375 | _1920x1080, 376 | Highest, 377 | } 378 | 379 | private void Dimensions(ResolutionPreset preset, out int width, out int height) 380 | { 381 | switch (preset) 382 | { 383 | case ResolutionPreset.Lowest: 384 | width = height = 50; 385 | break; 386 | case ResolutionPreset._640x480: 387 | width = 640; 388 | height = 480; 389 | break; 390 | case ResolutionPreset._1920x1080: 391 | width = 1920; 392 | height = 1080; 393 | break; 394 | case ResolutionPreset.Highest: 395 | width = height = 9999; 396 | break; 397 | case ResolutionPreset._1280x720: 398 | default: 399 | width = 1280; 400 | height = 720; 401 | break; 402 | } 403 | } 404 | } 405 | } -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/NatDeviceCamPreviewToMatHelperExample/NatDeviceCamPreviewToMatHelperExample.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7a2cd8859f80e4b4188b88f2442b1d3b 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/NatDeviceCamPreviewToMatHelperExample/NatDeviceCamPreviewToMatHelperExample.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d6973b7cefe924f48a9b2f3e00c22c2a 3 | DefaultImporter: 4 | userData: 5 | assetBundleName: 6 | assetBundleVariant: 7 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/NatDeviceWithOpenCVForUnityExample.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using UnityEngine; 3 | using UnityEngine.SceneManagement; 4 | using UnityEngine.UI; 5 | 6 | namespace NatDeviceWithOpenCVForUnityExample 7 | { 8 | 9 | public class NatDeviceWithOpenCVForUnityExample : MonoBehaviour 10 | { 11 | 12 | public static string GetNatDeviceVersion() 13 | { 14 | return "1.2.0"; 15 | } 16 | 17 | public enum FrameratePreset 18 | { 19 | _10, 20 | _15, 21 | _30, 22 | _60 23 | } 24 | 25 | public enum ResolutionPreset 26 | { 27 | Lowest, 28 | _640x480, 29 | _1280x720, 30 | _1920x1080, 31 | Highest, 32 | } 33 | 34 | [HeaderAttribute("Benchmark")] 35 | public Dropdown cameraResolutionDropdown; 36 | public Dropdown cameraFPSDropdown; 37 | private static ResolutionPreset cameraResolution = ResolutionPreset._1280x720; 38 | private static FrameratePreset cameraFramerate = FrameratePreset._30; 39 | private static bool performImageProcessingEachTime = false; 40 | 41 | [Header("UI")] 42 | public Text exampleTitle; 43 | public Text versionInfo; 44 | public ScrollRect scrollRect; 45 | private static float verticalNormalizedPosition = 1f; 46 | 47 | public static void CameraConfiguration(out int width, out int height, out int framerate) 48 | { 49 | switch (cameraResolution) 50 | { 51 | case ResolutionPreset.Lowest: 52 | width = height = 50; 53 | break; 54 | case ResolutionPreset._640x480: 55 | width = 640; 56 | height = 480; 57 | break; 58 | case ResolutionPreset._1920x1080: 59 | width = 1920; 60 | height = 1080; 61 | break; 62 | case ResolutionPreset.Highest: 63 | width = height = 9999; 64 | break; 65 | case ResolutionPreset._1280x720: 66 | default: 67 | width = 1280; 68 | height = 720; 69 | break; 70 | } 71 | switch (cameraFramerate) 72 | { 73 | case FrameratePreset._10: 74 | framerate = 10; 75 | break; 76 | case FrameratePreset._15: 77 | framerate = 15; 78 | break; 79 | case FrameratePreset._60: 80 | framerate = 60; 81 | break; 82 | case FrameratePreset._30: 83 | default: 84 | framerate = 30; 85 | break; 86 | } 87 | } 88 | 89 | public static void ExampleSceneConfiguration(out bool performImageProcessingEachTime) 90 | { 91 | performImageProcessingEachTime = NatDeviceWithOpenCVForUnityExample.performImageProcessingEachTime; 92 | } 93 | 94 | void Awake() 95 | { 96 | QualitySettings.vSyncCount = 0; 97 | Application.targetFrameRate = 60; 98 | } 99 | 100 | IEnumerator Start() 101 | { 102 | 103 | exampleTitle.text = "NatDeviceWithOpenCVForUnity Example " + Application.version; 104 | 105 | versionInfo.text = "NatDevice " + GetNatDeviceVersion(); 106 | versionInfo.text += " / " + OpenCVForUnity.CoreModule.Core.NATIVE_LIBRARY_NAME + " " + OpenCVForUnity.UnityUtils.Utils.getVersion() + " (" + OpenCVForUnity.CoreModule.Core.VERSION + ")"; 107 | versionInfo.text += " / UnityEditor " + Application.unityVersion; 108 | versionInfo.text += " / "; 109 | #if UNITY_EDITOR 110 | versionInfo.text += "Editor"; 111 | #elif UNITY_STANDALONE_WIN 112 | versionInfo.text += "Windows"; 113 | #elif UNITY_STANDALONE_OSX 114 | versionInfo.text += "Mac OSX"; 115 | #elif UNITY_STANDALONE_LINUX 116 | versionInfo.text += "Linux"; 117 | #elif UNITY_ANDROID 118 | versionInfo.text += "Android"; 119 | #elif UNITY_IOS 120 | versionInfo.text += "iOS"; 121 | #elif UNITY_WSA 122 | versionInfo.text += "WSA"; 123 | #elif UNITY_WEBGL 124 | versionInfo.text += "WebGL"; 125 | #endif 126 | versionInfo.text += " "; 127 | #if ENABLE_MONO 128 | versionInfo.text += "Mono"; 129 | #elif ENABLE_IL2CPP 130 | versionInfo.text += "IL2CPP"; 131 | #elif ENABLE_DOTNET 132 | versionInfo.text += ".NET"; 133 | #endif 134 | 135 | scrollRect.verticalNormalizedPosition = verticalNormalizedPosition; 136 | 137 | // Update GUI state 138 | cameraResolutionDropdown.value = (int)cameraResolution; 139 | cameraFPSDropdown.value = (int)cameraFramerate; 140 | 141 | 142 | #if (UNITY_IOS || UNITY_ANDROID) && !UNITY_EDITOR 143 | RuntimePermissionHelper runtimePermissionHelper = GetComponent(); 144 | yield return runtimePermissionHelper.hasUserAuthorizedCameraPermission(); 145 | yield return runtimePermissionHelper.hasUserAuthorizedExternalStorageWritePermission(); // It works only with Android devices. 146 | #endif 147 | 148 | yield break; 149 | } 150 | 151 | public void OnCameraResolutionDropdownValueChanged(int result) 152 | { 153 | cameraResolution = (ResolutionPreset)result; 154 | } 155 | 156 | public void OnCameraFPSDropdownValueChanged(int result) 157 | { 158 | cameraFramerate = (FrameratePreset)result; 159 | } 160 | 161 | public void OnScrollRectValueChanged() 162 | { 163 | verticalNormalizedPosition = scrollRect.verticalNormalizedPosition; 164 | } 165 | 166 | public void OnShowSystemInfoButtonClick() 167 | { 168 | SceneManager.LoadScene("ShowSystemInfo"); 169 | } 170 | 171 | public void OnShowLicenseButtonClick() 172 | { 173 | SceneManager.LoadScene("ShowLicense"); 174 | } 175 | 176 | public void OnNatDeviceCamPreviewOnlyExampleButtonClick() 177 | { 178 | SceneManager.LoadScene("NatDeviceCamPreviewOnlyExample"); 179 | } 180 | 181 | public void OnWebCamTextureOnlyExampleButtonClick() 182 | { 183 | SceneManager.LoadScene("WebCamTextureOnlyExample"); 184 | } 185 | 186 | public void OnNatDeviceCamPreviewToMatExampleButtonClick() 187 | { 188 | SceneManager.LoadScene("NatDeviceCamPreviewToMatExample"); 189 | } 190 | 191 | public void OnWebCamTextureToMatExampleButtonClick() 192 | { 193 | SceneManager.LoadScene("WebCamTextureToMatExample"); 194 | } 195 | 196 | public void OnNatDeviceCamPreviewToMatHelperExampleButtonClick() 197 | { 198 | SceneManager.LoadScene("NatDeviceCamPreviewToMatHelperExample"); 199 | } 200 | 201 | public void OnIntegrationWithNatShareExampleButtonClick() 202 | { 203 | SceneManager.LoadScene("IntegrationWithNatShareExample"); 204 | } 205 | } 206 | } -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/NatDeviceWithOpenCVForUnityExample.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3fc005588c60a0a4c827e3838c5f0e0d 3 | timeCreated: 1521862404 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/NatDeviceWithOpenCVForUnityExample.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 70b98c90e8c1b7e40862f0229eb0d567 3 | timeCreated: 1521862404 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 21e9747b132986c4b8c0ebb383902e9f 3 | folderAsset: yes 4 | timeCreated: 1522155797 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/Scripts/ExampleBase.cs: -------------------------------------------------------------------------------- 1 | using OpenCVForUnity.CoreModule; 2 | using OpenCVForUnity.ImgprocModule; 3 | using System; 4 | using UnityEngine; 5 | using UnityEngine.SceneManagement; 6 | using UnityEngine.UI; 7 | 8 | namespace NatDeviceWithOpenCVForUnityExample 9 | { 10 | 11 | public abstract class ExampleBase : MonoBehaviour where T : ICameraSource 12 | { 13 | 14 | [Header("Preview")] 15 | public RawImage rawImage; 16 | public AspectRatioFitter aspectFitter; 17 | 18 | [Header("Camera")] 19 | public bool useFrontCamera; 20 | 21 | [Header("Processing")] 22 | public ImageProcessingType imageProcessingType = ImageProcessingType.None; 23 | public Dropdown imageProcessingTypeDropdown; 24 | 25 | protected T cameraSource; 26 | 27 | protected int updateCount, onFrameCount, drawCount; 28 | protected float elapsed, updateFPS, onFrameFPS, drawFPS; 29 | 30 | 31 | #region --Lifecycle-- 32 | 33 | protected virtual void Start() 34 | { 35 | // Update UI 36 | if (imageProcessingTypeDropdown != null) 37 | imageProcessingTypeDropdown.value = (int)imageProcessingType; 38 | } 39 | 40 | protected virtual void Update() 41 | { 42 | updateCount++; 43 | elapsed += Time.deltaTime; 44 | if (elapsed >= 1f) 45 | { 46 | updateFPS = updateCount / elapsed; 47 | onFrameFPS = onFrameCount / elapsed; 48 | drawFPS = drawCount / elapsed; 49 | updateCount = onFrameCount = drawCount = 0; 50 | elapsed = 0f; 51 | } 52 | } 53 | 54 | protected virtual void OnStart() 55 | { 56 | //Debug.Log("##### OnStart() #####"); 57 | 58 | useFrontCamera = cameraSource.isFrontFacing; 59 | } 60 | 61 | protected virtual void OnFrame() 62 | { 63 | //Debug.Log("##### OnFrame() #####"); 64 | 65 | onFrameCount++; 66 | UpdateTexture(); 67 | drawCount++; 68 | } 69 | 70 | protected virtual void OnDestroy() 71 | { 72 | if (cameraSource != null) 73 | { 74 | cameraSource.Dispose(); 75 | cameraSource = default(T); 76 | } 77 | } 78 | 79 | #endregion 80 | 81 | 82 | #region --UI Callbacks-- 83 | 84 | public void OnBackButtonClick() 85 | { 86 | SceneManager.LoadScene("NatDeviceWithOpenCVForUnityExample"); 87 | } 88 | 89 | public async void OnPlayButtonClick() 90 | { 91 | //Debug.Log("##### OnPlayButton() #####"); 92 | 93 | if (cameraSource == null) return; 94 | 95 | try 96 | { 97 | await cameraSource.StartRunning(OnStart, OnFrame); 98 | } 99 | catch (ApplicationException e) 100 | { 101 | Debug.LogError(e.Message); 102 | } 103 | } 104 | 105 | public void OnStopButtonClick() 106 | { 107 | //Debug.Log("##### OnStopButton() #####"); 108 | 109 | if (cameraSource == null) return; 110 | 111 | cameraSource.StopRunning(); 112 | } 113 | 114 | public async void OnChangeCameraButtonClick() 115 | { 116 | //Debug.Log("##### OnChangeCameraButton() #####"); 117 | 118 | if (cameraSource == null) return; 119 | 120 | try 121 | { 122 | await cameraSource.SwitchCamera(); 123 | } 124 | catch (ApplicationException e) 125 | { 126 | Debug.LogError(e.Message); 127 | } 128 | } 129 | 130 | public void OnImageProcessingTypeDropdownValueChanged(int result) 131 | { 132 | imageProcessingType = (ImageProcessingType)result; 133 | } 134 | 135 | #endregion 136 | 137 | 138 | #region --Operations-- 139 | 140 | protected abstract void UpdateTexture(); 141 | 142 | protected void ProcessImage(Color32[] buffer, int width, int height, ImageProcessingType imageProcessingType) 143 | { 144 | switch (imageProcessingType) 145 | { 146 | case ImageProcessingType.DrawLine: 147 | // Draw a diagonal line on our image 148 | float inclination = height / (float)width; 149 | for (int i = 0; i < 4; i++) 150 | { 151 | for (int x = 0; x < width; x++) 152 | { 153 | int y = (int)(-inclination * x) + height - 2 + i; 154 | y = Mathf.Clamp(y, 0, height - 1); 155 | int p = (x) + (y * width); 156 | // Set pixels in the buffer 157 | buffer.SetValue(new Color32(255, 0, 0, 255), p); 158 | } 159 | } 160 | 161 | break; 162 | case ImageProcessingType.ConvertToGray: 163 | // Convert a four-channel pixel buffer to greyscale 164 | // Iterate over the buffer 165 | for (int i = 0; i < buffer.Length; i++) 166 | { 167 | var p = buffer[i]; 168 | // Get channel intensities 169 | byte r = p.r, g = p.g, b = p.b, a = p.a, 170 | // Use quick luminance approximation to save time and memory 171 | l = (byte)((r + r + r + b + g + g + g + g) >> 3); 172 | // Set pixels in the buffer 173 | buffer[i] = new Color32(l, l, l, a); 174 | } 175 | break; 176 | } 177 | } 178 | 179 | protected void ProcessImage(byte[] buffer, int width, int height, ImageProcessingType imageProcessingType) 180 | { 181 | switch (imageProcessingType) 182 | { 183 | case ImageProcessingType.DrawLine: 184 | // Draw a diagonal line on our image 185 | float inclination = height / (float)width; 186 | for (int i = 0; i < 4; i++) 187 | { 188 | for (int x = 0; x < width; x++) 189 | { 190 | int y = (int)(-inclination * x) + height - 2 + i; 191 | y = Mathf.Clamp(y, 0, height - 1); 192 | int p = (x * 4) + (y * width * 4); 193 | // Set pixels in the buffer 194 | buffer[p] = 255; 195 | buffer[p + 1] = 0; 196 | buffer[p + 2] = 0; 197 | buffer[p + 3] = 255; 198 | } 199 | } 200 | 201 | break; 202 | case ImageProcessingType.ConvertToGray: 203 | // Convert a four-channel pixel buffer to greyscale 204 | // Iterate over the buffer 205 | for (int i = 0; i < buffer.Length; i = i + 4) 206 | { 207 | // Get channel intensities 208 | byte r = buffer[i]; 209 | byte g = buffer[i + 1]; 210 | byte b = buffer[i + 2]; 211 | byte a = buffer[i + 3]; 212 | // Use quick luminance approximation to save time and memory 213 | byte l = (byte)((r + r + r + b + g + g + g + g) >> 3); 214 | // Set pixels in the buffer 215 | buffer[i] = buffer[i + 1] = buffer[i + 2] = l; 216 | buffer[i + 3] = a; 217 | } 218 | break; 219 | } 220 | } 221 | 222 | protected void ProcessImage(Mat frameMatrix, Mat grayMatrix, ImageProcessingType imageProcessingType) 223 | { 224 | switch (imageProcessingType) 225 | { 226 | case ImageProcessingType.DrawLine: 227 | Imgproc.line( 228 | frameMatrix, 229 | new Point(0, 0), 230 | new Point(frameMatrix.cols(), frameMatrix.rows()), 231 | new Scalar(255, 0, 0, 255), 232 | 4 233 | ); 234 | break; 235 | case ImageProcessingType.ConvertToGray: 236 | Imgproc.cvtColor(frameMatrix, grayMatrix, Imgproc.COLOR_RGBA2GRAY); 237 | Imgproc.cvtColor(grayMatrix, frameMatrix, Imgproc.COLOR_GRAY2RGBA); 238 | break; 239 | } 240 | } 241 | 242 | #endregion 243 | } 244 | 245 | public enum ImageProcessingType 246 | { 247 | None, 248 | DrawLine, 249 | ConvertToGray, 250 | } 251 | } -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/Scripts/ExampleBase.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7876b09c1405d4835a53efb593d78029 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/Scripts/ICameraSource.cs: -------------------------------------------------------------------------------- 1 | using OpenCVForUnity.CoreModule; 2 | using System; 3 | using System.Threading.Tasks; 4 | using UnityEngine; 5 | 6 | namespace NatDeviceWithOpenCVForUnityExample 7 | { 8 | 9 | public interface ICameraSource 10 | { 11 | 12 | #region --Properties-- 13 | 14 | int width { get; } 15 | 16 | int height { get; } 17 | 18 | bool isRunning { get; } 19 | 20 | bool isFrontFacing { get; } 21 | 22 | #endregion 23 | 24 | 25 | #region --Operations-- 26 | 27 | Task StartRunning(Action startCallback, Action frameCallback); 28 | 29 | void StopRunning(); 30 | 31 | void CaptureFrame(Mat matrix); 32 | 33 | void CaptureFrame(Color32[] pixelBuffer); 34 | 35 | void CaptureFrame(byte[] pixelBuffer); 36 | 37 | Task SwitchCamera(); 38 | 39 | void Dispose(); 40 | 41 | #endregion 42 | } 43 | } -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/Scripts/ICameraSource.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d7f3d8ae972b34e85823d6cd3323bfe7 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/Scripts/NatDeviceCamSource.cs: -------------------------------------------------------------------------------- 1 | using NatSuite.Devices; 2 | using NatSuite.Devices.Outputs; 3 | using OpenCVForUnity.CoreModule; 4 | using OpenCVForUnity.UtilsModule; 5 | using System; 6 | using System.Runtime.InteropServices; 7 | using System.Threading.Tasks; 8 | using UnityEngine; 9 | 10 | namespace NatDeviceWithOpenCVForUnityExample 11 | { 12 | 13 | public class NatDeviceCamSource : ICameraSource 14 | { 15 | 16 | #region --Op vars-- 17 | 18 | private Action startCallback, frameCallback; 19 | private int requestedWidth, requestedHeight, requestedFramerate; 20 | private MediaDeviceQuery deviceQuery; 21 | private PixelBufferOutput previewPixelBufferOutput; 22 | 23 | #endregion 24 | 25 | 26 | #region --Client API-- 27 | 28 | public int width { get; private set; } 29 | 30 | public int height { get; private set; } 31 | 32 | public long timestamp { get; private set; } 33 | 34 | public bool verticallyMirrored { get; private set; } 35 | 36 | public Matrix4x4 intrinsics { get; private set; } 37 | 38 | public float exposureBias { get; private set; } 39 | 40 | public float exposureDuration { get; private set; } 41 | 42 | public float ISO { get; private set; } 43 | 44 | public float focalLength { get; private set; } 45 | 46 | public float fNumber { get; private set; } 47 | 48 | public float brightness { get; private set; } 49 | 50 | 51 | public bool isRunning { get; private set; } 52 | 53 | public bool isFrontFacing { get { return activeCamera != null ? activeCamera.frontFacing : false; } } 54 | 55 | public CameraDevice activeCamera { get; private set; } 56 | 57 | public NatDeviceCamSource(int width, int height, int framerate = 30, bool front = false) 58 | { 59 | requestedWidth = width; 60 | requestedHeight = height; 61 | requestedFramerate = framerate; 62 | 63 | // Create a device query for device cameras 64 | deviceQuery = new MediaDeviceQuery(MediaDeviceCriteria.CameraDevice); 65 | 66 | // Pick camera 67 | if (deviceQuery.count == 0) 68 | { 69 | Debug.LogError("Camera device does not exist."); 70 | return; 71 | } 72 | 73 | for (var i = 0; i < deviceQuery.count; i++) 74 | { 75 | activeCamera = deviceQuery.current as CameraDevice; 76 | if (activeCamera != null && activeCamera.frontFacing == front) break; 77 | deviceQuery.Advance(); 78 | activeCamera = null; 79 | } 80 | 81 | if (activeCamera == null) 82 | { 83 | Debug.LogError("Camera is null. Consider using " + (front ? "rear" : "front") + " camera."); 84 | return; 85 | } 86 | 87 | activeCamera.previewResolution = (width: requestedWidth, height: requestedHeight); 88 | activeCamera.frameRate = requestedFramerate; 89 | } 90 | 91 | public void Dispose() 92 | { 93 | StopRunning(); 94 | 95 | activeCamera = null; 96 | } 97 | 98 | public async Task StartRunning(Action startCallback, Action frameCallback) 99 | { 100 | if (activeCamera == null || isRunning) 101 | return; 102 | 103 | this.startCallback = startCallback; 104 | this.frameCallback = frameCallback; 105 | 106 | if (previewPixelBufferOutput == null) 107 | previewPixelBufferOutput = new PixelBufferOutput(); 108 | 109 | activeCamera.StartRunning(OnPixelBufferOutputReceived); 110 | 111 | await Task.Yield(); 112 | } 113 | 114 | public void StopRunning() 115 | { 116 | if (activeCamera == null || !isRunning) 117 | return; 118 | 119 | isRunning = false; 120 | 121 | if (previewPixelBufferOutput != null) 122 | { 123 | previewPixelBufferOutput.Dispose(); 124 | previewPixelBufferOutput = null; 125 | } 126 | 127 | if (activeCamera.running) 128 | activeCamera.StopRunning(); 129 | } 130 | 131 | public void CaptureFrame(Mat matrix) 132 | { 133 | if (!isRunning) return; 134 | 135 | if (matrix.width() != previewPixelBufferOutput.width || matrix.height() != previewPixelBufferOutput.height) 136 | throw new ArgumentException("matrix and CamSource image need to be the same size."); 137 | 138 | MatUtils.copyToMat(previewPixelBufferOutput.pixelBuffer, matrix); 139 | Core.flip(matrix, matrix, 0); 140 | } 141 | 142 | public void CaptureFrame(Color32[] pixelBuffer) 143 | { 144 | if (!isRunning) return; 145 | 146 | if (pixelBuffer.Length * 4 != previewPixelBufferOutput.pixelBuffer.Length) 147 | throw new ArgumentException("pixelBuffer and CamSource image need to be the same size."); 148 | 149 | unsafe 150 | { 151 | GCHandle pin = GCHandle.Alloc(pixelBuffer, GCHandleType.Pinned); 152 | Buffer.MemoryCopy(Unity.Collections.LowLevel.Unsafe.NativeArrayUnsafeUtility.GetUnsafeReadOnlyPtr(previewPixelBufferOutput.pixelBuffer), (void*)pin.AddrOfPinnedObject(), pixelBuffer.Length * 4, previewPixelBufferOutput.pixelBuffer.Length); 153 | pin.Free(); 154 | } 155 | } 156 | 157 | public void CaptureFrame(byte[] pixelBuffer) 158 | { 159 | if (!isRunning) return; 160 | 161 | if (pixelBuffer.Length != previewPixelBufferOutput.pixelBuffer.Length) 162 | throw new ArgumentException("pixelBuffer and CamSource image need to be the same size."); 163 | 164 | previewPixelBufferOutput.pixelBuffer.CopyTo(pixelBuffer); 165 | } 166 | 167 | public async Task SwitchCamera() 168 | { 169 | if (activeCamera == null) 170 | return; 171 | 172 | var _isRunning = isRunning; 173 | 174 | Dispose(); 175 | 176 | deviceQuery.Advance(); 177 | activeCamera = deviceQuery.current as CameraDevice; 178 | 179 | activeCamera.previewResolution = (width: requestedWidth, height: requestedHeight); 180 | activeCamera.frameRate = requestedFramerate; 181 | 182 | await StartRunning(startCallback, frameCallback); 183 | 184 | if (!_isRunning) 185 | StopRunning(); 186 | } 187 | 188 | #endregion 189 | 190 | 191 | #region --Operations-- 192 | 193 | private void OnPixelBufferOutputReceived(CameraImage image) 194 | { 195 | if (previewPixelBufferOutput == null) 196 | return; 197 | 198 | // Process only when the latest previewResolution and CameraImage size match. 199 | if (activeCamera == null || activeCamera.previewResolution.width != image.width || activeCamera.previewResolution.height != image.height) 200 | return; 201 | 202 | timestamp = image.timestamp; 203 | verticallyMirrored = image.verticallyMirrored; 204 | float[] intrinsics = image.intrinsics; 205 | this.intrinsics = (intrinsics != null) ? 206 | new Matrix4x4( 207 | new Vector4(intrinsics[0], intrinsics[3], intrinsics[6]), 208 | new Vector4(intrinsics[1], intrinsics[4], intrinsics[7]), 209 | new Vector4(intrinsics[2], intrinsics[5], intrinsics[8]), 210 | new Vector4()) 211 | : Matrix4x4.zero; 212 | exposureBias = image.exposureBias ?? -1f; 213 | exposureDuration = image.exposureDuration ?? -1f; 214 | ISO = image.ISO ?? -1f; 215 | focalLength = image.focalLength ?? -1f; 216 | fNumber = image.fNumber ?? -1f; 217 | brightness = image.brightness ?? -1f; 218 | 219 | 220 | bool firstFrame = !previewPixelBufferOutput.pixelBuffer.IsCreated; 221 | 222 | previewPixelBufferOutput.Update(image); 223 | 224 | if (firstFrame) 225 | { 226 | width = previewPixelBufferOutput.width; 227 | height = previewPixelBufferOutput.height; 228 | 229 | isRunning = true; 230 | 231 | startCallback(); 232 | } 233 | else 234 | { 235 | frameCallback(); 236 | } 237 | 238 | } 239 | 240 | #endregion 241 | } 242 | } -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/Scripts/NatDeviceCamSource.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 84e02125237fe4d6f865b3862bfd52c3 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/Scripts/Utils.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a69a2a8276734bb4eb9e353b5b07354a 3 | folderAsset: yes 4 | timeCreated: 1522155806 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/Scripts/Utils/FpsMonitor.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | 4 | namespace NatDeviceWithOpenCVForUnityExample 5 | { 6 | // v1.0.1 7 | public class FpsMonitor : MonoBehaviour 8 | { 9 | int tick = 0; 10 | float elapsed = 0; 11 | float fps = 0; 12 | 13 | public enum Alignment 14 | { 15 | LeftTop, 16 | RightTop, 17 | LeftBottom, 18 | RightBottom, 19 | } 20 | 21 | public Alignment alignment = Alignment.RightTop; 22 | 23 | const float GUI_WIDTH = 75f; 24 | const float GUI_HEIGHT = 30f; 25 | const float MARGIN_X = 10f; 26 | const float MARGIN_Y = 10f; 27 | const float INNER_X = 8f; 28 | const float INNER_Y = 5f; 29 | const float GUI_CONSOLE_HEIGHT = 50f; 30 | 31 | public Vector2 offset = new Vector2(MARGIN_X, MARGIN_Y); 32 | public bool boxVisible = true; 33 | public float boxWidth = GUI_WIDTH; 34 | public float boxHeight = GUI_HEIGHT; 35 | public Vector2 padding = new Vector2(INNER_X, INNER_Y); 36 | public float consoleHeight = GUI_CONSOLE_HEIGHT; 37 | 38 | GUIStyle console_labelStyle; 39 | 40 | float x, y; 41 | Rect outer; 42 | Rect inner; 43 | 44 | float console_x, console_y; 45 | Rect console_outer; 46 | Rect console_inner; 47 | 48 | int oldScrWidth; 49 | int oldScrHeight; 50 | 51 | Dictionary outputDict = new Dictionary(); 52 | 53 | protected string _consoleText = null; 54 | public virtual string consoleText 55 | { 56 | get { return _consoleText; } 57 | set 58 | { 59 | _consoleText = value; 60 | toast_time = -1; 61 | } 62 | } 63 | 64 | int toast_time = -1; 65 | 66 | // Use this for initialization 67 | void Start() 68 | { 69 | console_labelStyle = new GUIStyle(); 70 | console_labelStyle.fontSize = 32; 71 | console_labelStyle.fontStyle = FontStyle.Normal; 72 | console_labelStyle.wordWrap = true; 73 | console_labelStyle.normal.textColor = Color.white; 74 | 75 | oldScrWidth = Screen.width; 76 | oldScrHeight = Screen.height; 77 | LocateGUI(); 78 | } 79 | 80 | // Update is called once per frame 81 | void Update() 82 | { 83 | tick++; 84 | elapsed += Time.deltaTime; 85 | if (elapsed >= 1f) 86 | { 87 | fps = tick / elapsed; 88 | tick = 0; 89 | elapsed = 0; 90 | } 91 | 92 | if (toast_time > 0) 93 | { 94 | toast_time = toast_time - 1; 95 | } 96 | } 97 | 98 | void OnGUI() 99 | { 100 | if (oldScrWidth != Screen.width || oldScrHeight != Screen.height) 101 | { 102 | LocateGUI(); 103 | } 104 | oldScrWidth = Screen.width; 105 | oldScrHeight = Screen.height; 106 | 107 | if (boxVisible) 108 | { 109 | GUI.Box(outer, ""); 110 | } 111 | 112 | GUILayout.BeginArea(inner); 113 | { 114 | GUILayout.BeginVertical(); 115 | GUILayout.Label("fps : " + fps.ToString("F1")); 116 | foreach (KeyValuePair pair in outputDict) 117 | { 118 | GUILayout.Label(pair.Key + " : " + pair.Value); 119 | } 120 | GUILayout.EndVertical(); 121 | } 122 | GUILayout.EndArea(); 123 | 124 | if (!string.IsNullOrEmpty(consoleText)) 125 | { 126 | if (toast_time != 0) 127 | { 128 | if (boxVisible) 129 | { 130 | GUI.Box(console_outer, ""); 131 | } 132 | 133 | GUILayout.BeginArea(console_inner); 134 | { 135 | GUILayout.BeginVertical(); 136 | GUILayout.Label(consoleText, console_labelStyle); 137 | GUILayout.EndVertical(); 138 | } 139 | GUILayout.EndArea(); 140 | } 141 | } 142 | } 143 | 144 | public void Add(string key, string value) 145 | { 146 | if (outputDict.ContainsKey(key)) 147 | { 148 | outputDict[key] = value; 149 | } 150 | else 151 | { 152 | outputDict.Add(key, value); 153 | } 154 | } 155 | 156 | public void Remove(string key) 157 | { 158 | outputDict.Remove(key); 159 | } 160 | 161 | public void Clear() 162 | { 163 | outputDict.Clear(); 164 | } 165 | 166 | public void LocateGUI() 167 | { 168 | x = GetAlignedX(alignment, boxWidth); 169 | y = GetAlignedY(alignment, boxHeight); 170 | outer = new Rect(x, y, boxWidth, boxHeight); 171 | inner = new Rect(x + padding.x, y + padding.y, boxWidth, boxHeight); 172 | 173 | console_x = GetAlignedX(Alignment.LeftBottom, Screen.width); 174 | console_y = GetAlignedY(Alignment.LeftBottom, consoleHeight); 175 | console_outer = new Rect(console_x, console_y, Screen.width - offset.x * 2, consoleHeight); 176 | console_inner = new Rect(console_x + padding.x, console_y + padding.y, Screen.width - offset.x * 2 - padding.x, consoleHeight); 177 | } 178 | 179 | public void Toast(string message, int time = 120) 180 | { 181 | _consoleText = message; 182 | toast_time = (time < 60) ? 60 : time; 183 | } 184 | 185 | float GetAlignedX(Alignment anchor, float w) 186 | { 187 | switch (anchor) 188 | { 189 | default: 190 | case Alignment.LeftTop: 191 | case Alignment.LeftBottom: 192 | return offset.x; 193 | 194 | case Alignment.RightTop: 195 | case Alignment.RightBottom: 196 | return Screen.width - w - offset.x; 197 | } 198 | } 199 | 200 | float GetAlignedY(Alignment anchor, float h) 201 | { 202 | switch (anchor) 203 | { 204 | default: 205 | case Alignment.LeftTop: 206 | case Alignment.RightTop: 207 | return offset.y; 208 | 209 | case Alignment.LeftBottom: 210 | case Alignment.RightBottom: 211 | return Screen.height - h - offset.y; 212 | } 213 | } 214 | } 215 | } -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/Scripts/Utils/FpsMonitor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9730a00114a61104b87dc34be31889c0 3 | timeCreated: 1521859037 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/Scripts/Utils/NatDeviceCamPreviewToMatHelper.cs: -------------------------------------------------------------------------------- 1 | using NatSuite.Devices; 2 | using NatSuite.Devices.Outputs; 3 | using OpenCVForUnity.CoreModule; 4 | using OpenCVForUnity.ImgprocModule; 5 | using OpenCVForUnity.UnityUtils.Helper; 6 | using OpenCVForUnity.UtilsModule; 7 | using System; 8 | using System.Collections; 9 | using UnityEngine; 10 | 11 | namespace NatDeviceWithOpenCVForUnity.UnityUtils.Helper 12 | { 13 | /// 14 | /// This is called every time there is the current frame image mat available. 15 | /// The Mat object's type is 'CV_8UC4' or 'CV_8UC3' or 'CV_8UC1' (ColorFormat is determined by the outputColorFormat setting). 16 | /// 17 | /// The recently captured frame image mat. 18 | /// Pixel buffer timestamp in nanoseconds. 19 | public delegate void FrameMatAcquiredCallback(Mat mat, long timestamp); 20 | 21 | /// 22 | /// NatDeviceCamPreview to mat helper. 23 | /// v 1.0.3 24 | /// Depends on NatDevice version 1.2.0 or later. 25 | /// Depends on OpenCVForUnity version 2.4.4 (WebCamTextureToMatHelper v 1.1.3 or later. 26 | /// 27 | public class NatDeviceCamPreviewToMatHelper : WebCamTextureToMatHelper 28 | { 29 | /// 30 | /// This will be called whenever the current frame image available is converted to Mat. 31 | /// The Mat object's type is 'CV_8UC4' or 'CV_8UC3' or 'CV_8UC1' (ColorFormat is determined by the outputColorFormat setting). 32 | /// You must properly initialize the NatDeviceCamPreviewToMatHelper, 33 | /// including calling Play() before this event will begin firing. 34 | /// 35 | public virtual event FrameMatAcquiredCallback frameMatAcquired; 36 | 37 | 38 | #region --NatDevice CameraDevice Properties-- 39 | 40 | public virtual bool defaultForMediaType => GetNatDeviceCameraDevice() != null ? GetNatDeviceCameraDevice().defaultForMediaType : default; 41 | 42 | public virtual float exposureBias_device // exposureBias 43 | { 44 | get { return GetNatDeviceCameraDevice() != null ? GetNatDeviceCameraDevice().exposureBias : default; } 45 | set { if (GetNatDeviceCameraDevice() != null) GetNatDeviceCameraDevice().exposureBias = value; } 46 | } 47 | 48 | public virtual (float min, float max) exposureBiasRange 49 | { 50 | get { return GetNatDeviceCameraDevice() != null ? GetNatDeviceCameraDevice().exposureBiasRange : default; } 51 | } 52 | 53 | public virtual (float min, float max) exposureDurationRange 54 | { 55 | get { return GetNatDeviceCameraDevice() != null ? GetNatDeviceCameraDevice().exposureDurationRange : default; } 56 | } 57 | 58 | public virtual CameraDevice.ExposureMode exposureMode 59 | { 60 | get { return GetNatDeviceCameraDevice() != null ? GetNatDeviceCameraDevice().exposureMode : default; } 61 | set { if (GetNatDeviceCameraDevice() != null) GetNatDeviceCameraDevice().exposureMode = value; } 62 | } 63 | 64 | public virtual bool exposurePointSupported => GetNatDeviceCameraDevice() != null ? GetNatDeviceCameraDevice().exposurePointSupported : default; 65 | 66 | public virtual (float width, float height) fieldOfView 67 | { 68 | get { return GetNatDeviceCameraDevice() != null ? GetNatDeviceCameraDevice().fieldOfView : default; } 69 | } 70 | 71 | public virtual CameraDevice.FlashMode flashMode 72 | { 73 | get { return (GetNatDeviceCameraDevice() != null && GetNatDeviceCameraDevice().running) ? GetNatDeviceCameraDevice().flashMode : default; } 74 | set { if (GetNatDeviceCameraDevice() != null) GetNatDeviceCameraDevice().flashMode = value; } 75 | } 76 | 77 | public virtual bool flashSupported => GetNatDeviceCameraDevice() != null ? GetNatDeviceCameraDevice().flashSupported : default; 78 | 79 | public virtual CameraDevice.FocusMode focusMode 80 | { 81 | get { return GetNatDeviceCameraDevice() != null ? GetNatDeviceCameraDevice().focusMode : default; } 82 | set { if (GetNatDeviceCameraDevice() != null) GetNatDeviceCameraDevice().focusMode = value; } 83 | } 84 | 85 | public virtual bool focusPointSupported => GetNatDeviceCameraDevice() != null ? GetNatDeviceCameraDevice().focusPointSupported : default; 86 | 87 | public virtual int frameRate 88 | { 89 | get { return GetNatDeviceCameraDevice() != null ? GetNatDeviceCameraDevice().frameRate : default; } 90 | set { if (GetNatDeviceCameraDevice() != null) GetNatDeviceCameraDevice().frameRate = value; } 91 | } 92 | 93 | public virtual bool frontFacing => GetNatDeviceCameraDevice() != null ? GetNatDeviceCameraDevice().frontFacing : default; 94 | 95 | public virtual (float min, float max) ISORange 96 | { 97 | get { return GetNatDeviceCameraDevice() != null ? GetNatDeviceCameraDevice().ISORange : default; } 98 | } 99 | 100 | public virtual DeviceLocation location => GetNatDeviceCameraDevice() != null ? GetNatDeviceCameraDevice().location : default; 101 | 102 | public virtual string name_device => GetNatDeviceCameraDevice() != null ? GetNatDeviceCameraDevice().name : ""; // name 103 | 104 | public virtual (int width, int height) previewResolution 105 | { 106 | get { return GetNatDeviceCameraDevice() != null ? GetNatDeviceCameraDevice().previewResolution : default; } 107 | set { if (GetNatDeviceCameraDevice() != null) GetNatDeviceCameraDevice().previewResolution = (width: value.width, height: value.height); } 108 | } 109 | 110 | public virtual (int width, int height) photoResolution 111 | { 112 | get { return GetNatDeviceCameraDevice() != null ? GetNatDeviceCameraDevice().photoResolution : default; } 113 | set { if (GetNatDeviceCameraDevice() != null) GetNatDeviceCameraDevice().photoResolution = (width: value.width, height: value.height); } 114 | } 115 | 116 | public virtual bool running => GetNatDeviceCameraDevice() != null ? GetNatDeviceCameraDevice().running : default; 117 | 118 | public virtual bool torchEnabled 119 | { 120 | get { return GetNatDeviceCameraDevice() != null ? GetNatDeviceCameraDevice().torchEnabled : default; } 121 | set { if (GetNatDeviceCameraDevice() != null) GetNatDeviceCameraDevice().torchEnabled = value; } 122 | } 123 | 124 | public virtual bool torchSupported => GetNatDeviceCameraDevice() != null ? GetNatDeviceCameraDevice().torchSupported : default; 125 | 126 | public virtual string uniqueID => GetNatDeviceCameraDevice() != null ? GetNatDeviceCameraDevice().uniqueID : ""; 127 | 128 | public virtual bool whiteBalanceLock 129 | { 130 | get { return GetNatDeviceCameraDevice() != null ? GetNatDeviceCameraDevice().whiteBalanceLock : default; } 131 | set { if (GetNatDeviceCameraDevice() != null) GetNatDeviceCameraDevice().whiteBalanceLock = value; } 132 | } 133 | 134 | public virtual bool whiteBalanceLockSupported => GetNatDeviceCameraDevice() != null ? GetNatDeviceCameraDevice().whiteBalanceLockSupported : default; 135 | 136 | public virtual (float min, float max) zoomRange 137 | { 138 | get { return GetNatDeviceCameraDevice() != null ? GetNatDeviceCameraDevice().zoomRange : default; } 139 | } 140 | 141 | public virtual float zoomRatio 142 | { 143 | get { return GetNatDeviceCameraDevice() != null ? GetNatDeviceCameraDevice().zoomRatio : default; } 144 | set { if (GetNatDeviceCameraDevice() != null) GetNatDeviceCameraDevice().zoomRatio = value; } 145 | } 146 | 147 | #endregion 148 | 149 | 150 | #region --NatDevice CameraDevice Functions-- 151 | 152 | public virtual void CapturePhoto(Action handler) 153 | { 154 | if (GetNatDeviceCameraDevice() != null) GetNatDeviceCameraDevice().CapturePhoto(handler); 155 | } 156 | 157 | public virtual bool ExposureModeSupported(CameraDevice.ExposureMode exposureMode) 158 | { 159 | return GetNatDeviceCameraDevice() != null ? GetNatDeviceCameraDevice().ExposureModeSupported(exposureMode) : default; 160 | } 161 | 162 | public virtual bool FocusModeSupported(CameraDevice.FocusMode focusMode) 163 | { 164 | return GetNatDeviceCameraDevice() != null ? GetNatDeviceCameraDevice().FocusModeSupported(focusMode) : default; 165 | } 166 | 167 | public virtual void SetExposureDuration(float duration, float ISO) 168 | { 169 | if (GetNatDeviceCameraDevice() != null) GetNatDeviceCameraDevice().SetExposureDuration(duration, ISO); 170 | } 171 | 172 | public virtual void SetExposurePoint(float x, float y) 173 | { 174 | if (GetNatDeviceCameraDevice() != null) GetNatDeviceCameraDevice().SetExposurePoint(x, y); 175 | } 176 | 177 | public virtual void SetFocusPoint(float x, float y) 178 | { 179 | if (GetNatDeviceCameraDevice() != null) GetNatDeviceCameraDevice().SetFocusPoint(x, y); 180 | } 181 | 182 | #endregion 183 | 184 | 185 | #region --NatDevice CameraImage Properties-- 186 | 187 | public long timestamp { get; private set; } 188 | 189 | public bool verticallyMirrored { get; private set; } 190 | 191 | public Matrix4x4 intrinsics { get; private set; } 192 | 193 | public float exposureBias { get; private set; } 194 | 195 | public float exposureDuration { get; private set; } 196 | 197 | public float ISO { get; private set; } 198 | 199 | public float focalLength { get; private set; } 200 | 201 | public float fNumber { get; private set; } 202 | 203 | public float brightness { get; private set; } 204 | 205 | #endregion 206 | 207 | 208 | #if (UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || UNITY_IOS || UNITY_ANDROID) && !DISABLE_NATDEVICE_API 209 | 210 | public override float requestedFPS 211 | { 212 | get { return _requestedFPS; } 213 | set 214 | { 215 | _requestedFPS = Mathf.Clamp(value, -1f, float.MaxValue); 216 | if (hasInitDone) 217 | { 218 | Initialize(); 219 | } 220 | } 221 | } 222 | 223 | protected bool isStartWaiting = false; 224 | protected bool didUpdateThisFrame = false; 225 | protected bool didUpdatePreviewPixelBufferInCurrentFrame = false; 226 | protected CameraDevice cameraDevice; 227 | protected PixelBufferOutput previewPixelBufferOutput; 228 | protected int previewWidth; 229 | protected int previewHeight; 230 | 231 | protected bool didCameraRunningBeforeSuspend = false; 232 | 233 | protected virtual void LateUpdate() 234 | { 235 | if (didUpdateThisFrame && !didUpdatePreviewPixelBufferInCurrentFrame) 236 | didUpdateThisFrame = false; 237 | 238 | didUpdatePreviewPixelBufferInCurrentFrame = false; 239 | } 240 | 241 | protected virtual IEnumerator OnApplicationPause(bool pauseStatus) 242 | { 243 | while (isStartWaiting) 244 | { 245 | yield return null; 246 | } 247 | 248 | if (!hasInitDone) 249 | yield break; 250 | 251 | // The developer needs to do the camera suspend process oneself so that it is synchronized with the app suspend. 252 | if (pauseStatus) 253 | { 254 | didCameraRunningBeforeSuspend = cameraDevice.running; 255 | 256 | if (cameraDevice.running) 257 | { 258 | cameraDevice.StopRunning(); 259 | didUpdateThisFrame = false; 260 | didUpdatePreviewPixelBufferInCurrentFrame = false; 261 | } 262 | } 263 | else 264 | { 265 | if (!cameraDevice.running && didCameraRunningBeforeSuspend) 266 | { 267 | isStartWaiting = true; 268 | cameraDevice.StartRunning(OnPixelBufferReceived); 269 | } 270 | } 271 | } 272 | 273 | private void OnPixelBufferReceived(CameraImage image) 274 | { 275 | if (previewPixelBufferOutput == null) 276 | return; 277 | 278 | // Process only when the latest previewResolution and CameraImage size match. 279 | if (cameraDevice == null || cameraDevice.previewResolution.width != image.width || cameraDevice.previewResolution.height != image.height) 280 | return; 281 | 282 | timestamp = image.timestamp; 283 | verticallyMirrored = image.verticallyMirrored; 284 | float[] intrinsics = image.intrinsics; 285 | this.intrinsics = (intrinsics != null) ? 286 | new Matrix4x4( 287 | new Vector4(intrinsics[0], intrinsics[3], intrinsics[6]), 288 | new Vector4(intrinsics[1], intrinsics[4], intrinsics[7]), 289 | new Vector4(intrinsics[2], intrinsics[5], intrinsics[8]), 290 | new Vector4()) 291 | : Matrix4x4.zero; 292 | exposureBias = image.exposureBias ?? -1f; 293 | exposureDuration = image.exposureDuration ?? -1f; 294 | ISO = image.ISO ?? -1f; 295 | focalLength = image.focalLength ?? -1f; 296 | fNumber = image.fNumber ?? -1f; 297 | brightness = image.brightness ?? -1f; 298 | 299 | 300 | bool firstFrame = !previewPixelBufferOutput.pixelBuffer.IsCreated; 301 | previewPixelBufferOutput.Update(image); 302 | 303 | if (firstFrame) 304 | { 305 | previewWidth = previewPixelBufferOutput.width; 306 | previewHeight = previewPixelBufferOutput.height; 307 | } 308 | 309 | if (isStartWaiting) 310 | { 311 | isStartWaiting = false; 312 | } 313 | 314 | didUpdateThisFrame = true; 315 | didUpdatePreviewPixelBufferInCurrentFrame = true; 316 | 317 | if (hasInitDone && frameMatAcquired != null) 318 | { 319 | frameMatAcquired.Invoke(GetMat(), timestamp); 320 | } 321 | } 322 | 323 | 324 | // Update is called once per frame 325 | protected override void Update() 326 | { 327 | if (hasInitDone) 328 | { 329 | // Catch the orientation change of the screen and correct the mat image to the correct direction. 330 | if (screenOrientation != Screen.orientation) 331 | { 332 | Initialize(); 333 | } 334 | } 335 | } 336 | 337 | /// 338 | /// Raises the destroy event. 339 | /// 340 | protected override void OnDestroy() 341 | { 342 | Dispose(); 343 | 344 | if (cameraDevice != null && cameraDevice.running) 345 | cameraDevice.StopRunning(); 346 | cameraDevice = null; 347 | } 348 | 349 | /// 350 | /// Initializes this instance by coroutine. 351 | /// 352 | protected override IEnumerator _Initialize() 353 | { 354 | if (hasInitDone) 355 | { 356 | ReleaseResources(); 357 | 358 | if (onDisposed != null) 359 | onDisposed.Invoke(); 360 | } 361 | 362 | isInitWaiting = true; 363 | 364 | while (isStartWaiting) 365 | { 366 | yield return null; 367 | } 368 | 369 | if (cameraDevice != null && cameraDevice.running) 370 | cameraDevice.StopRunning(); 371 | cameraDevice = null; 372 | 373 | 374 | // Checks camera permission state. 375 | IEnumerator coroutine = hasUserAuthorizedCameraPermission(); 376 | yield return coroutine; 377 | 378 | if (!(bool)coroutine.Current) 379 | { 380 | isInitWaiting = false; 381 | initCoroutine = null; 382 | 383 | if (onErrorOccurred != null) 384 | onErrorOccurred.Invoke(ErrorCode.CAMERA_PERMISSION_DENIED); 385 | 386 | yield break; 387 | } 388 | 389 | 390 | // Creates the camera 391 | MediaDeviceQuery deviceQuery = new MediaDeviceQuery(MediaDeviceCriteria.CameraDevice); 392 | 393 | if (!String.IsNullOrEmpty(requestedDeviceName)) 394 | { 395 | int requestedDeviceIndex = -1; 396 | if (Int32.TryParse(requestedDeviceName, out requestedDeviceIndex)) 397 | { 398 | if (requestedDeviceIndex >= 0 && requestedDeviceIndex < deviceQuery.count) 399 | { 400 | cameraDevice = deviceQuery[requestedDeviceIndex] as CameraDevice; 401 | } 402 | } 403 | else 404 | { 405 | for (int cameraIndex = 0; cameraIndex < deviceQuery.count; cameraIndex++) 406 | { 407 | if (deviceQuery[cameraIndex].uniqueID == requestedDeviceName) 408 | { 409 | cameraDevice = deviceQuery[cameraIndex] as CameraDevice; 410 | break; 411 | } 412 | } 413 | } 414 | if (cameraDevice == null) 415 | Debug.Log("Cannot find camera device " + requestedDeviceName + "."); 416 | } 417 | 418 | if (cameraDevice == null) 419 | { 420 | // Checks how many and which cameras are available on the device 421 | for (int cameraIndex = 0; cameraIndex < deviceQuery.count; cameraIndex++) 422 | { 423 | cameraDevice = deviceQuery[cameraIndex] as CameraDevice; 424 | 425 | if (cameraDevice != null && cameraDevice.frontFacing == requestedIsFrontFacing) 426 | { 427 | break; 428 | } 429 | cameraDevice = null; 430 | } 431 | } 432 | 433 | if (cameraDevice == null) 434 | { 435 | if (deviceQuery.count > 0) 436 | { 437 | cameraDevice = deviceQuery[0] as CameraDevice; 438 | } 439 | 440 | if (cameraDevice == null) 441 | { 442 | isInitWaiting = false; 443 | initCoroutine = null; 444 | 445 | if (onErrorOccurred != null) 446 | onErrorOccurred.Invoke(ErrorCode.CAMERA_DEVICE_NOT_EXIST); 447 | 448 | yield break; 449 | } 450 | } 451 | 452 | // Set the camera's preview resolution and frameRate 453 | cameraDevice.previewResolution = (width: requestedWidth, height: requestedHeight); 454 | cameraDevice.frameRate = (int)requestedFPS; 455 | 456 | // Starts the camera 457 | isStartWaiting = true; 458 | didUpdateThisFrame = false; 459 | didUpdatePreviewPixelBufferInCurrentFrame = false; 460 | 461 | previewPixelBufferOutput = new PixelBufferOutput(); 462 | cameraDevice.StartRunning(OnPixelBufferReceived); 463 | 464 | int initFrameCount = 0; 465 | bool isTimeout = false; 466 | 467 | while (true) 468 | { 469 | if (initFrameCount > timeoutFrameCount) 470 | { 471 | isTimeout = true; 472 | break; 473 | } 474 | else if (didUpdateThisFrame) 475 | { 476 | Debug.Log("NatDeviceCamPreviewToMatHelper:: " + "name:" + cameraDevice.name + " width:" + previewWidth + " height:" + previewHeight + " fps:" + cameraDevice.frameRate 477 | + " isFrongFacing:" + cameraDevice.frontFacing); 478 | 479 | baseMat = new Mat(previewHeight, previewWidth, CvType.CV_8UC4); 480 | 481 | if (baseColorFormat == outputColorFormat) 482 | { 483 | frameMat = baseMat; 484 | } 485 | else 486 | { 487 | frameMat = new Mat(baseMat.rows(), baseMat.cols(), CvType.CV_8UC(Channels(outputColorFormat)), new Scalar(0, 0, 0, 255)); 488 | } 489 | 490 | screenOrientation = Screen.orientation; 491 | screenWidth = Screen.width; 492 | screenHeight = Screen.height; 493 | 494 | if (rotate90Degree) 495 | rotatedFrameMat = new Mat(frameMat.cols(), frameMat.rows(), CvType.CV_8UC(Channels(outputColorFormat)), new Scalar(0, 0, 0, 255)); 496 | 497 | isInitWaiting = false; 498 | hasInitDone = true; 499 | initCoroutine = null; 500 | 501 | if (onInitialized != null) 502 | onInitialized.Invoke(); 503 | 504 | break; 505 | } 506 | else 507 | { 508 | initFrameCount++; 509 | yield return null; 510 | } 511 | } 512 | 513 | if (isTimeout) 514 | { 515 | if (cameraDevice.running) 516 | cameraDevice.StopRunning(); 517 | cameraDevice = null; 518 | 519 | isInitWaiting = false; 520 | initCoroutine = null; 521 | 522 | if (onErrorOccurred != null) 523 | onErrorOccurred.Invoke(ErrorCode.TIMEOUT); 524 | } 525 | } 526 | 527 | /// 528 | /// Starts the camera. 529 | /// 530 | public override void Play() 531 | { 532 | if (hasInitDone) 533 | StartCoroutine(_Play()); 534 | } 535 | 536 | protected virtual IEnumerator _Play() 537 | { 538 | while (isStartWaiting) 539 | { 540 | yield return null; 541 | } 542 | 543 | if (!hasInitDone || cameraDevice.running) yield break; 544 | 545 | isStartWaiting = true; 546 | 547 | cameraDevice.StartRunning(OnPixelBufferReceived); 548 | } 549 | 550 | /// 551 | /// Pauses the active camera. 552 | /// 553 | public override void Pause() 554 | { 555 | if (hasInitDone) 556 | StartCoroutine(_Stop()); 557 | } 558 | 559 | /// 560 | /// Stops the active camera. 561 | /// 562 | public override void Stop() 563 | { 564 | if (hasInitDone) 565 | StartCoroutine(_Stop()); 566 | } 567 | protected virtual IEnumerator _Stop() 568 | { 569 | while (isStartWaiting) 570 | { 571 | yield return null; 572 | } 573 | 574 | if (!hasInitDone || !cameraDevice.running) yield break; 575 | 576 | cameraDevice.StopRunning(); 577 | didUpdateThisFrame = false; 578 | didUpdatePreviewPixelBufferInCurrentFrame = false; 579 | } 580 | 581 | /// 582 | /// Indicates whether the active camera is currently playing. 583 | /// 584 | /// true, if the active camera is playing, false otherwise. 585 | public override bool IsPlaying() 586 | { 587 | return hasInitDone ? cameraDevice.running : false; 588 | } 589 | 590 | /// 591 | /// Indicates whether the active camera device is currently front facng. 592 | /// 593 | /// true, if the active camera device is front facng, false otherwise. 594 | public override bool IsFrontFacing() 595 | { 596 | return hasInitDone ? cameraDevice.frontFacing : false; 597 | } 598 | 599 | /// 600 | /// Returns the active camera device name. 601 | /// 602 | /// The active camera device name. 603 | public override string GetDeviceName() 604 | { 605 | return hasInitDone ? cameraDevice.name : ""; 606 | } 607 | 608 | /// 609 | /// Returns the active camera framerate. 610 | /// 611 | /// The active camera framerate. 612 | public override float GetFPS() 613 | { 614 | return hasInitDone ? cameraDevice.frameRate : -1f; 615 | } 616 | 617 | /// 618 | /// Returns the active WebcamTexture. 619 | /// 620 | /// The active WebcamTexture. 621 | public override WebCamTexture GetWebCamTexture() 622 | { 623 | return null; 624 | } 625 | 626 | /// 627 | /// Indicates whether the video buffer of the frame has been updated. 628 | /// 629 | /// true, if the video buffer has been updated false otherwise. 630 | public override bool DidUpdateThisFrame() 631 | { 632 | if (!hasInitDone) 633 | return false; 634 | 635 | return didUpdateThisFrame; 636 | } 637 | #endif 638 | 639 | /// 640 | /// Returns the NatDevice camera device. 641 | /// 642 | /// The NatDevice camera device. 643 | public virtual CameraDevice GetNatDeviceCameraDevice() 644 | { 645 | #if (UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || UNITY_IOS || UNITY_ANDROID) && !DISABLE_NATDEVICE_API 646 | return cameraDevice; 647 | #else 648 | return null; 649 | #endif 650 | } 651 | 652 | #if (UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || UNITY_IOS || UNITY_ANDROID) && !DISABLE_NATDEVICE_API 653 | /// 654 | /// Gets the mat of the current frame. 655 | /// The Mat object's type is 'CV_8UC4' or 'CV_8UC3' or 'CV_8UC1' (ColorFormat is determined by the outputColorFormat setting). 656 | /// Please do not dispose of the returned mat as it will be reused. 657 | /// 658 | /// The mat of the current frame. 659 | public override Mat GetMat() 660 | { 661 | if (!hasInitDone || !cameraDevice.running || previewPixelBufferOutput == null) 662 | { 663 | return (rotatedFrameMat != null) ? rotatedFrameMat : frameMat; 664 | } 665 | 666 | if (baseColorFormat == outputColorFormat) 667 | { 668 | if (baseMat.IsDisposed) 669 | { 670 | baseMat = new Mat(previewHeight, previewWidth, CvType.CV_8UC4); 671 | frameMat = baseMat; 672 | } 673 | 674 | MatUtils.copyToMat(previewPixelBufferOutput.pixelBuffer, frameMat); 675 | } 676 | else 677 | { 678 | if (frameMat.IsDisposed) 679 | { 680 | frameMat = new Mat(baseMat.rows(), baseMat.cols(), CvType.CV_8UC(Channels(outputColorFormat))); 681 | } 682 | 683 | MatUtils.copyToMat(previewPixelBufferOutput.pixelBuffer, baseMat); 684 | Imgproc.cvtColor(baseMat, frameMat, ColorConversionCodes(baseColorFormat, outputColorFormat)); 685 | } 686 | 687 | FlipMat(frameMat, flipVertical, flipHorizontal); 688 | if (rotatedFrameMat != null) 689 | { 690 | if (rotatedFrameMat.IsDisposed) 691 | { 692 | rotatedFrameMat = new Mat(frameMat.cols(), frameMat.rows(), CvType.CV_8UC(Channels(outputColorFormat))); 693 | } 694 | 695 | Core.rotate(frameMat, rotatedFrameMat, Core.ROTATE_90_CLOCKWISE); 696 | return rotatedFrameMat; 697 | } 698 | else 699 | { 700 | return frameMat; 701 | } 702 | } 703 | 704 | /// 705 | /// Flips the mat. 706 | /// 707 | /// Mat. 708 | protected override void FlipMat(Mat mat, bool flipVertical, bool flipHorizontal) 709 | { 710 | int flipCode = 0; 711 | 712 | if (flipVertical) 713 | { 714 | if (flipCode == int.MinValue) 715 | { 716 | flipCode = 0; 717 | } 718 | else if (flipCode == 0) 719 | { 720 | flipCode = int.MinValue; 721 | } 722 | else if (flipCode == 1) 723 | { 724 | flipCode = -1; 725 | } 726 | else if (flipCode == -1) 727 | { 728 | flipCode = 1; 729 | } 730 | } 731 | 732 | if (flipHorizontal) 733 | { 734 | if (flipCode == int.MinValue) 735 | { 736 | flipCode = 1; 737 | } 738 | else if (flipCode == 0) 739 | { 740 | flipCode = -1; 741 | } 742 | else if (flipCode == 1) 743 | { 744 | flipCode = int.MinValue; 745 | } 746 | else if (flipCode == -1) 747 | { 748 | flipCode = 0; 749 | } 750 | } 751 | 752 | if (flipCode > int.MinValue) 753 | { 754 | Core.flip(mat, mat, flipCode); 755 | } 756 | } 757 | 758 | /// 759 | /// To release the resources. 760 | /// 761 | protected override void ReleaseResources() 762 | { 763 | isInitWaiting = false; 764 | hasInitDone = false; 765 | 766 | if (previewPixelBufferOutput != null) 767 | { 768 | previewPixelBufferOutput.Dispose(); 769 | previewPixelBufferOutput = null; 770 | } 771 | 772 | didUpdateThisFrame = false; 773 | didUpdatePreviewPixelBufferInCurrentFrame = false; 774 | 775 | if (frameMat != null) 776 | { 777 | frameMat.Dispose(); 778 | frameMat = null; 779 | } 780 | if (baseMat != null) 781 | { 782 | baseMat.Dispose(); 783 | baseMat = null; 784 | } 785 | if (rotatedFrameMat != null) 786 | { 787 | rotatedFrameMat.Dispose(); 788 | rotatedFrameMat = null; 789 | } 790 | } 791 | 792 | /// 793 | /// Releases all resource used by the object. 794 | /// 795 | /// Call when you are finished using the . The 796 | /// method leaves the in an unusable state. After 797 | /// calling , you must release all references to the so 798 | /// the garbage collector can reclaim the memory that the was occupying. 799 | public override void Dispose() 800 | { 801 | if (colors != null) 802 | colors = null; 803 | 804 | if (isInitWaiting) 805 | { 806 | 807 | CancelInitCoroutine(); 808 | 809 | frameMatAcquired = null; 810 | 811 | if (cameraDevice != null) 812 | { 813 | if (this != null && this.isActiveAndEnabled) 814 | StartCoroutine(_Dispose()); 815 | } 816 | 817 | ReleaseResources(); 818 | } 819 | else if (hasInitDone) 820 | { 821 | frameMatAcquired = null; 822 | 823 | if (this != null && this.isActiveAndEnabled) 824 | StartCoroutine(_Dispose()); 825 | 826 | ReleaseResources(); 827 | 828 | if (onDisposed != null) 829 | onDisposed.Invoke(); 830 | } 831 | } 832 | 833 | protected virtual IEnumerator _Dispose() 834 | { 835 | while (isStartWaiting) 836 | { 837 | yield return null; 838 | } 839 | 840 | if (cameraDevice.running) 841 | cameraDevice.StopRunning(); 842 | cameraDevice = null; 843 | } 844 | #endif 845 | 846 | } 847 | } -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/Scripts/Utils/NatDeviceCamPreviewToMatHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: af1f30f564c42fd4a992788aa16ace23 3 | timeCreated: 1524605908 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/Scripts/Utils/RuntimePermissionHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using UnityEngine; 3 | 4 | namespace NatDeviceWithOpenCVForUnityExample 5 | { 6 | public class RuntimePermissionHelper : MonoBehaviour 7 | { 8 | 9 | public virtual IEnumerator hasUserAuthorizedCameraPermission() 10 | { 11 | #if UNITY_IOS && UNITY_2018_1_OR_NEWER 12 | UserAuthorization mode = UserAuthorization.WebCam; 13 | if (!Application.HasUserAuthorization(mode)) 14 | { 15 | yield return RequestUserAuthorization(mode); 16 | } 17 | yield return Application.HasUserAuthorization(mode); 18 | #elif UNITY_ANDROID && UNITY_2018_3_OR_NEWER 19 | string permission = UnityEngine.Android.Permission.Camera; 20 | if (!UnityEngine.Android.Permission.HasUserAuthorizedPermission(permission)) 21 | { 22 | yield return RequestUserPermission(permission); 23 | } 24 | yield return UnityEngine.Android.Permission.HasUserAuthorizedPermission(permission); 25 | #else 26 | yield return true; 27 | #endif 28 | } 29 | 30 | public virtual IEnumerator hasUserAuthorizedMicrophonePermission() 31 | { 32 | #if UNITY_IOS && UNITY_2018_1_OR_NEWER 33 | UserAuthorization mode = UserAuthorization.Microphone; 34 | if (!Application.HasUserAuthorization(mode)) 35 | { 36 | yield return RequestUserAuthorization(mode); 37 | } 38 | yield return Application.HasUserAuthorization(mode); 39 | #elif UNITY_ANDROID && UNITY_2018_3_OR_NEWER 40 | string permission = UnityEngine.Android.Permission.Microphone; 41 | if (!UnityEngine.Android.Permission.HasUserAuthorizedPermission(permission)) 42 | { 43 | yield return RequestUserPermission(permission); 44 | } 45 | yield return UnityEngine.Android.Permission.HasUserAuthorizedPermission(permission); 46 | #else 47 | yield return true; 48 | #endif 49 | } 50 | 51 | public virtual IEnumerator hasUserAuthorizedExternalStorageWritePermission() 52 | { 53 | #if UNITY_ANDROID && UNITY_2018_3_OR_NEWER 54 | string permission = UnityEngine.Android.Permission.ExternalStorageWrite; 55 | if (!UnityEngine.Android.Permission.HasUserAuthorizedPermission(permission)) 56 | { 57 | yield return RequestUserPermission(permission); 58 | } 59 | yield return UnityEngine.Android.Permission.HasUserAuthorizedPermission(permission); 60 | #else 61 | yield return true; 62 | #endif 63 | } 64 | 65 | #if (UNITY_IOS && UNITY_2018_1_OR_NEWER) || (UNITY_ANDROID && UNITY_2018_3_OR_NEWER) 66 | protected bool isUserRequestingPermission; 67 | 68 | protected virtual IEnumerator OnApplicationFocus(bool hasFocus) 69 | { 70 | yield return null; 71 | 72 | if (isUserRequestingPermission && hasFocus) 73 | isUserRequestingPermission = false; 74 | } 75 | 76 | #if UNITY_IOS 77 | protected virtual IEnumerator RequestUserAuthorization(UserAuthorization mode) 78 | { 79 | isUserRequestingPermission = true; 80 | yield return Application.RequestUserAuthorization(mode); 81 | 82 | float timeElapsed = 0; 83 | while (isUserRequestingPermission) 84 | { 85 | if (timeElapsed > 0.25f) 86 | { 87 | isUserRequestingPermission = false; 88 | yield break; 89 | } 90 | timeElapsed += Time.deltaTime; 91 | 92 | yield return null; 93 | } 94 | yield break; 95 | } 96 | #elif UNITY_ANDROID 97 | protected virtual IEnumerator RequestUserPermission(string permission) 98 | { 99 | isUserRequestingPermission = true; 100 | UnityEngine.Android.Permission.RequestUserPermission(permission); 101 | 102 | float timeElapsed = 0; 103 | while (isUserRequestingPermission) 104 | { 105 | if (timeElapsed > 0.25f) 106 | { 107 | isUserRequestingPermission = false; 108 | yield break; 109 | } 110 | timeElapsed += Time.deltaTime; 111 | 112 | yield return null; 113 | } 114 | yield break; 115 | } 116 | #endif 117 | #endif 118 | } 119 | } -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/Scripts/Utils/RuntimePermissionHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0e036a041bcf1924b912512e8bdf9bd2 3 | timeCreated: 1553402189 4 | licenseType: Free 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/Scripts/WebCamMatSource.cs: -------------------------------------------------------------------------------- 1 | using OpenCVForUnity.CoreModule; 2 | using OpenCVForUnity.UnityUtils; 3 | using OpenCVForUnity.UtilsModule; 4 | using System; 5 | using System.Threading.Tasks; 6 | using UnityEngine; 7 | 8 | namespace NatDeviceWithOpenCVForUnityExample 9 | { 10 | 11 | public class WebCamMatSource : ICameraSource 12 | { 13 | 14 | #region --Op vars-- 15 | 16 | private WebCamDevice cameraDevice; 17 | private Action startCallback, frameCallback; 18 | private Mat sourceMatrix, uprightMatrix; 19 | private Color32[] bufferColors; 20 | private int requestedWidth, requestedHeight, requestedFramerate; 21 | private int cameraIndex; 22 | private bool firstFrame; 23 | private DeviceOrientation orientation; 24 | private bool rotate90Degree; 25 | 26 | private WebCamMatSourceAttachment attachment; 27 | private class WebCamMatSourceAttachment : MonoBehaviour 28 | { 29 | public Action @delegate; 30 | void Awake() => DontDestroyOnLoad(this.gameObject); 31 | void Update() => @delegate?.Invoke(); 32 | } 33 | 34 | #endregion 35 | 36 | 37 | #region --Client API-- 38 | 39 | public int width { get { return uprightMatrix.width(); } } 40 | 41 | public int height { get { return uprightMatrix.height(); } } 42 | 43 | public bool isRunning { get { return (activeCamera && !firstFrame) ? activeCamera.isPlaying : false; } } 44 | 45 | public bool isFrontFacing { get { return activeCamera ? cameraDevice.isFrontFacing : false; } } 46 | 47 | public WebCamTexture activeCamera { get; private set; } 48 | 49 | public WebCamMatSource(int width, int height, int framerate = 30, bool front = false) 50 | { 51 | requestedWidth = width; 52 | requestedHeight = height; 53 | requestedFramerate = framerate; 54 | #if UNITY_ANDROID && !UNITY_EDITOR 55 | // Set the requestedFPS parameter to avoid the problem of the WebCamTexture image becoming low light on some Android devices. (Pixel, Pixel 2) 56 | // https://forum.unity.com/threads/released-opencv-for-unity.277080/page-33#post-3445178 57 | framerate = front ? 15 : framerate; 58 | #endif 59 | orientation = (DeviceOrientation)(int)Screen.orientation; 60 | 61 | // Pick camera 62 | var devices = WebCamTexture.devices; 63 | if (devices.Length == 0) 64 | { 65 | Debug.LogError("Camera device does not exist."); 66 | return; 67 | } 68 | 69 | for (; cameraIndex < devices.Length; cameraIndex++) 70 | if (devices[cameraIndex].isFrontFacing == front) 71 | break; 72 | 73 | if (cameraIndex == devices.Length) 74 | { 75 | Debug.LogError("Camera is null. Consider using " + (front ? "rear" : "front") + " camera."); 76 | return; 77 | } 78 | 79 | cameraDevice = devices[cameraIndex]; 80 | activeCamera = new WebCamTexture(cameraDevice.name, requestedWidth, requestedHeight, framerate); 81 | } 82 | 83 | public void Dispose() 84 | { 85 | StopRunning(); 86 | 87 | if (activeCamera != null) 88 | { 89 | WebCamTexture.Destroy(activeCamera); 90 | activeCamera = null; 91 | } 92 | if (sourceMatrix != null) 93 | sourceMatrix.Dispose(); 94 | if (uprightMatrix != null) 95 | uprightMatrix.Dispose(); 96 | sourceMatrix = 97 | uprightMatrix = null; 98 | bufferColors = null; 99 | } 100 | 101 | public Task StartRunning(Action startCallback, Action frameCallback) 102 | { 103 | var startTask = new TaskCompletionSource(); 104 | 105 | if (activeCamera == null || (activeCamera != null && activeCamera.isPlaying)) 106 | return startTask.Task; 107 | 108 | this.startCallback = startCallback; 109 | this.frameCallback = frameCallback; 110 | firstFrame = true; 111 | activeCamera.Play(); 112 | 113 | attachment = new GameObject("NatDeviceWithOpenCVForUnityExample WebCamMatSource Helper").AddComponent(); 114 | attachment.@delegate = () => 115 | { 116 | OnFrame(); 117 | }; 118 | 119 | startTask.SetResult(true); 120 | return startTask.Task; 121 | } 122 | 123 | public void StopRunning() 124 | { 125 | if (activeCamera == null) 126 | return; 127 | 128 | if (attachment != null) 129 | { 130 | attachment.@delegate = default; 131 | WebCamMatSourceAttachment.Destroy(attachment.gameObject); 132 | attachment = default; 133 | } 134 | 135 | activeCamera.Stop(); 136 | } 137 | 138 | public void CaptureFrame(Mat matrix) 139 | { 140 | if (uprightMatrix == null) return; 141 | 142 | if ((int)matrix.total() * (int)matrix.elemSize() != (int)uprightMatrix.total() * (int)uprightMatrix.elemSize()) 143 | throw new ArgumentException("matrix and CamSource image need to be the same size."); 144 | 145 | uprightMatrix.copyTo(matrix); 146 | } 147 | 148 | public void CaptureFrame(Color32[] pixelBuffer) 149 | { 150 | if (uprightMatrix == null) return; 151 | 152 | if (pixelBuffer.Length * 4 != (int)uprightMatrix.total() * (int)uprightMatrix.elemSize()) 153 | throw new ArgumentException("pixelBuffer and CamSource image need to be the same size."); 154 | 155 | MatUtils.copyFromMat(uprightMatrix, pixelBuffer); 156 | } 157 | 158 | public void CaptureFrame(byte[] pixelBuffer) 159 | { 160 | if (uprightMatrix == null) return; 161 | 162 | if (pixelBuffer.Length != (int)uprightMatrix.total() * (int)uprightMatrix.elemSize()) 163 | throw new ArgumentException("pixelBuffer and CamSource image need to be the same size."); 164 | 165 | MatUtils.copyFromMat(uprightMatrix, pixelBuffer); 166 | } 167 | 168 | public async Task SwitchCamera() 169 | { 170 | if (activeCamera == null) 171 | return; 172 | 173 | var _isRunning = activeCamera.isPlaying; 174 | 175 | Dispose(); 176 | 177 | var devices = WebCamTexture.devices; 178 | cameraIndex = ++cameraIndex % devices.Length; 179 | cameraDevice = devices[cameraIndex]; 180 | 181 | bool front = cameraDevice.isFrontFacing; 182 | int framerate = requestedFramerate; 183 | #if UNITY_ANDROID && !UNITY_EDITOR 184 | // Set the requestedFPS parameter to avoid the problem of the WebCamTexture image becoming low light on some Android devices. (Pixel, Pixel 2) 185 | // https://forum.unity.com/threads/released-opencv-for-unity.277080/page-33#post-3445178 186 | framerate = front ? 15 : framerate; 187 | #endif 188 | activeCamera = new WebCamTexture(cameraDevice.name, requestedWidth, requestedHeight, framerate); 189 | await StartRunning(startCallback, frameCallback); 190 | 191 | if (!_isRunning) 192 | StopRunning(); 193 | } 194 | 195 | #endregion 196 | 197 | 198 | #region --Operations-- 199 | 200 | private void OnFrame() 201 | { 202 | if (!activeCamera.isPlaying || !activeCamera.didUpdateThisFrame) 203 | return; 204 | 205 | // Check matrix 206 | sourceMatrix = sourceMatrix ?? new Mat(activeCamera.height, activeCamera.width, CvType.CV_8UC4); 207 | uprightMatrix = uprightMatrix ?? new Mat(); 208 | bufferColors = bufferColors ?? new Color32[activeCamera.width * activeCamera.height]; 209 | 210 | // Update matrix 211 | Utils.webCamTextureToMat(activeCamera, sourceMatrix, bufferColors, false); 212 | 213 | 214 | if (firstFrame) 215 | { 216 | rotate90Degree = false; 217 | 218 | #if !UNITY_EDITOR && !(UNITY_STANDALONE || UNITY_WEBGL) 219 | switch (orientation) 220 | { 221 | case DeviceOrientation.LandscapeLeft: 222 | case DeviceOrientation.LandscapeRight: 223 | break; 224 | case DeviceOrientation.Portrait: 225 | case DeviceOrientation.PortraitUpsideDown: 226 | rotate90Degree = true; 227 | break; 228 | } 229 | #endif 230 | } 231 | 232 | int flipCode = 0; 233 | if (cameraDevice.isFrontFacing) 234 | { 235 | if (activeCamera.videoRotationAngle == 0 || activeCamera.videoRotationAngle == 90) 236 | { 237 | flipCode = -1; 238 | } 239 | else if (activeCamera.videoRotationAngle == 180 || activeCamera.videoRotationAngle == 270) 240 | { 241 | flipCode = int.MinValue; 242 | } 243 | } 244 | else 245 | { 246 | if (activeCamera.videoRotationAngle == 180 || activeCamera.videoRotationAngle == 270) 247 | { 248 | flipCode = 1; 249 | } 250 | } 251 | 252 | if (rotate90Degree && cameraDevice.isFrontFacing) 253 | { 254 | if (flipCode == int.MinValue) 255 | { 256 | flipCode = -1; 257 | } 258 | else if (flipCode == 0) 259 | { 260 | flipCode = 1; 261 | } 262 | else if (flipCode == 1) 263 | { 264 | flipCode = 0; 265 | } 266 | else if (flipCode == -1) 267 | { 268 | flipCode = int.MinValue; 269 | } 270 | } 271 | 272 | if (flipCode > int.MinValue) 273 | { 274 | Core.flip(sourceMatrix, sourceMatrix, flipCode); 275 | } 276 | 277 | if (rotate90Degree) 278 | { 279 | Core.rotate(sourceMatrix, uprightMatrix, Core.ROTATE_90_CLOCKWISE); 280 | } 281 | else 282 | { 283 | sourceMatrix.copyTo(uprightMatrix); 284 | } 285 | 286 | 287 | // Invoke client callbacks 288 | if (firstFrame) 289 | { 290 | startCallback(); 291 | firstFrame = false; 292 | } 293 | 294 | frameCallback(); 295 | } 296 | 297 | #endregion 298 | } 299 | } -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/Scripts/WebCamMatSource.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c02e9458fdffa45a6a262ed1919b780e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/Scripts/WebCamSource.cs: -------------------------------------------------------------------------------- 1 | using OpenCVForUnity.CoreModule; 2 | using OpenCVForUnity.UtilsModule; 3 | using System; 4 | using System.Runtime.InteropServices; 5 | using System.Threading.Tasks; 6 | using UnityEngine; 7 | 8 | namespace NatDeviceWithOpenCVForUnityExample 9 | { 10 | 11 | public class WebCamSource : ICameraSource 12 | { 13 | 14 | #region --Op vars-- 15 | 16 | private WebCamDevice cameraDevice; 17 | private Action startCallback, frameCallback; 18 | private Color32[] sourceBuffer, uprightBuffer; 19 | private int requestedWidth, requestedHeight, requestedFramerate; 20 | private int cameraIndex; 21 | private bool firstFrame; 22 | private DeviceOrientation orientation; 23 | private bool rotate90Degree; 24 | 25 | private WebCamSourceAttachment attachment; 26 | private class WebCamSourceAttachment : MonoBehaviour 27 | { 28 | public Action @delegate; 29 | void Awake() => DontDestroyOnLoad(this.gameObject); 30 | void Update() => @delegate?.Invoke(); 31 | } 32 | 33 | #endregion 34 | 35 | 36 | #region --Client API-- 37 | 38 | public int width { get; private set; } 39 | 40 | public int height { get; private set; } 41 | 42 | public bool isRunning { get { return (activeCamera && !firstFrame) ? activeCamera.isPlaying : false; } } 43 | 44 | public bool isFrontFacing { get { return activeCamera ? cameraDevice.isFrontFacing : false; } } 45 | 46 | public WebCamTexture activeCamera { get; private set; } 47 | 48 | public WebCamSource(int width, int height, int framerate = 30, bool front = false) 49 | { 50 | requestedWidth = width; 51 | requestedHeight = height; 52 | requestedFramerate = framerate; 53 | #if UNITY_ANDROID && !UNITY_EDITOR 54 | // Set the requestedFPS parameter to avoid the problem of the WebCamTexture image becoming low light on some Android devices. (Pixel, Pixel 2) 55 | // https://forum.unity.com/threads/released-opencv-for-unity.277080/page-33#post-3445178 56 | framerate = front ? 15 : framerate; 57 | #endif 58 | orientation = (DeviceOrientation)(int)Screen.orientation; 59 | 60 | // Pick camera 61 | var devices = WebCamTexture.devices; 62 | if (devices.Length == 0) 63 | { 64 | Debug.LogError("Camera device does not exist."); 65 | return; 66 | } 67 | 68 | for (; cameraIndex < devices.Length; cameraIndex++) 69 | if (devices[cameraIndex].isFrontFacing == front) 70 | break; 71 | 72 | if (cameraIndex == devices.Length) 73 | { 74 | Debug.LogError("Camera is null. Consider using " + (front ? "rear" : "front") + " camera."); 75 | return; 76 | } 77 | 78 | cameraDevice = devices[cameraIndex]; 79 | activeCamera = new WebCamTexture(cameraDevice.name, requestedWidth, requestedHeight, framerate); 80 | } 81 | 82 | public void Dispose() 83 | { 84 | StopRunning(); 85 | 86 | if (activeCamera != null) 87 | { 88 | WebCamTexture.Destroy(activeCamera); 89 | activeCamera = null; 90 | } 91 | sourceBuffer = null; 92 | uprightBuffer = null; 93 | } 94 | 95 | public Task StartRunning(Action startCallback, Action frameCallback) 96 | { 97 | var startTask = new TaskCompletionSource(); 98 | 99 | if (activeCamera == null || (activeCamera != null && activeCamera.isPlaying)) 100 | return startTask.Task; 101 | 102 | this.startCallback = startCallback; 103 | this.frameCallback = frameCallback; 104 | firstFrame = true; 105 | activeCamera.Play(); 106 | 107 | attachment = new GameObject("NatDeviceWithOpenCVForUnityExample WebCamSource Helper").AddComponent(); 108 | attachment.@delegate = () => 109 | { 110 | OnFrame(); 111 | }; 112 | 113 | startTask.SetResult(true); 114 | return startTask.Task; 115 | } 116 | 117 | public void StopRunning() 118 | { 119 | if (activeCamera == null) 120 | return; 121 | 122 | if (attachment != null) 123 | { 124 | attachment.@delegate = default; 125 | WebCamSourceAttachment.Destroy(attachment.gameObject); 126 | attachment = default; 127 | } 128 | 129 | activeCamera.Stop(); 130 | } 131 | 132 | public void CaptureFrame(Mat matrix) 133 | { 134 | if (uprightBuffer == null) return; 135 | 136 | if ((int)matrix.total() * (int)matrix.elemSize() != uprightBuffer.Length * 4) 137 | throw new ArgumentException("matrix and CamSource image need to be the same size."); 138 | 139 | MatUtils.copyToMat(uprightBuffer, matrix); 140 | Core.flip(matrix, matrix, 0); 141 | } 142 | 143 | public void CaptureFrame(Color32[] pixelBuffer) 144 | { 145 | if (uprightBuffer == null) return; 146 | 147 | if (pixelBuffer.Length != uprightBuffer.Length) 148 | throw new ArgumentException("pixelBuffer and CamSource image need to be the same size."); 149 | 150 | Array.Copy(uprightBuffer, pixelBuffer, uprightBuffer.Length); 151 | } 152 | 153 | public void CaptureFrame(byte[] pixelBuffer) 154 | { 155 | if (uprightBuffer == null) return; 156 | 157 | if (pixelBuffer.Length != uprightBuffer.Length * 4) 158 | throw new ArgumentException("pixelBuffer and CamSource image need to be the same size."); 159 | 160 | GCHandle pin = GCHandle.Alloc(uprightBuffer, GCHandleType.Pinned); 161 | Marshal.Copy(pin.AddrOfPinnedObject(), pixelBuffer, 0, pixelBuffer.Length); 162 | pin.Free(); 163 | } 164 | 165 | public async Task SwitchCamera() 166 | { 167 | if (activeCamera == null) 168 | return; 169 | 170 | var _isRunning = activeCamera.isPlaying; 171 | 172 | Dispose(); 173 | 174 | var devices = WebCamTexture.devices; 175 | cameraIndex = ++cameraIndex % devices.Length; 176 | cameraDevice = devices[cameraIndex]; 177 | 178 | bool front = cameraDevice.isFrontFacing; 179 | int framerate = requestedFramerate; 180 | #if UNITY_ANDROID && !UNITY_EDITOR 181 | // Set the requestedFPS parameter to avoid the problem of the WebCamTexture image becoming low light on some Android devices. (Pixel, Pixel 2) 182 | // https://forum.unity.com/threads/released-opencv-for-unity.277080/page-33#post-3445178 183 | framerate = front ? 15 : framerate; 184 | #endif 185 | 186 | activeCamera = new WebCamTexture(cameraDevice.name, requestedWidth, requestedHeight, framerate); 187 | await StartRunning(startCallback, frameCallback); 188 | 189 | if (!_isRunning) 190 | StopRunning(); 191 | } 192 | 193 | #endregion 194 | 195 | 196 | #region --Operations-- 197 | 198 | private void OnFrame() 199 | { 200 | if (!activeCamera.isPlaying || !activeCamera.didUpdateThisFrame) 201 | return; 202 | 203 | // Check buffers 204 | sourceBuffer = sourceBuffer ?? activeCamera.GetPixels32(); 205 | uprightBuffer = uprightBuffer ?? new Color32[sourceBuffer.Length]; 206 | // Update buffers 207 | activeCamera.GetPixels32(sourceBuffer); 208 | 209 | if (firstFrame) 210 | { 211 | rotate90Degree = false; 212 | 213 | #if !UNITY_EDITOR && !(UNITY_STANDALONE || UNITY_WEBGL) 214 | switch (orientation) 215 | { 216 | case DeviceOrientation.LandscapeLeft: 217 | case DeviceOrientation.LandscapeRight: 218 | width = activeCamera.width; 219 | height = activeCamera.height; 220 | break; 221 | case DeviceOrientation.Portrait: 222 | case DeviceOrientation.PortraitUpsideDown: 223 | width = activeCamera.height; 224 | height = activeCamera.width; 225 | rotate90Degree = true; 226 | break; 227 | } 228 | #else 229 | width = activeCamera.width; 230 | height = activeCamera.height; 231 | #endif 232 | } 233 | 234 | int flipCode = int.MinValue; 235 | if (cameraDevice.isFrontFacing) 236 | { 237 | if (activeCamera.videoRotationAngle == 0 || activeCamera.videoRotationAngle == 90) 238 | { 239 | flipCode = 1; 240 | } 241 | else if (activeCamera.videoRotationAngle == 180 || activeCamera.videoRotationAngle == 270) 242 | { 243 | flipCode = 0; 244 | } 245 | } 246 | else 247 | { 248 | if (activeCamera.videoRotationAngle == 180 || activeCamera.videoRotationAngle == 270) 249 | { 250 | flipCode = -1; 251 | } 252 | } 253 | 254 | if (rotate90Degree && cameraDevice.isFrontFacing) 255 | { 256 | if (flipCode == int.MinValue) 257 | { 258 | flipCode = -1; 259 | } 260 | else if (flipCode == 0) 261 | { 262 | flipCode = 1; 263 | } 264 | else if (flipCode == 1) 265 | { 266 | flipCode = 0; 267 | } 268 | else if (flipCode == -1) 269 | { 270 | flipCode = int.MinValue; 271 | } 272 | } 273 | 274 | if (flipCode > int.MinValue) 275 | { 276 | if (flipCode == 0) 277 | { 278 | FlipVertical(sourceBuffer, activeCamera.width, activeCamera.height, sourceBuffer); 279 | } 280 | else if (flipCode == 1) 281 | { 282 | FlipHorizontal(sourceBuffer, activeCamera.width, activeCamera.height, sourceBuffer); 283 | } 284 | else if (flipCode == -1) 285 | { 286 | Rotate(sourceBuffer, activeCamera.width, activeCamera.height, sourceBuffer, 2); 287 | } 288 | } 289 | 290 | if (rotate90Degree) 291 | { 292 | Rotate(sourceBuffer, activeCamera.width, activeCamera.height, uprightBuffer, 1); 293 | } 294 | else 295 | { 296 | Array.Copy(sourceBuffer, uprightBuffer, sourceBuffer.Length); 297 | } 298 | 299 | // Invoke client callbacks 300 | if (firstFrame) 301 | { 302 | startCallback(); 303 | firstFrame = false; 304 | } 305 | 306 | frameCallback(); 307 | } 308 | 309 | #endregion 310 | 311 | 312 | #region --Utilities-- 313 | 314 | private static void FlipVertical(Color32[] src, int width, int height, Color32[] dst) 315 | { 316 | for (var i = 0; i < height / 2; i++) 317 | { 318 | var y = i * width; 319 | var x = (height - i - 1) * width; 320 | for (var j = 0; j < width; j++) 321 | { 322 | int s = y + j; 323 | int t = x + j; 324 | Color32 c = src[s]; 325 | dst[s] = src[t]; 326 | dst[t] = c; 327 | } 328 | } 329 | } 330 | 331 | private static void FlipHorizontal(Color32[] src, int width, int height, Color32[] dst) 332 | { 333 | for (int i = 0; i < height; i++) 334 | { 335 | int y = i * width; 336 | int x = y + width - 1; 337 | for (var j = 0; j < width / 2; j++) 338 | { 339 | int s = y + j; 340 | int t = x - j; 341 | Color32 c = src[s]; 342 | dst[s] = src[t]; 343 | dst[t] = c; 344 | } 345 | } 346 | } 347 | 348 | private static void Rotate(Color32[] src, int srcWidth, int srcHeight, Color32[] dst, int rotation) 349 | { 350 | int i; 351 | switch (rotation) 352 | { 353 | case 0: 354 | Array.Copy(src, dst, src.Length); 355 | break; 356 | case 1: 357 | // Rotate 90 degrees (CLOCKWISE) 358 | i = 0; 359 | for (int x = srcWidth - 1; x >= 0; x--) 360 | { 361 | for (int y = 0; y < srcHeight; y++) 362 | { 363 | dst[i] = src[x + y * srcWidth]; 364 | i++; 365 | } 366 | } 367 | break; 368 | case 2: 369 | // Rotate 180 degrees 370 | i = src.Length; 371 | for (int x = 0; x < i / 2; x++) 372 | { 373 | Color32 t = src[x]; 374 | dst[x] = src[i - x - 1]; 375 | dst[i - x - 1] = t; 376 | } 377 | break; 378 | case 3: 379 | // Rotate 90 degrees (COUNTERCLOCKWISE) 380 | i = 0; 381 | for (int x = 0; x < srcWidth; x++) 382 | { 383 | for (int y = srcHeight - 1; y >= 0; y--) 384 | { 385 | dst[i] = src[x + y * srcWidth]; 386 | i++; 387 | } 388 | } 389 | break; 390 | } 391 | } 392 | 393 | #endregion 394 | } 395 | } -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/Scripts/WebCamSource.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 486b80aae3ddd4e14bb0406376991414 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/ShowLicense.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.SceneManagement; 3 | 4 | namespace NatDeviceWithOpenCVForUnityExample 5 | { 6 | 7 | public class ShowLicense : MonoBehaviour 8 | { 9 | 10 | public void OnBackButtonClick() 11 | { 12 | SceneManager.LoadScene("NatDeviceWithOpenCVForUnityExample"); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/ShowLicense.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 599febf5582a8084bbb793443573466c 3 | timeCreated: 1521862659 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/ShowLicense.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8d1000b636372dc4e8ce1be55a9f0e58 3 | timeCreated: 1521862659 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/ShowSystemInfo.cs: -------------------------------------------------------------------------------- 1 | using OpenCVForUnity.CoreModule; 2 | using OpenCVForUnity.UnityUtils; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Reflection; 6 | using System.Text; 7 | using UnityEngine; 8 | using UnityEngine.SceneManagement; 9 | using UnityEngine.UI; 10 | 11 | namespace NatDeviceWithOpenCVForUnityExample 12 | { 13 | public class ShowSystemInfo : MonoBehaviour 14 | { 15 | public Text systemInfoText; 16 | public InputField systemInfoInputField; 17 | 18 | private const string ASSET_NAME = "OpenCVForUnity"; 19 | 20 | // Use this for initialization 21 | void Start() 22 | { 23 | 24 | StringBuilder sb = new StringBuilder(); 25 | sb.Append("###### Build Info ######\n"); 26 | IDictionary buildInfo = GetBuildInfo(); 27 | foreach (string key in buildInfo.Keys) 28 | { 29 | sb.Append(key).Append(" = ").Append(buildInfo[key]).Append("\n"); 30 | } 31 | sb.Append("\n"); 32 | 33 | #if UNITY_IOS || (UNITY_ANDROID && UNITY_2018_3_OR_NEWER) 34 | sb.Append("###### Device Info ######\n"); 35 | IDictionary deviceInfo = GetDeviceInfo(); 36 | foreach (string key in deviceInfo.Keys) 37 | { 38 | sb.Append(key).Append(" = ").Append(deviceInfo[key]).Append("\n"); 39 | } 40 | sb.Append("\n"); 41 | #endif 42 | 43 | sb.Append("###### System Info ######\n"); 44 | IDictionary systemInfo = GetSystemInfo(); 45 | foreach (string key in systemInfo.Keys) 46 | { 47 | sb.Append(key).Append(" = ").Append(systemInfo[key]).Append("\n"); 48 | } 49 | sb.Append("#########################\n"); 50 | 51 | systemInfoText.text = systemInfoInputField.text = sb.ToString(); 52 | Debug.Log(sb.ToString()); 53 | } 54 | 55 | // Update is called once per frame 56 | void Update() 57 | { 58 | 59 | } 60 | 61 | public Dictionary GetBuildInfo() 62 | { 63 | Dictionary dict = new Dictionary(); 64 | 65 | dict.Add(ASSET_NAME + " version", Core.NATIVE_LIBRARY_NAME + " " + Utils.getVersion() + " (" + Core.VERSION + ")"); 66 | dict.Add("Build Unity version", Application.unityVersion); 67 | 68 | #if UNITY_EDITOR 69 | dict.Add("Build target", "Editor"); 70 | #elif UNITY_STANDALONE_WIN 71 | dict.Add("Build target", "Windows"); 72 | #elif UNITY_STANDALONE_OSX 73 | dict.Add("Build target", "Mac OSX"); 74 | #elif UNITY_STANDALONE_LINUX 75 | dict.Add("Build target", "Linux"); 76 | #elif UNITY_ANDROID 77 | dict.Add("Build target", "Android"); 78 | #elif UNITY_IOS 79 | dict.Add("Build target", "iOS"); 80 | #elif UNITY_WSA 81 | dict.Add("Build target", "WSA"); 82 | #elif UNITY_WEBGL 83 | dict.Add("Build target", "WebGL"); 84 | #elif PLATFORM_LUMIN 85 | dict.Add("Build target", "LUMIN"); 86 | #else 87 | dict.Add("Build target", ""); 88 | #endif 89 | 90 | #if ENABLE_MONO 91 | dict.Add("Scripting backend", "Mono"); 92 | #elif ENABLE_IL2CPP 93 | dict.Add("Scripting backend", "IL2CPP"); 94 | #elif ENABLE_DOTNET 95 | dict.Add("Scripting backend", ".NET"); 96 | #else 97 | dict.Add("Scripting backend", ""); 98 | #endif 99 | 100 | #if OPENCV_USE_UNSAFE_CODE 101 | dict.Add("Allow 'unsafe' Code", "Enabled"); 102 | #else 103 | dict.Add("Allow 'unsafe' Code", "Disabled"); 104 | #endif 105 | 106 | return dict; 107 | } 108 | 109 | public Dictionary GetDeviceInfo() 110 | { 111 | Dictionary dict = new Dictionary(); 112 | 113 | #if UNITY_IOS 114 | dict.Add("iOS.Device.generation", UnityEngine.iOS.Device.generation.ToString()); 115 | dict.Add("iOS.Device.systemVersion", UnityEngine.iOS.Device.systemVersion.ToString()); 116 | #endif 117 | #if UNITY_IOS && UNITY_2018_1_OR_NEWER 118 | dict.Add("UserAuthorization.WebCam", Application.HasUserAuthorization(UserAuthorization.WebCam).ToString()); 119 | dict.Add("UserAuthorization.Microphone", Application.HasUserAuthorization(UserAuthorization.Microphone).ToString()); 120 | #endif 121 | #if UNITY_ANDROID && UNITY_2018_3_OR_NEWER 122 | dict.Add("Android.Permission.Camera", UnityEngine.Android.Permission.HasUserAuthorizedPermission(UnityEngine.Android.Permission.Camera).ToString()); 123 | dict.Add("Android.Permission.CoarseLocation", UnityEngine.Android.Permission.HasUserAuthorizedPermission(UnityEngine.Android.Permission.CoarseLocation).ToString()); 124 | dict.Add("Android.Permission.ExternalStorageRead", UnityEngine.Android.Permission.HasUserAuthorizedPermission(UnityEngine.Android.Permission.ExternalStorageRead).ToString()); 125 | dict.Add("Android.Permission.ExternalStorageWrite", UnityEngine.Android.Permission.HasUserAuthorizedPermission(UnityEngine.Android.Permission.ExternalStorageWrite).ToString()); 126 | dict.Add("Android.Permission.FineLocation", UnityEngine.Android.Permission.HasUserAuthorizedPermission(UnityEngine.Android.Permission.FineLocation).ToString()); 127 | dict.Add("Android.Permission.Microphone", UnityEngine.Android.Permission.HasUserAuthorizedPermission(UnityEngine.Android.Permission.Microphone).ToString()); 128 | #endif 129 | 130 | return dict; 131 | } 132 | 133 | /// SystemInfo Class Propertys 134 | public SortedDictionary GetSystemInfo() 135 | { 136 | SortedDictionary dict = new SortedDictionary(); 137 | 138 | Type type = typeof(SystemInfo); 139 | MemberInfo[] members = type.GetMembers( 140 | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); 141 | 142 | foreach (MemberInfo mb in members) 143 | { 144 | try 145 | { 146 | if (mb.MemberType == MemberTypes.Property) 147 | { 148 | if (mb.Name == "deviceUniqueIdentifier") 149 | { 150 | dict.Add(mb.Name, "xxxxxxxxxxxxxxxxxxxxxxxx"); 151 | continue; 152 | } 153 | 154 | PropertyInfo pr = type.GetProperty(mb.Name); 155 | 156 | if (pr != null) 157 | { 158 | object resobj = pr.GetValue(type, null); 159 | dict.Add(mb.Name, resobj.ToString()); 160 | } 161 | else 162 | { 163 | dict.Add(mb.Name, ""); 164 | } 165 | } 166 | } 167 | catch (Exception e) 168 | { 169 | Debug.Log("Exception: " + e); 170 | } 171 | } 172 | 173 | return dict; 174 | } 175 | 176 | public void OnBackButtonClick() 177 | { 178 | SceneManager.LoadScene("NatDeviceWithOpenCVForUnityExample"); 179 | } 180 | } 181 | } -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/ShowSystemInfo.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ebfaa02d802aac44399fcf98a93f24f0 3 | timeCreated: 1522792936 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/ShowSystemInfo.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9ce31c29464a23a4380beca317fc5b01 3 | timeCreated: 1522792936 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/WebCamTextureOnlyExample.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8522a0c763b132a49bbb1568e9f6fcae 3 | folderAsset: yes 4 | timeCreated: 1522155404 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/WebCamTextureOnlyExample/WebCamTextureOnlyExample.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace NatDeviceWithOpenCVForUnityExample 4 | { 5 | 6 | /// 7 | /// WebCamTexture Only Example 8 | /// An example of displaying the preview frame of camera only using WebCamTexture API. 9 | /// 10 | public class WebCamTextureOnlyExample : ExampleBase 11 | { 12 | 13 | Texture2D texture; 14 | byte[] pixelBuffer; 15 | 16 | FpsMonitor fpsMonitor; 17 | 18 | #region --ExampleBase-- 19 | 20 | protected override async void Start() 21 | { 22 | base.Start(); 23 | 24 | fpsMonitor = GetComponent(); 25 | if (fpsMonitor != null) 26 | { 27 | fpsMonitor.Add("Name", "WebCamTextureOnlyExample"); 28 | fpsMonitor.Add("onFrameFPS", onFrameFPS.ToString("F1")); 29 | fpsMonitor.Add("drawFPS", drawFPS.ToString("F1")); 30 | fpsMonitor.Add("width", ""); 31 | fpsMonitor.Add("height", ""); 32 | fpsMonitor.Add("isFrontFacing", ""); 33 | fpsMonitor.Add("orientation", ""); 34 | } 35 | 36 | // Load global camera benchmark settings. 37 | int width, height, framerate; 38 | NatDeviceWithOpenCVForUnityExample.CameraConfiguration(out width, out height, out framerate); 39 | // Create camera source 40 | cameraSource = new WebCamSource(width, height, framerate, useFrontCamera); 41 | if (!cameraSource.activeCamera) 42 | cameraSource = new WebCamSource(width, height, framerate, !useFrontCamera); 43 | await cameraSource.StartRunning(OnStart, OnFrame); 44 | } 45 | 46 | protected override void OnStart() 47 | { 48 | base.OnStart(); 49 | 50 | // Create pixel buffer 51 | pixelBuffer = new byte[cameraSource.width * cameraSource.height * 4]; 52 | // Create texture 53 | if (texture != null) 54 | Texture2D.Destroy(texture); 55 | texture = new Texture2D( 56 | cameraSource.width, 57 | cameraSource.height, 58 | TextureFormat.RGBA32, 59 | false, 60 | false 61 | ); 62 | // Display texture 63 | rawImage.texture = texture; 64 | aspectFitter.aspectRatio = cameraSource.width / (float)cameraSource.height; 65 | Debug.Log("WebCam camera source started with resolution: " + cameraSource.width + "x" + cameraSource.height + " isFrontFacing: " + cameraSource.isFrontFacing); 66 | 67 | if (fpsMonitor != null) 68 | { 69 | fpsMonitor.Add("width", cameraSource.width.ToString()); 70 | fpsMonitor.Add("height", cameraSource.height.ToString()); 71 | fpsMonitor.Add("isFrontFacing", cameraSource.isFrontFacing.ToString()); 72 | fpsMonitor.Add("orientation", Screen.orientation.ToString()); 73 | } 74 | } 75 | 76 | protected override void Update() 77 | { 78 | base.Update(); 79 | 80 | if (updateCount == 0) 81 | { 82 | if (fpsMonitor != null) 83 | { 84 | fpsMonitor.Add("onFrameFPS", onFrameFPS.ToString("F1")); 85 | fpsMonitor.Add("drawFPS", drawFPS.ToString("F1")); 86 | fpsMonitor.Add("orientation", Screen.orientation.ToString()); 87 | } 88 | } 89 | } 90 | 91 | protected override void UpdateTexture() 92 | { 93 | cameraSource.CaptureFrame(pixelBuffer); 94 | ProcessImage(pixelBuffer, texture.width, texture.height, imageProcessingType); 95 | texture.LoadRawTextureData(pixelBuffer); 96 | texture.Apply(); 97 | } 98 | 99 | protected override void OnDestroy() 100 | { 101 | base.OnDestroy(); 102 | 103 | Texture2D.Destroy(texture); 104 | texture = null; 105 | pixelBuffer = null; 106 | } 107 | 108 | #endregion 109 | 110 | } 111 | } -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/WebCamTextureOnlyExample/WebCamTextureOnlyExample.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 39f2790264240404281d4d8069864b53 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/WebCamTextureOnlyExample/WebCamTextureOnlyExample.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 247e68aaae4c3a4478a32b7849213734 3 | DefaultImporter: 4 | userData: 5 | assetBundleName: 6 | assetBundleVariant: 7 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/WebCamTextureToMatExample.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fb415b3de5b7e55478861734060ef255 3 | folderAsset: yes 4 | timeCreated: 1522155404 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/WebCamTextureToMatExample/WebCamTextureToMatExample.cs: -------------------------------------------------------------------------------- 1 | using OpenCVForUnity.CoreModule; 2 | using OpenCVForUnity.UnityUtils; 3 | using UnityEngine; 4 | 5 | namespace NatDeviceWithOpenCVForUnityExample 6 | { 7 | 8 | /// 9 | /// WebCamTexture To Mat Example 10 | /// An example of converting a WebCamTexture image to OpenCV's Mat format. 11 | /// 12 | public class WebCamTextureToMatExample : ExampleBase 13 | { 14 | 15 | Mat frameMatrix, grayMatrix; 16 | Texture2D texture; 17 | 18 | FpsMonitor fpsMonitor; 19 | 20 | #region --ExampleBase-- 21 | 22 | protected override async void Start() 23 | { 24 | base.Start(); 25 | 26 | fpsMonitor = GetComponent(); 27 | if (fpsMonitor != null) 28 | { 29 | fpsMonitor.Add("Name", "WebCamTextureToMatExample"); 30 | fpsMonitor.Add("onFrameFPS", onFrameFPS.ToString("F1")); 31 | fpsMonitor.Add("drawFPS", drawFPS.ToString("F1")); 32 | fpsMonitor.Add("width", ""); 33 | fpsMonitor.Add("height", ""); 34 | fpsMonitor.Add("isFrontFacing", ""); 35 | fpsMonitor.Add("orientation", ""); 36 | } 37 | 38 | // Load global camera benchmark settings. 39 | int width, height, framerate; 40 | NatDeviceWithOpenCVForUnityExample.CameraConfiguration(out width, out height, out framerate); 41 | // Create camera source 42 | cameraSource = new WebCamMatSource(width, height, framerate, useFrontCamera); 43 | if (!cameraSource.activeCamera) 44 | cameraSource = new WebCamMatSource(width, height, framerate, !useFrontCamera); 45 | await cameraSource.StartRunning(OnStart, OnFrame); 46 | } 47 | 48 | protected override void OnStart() 49 | { 50 | base.OnStart(); 51 | 52 | // Create matrices 53 | if (frameMatrix != null) 54 | frameMatrix.Dispose(); 55 | frameMatrix = new Mat(cameraSource.height, cameraSource.width, CvType.CV_8UC4); 56 | if (grayMatrix != null) 57 | grayMatrix.Dispose(); 58 | grayMatrix = new Mat(cameraSource.height, cameraSource.width, CvType.CV_8UC1); 59 | // Create texture 60 | if (texture != null) 61 | Texture2D.Destroy(texture); 62 | texture = new Texture2D( 63 | cameraSource.width, 64 | cameraSource.height, 65 | TextureFormat.RGBA32, 66 | false, 67 | false 68 | ); 69 | // Display texture 70 | rawImage.texture = texture; 71 | aspectFitter.aspectRatio = cameraSource.width / (float)cameraSource.height; 72 | Debug.Log("WebCam camera source started with resolution: " + cameraSource.width + "x" + cameraSource.height + " isFrontFacing: " + cameraSource.isFrontFacing); 73 | 74 | if (fpsMonitor != null) 75 | { 76 | fpsMonitor.Add("width", cameraSource.width.ToString()); 77 | fpsMonitor.Add("height", cameraSource.height.ToString()); 78 | fpsMonitor.Add("isFrontFacing", cameraSource.isFrontFacing.ToString()); 79 | fpsMonitor.Add("orientation", Screen.orientation.ToString()); 80 | } 81 | } 82 | 83 | protected override void Update() 84 | { 85 | base.Update(); 86 | 87 | if (updateCount == 0) 88 | { 89 | if (fpsMonitor != null) 90 | { 91 | fpsMonitor.Add("onFrameFPS", onFrameFPS.ToString("F1")); 92 | fpsMonitor.Add("drawFPS", drawFPS.ToString("F1")); 93 | fpsMonitor.Add("orientation", Screen.orientation.ToString()); 94 | } 95 | } 96 | } 97 | 98 | protected override void UpdateTexture() 99 | { 100 | cameraSource.CaptureFrame(frameMatrix); 101 | ProcessImage(frameMatrix, grayMatrix, imageProcessingType); 102 | // Convert to Texture2D 103 | Utils.fastMatToTexture2D(frameMatrix, texture); 104 | } 105 | 106 | protected override void OnDestroy() 107 | { 108 | base.OnDestroy(); 109 | 110 | grayMatrix.Dispose(); 111 | frameMatrix.Dispose(); 112 | Texture2D.Destroy(texture); 113 | texture = null; 114 | grayMatrix = 115 | frameMatrix = null; 116 | } 117 | 118 | #endregion 119 | 120 | } 121 | } -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/WebCamTextureToMatExample/WebCamTextureToMatExample.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f2163b2acf1d92b4591f93c90a5e82f2 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/WebCamTextureToMatExample/WebCamTextureToMatExample.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b90a2bbbb939a5a45aab414e3f5a7a56 3 | DefaultImporter: 4 | userData: 5 | assetBundleName: 6 | assetBundleVariant: 7 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/link.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Assets/NatDeviceWithOpenCVForUnityExample/link.xml.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d11dbcae93faacf48a73bef9bee50163 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # This example project has been deprecated. 2 | **The “NatDevice” and “NatShare” assets that the integration example depends on have been deprecated in the Unity Asset Store. These features appear to have been merged and evolved into a new asset called VideoKit (https://www.videokit.ai/).** 3 | 4 | --- 5 | 6 | # NatDevice With OpenCVForUnity Example 7 | - An example of a benchmark test integrating NatDevice and OpenCVForUnity. (Comparison between WebCamTexture and NatDevice API) 8 | - An example of replacing WebCamTextureToMatHelper with NatDeviceCamPreviewToMatHelper. 9 | - An example of native sharing and save to the camera roll using NatShare API. 10 | 11 | 12 | ## Environment 13 | - Anddroid (Pixel 3a) / iOS (iPhoneSE2) 14 | - Unity >= 2020.3.31f1+ 15 | - Scripting backend MONO / IL2CPP 16 | - [NatDevice - Media Device API](https://assetstore.unity.com/packages/tools/integration/natdevice-media-device-api-162053?aid=1011l4ehR) 1.2.0+ 17 | - [NatShare - Mobile Sharing API](https://github.com/natsuite/NatShare) 1.2.6+ 18 | - [OpenCV for Unity](https://assetstore.unity.com/packages/tools/integration/opencv-for-unity-21088?aid=1011l4ehR) 2.4.7+ 19 | 20 | 21 | ## Demo 22 | - Android [NatDeviceWithOpenCVForUnityExample.apk](https://github.com/EnoxSoftware/NatDeviceWithOpenCVForUnityExample/releases) 23 | 24 | 25 | ## Setup 26 | 1. Download the latest release unitypackage. [NatDeviceWithOpenCVForUnityExample.unitypackage](https://github.com/EnoxSoftware/NatDeviceWithOpenCVForUnityExample/releases) 27 | 1. Create a new project. (NatDeviceWithOpenCVForUnityExample) 28 | * Enable "Allow 'unsafe' Code" option in the "Player Settings > Other Settings" Inspector. 29 | 1. Import NatDevice. 30 | 1. Import NatShare. 31 | 1. Import OpenCVForUnity. 32 | * Setup the OpenCVForUnity. (Tools > OpenCV for Unity > Set Plugin Import Settings) 33 | * Select MenuItem[Tools/OpenCV for Unity/Use Unsafe Code]. 34 | ![Use_UnsafeCode.PNG](Use_UnsafeCode.png) 35 | ![AllowUnsafeCode.PNG](AllowUnsafeCode.png) 36 | 1. Import the NatDeviceWithOpenCVForUnityExample.unitypackage. 37 | 1. Change the "Minimum API Level" to 24 or higher in the "Player Settings (Androd)" Inspector. 38 | 1. Change the "Target minimum iOS Version" to 13 or higher in the "Player Settings (iOS)" Inspector. 39 | * Set the reason for accessing the camera in "cameraUsageDescription". 40 | 1. Add the "Assets/NatDeviceWithOpenCVForUnityExample/*.unity" files to the "Scenes In Build" list in the "Build Settings" window. 41 | 1. Build and Deploy to Android and iOS. 42 | 43 | 44 | ## Android Instructions 45 | Build requires Android SDK Platform 29 or higher. 46 | 47 | 48 | ## iOS Instructions 49 | After building an Xcode project from Unity, add the following keys to the `Info.plist` file with a good description: 50 | - `NSPhotoLibraryUsageDescription` 51 | - `NSPhotoLibraryAddUsageDescription` 52 | 53 | 54 | ## ScreenShot 55 | ![screenshot01.jpg](screenshot01.jpg) 56 | ![screenshot02.jpg](screenshot02.jpg) 57 | ![screenshot03.jpg](screenshot03.jpg) 58 | -------------------------------------------------------------------------------- /Use_UnsafeCode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnoxSoftware/NatDeviceWithOpenCVForUnityExample/4bf5536abc1a2088686e63e375128af84d8454d9/Use_UnsafeCode.png -------------------------------------------------------------------------------- /screenshot01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnoxSoftware/NatDeviceWithOpenCVForUnityExample/4bf5536abc1a2088686e63e375128af84d8454d9/screenshot01.jpg -------------------------------------------------------------------------------- /screenshot02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnoxSoftware/NatDeviceWithOpenCVForUnityExample/4bf5536abc1a2088686e63e375128af84d8454d9/screenshot02.jpg -------------------------------------------------------------------------------- /screenshot03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnoxSoftware/NatDeviceWithOpenCVForUnityExample/4bf5536abc1a2088686e63e375128af84d8454d9/screenshot03.jpg --------------------------------------------------------------------------------