From 748e14d56ed31ac2d8ede12885d32e85379eb42a Mon Sep 17 00:00:00 2001 From: Jan Lukas Gernert Date: Mon, 8 Oct 2018 13:57:23 +0200 Subject: [PATCH 1/6] SICK Visionary-T Pro --- .../Sick.VisionaryT.Pro/CameraModel.cs | 55 +++ .../Properties/AssemblyInfo.cs | 20 + .../Properties/Resources.Designer.cs | 73 ++++ .../Properties/Resources.resx | 124 ++++++ .../Sick.VisionaryT.Pro.csproj | 97 +++++ BetaCameras/Sick.VisionaryT.Pro/SickIcon.ico | Bin 0 -> 370070 bytes .../Sick.VisionaryT.Pro/VisionaryTPro.cs | 357 ++++++++++++++++++ BetaCameras/Sick.VisionaryT/VisionaryT.cs | 12 +- MetriCam2_SDK.sln | 19 + Samples/MinimalSample/MinimalSample.csproj | 30 +- Scripts/Jenkinsfile.groovy | 2 +- 11 files changed, 763 insertions(+), 26 deletions(-) create mode 100644 BetaCameras/Sick.VisionaryT.Pro/CameraModel.cs create mode 100644 BetaCameras/Sick.VisionaryT.Pro/Properties/AssemblyInfo.cs create mode 100644 BetaCameras/Sick.VisionaryT.Pro/Properties/Resources.Designer.cs create mode 100644 BetaCameras/Sick.VisionaryT.Pro/Properties/Resources.resx create mode 100644 BetaCameras/Sick.VisionaryT.Pro/Sick.VisionaryT.Pro.csproj create mode 100644 BetaCameras/Sick.VisionaryT.Pro/SickIcon.ico create mode 100644 BetaCameras/Sick.VisionaryT.Pro/VisionaryTPro.cs diff --git a/BetaCameras/Sick.VisionaryT.Pro/CameraModel.cs b/BetaCameras/Sick.VisionaryT.Pro/CameraModel.cs new file mode 100644 index 00000000..038338d2 --- /dev/null +++ b/BetaCameras/Sick.VisionaryT.Pro/CameraModel.cs @@ -0,0 +1,55 @@ +// Copyright (c) Metrilus GmbH +// MetriCam 2 is licensed under the MIT license. See License.txt for full license text. +using Newtonsoft.Json; + +namespace MetriCam2.Cameras.Internal.Sick +{ + class CameraObject + { + [JsonProperty(PropertyName = "class")] + public string CameraClass { get; set; } + + public CameraData Data { get; set; } + } + + class CameraData + { + public string CameraID { get; set; } + public int ImageWidth { get; set; } + public int ImageHeight { get; set; } + public float FocalDistance { get; set; } + public string FocalDistanceUnit { get; set; } + public float[][] IntrinsicK { get; set; } + public float[][] WorldToSensorDistortion { get; set; } + public float[][] SensorToWorldDistortion { get; set; } + public float[][] WorldToView { get; set; } + public Point PixelSize { get; set; } + public Point Origin { get; set; } + public string HandleZeroPixels { get; set; } + public ImageData Data { get; set; } + } + + class ImageData + { + public string ImageType { get; set; } + public int Width { get; set; } + public int Height { get; set; } + public Pixels Pixels { get; set; } + } + + class Pixels + { + public int numOfElems { get; set; } + public int elemSz { get; set; } + public string endian { get; set; } + public string[] elemTypes { get; set; } + public string data { get; set; } + } + + class Point + { + public int x { get; set; } + public int y { get; set; } + public int z { get; set; } + } +} diff --git a/BetaCameras/Sick.VisionaryT.Pro/Properties/AssemblyInfo.cs b/BetaCameras/Sick.VisionaryT.Pro/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..82f9a647 --- /dev/null +++ b/BetaCameras/Sick.VisionaryT.Pro/Properties/AssemblyInfo.cs @@ -0,0 +1,20 @@ +// Copyright (c) Metrilus GmbH +// MetriCam 2 is licensed under the MIT license. See License.txt for full license text. + +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MetriCam 2: SICK Visionary-T-Pro wrapper")] +[assembly: AssemblyDescription("MetriCam 2 wrapper for SICK Visionary-T-Pro cameras")] +[assembly: MetriCam2.Attributes.ContainsCameraImplementations] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("658d0052-ccd1-4b52-9af9-6c0ece90cd3e")] diff --git a/BetaCameras/Sick.VisionaryT.Pro/Properties/Resources.Designer.cs b/BetaCameras/Sick.VisionaryT.Pro/Properties/Resources.Designer.cs new file mode 100644 index 00000000..e9fcb4f4 --- /dev/null +++ b/BetaCameras/Sick.VisionaryT.Pro/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace MetriCam2.Cameras.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MetriCam2.Cameras.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). + /// + public static System.Drawing.Icon SickIcon { + get { + object obj = ResourceManager.GetObject("SickIcon", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + } +} diff --git a/BetaCameras/Sick.VisionaryT.Pro/Properties/Resources.resx b/BetaCameras/Sick.VisionaryT.Pro/Properties/Resources.resx new file mode 100644 index 00000000..3d12a2df --- /dev/null +++ b/BetaCameras/Sick.VisionaryT.Pro/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\SickIcon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/BetaCameras/Sick.VisionaryT.Pro/Sick.VisionaryT.Pro.csproj b/BetaCameras/Sick.VisionaryT.Pro/Sick.VisionaryT.Pro.csproj new file mode 100644 index 00000000..be9f3dff --- /dev/null +++ b/BetaCameras/Sick.VisionaryT.Pro/Sick.VisionaryT.Pro.csproj @@ -0,0 +1,97 @@ + + + + + + Debug + x64 + {D01829D2-B553-4C4B-B392-2437E6A130B5} + Library + Properties + MetriCam2.Cameras + MetriCam2.Cameras.Sick.VisionaryT.Pro + v4.5 + 512 + + + + true + ..\..\bin\x64\Debug\ + DEBUG;TRACE + full + x64 + prompt + MinimumRecommendedRules.ruleset + true + true + false + + + ..\..\bin\x64\Release\ + TRACE + true + pdbonly + x64 + prompt + MinimumRecommendedRules.ruleset + true + true + false + + + + $(LibrariesPath)Metrilus.Util.dll + + + False + $(LibrariesPath)Newtonsoft.Json.dll + + + + + + + + + + + + + SolutionAssemblyInfo.cs + + + + True + True + Resources.resx + + + + + + + {342f049e-668b-4351-b21d-75e4bef5a1e4} + MetriCam2 + + + + + .licenseheader + + + + + PublicResXFileCodeGenerator + Resources.Designer.cs + + + + + + \ No newline at end of file diff --git a/BetaCameras/Sick.VisionaryT.Pro/SickIcon.ico b/BetaCameras/Sick.VisionaryT.Pro/SickIcon.ico new file mode 100644 index 0000000000000000000000000000000000000000..09841e09e00d07fe15da2a168dc69ea98ebf54da GIT binary patch literal 370070 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

GY~$b zv4c4FejtCI!h7}62P{6r$oH#pU!8S(e@g2+Q98X>Mek$*u5j=S!rs|Z=m%~d>+OEL z-Yug0qqRrug0r;in_N*`Pd_$b^X3#VCVh{yMDi~ zx`)`Uzj=SLy=-~!urqGw`-IiKxMx!4tllH*eow3Iy*S*j*zi|&W95`=zv8cm1O0vl zZV&vG{>S?i-+|+Yadf*+fxl(1@8$2=4l++iSAYNOH}1GcB97Q=5c?*)%=;>0+{=!C zi{WpuUdHNw$CQ85^j7EJ5EBPCq_KSu;ctj7`kP~H?}PZg2&`wsn$^+Wcc;<8`&6Gi zvMWs<>C@i_aTs&z)=Eh93Jc);a#7)~)jU;LzhA!8(kWYdzf} zz6XyF-ibAnf0%aRdjr>1@cTBu&kk?;1lGEIpVk9%O(fSBk;l-Z?@L?xJrM7x3imY + /// MetriCam2 wrapper for Sick Visionary-T Pro cameras. + /// + public class VisionaryTPro : Camera + { + private Thread _updateThread; + private Socket _socket; + private char[] _frontJsonData = null; + private char[] _backJsonData = null; + private int _intensityJsonOffset; + private int _intensityJsonSize; + private int _distanceJsonOffset; + private int _distanceJsonSize; + private int _imageHeight = 0; + private int _imageWidth = 0; + private AutoResetEvent _frameAvailable = new AutoResetEvent(false); + private CancellationTokenSource _cancelUpdateThreadSource; + private ProjectiveTransformationZhang _intrinsics = null; + private const int NumFrameRetries = 3; + private string _updateThreadError = null; + + private ParamDesc IPAddressDesc + { + get + { + return new ParamDesc() + { + Description = "IP address", + ReadableWhen = ParamDesc.ConnectionStates.Disconnected | ParamDesc.ConnectionStates.Connected, + WritableWhen = ParamDesc.ConnectionStates.Disconnected + }; + } + } + + public string IPAddress { get; set; } + + + private ParamDesc PortDesc + { + get + { + return new ParamDesc() + { + Description = "Port", + ReadableWhen = ParamDesc.ConnectionStates.Disconnected | ParamDesc.ConnectionStates.Connected, + WritableWhen = ParamDesc.ConnectionStates.Disconnected + }; + } + } + public int Port { get; set; } = 2115; + +#if !NETSTANDARD2_0 + public override Icon CameraIcon => Properties.Resources.SickIcon; +#endif + + public VisionaryTPro() + : base() + { + + } + + #region MetriCam2 Camera Interface + + public new string Name { get => "Visionary-T-Pro"; } + public new string Vendor { get => "Sick"; } + + protected override void LoadAllAvailableChannels() + { + ChannelRegistry cr = ChannelRegistry.Instance; + + Channels.Clear(); + + Channels.Add(cr.RegisterChannel(ChannelNames.Intensity)); + Channels.Add(cr.RegisterChannel(ChannelNames.Distance)); + } + + + protected override void ConnectImpl() + { + _updateThreadError = null; + _updateThread = new Thread(new ThreadStart(UpdateLoop)); + _cancelUpdateThreadSource = new CancellationTokenSource(); + + if (string.IsNullOrEmpty(IPAddress)) + { + string msg = string.Format("IP address is not set. It must be set before connecting."); + log.Error(msg); + throw ExceptionBuilder.Build(typeof(ConnectionFailedException), Name, "error_connectionFailed", msg); + } + + try + { + IPAddress camIP = System.Net.IPAddress.Parse(IPAddress); + _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + IPEndPoint ep = new IPEndPoint(camIP, Port); + _socket.Connect(ep); + } + catch(Exception) + { + string msg = $"Error connecting to IP address '{IPAddress}:{Port}'."; + log.Error(msg); + throw ExceptionBuilder.Build(typeof(ConnectionFailedException), Name, "error_connectionFailed", msg); + } + + ActivateChannel(ChannelNames.Distance); + ActivateChannel(ChannelNames.Intensity); + SelectChannel(ChannelNames.Intensity); + + _updateThread.Start(); + } + + protected override void DisconnectImpl() + { + _cancelUpdateThreadSource.Cancel(); + _updateThread.Join(); + _socket.Close(); + _frameAvailable.Reset(); + } + + protected override void UpdateImpl() + { + _frameAvailable.WaitOne(); + + if (null != _updateThreadError) + { + Disconnect(); + throw new ImageAcquisitionFailedException(_updateThreadError); + } + + _frontJsonData = _backJsonData; + } + + protected override CameraImage CalcChannelImpl(string channelName) + { + switch (channelName) + { + case ChannelNames.Intensity: + return ParseImage(_frontJsonData, _intensityJsonOffset, _intensityJsonSize, 1.0f); + case ChannelNames.Distance: + return ParseImage(_frontJsonData, _distanceJsonOffset, _distanceJsonSize); + } + + log.Error(Name + ": Invalid channelname: " + channelName); + return null; + } + + #endregion + + private void UpdateLoop() + { + int consecutiveFailCounter = 0; + while (!_cancelUpdateThreadSource.Token.IsCancellationRequested) + { + try + { + // 0 - CameraModel + // 1 - distance Image + // 2 - intensity Image + SyncCola(); + uint jsonSize = ReceiveDataSize(); + _backJsonData = ReceiveJsonString(jsonSize); + if(null == _intrinsics) + { + string json = new string(_backJsonData); + var frameData = JsonConvert.DeserializeObject>(json); + _intrinsics = ParseIntrinsics(frameData[0]); + _imageWidth = frameData[1].Data.Data.Width; + _imageHeight = frameData[1].Data.Data.Height; + + //Determine the offsets of intensity and distance image, which are stable over time. + string needle = "\"data\":\""; + int start_first_img = json.IndexOf(needle, 0) + needle.Length; + int end_first_img = json.IndexOf("\"", start_first_img); + _distanceJsonOffset = start_first_img; + _distanceJsonSize = end_first_img - start_first_img; + int start_second_img = json.IndexOf(needle, end_first_img) + needle.Length; + int end_second_img = json.IndexOf("\"", start_second_img); + _intensityJsonOffset = start_second_img; + _intensityJsonSize = end_second_img - start_second_img; + + if ("uint16" != frameData[1].Data.Data.ImageType + && "uint16" != frameData[2].Data.Data.ImageType) + { + string msg = $"{Name}: Frame data has unexpected format: '{frameData[1].Data.Data.ImageType}', expected: 'uint16'"; + log.Error(msg); + throw new ImageAcquisitionFailedException(msg); + } + + if ("little" != frameData[1].Data.Data.Pixels.endian + && "little" != frameData[2].Data.Data.Pixels.endian) + { + string msg = $"{Name}: Frame data has unexpected endian: '{frameData[1].Data.Data.Pixels.endian}', expected: 'little'"; + log.Error(msg); + throw new ImageAcquisitionFailedException(msg); + } + } + _frameAvailable.Set(); + } + catch(Exception e) + { + consecutiveFailCounter++; + if (consecutiveFailCounter > NumFrameRetries) + { + string msg = $"{Name}: Receive failed more than {NumFrameRetries} times in a row. Shutting down update loop."; + log.Error(msg); + log.Error(e.Message); + _updateThreadError = msg; + _frameAvailable.Set(); + break; + } + } + + // reset counter after sucessfull fetch + consecutiveFailCounter = 0; + } + } + + private void SyncCola() + { + int elements = 0; + while(elements < 4) + { + byte[] buffer = new byte[1]; + _socket.Receive(buffer, 1, SocketFlags.None); + + if(buffer[0] == 0x02) + { + elements++; + } + else + { + elements = 0; + } + } + } + + private uint ReceiveDataSize() + { + uint bufferSize = sizeof(uint); + byte[] buffer = new byte[bufferSize]; + _socket.Receive(buffer, (int)bufferSize, SocketFlags.None); + Array.Reverse(buffer); + return BitConverter.ToUInt32(buffer, 0); + } + + private char[] ReceiveJsonString(uint dataSize) + { + byte[] buffer = new byte[dataSize]; + uint bytesReceived = 0; + + while(bytesReceived < dataSize) + { + int received = _socket.Receive(buffer, (int)bytesReceived, (int)(dataSize - bytesReceived), SocketFlags.None, out SocketError error); + bytesReceived += (uint)received; + } + try + { + return Encoding.UTF8.GetChars(buffer); + } + catch(Exception e) + { + string msg = $"{Name}: Invalid UTF-8 byte sequence received: {e.Message}"; + log.Error(msg); + throw new ImageAcquisitionFailedException(msg); + } + } + + private ProjectiveTransformationZhang ParseIntrinsics(CameraObject metaObj) + { + if (null == metaObj.Data.IntrinsicK) + { + string msg = $"{Name}: Invalid camera meta information received"; + log.Error(msg); + throw new ImageAcquisitionFailedException(msg); + } + + return new ProjectiveTransformationZhang( + metaObj.Data.ImageWidth, + metaObj.Data.ImageHeight, + metaObj.Data.IntrinsicK[0][0], + metaObj.Data.IntrinsicK[1][1], + metaObj.Data.IntrinsicK[0][2], + metaObj.Data.IntrinsicK[1][2], + metaObj.Data.SensorToWorldDistortion[0][0], + metaObj.Data.SensorToWorldDistortion[1][0], + metaObj.Data.SensorToWorldDistortion[2][0], + metaObj.Data.SensorToWorldDistortion[3][0], + metaObj.Data.SensorToWorldDistortion[4][0] + ); + } + + private unsafe FloatCameraImage ParseImage(char[] base64Data, int offset, int length, float scaleFactor = 1000.0f) + { + byte[] raw = Convert.FromBase64CharArray(base64Data, offset, length); + + FloatCameraImage image = new FloatCameraImage(_imageWidth, _imageHeight); + + fixed (byte* rawData = raw) + { + ushort* ushortData = (ushort*)rawData; + if (scaleFactor != 1.0f) + { + for (int i = 0; i < image.Length; i++) + { + image[i] = *ushortData / scaleFactor; + ushortData++; + } + } + else + { + for (int i = 0; i < image.Length; i++) + { + image[i] = *ushortData; + ushortData++; + } + } + } + + return image; + } + + public override IProjectiveTransformation GetIntrinsics(string channelName) + { + if (null == _intrinsics) + { + // wait for first frameset to arrive and check availablity of intrinsics again + UpdateImpl(); + + if (null == _intrinsics) + { + string msg = $"{Name}: No intrinsics available"; + log.Error(msg); + throw new MetriCam2Exception(msg); + } + } + + return _intrinsics; + } + } +} diff --git a/BetaCameras/Sick.VisionaryT/VisionaryT.cs b/BetaCameras/Sick.VisionaryT/VisionaryT.cs index c458cd7f..e2bb9779 100644 --- a/BetaCameras/Sick.VisionaryT/VisionaryT.cs +++ b/BetaCameras/Sick.VisionaryT/VisionaryT.cs @@ -26,7 +26,7 @@ public class VisionaryT : Camera // ipAddress to connect to private string ipAddress; // device handle - private Device device; + private Device _device; private Control _control; // image data contains information about the current frame e.g. width and height @@ -155,7 +155,7 @@ public VisionaryT() : base() { ipAddress = ""; - device = null; + _device = null; _frontFrameData = null; _backFrameData = null; _updateThread = null; @@ -202,7 +202,7 @@ protected override void ConnectImpl() log.Error(msg); throw ExceptionBuilder.Build(typeof(ConnectionFailedException), Name, "error_connectionFailed", msg); } - device = new Device(ipAddress, this, log); + _device = new Device(ipAddress, this, log); _control = new Control(log, ipAddress); _control.StartStream(); @@ -227,8 +227,8 @@ protected override void DisconnectImpl() _updateThread = null; _control.Close(); _control = null; - device.Disconnect(); - device = null; + _device.Disconnect(); + _device = null; } ///

@@ -292,7 +292,7 @@ private void UpdateLoop() { lock (_backLock) { - byte[] imageBuffer = device.GetFrameData(); + byte[] imageBuffer = _device.GetFrameData(); _backFrameData = new FrameData(imageBuffer, this, log); _frameAvailable.Set(); } diff --git a/MetriCam2_SDK.sln b/MetriCam2_SDK.sln index 22a2a791..2912e15c 100644 --- a/MetriCam2_SDK.sln +++ b/MetriCam2_SDK.sln @@ -83,6 +83,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaslerACE", "BetaCameras\Ba EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pico", "BetaCameras\Pico\Pico.csproj", "{1FAD1F90-D37E-40CA-BBF0-6A33E82F8812}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sick.VisionaryT.Pro", "BetaCameras\Sick.VisionaryT.Pro\Sick.VisionaryT.Pro.csproj", "{D01829D2-B553-4C4B-B392-2437E6A130B5}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -555,6 +557,22 @@ Global {1FAD1F90-D37E-40CA-BBF0-6A33E82F8812}.ReleaseStrongName|Any CPU.ActiveCfg = Release|Any CPU {1FAD1F90-D37E-40CA-BBF0-6A33E82F8812}.ReleaseStrongName|x64.ActiveCfg = Release|Any CPU {1FAD1F90-D37E-40CA-BBF0-6A33E82F8812}.ReleaseStrongName|x86.ActiveCfg = Release|Any CPU + {D01829D2-B553-4C4B-B392-2437E6A130B5}.Debug|Any CPU.ActiveCfg = Debug|x64 + {D01829D2-B553-4C4B-B392-2437E6A130B5}.Debug|x64.ActiveCfg = Debug|x64 + {D01829D2-B553-4C4B-B392-2437E6A130B5}.Debug|x64.Build.0 = Debug|x64 + {D01829D2-B553-4C4B-B392-2437E6A130B5}.Debug|x86.ActiveCfg = Debug|x64 + {D01829D2-B553-4C4B-B392-2437E6A130B5}.DebugStrongName|Any CPU.ActiveCfg = Release|x64 + {D01829D2-B553-4C4B-B392-2437E6A130B5}.DebugStrongName|Any CPU.Build.0 = Release|x64 + {D01829D2-B553-4C4B-B392-2437E6A130B5}.DebugStrongName|x64.ActiveCfg = Debug|x64 + {D01829D2-B553-4C4B-B392-2437E6A130B5}.DebugStrongName|x86.ActiveCfg = DebugStrongName|x64 + {D01829D2-B553-4C4B-B392-2437E6A130B5}.Release|Any CPU.ActiveCfg = Release|x64 + {D01829D2-B553-4C4B-B392-2437E6A130B5}.Release|x64.ActiveCfg = Release|x64 + {D01829D2-B553-4C4B-B392-2437E6A130B5}.Release|x64.Build.0 = Release|x64 + {D01829D2-B553-4C4B-B392-2437E6A130B5}.Release|x86.ActiveCfg = Release|x64 + {D01829D2-B553-4C4B-B392-2437E6A130B5}.ReleaseStrongName|Any CPU.ActiveCfg = Release|x64 + {D01829D2-B553-4C4B-B392-2437E6A130B5}.ReleaseStrongName|Any CPU.Build.0 = Release|x64 + {D01829D2-B553-4C4B-B392-2437E6A130B5}.ReleaseStrongName|x64.ActiveCfg = Release|x64 + {D01829D2-B553-4C4B-B392-2437E6A130B5}.ReleaseStrongName|x86.ActiveCfg = ReleaseStrongName|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -583,6 +601,7 @@ Global {9CBCE2AB-4E19-4344-B3CF-67D07CC9C8FC} = {4817E415-1337-4CA1-BF30-23D3EA0F806B} {474D94F4-857B-4199-97AF-C600AED44406} = {4817E415-1337-4CA1-BF30-23D3EA0F806B} {1FAD1F90-D37E-40CA-BBF0-6A33E82F8812} = {4817E415-1337-4CA1-BF30-23D3EA0F806B} + {D01829D2-B553-4C4B-B392-2437E6A130B5} = {4817E415-1337-4CA1-BF30-23D3EA0F806B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E4CD8F0D-A50B-44DC-80D3-0C789213BF2B} diff --git a/Samples/MinimalSample/MinimalSample.csproj b/Samples/MinimalSample/MinimalSample.csproj index a97470d3..41b63f3c 100644 --- a/Samples/MinimalSample/MinimalSample.csproj +++ b/Samples/MinimalSample/MinimalSample.csproj @@ -101,24 +101,6 @@ - - - {c82202f8-55db-4511-b006-c88ff3e4427e} - OrbbecOpenNI - - - {de18d143-c624-4941-b8a1-0f91262d3350} - Sick.VisionaryT - - - {01c2fb4d-1f35-4855-9b53-0480519387c5} - WebCam - - - {342f049e-668b-4351-b21d-75e4bef5a1e4} - MetriCam2 - - .licenseheader @@ -132,6 +114,16 @@ false + + + {c82202f8-55db-4511-b006-c88ff3e4427e} + OrbbecOpenNI + + + {342f049e-668b-4351-b21d-75e4bef5a1e4} + MetriCam2 + + - + \ No newline at end of file diff --git a/Scripts/Jenkinsfile.groovy b/Scripts/Jenkinsfile.groovy index 542892cd..99f5dfeb 100644 --- a/Scripts/Jenkinsfile.groovy +++ b/Scripts/Jenkinsfile.groovy @@ -9,7 +9,7 @@ pipeline { def V_MINOR = "${versionInfo['VERSION_MINOR']}" def V_BUILD = "${versionInfo['VERSION_BUILD']}" - def dllsToDeployX64 = 'CookComputing.XmlRpcV2 MetriCam2.Cameras.BaslerACE MetriCam2.Cameras.BaslerToF MetriCam2.Cameras.ifm MetriCam2.Cameras.Kinect2 MetriCam2.Cameras.MatrixVision MetriCam2.Cameras.OrbbecOpenNI MetriCam2.Cameras.Sick.TiM561 MetriCam2.Cameras.Sick.VisionaryT MetriCam2.Cameras.SVS MetriCam2.Cameras.TIVoxel MetriCam2.Cameras.UEye MetriCam2.Cameras.WebCam MetriCam2.Cameras.Pico' + def dllsToDeployX64 = 'CookComputing.XmlRpcV2 MetriCam2.Cameras.BaslerACE MetriCam2.Cameras.BaslerToF MetriCam2.Cameras.ifm MetriCam2.Cameras.Kinect2 MetriCam2.Cameras.MatrixVision MetriCam2.Cameras.OrbbecOpenNI MetriCam2.Cameras.Sick.TiM561 MetriCam2.Cameras.Sick.VisionaryT MetriCam2.Cameras.Sick.VisionaryT.Pro MetriCam2.Cameras.SVS MetriCam2.Cameras.TIVoxel MetriCam2.Cameras.UEye MetriCam2.Cameras.WebCam MetriCam2.Cameras.Pico' def dllsToDeployAnyCPU = 'Intel.RealSense log4net MathNet.Numerics MetriCam2 MetriCam2.Cameras.RealSense2 MetriCam2.Controls Metrilus.Util Newtonsoft.Json' def dllsToDeployNetStandard = 'MetriCam2 MetriCam2.Cameras.RealSense2 Metrilus.Util' def dllsToDeployX64StrongName = 'MetriCam2.Cameras.Kinect2 MetriCam2.Cameras.OrbbecOpenNI MetriCam2.Cameras.Sick.VisionaryT' From 11750f47e139c9768714e171e12fca2b966510d4 Mon Sep 17 00:00:00 2001 From: sisiplac Date: Thu, 28 Feb 2019 09:33:46 +0100 Subject: [PATCH 2/6] Remove GetIntrinsics and implement Calc3D instead. --- .../Sick.VisionaryT.Pro/VisionaryTPro.cs | 113 ++++++++++++------ 1 file changed, 77 insertions(+), 36 deletions(-) diff --git a/BetaCameras/Sick.VisionaryT.Pro/VisionaryTPro.cs b/BetaCameras/Sick.VisionaryT.Pro/VisionaryTPro.cs index 737155af..0ac6e59b 100644 --- a/BetaCameras/Sick.VisionaryT.Pro/VisionaryTPro.cs +++ b/BetaCameras/Sick.VisionaryT.Pro/VisionaryTPro.cs @@ -20,6 +20,21 @@ namespace MetriCam2.Cameras /// public class VisionaryTPro : Camera { + #region Types + private class InverseBrownConradyParams + { + public float Fx { get; set; } + public float Fy { get; set; } + public float Cx { get; set; } + public float Cy { get; set; } + public float K1 { get; set; } + public float K2 { get; set; } + public float K3 { get; set; } + public float P1 { get; set; } + public float P2 { get; set; } + } + #endregion + private Thread _updateThread; private Socket _socket; private char[] _frontJsonData = null; @@ -32,7 +47,7 @@ public class VisionaryTPro : Camera private int _imageWidth = 0; private AutoResetEvent _frameAvailable = new AutoResetEvent(false); private CancellationTokenSource _cancelUpdateThreadSource; - private ProjectiveTransformationZhang _intrinsics = null; + private Point3fCameraImage _directions = null; private const int NumFrameRetries = 3; private string _updateThreadError = null; @@ -89,6 +104,7 @@ protected override void LoadAllAvailableChannels() Channels.Add(cr.RegisterChannel(ChannelNames.Intensity)); Channels.Add(cr.RegisterChannel(ChannelNames.Distance)); + Channels.Add(cr.RegisterChannel(ChannelNames.Point3DImage)); } @@ -120,6 +136,7 @@ protected override void ConnectImpl() } ActivateChannel(ChannelNames.Distance); + ActivateChannel(ChannelNames.Point3DImage); ActivateChannel(ChannelNames.Intensity); SelectChannel(ChannelNames.Intensity); @@ -155,12 +172,54 @@ protected override CameraImage CalcChannelImpl(string channelName) return ParseImage(_frontJsonData, _intensityJsonOffset, _intensityJsonSize, 1.0f); case ChannelNames.Distance: return ParseImage(_frontJsonData, _distanceJsonOffset, _distanceJsonSize); + case ChannelNames.Point3DImage: + return GetScaledDistances(ParseImage(_frontJsonData, _distanceJsonOffset, _distanceJsonSize)); } log.Error(Name + ": Invalid channelname: " + channelName); return null; } + + //TODO: Metrilus.Util should implement the *-operator on FloatCameraImage and Point3fCameraImage in future. Then just replace this method. + private Point3fCameraImage GetScaledDistances(FloatCameraImage distances) + { + Point3fCameraImage coords = new Point3fCameraImage(distances.Width, distances.Height); + for(int i = 0; i < coords.Length; i++) + { + coords[i] = distances[i] * _directions[i]; + } + return coords; + } + + private Point3fCameraImage CalcDirections(InverseBrownConradyParams intrinsics, int width, int height) + { + Point3fCameraImage directions = new Point3fCameraImage(width, height); + for (int row = 0; row < height; row++) + { + float yp = (intrinsics.Cy - row) / intrinsics.Fy; + float yp2 = yp * yp; + + for (int col = 0; col < width; col++) + { + float xp = (intrinsics.Cx - col) / intrinsics.Fx; + + // correct the camera distortion + float r2 = xp * xp + yp2; + float r4 = r2 * r2; + float k = 1 + intrinsics.K1 * r2 + intrinsics.K2 * r4; + + // Undistorted direction vector of the point + float x = xp * k; + float y = yp * k; + float s0Inv = (float)(1 / Math.Sqrt(x * x + y * y + 1)); //z is 1, since x and y are coordinates on normalized image plane. + + directions[row, col] = new Point3f(-x * s0Inv, -y * s0Inv, s0Inv); + } + } + return directions; + } + #endregion private void UpdateLoop() @@ -176,13 +235,14 @@ private void UpdateLoop() SyncCola(); uint jsonSize = ReceiveDataSize(); _backJsonData = ReceiveJsonString(jsonSize); - if(null == _intrinsics) + if(null == _directions) { string json = new string(_backJsonData); - var frameData = JsonConvert.DeserializeObject>(json); - _intrinsics = ParseIntrinsics(frameData[0]); + var frameData = JsonConvert.DeserializeObject>(json); _imageWidth = frameData[1].Data.Data.Width; _imageHeight = frameData[1].Data.Data.Height; + InverseBrownConradyParams intrinsics = ParseIntrinsics(frameData[0]); + _directions = CalcDirections(intrinsics, _imageWidth, _imageHeight); //Determine the offsets of intensity and distance image, which are stable over time. string needle = "\"data\":\""; @@ -282,7 +342,7 @@ private char[] ReceiveJsonString(uint dataSize) } } - private ProjectiveTransformationZhang ParseIntrinsics(CameraObject metaObj) + private InverseBrownConradyParams ParseIntrinsics(CameraObject metaObj) { if (null == metaObj.Data.IntrinsicK) { @@ -291,19 +351,18 @@ private ProjectiveTransformationZhang ParseIntrinsics(CameraObject metaObj) throw new ImageAcquisitionFailedException(msg); } - return new ProjectiveTransformationZhang( - metaObj.Data.ImageWidth, - metaObj.Data.ImageHeight, - metaObj.Data.IntrinsicK[0][0], - metaObj.Data.IntrinsicK[1][1], - metaObj.Data.IntrinsicK[0][2], - metaObj.Data.IntrinsicK[1][2], - metaObj.Data.SensorToWorldDistortion[0][0], - metaObj.Data.SensorToWorldDistortion[1][0], - metaObj.Data.SensorToWorldDistortion[2][0], - metaObj.Data.SensorToWorldDistortion[3][0], - metaObj.Data.SensorToWorldDistortion[4][0] - ); + return new InverseBrownConradyParams() + { + Fx = metaObj.Data.IntrinsicK[0][0], + Fy = metaObj.Data.IntrinsicK[1][1], + Cx = metaObj.Data.IntrinsicK[0][2], + Cy = metaObj.Data.IntrinsicK[1][2], + K1 = metaObj.Data.SensorToWorldDistortion[0][0], + K2 = metaObj.Data.SensorToWorldDistortion[1][0], + P1 = metaObj.Data.SensorToWorldDistortion[2][0], + P2 = metaObj.Data.SensorToWorldDistortion[3][0], + K3 = metaObj.Data.SensorToWorldDistortion[4][0] + }; } private unsafe FloatCameraImage ParseImage(char[] base64Data, int offset, int length, float scaleFactor = 1000.0f) @@ -335,23 +394,5 @@ private unsafe FloatCameraImage ParseImage(char[] base64Data, int offset, int le return image; } - - public override IProjectiveTransformation GetIntrinsics(string channelName) - { - if (null == _intrinsics) - { - // wait for first frameset to arrive and check availablity of intrinsics again - UpdateImpl(); - - if (null == _intrinsics) - { - string msg = $"{Name}: No intrinsics available"; - log.Error(msg); - throw new MetriCam2Exception(msg); - } - } - - return _intrinsics; - } } } From 3b8060c2758919f77d45b7850f531cebd04647db Mon Sep 17 00:00:00 2001 From: f00f <582746+f00f@users.noreply.github.com> Date: Fri, 1 Mar 2019 10:41:46 +0100 Subject: [PATCH 3/6] Add 'Vendor' property to Visionary-T. --- BetaCameras/Sick.VisionaryT.Pro/VisionaryTPro.cs | 4 ++-- BetaCameras/Sick.VisionaryT/VisionaryT.cs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/BetaCameras/Sick.VisionaryT.Pro/VisionaryTPro.cs b/BetaCameras/Sick.VisionaryT.Pro/VisionaryTPro.cs index 0ac6e59b..d327cc0f 100644 --- a/BetaCameras/Sick.VisionaryT.Pro/VisionaryTPro.cs +++ b/BetaCameras/Sick.VisionaryT.Pro/VisionaryTPro.cs @@ -93,8 +93,8 @@ public VisionaryTPro() #region MetriCam2 Camera Interface - public new string Name { get => "Visionary-T-Pro"; } - public new string Vendor { get => "Sick"; } + public override string Name { get => "Visionary-T-Pro"; } + public override string Vendor { get => "Sick"; } protected override void LoadAllAvailableChannels() { diff --git a/BetaCameras/Sick.VisionaryT/VisionaryT.cs b/BetaCameras/Sick.VisionaryT/VisionaryT.cs index e2bb9779..31e56cfe 100644 --- a/BetaCameras/Sick.VisionaryT/VisionaryT.cs +++ b/BetaCameras/Sick.VisionaryT/VisionaryT.cs @@ -167,7 +167,8 @@ public VisionaryT() #region MetriCam2 Camera Interface #region MetriCam2 Camera Interface Properties /// The camera's name. - public new string Name { get => "Visionary-T"; } + public override string Name { get => "Visionary-T"; } + public override string Vendor { get => "Sick"; } #endregion #region MetriCam2 Camera Interface Methods From fbf30608b40f200091f1fa3e52e8cee0f799a06d Mon Sep 17 00:00:00 2001 From: Jan Lukas Gernert Date: Wed, 6 Mar 2019 09:42:54 +0100 Subject: [PATCH 4/6] fix format & endian check --- BetaCameras/Sick.VisionaryT.Pro/VisionaryTPro.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/BetaCameras/Sick.VisionaryT.Pro/VisionaryTPro.cs b/BetaCameras/Sick.VisionaryT.Pro/VisionaryTPro.cs index d327cc0f..59eb790d 100644 --- a/BetaCameras/Sick.VisionaryT.Pro/VisionaryTPro.cs +++ b/BetaCameras/Sick.VisionaryT.Pro/VisionaryTPro.cs @@ -256,17 +256,19 @@ private void UpdateLoop() _intensityJsonSize = end_second_img - start_second_img; if ("uint16" != frameData[1].Data.Data.ImageType - && "uint16" != frameData[2].Data.Data.ImageType) + || "uint16" != frameData[2].Data.Data.ImageType) { - string msg = $"{Name}: Frame data has unexpected format: '{frameData[1].Data.Data.ImageType}', expected: 'uint16'"; + string format = frameData[1].Data.Data.ImageType != "uint16" ? frameData[1].Data.Data.ImageType : frameData[2].Data.Data.ImageType; + string msg = $"{Name}: Frame data has unexpected format: '{format}', expected: 'uint16'"; log.Error(msg); throw new ImageAcquisitionFailedException(msg); } if ("little" != frameData[1].Data.Data.Pixels.endian - && "little" != frameData[2].Data.Data.Pixels.endian) + || "little" != frameData[2].Data.Data.Pixels.endian) { - string msg = $"{Name}: Frame data has unexpected endian: '{frameData[1].Data.Data.Pixels.endian}', expected: 'little'"; + string endian = frameData[1].Data.Data.Pixels.endian != "little" ? frameData[1].Data.Data.Pixels.endian : frameData[2].Data.Data.Pixels.endian; + string msg = $"{Name}: Frame data has unexpected endian: '{endian}', expected: 'little'"; log.Error(msg); throw new ImageAcquisitionFailedException(msg); } From 627b09ce0ddfdfea91b10becd8c5b7e45374974e Mon Sep 17 00:00:00 2001 From: Jan Lukas Gernert Date: Wed, 6 Mar 2019 09:48:27 +0100 Subject: [PATCH 5/6] sort using statements --- BetaCameras/Sick.VisionaryT.Pro/VisionaryTPro.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/BetaCameras/Sick.VisionaryT.Pro/VisionaryTPro.cs b/BetaCameras/Sick.VisionaryT.Pro/VisionaryTPro.cs index 59eb790d..d449a1c2 100644 --- a/BetaCameras/Sick.VisionaryT.Pro/VisionaryTPro.cs +++ b/BetaCameras/Sick.VisionaryT.Pro/VisionaryTPro.cs @@ -2,12 +2,12 @@ // MetriCam 2 is licensed under the MIT license. See License.txt for full license text. using System; -using System.Threading; +using System.Collections.Generic; +using System.Drawing; using System.Net; using System.Net.Sockets; using System.Text; -using System.Collections.Generic; -using System.Drawing; +using System.Threading; using Newtonsoft.Json; using Metrilus.Util; using MetriCam2.Exceptions; From 2dad023c7892f5e24844d6a339e7e397d96a95b4 Mon Sep 17 00:00:00 2001 From: Jan Lukas Gernert Date: Wed, 6 Mar 2019 09:58:47 +0100 Subject: [PATCH 6/6] use update thread exception as inner exception for updateImpl --- BetaCameras/Sick.VisionaryT.Pro/VisionaryTPro.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/BetaCameras/Sick.VisionaryT.Pro/VisionaryTPro.cs b/BetaCameras/Sick.VisionaryT.Pro/VisionaryTPro.cs index d449a1c2..9e1435b2 100644 --- a/BetaCameras/Sick.VisionaryT.Pro/VisionaryTPro.cs +++ b/BetaCameras/Sick.VisionaryT.Pro/VisionaryTPro.cs @@ -50,6 +50,7 @@ private class InverseBrownConradyParams private Point3fCameraImage _directions = null; private const int NumFrameRetries = 3; private string _updateThreadError = null; + private Exception _updateThreadException = null; private ParamDesc IPAddressDesc { @@ -111,6 +112,7 @@ protected override void LoadAllAvailableChannels() protected override void ConnectImpl() { _updateThreadError = null; + _updateThreadException = null; _updateThread = new Thread(new ThreadStart(UpdateLoop)); _cancelUpdateThreadSource = new CancellationTokenSource(); @@ -158,7 +160,14 @@ protected override void UpdateImpl() if (null != _updateThreadError) { Disconnect(); - throw new ImageAcquisitionFailedException(_updateThreadError); + if (null != _updateThreadException) + { + throw new ImageAcquisitionFailedException(_updateThreadError, _updateThreadException); + } + else + { + throw new ImageAcquisitionFailedException(_updateThreadError); + } } _frontJsonData = _backJsonData; @@ -284,6 +293,7 @@ private void UpdateLoop() log.Error(msg); log.Error(e.Message); _updateThreadError = msg; + _updateThreadException = e; _frameAvailable.Set(); break; }