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

733 lines
29 KiB

//----------------------------------------------------------------------------
// Copyright (C) 2004-2023 by EMGU Corporation. All rights reserved.
//----------------------------------------------------------------------------
using System;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;
using System.IO;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Collections.Generic;
using System.Reflection;
namespace Emgu.Util
{
/// <summary>
/// utilities functions for Emgu
/// </summary>
public static class Toolbox
{
#region xml serilization and deserialization
/// <summary>
/// Convert an object to an xml document
/// </summary>
/// <typeparam name="T">The type of the object to be converted</typeparam>
/// <param name="sourceObject">The object to be serialized</param>
/// <returns>An xml document that represents the object</returns>
public static XDocument XmlSerialize<T>(T sourceObject)
{
StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter(sb))
(new XmlSerializer(typeof(T))).Serialize(sw, sourceObject);
return XDocument.Parse(sb.ToString());
}
/// <summary>
/// Convert an object to an xml document
/// </summary>
/// <typeparam name="T">The type of the object to be converted</typeparam>
/// <param name="sourceObject">The object to be serialized</param>
/// <param name="knownTypes">Other types that it must known ahead to serialize the object</param>
/// <returns>An xml document that represents the object</returns>
public static XDocument XmlSerialize<T>(T sourceObject, Type[] knownTypes)
{
StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter(sb))
(new XmlSerializer(typeof(T), knownTypes)).Serialize(sw, sourceObject);
return XDocument.Parse(sb.ToString());
}
/// <summary>
/// Convert an xml document to an object
/// </summary>
/// <typeparam name="T">The type of the object to be converted to</typeparam>
/// <param name="document">The xml document</param>
/// <returns>The object representation as a result of the deserialization of the xml document</returns>
public static T XmlDeserialize<T>(XDocument document)
{
using (XmlReader reader = document.Root.CreateReader())
{
if (reader.CanReadBinaryContent)
return (T)(new XmlSerializer(typeof(T))).Deserialize(reader);
else
{
return XmlStringDeserialize<T>(document.ToString());
}
}
}
/// <summary>
/// Convert an xml document to an object
/// </summary>
/// <typeparam name="T">The type of the object to be converted to</typeparam>
/// <param name="xDoc">The xml document</param>
/// <param name="knownTypes">Other types that it must known ahead to deserialize the object</param>
/// <returns>The object representation as a result of the deserialization of the xml document</returns>
public static T XmlDeserialize<T>(XDocument xDoc, Type[] knownTypes)
{
using (XmlReader reader = xDoc.Root.CreateReader())
{
if (reader.CanReadBinaryContent)
return (T)(new XmlSerializer(typeof(T), knownTypes)).Deserialize(reader);
else
{
using (StringReader stringReader = new StringReader(xDoc.ToString()))
{
return (T)(new XmlSerializer(typeof(T), knownTypes)).Deserialize(stringReader);
}
}
}
}
/// <summary>
/// Convert an xml string to an object
/// </summary>
/// <typeparam name="T">The type of the object to be converted to</typeparam>
/// <param name="xmlString">The xml document as a string</param>
/// <returns>The object representation as a result of the deserialization of the xml string</returns>
public static T XmlStringDeserialize<T>(String xmlString)
{
using (StringReader stringReader = new StringReader(xmlString))
return (T)(new XmlSerializer(typeof(T))).Deserialize(stringReader);
}
#endregion
/// <summary>
/// Similar to Marshal.SizeOf function
/// </summary>
/// <typeparam name="T">The type</typeparam>
/// <returns>The size of T in bytes</returns>
public static int SizeOf<T>()
{
return Marshal.SizeOf<T>();
}
/*
/// <summary>
/// Read a text file to an array of string, each row are separated using by the input separator
/// </summary>
/// <param name="fileName">The text file to read from</param>
/// <param name="seperator">The row separator</param>
/// <returns></returns>
public static string FileToString(string fileName, char separator)
{
StringBuilder res = new StringBuilder();
string input;
using (StreamReader sr = File.OpenText(fileName))
while ((input = sr.ReadLine()) != null)
res.AppendFormat("{0}{1}", input, separator);
return res.ToString();
}*/
/// <summary>
/// Merges two byte vector into one
/// </summary>
/// <param name="a">the first byte vector to be merged</param>
/// <param name="b">the second byte vector to be merged</param>
/// <returns>The bytes that is a concatenation of a and b</returns>
public static Byte[] MergeBytes(Byte[] a, Byte[] b)
{
Byte[] c = new byte[a.Length + b.Length]; // just one array allocation
Buffer.BlockCopy(a, 0, c, 0, a.Length);
Buffer.BlockCopy(b, 0, c, a.Length, b.Length);
return c;
}
/// <summary>
/// Call a command from command line
/// </summary>
/// <param name="execFileName">The name of the executable</param>
/// <param name="arguments">The arguments to the executable</param>
/// <returns>The standard output</returns>
public static string ExecuteCmd(string execFileName, string arguments)
{
using (Process processor = new Process())
{
processor.StartInfo.FileName = execFileName;
processor.StartInfo.Arguments = arguments;
processor.StartInfo.UseShellExecute = false;
processor.StartInfo.RedirectStandardOutput = true;
processor.StartInfo.RedirectStandardError = true;
//string error = string.Empty;
try
{
processor.Start();
}
catch (Exception)
{
//error = e.Message;
}
//processor.BeginErrorReadLine();
//String error2 = processor.StandardError.ReadToEnd();
string output = processor.StandardOutput.ReadToEnd();
processor.WaitForExit();
processor.Close();
return output;
}
}
/// <summary>
/// Use reflection to find the base type. If such type do not exist, null is returned
/// </summary>
/// <param name="currentType">The type to search from</param>
/// <param name="baseClassName">The name of the base class to search</param>
/// <returns>The base type</returns>
public static Type GetBaseType(Type currentType, String baseClassName)
{
if (currentType.Name.Equals(baseClassName))
return currentType;
Type baseType = currentType.BaseType;
return (baseType == null) ?
null : GetBaseType(baseType, baseClassName);
}
#region memory copy
/// <summary>
/// Convert some generic vector to vector of Bytes
/// </summary>
/// <typeparam name="TData">type of the input vector</typeparam>
/// <param name="data">array of data</param>
/// <returns>the byte vector</returns>
public static Byte[] ToBytes<TData>(TData[] data)
{
int size = Marshal.SizeOf<TData>() * data.Length;
Byte[] res = new Byte[size];
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
Marshal.Copy(handle.AddrOfPinnedObject(), res, 0, size);
handle.Free();
return res;
}
/// <summary>
/// Perform first degree interpolation give the sorted data <paramref name="src"/> and the interpolation <paramref name="indexes"/>
/// </summary>
/// <param name="src">The sorted data that will be interpolated from</param>
/// <param name="indexes">The indexes of the interpolate result</param>
/// <typeparam name="T">The type of the data to be interpolated</typeparam>
/// <returns>The interpolated data</returns>
public static IEnumerable<T> LinearInterpolate<T>(IEnumerable<T> src, IEnumerable<double> indexes) where T : IInterpolatable<T>, new()
{
using (IEnumerator<T> sampleEnumerator = src.GetEnumerator())
{
if (!sampleEnumerator.MoveNext())
yield break;
T old = sampleEnumerator.Current;
if (!sampleEnumerator.MoveNext())
yield break;
T current = sampleEnumerator.Current;
foreach (double index in indexes)
{
while (index > current.InterpolationIndex && sampleEnumerator.MoveNext())
{
old = current;
current = sampleEnumerator.Current;
}
//yield return LinearInterpolate(old, current, index);
yield return old.LinearInterpolate(current, index);
}
}
}
/// <summary>
/// Get subsamples with the specific rate
/// </summary>
/// <param name="src">The source which the subsamples will be derived from</param>
/// <param name="subsampleRate">The subsample rate</param>
/// <returns><paramref name="src"/> subsampled with the specific rate </returns>
/// <typeparam name="T">The type of the object</typeparam>
public static IEnumerable<T> LinearSubsample<T>(IEnumerable<T> src, double subsampleRate) where T : IInterpolatable<T>, new()
{
using (IEnumerator<T> sampleEnumerator = src.GetEnumerator())
{
if (!sampleEnumerator.MoveNext())
yield break;
T old = sampleEnumerator.Current;
yield return old;
if (!sampleEnumerator.MoveNext())
yield break;
T current = sampleEnumerator.Current;
double currentIndex = old.InterpolationIndex + subsampleRate;
bool endOfSubsample = false;
while (!endOfSubsample)
{
while (currentIndex > current.InterpolationIndex)
{
if (endOfSubsample = !sampleEnumerator.MoveNext())
break;
old = current;
current = sampleEnumerator.Current;
}
if (!endOfSubsample)
{
yield return old.LinearInterpolate(current, currentIndex);
//yield return LinearInterpolate(old, current, currentIndex);
currentIndex += subsampleRate;
}
}
}
}
/// <summary>
/// Joining multiple index ascending IInterpolatables together as a single index ascending IInterpolatable.
/// </summary>
/// <typeparam name="T">The type of objects that will be joined</typeparam>
/// <param name="enums">The enumerables, each should be stored in index ascending order</param>
/// <returns>A single enumerable sorted in index ascending order</returns>
public static IEnumerable<T> JoinInterpolatables<T>(params IEnumerable<T>[] enums) where T : IInterpolatable<T>, new()
{
if (enums.Length == 0)
yield break;
else if (enums.Length == 1)
{
foreach (T sample in enums[0])
yield return sample;
}
else if (enums.Length == 2)
{
foreach (T sample in JoinTwoInterpolatables(enums[0], enums[1]))
yield return sample;
}
else
{
int middle = enums.Length / 2;
IEnumerable<T>[] lower = new IEnumerable<T>[middle];
IEnumerable<T>[] upper = new IEnumerable<T>[enums.Length - middle];
Array.Copy(enums, lower, middle);
Array.Copy(enums, middle, upper, 0, enums.Length - middle);
foreach (T sample in JoinTwoInterpolatables<T>(JoinInterpolatables<T>(lower), JoinInterpolatables<T>(upper)))
yield return sample;
}
}
private static IEnumerable<T> JoinTwoInterpolatables<T>(IEnumerable<T> enum1, IEnumerable<T> enum2) where T : IInterpolatable<T>, new()
{
IEnumerator<T> l1 = enum1.GetEnumerator();
IEnumerator<T> l2 = enum2.GetEnumerator();
if (!l1.MoveNext())
{
while (l2.MoveNext())
yield return l2.Current;
yield break;
}
else if (!l2.MoveNext())
{
while (l1.MoveNext())
yield return l1.Current;
yield break;
}
T s1 = l1.Current;
T s2 = l2.Current;
while (true)
{
if (s1.InterpolationIndex < s2.InterpolationIndex)
{
yield return s1;
if (l1.MoveNext())
s1 = l1.Current;
else
{
while (l2.MoveNext())
yield return l2.Current;
yield break;
}
}
else
{
yield return s2;
if (l2.MoveNext())
s2 = l2.Current;
else
{
while (l1.MoveNext())
yield return l1.Current;
yield break;
}
}
}
}
/*
/// <summary>
/// Use the two IInterpolatable and the index to perform first degree interpolation
/// </summary>
/// <param name="i1">The first element to interpolate from</param>
/// <param name="i2">The second eleemnt to interpolate from</param>
/// <param name="index">The interpolation index</param>
/// <returns>The interpolatation result</returns>
private static T LinearInterpolate<T>(T i1, T i2, double index) where T : IInterpolatable<T>, new()
{
double f = (i2.InterpolationIndex - index) / (i2.InterpolationIndex - i1.InterpolationIndex);
//compute result = i1 * f + i2 * (1.0 - f)
T a = new T();
a.Add(i1);
a.Mul(f);
T b = new T();
b.Add(i2);
b.Mul(1.0 - f);
a.Add(b);
return a;
}*/
#endregion
private static System.Collections.Generic.Dictionary<String, AssemblyName> _assemblyNameDict = new Dictionary<String, AssemblyName>();
/// <summary>
/// Load all the assemblies.
/// </summary>
/// <returns>All the assemblies loaded.</returns>
public static System.Reflection.Assembly[] LoadAllDependentAssemblies()
{
try
{
lock (_assemblyNameDict)
{
System.Reflection.Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
bool dirty = false;
foreach (Assembly assembly in assemblies)
{
AssemblyName name = assembly.GetName();
if (!_assemblyNameDict.ContainsKey(name.ToString()))
_assemblyNameDict.Add(name.ToString(), name);
}
foreach (Assembly assembly in assemblies)
{
AssemblyName[] referencedAssemblyNames = assembly.GetReferencedAssemblies();
foreach (AssemblyName name in referencedAssemblyNames)
{
if (!_assemblyNameDict.ContainsKey(name.ToString()))
{
try
{
Assembly.Load(name);
_assemblyNameDict.Add(name.ToString(), name);
dirty = true;
}
catch (Exception e)
{
//if failed to load, it is ok, we will continue.
Debug.WriteLine(e);
}
}
}
}
if (dirty)
return AppDomain.CurrentDomain.GetAssemblies();
else
{
return assemblies;
}
}
}
catch (Exception e)
{
Debug.WriteLine(e);
}
return null;
}
/// <summary>
/// Get the interface implementation from assemblies
/// </summary>
/// <typeparam name="T">The interface</typeparam>
/// <returns>The types that implement the specific interface</returns>
public static Type[] GetInterfaceImplementationFromAssembly<T>()
{
System.Reflection.Assembly[] assemblies = LoadAllDependentAssemblies();
List<Type> types = new List<Type>();
if (assemblies != null)
{
foreach (Assembly assembly in assemblies)
{
foreach (Type t in assembly.GetTypes())
{
if (typeof(T).IsAssignableFrom(t) && typeof(T) != t)
{
types.Add(t);
}
}
}
}
return types.ToArray();
}
/// <summary>
/// Find the loaded assembly with the specific assembly name
/// </summary>
/// <param name="assembleName">The name of the assembly</param>
/// <returns>The assembly.</returns>
public static System.Reflection.Assembly FindAssembly(String assembleName)
{
try
{
System.Reflection.Assembly[] asms = AppDomain.CurrentDomain.GetAssemblies();
foreach (System.Reflection.Assembly asm in asms)
{
if (asm.ManifestModule.Name.Equals(assembleName))
return asm;
}
}
catch (Exception exception)
{
Trace.WriteLine(String.Format("FindAssembly({0}) failed: {1}", assembleName, exception.Message));
}
return null;
}
private static IntPtr LoadLibraryExWindows(String dllname, int flags)
{
IntPtr handler = LoadLibraryEx(dllname, IntPtr.Zero, flags);
if (handler == IntPtr.Zero)
{
int error = Marshal.GetLastWin32Error();
System.ComponentModel.Win32Exception ex = new System.ComponentModel.Win32Exception(error);
System.Diagnostics.Trace.WriteLine(String.Format(
"LoadLibraryEx(\"{0}\", 0, {3}) failed with error code {1}: {2}",
dllname,
(uint) error,
ex.Message,
flags));
if (error == 5)
{
System.Diagnostics.Trace.WriteLine(String.Format(
"Please check if the current user has execute permission for file: {0} ", dllname));
}
}
else
{
System.Diagnostics.Trace.WriteLine(String.Format("LoadLibraryEx(\"{0}\", 0, {1}) successfully loaded library.", dllname, flags));
}
return handler;
}
private static IntPtr LoadLibraryWindows(String dllname)
{
const int loadLibrarySearchDllLoadDir = 0x00000100;
const int loadLibrarySearchDefaultDirs = 0x00001000;
int flags;
if (System.IO.Path.IsPathRooted(dllname))
{
flags = loadLibrarySearchDllLoadDir | loadLibrarySearchDefaultDirs;
}
else
{
flags = loadLibrarySearchDefaultDirs;
}
IntPtr handler = LoadLibraryExWindows(dllname, flags);
if (handler == IntPtr.Zero)
{
//Try again with the '0' flags.
//The first attempt above may fail, if the native dll is within a folder in the PATH environment variable.
//The call below will also search for folders in PATH environment variable.
handler = LoadLibraryExWindows(dllname, 0);
}
// LoadPackagedLibrary() is supported from Windows 8 (6.2) onwards
if (handler == IntPtr.Zero && Environment.OSVersion.Version >= new Version(6, 2))
{
//Also try loadPackagedLibrary
IntPtr packagedLibraryHandler = LoadPackagedLibrary(dllname, 0);
if (packagedLibraryHandler == IntPtr.Zero)
{
int error = Marshal.GetLastWin32Error();
var ex = new System.ComponentModel.Win32Exception(error);
System.Diagnostics.Debug.WriteLine(String.Format(
"LoadPackagedLibrary {0} failed with error code {1}: {2}", dllname, (uint)error,
ex.Message));
}
else
{
System.Diagnostics.Trace.WriteLine(String.Format("LoadPackagedLibrary loaded: {0}", dllname));
return packagedLibraryHandler;
}
}
return handler;
}
/// <summary>
/// Maps the specified executable module into the address space of the calling process.
/// </summary>
/// <param name="dllname">The name of the dll</param>
/// <returns>The handle to the library</returns>
public static IntPtr LoadLibrary(String dllname)
{
#if UNITY_EDITOR_WIN
return LoadLibraryWindows(dllname);
#else
if (Platform.OperationSystem == Emgu.Util.Platform.OS.Windows)
{
return LoadLibraryWindows(dllname);
}
else
{
IntPtr handler;
try
{
handler = Dlopen(dllname, 0x00102); // 0x00002 == RTLD_NOW, 0x00100 = RTL_GLOBAL
if (handler == IntPtr.Zero)
{
System.Diagnostics.Trace.WriteLine(String.Format("Failed to use dlopen to load {0}", dllname));
}
}
catch
{
System.Diagnostics.Trace.WriteLine(String.Format("Failed to use dlopen from libdl.so to load {0}, will try using libdl.so.2 instead", dllname));
handler = Dlopen2(dllname, 0x00102); // 0x00002 == RTLD_NOW, 0x00100 = RTL_GLOBAL
if (handler == IntPtr.Zero)
{
System.Diagnostics.Trace.WriteLine(String.Format("Failed to use dlopen from libdl.so.2 to load {0}", dllname));
}
}
return handler;
}
#endif
}
/*
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
static extern UIntPtr GetProcAddress(IntPtr hModule, string procName);
private static bool? _kernel32HasLoadPackagedLibrary = null;
private static IntPtr LoadPackagedLibrarySafe(String fileName, int dwFlags)
{
if (_kernel32HasLoadPackagedLibrary == null)
{
UIntPtr = GetProcAddress("")
}
}*/
[DllImport("Kernel32.dll", SetLastError = true)]
private static extern IntPtr LoadPackagedLibrary(
[MarshalAs(UnmanagedType.LPStr)]
String fileName,
int dwFlags);
[DllImport("Kernel32.dll", SetLastError = true)]
private static extern IntPtr LoadLibraryEx(
[MarshalAs(UnmanagedType.LPStr)]
String fileName,
IntPtr hFile,
int dwFlags);
[DllImport("dl", EntryPoint = "dlopen")]
private static extern IntPtr Dlopen(
[MarshalAs(UnmanagedType.LPStr)]
String dllname, int mode);
[DllImport("libdl.so.2", EntryPoint = "dlopen")]
private static extern IntPtr Dlopen2(
[MarshalAs(UnmanagedType.LPStr)]
String dllname, int mode);
/*
/// <summary>
/// Decrements the reference count of the loaded dynamic-link library (DLL). When the reference count reaches zero, the module is unmapped from the address space of the calling process and the handle is no longer valid
/// </summary>
/// <param name="handle">The handle to the library</param>
/// <returns>If the function succeeds, the return value is true. If the function fails, the return value is false.</returns>
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool FreeLibrary(IntPtr handle);
*/
/// <summary>
/// Set the directory to the search path used to locate DLLs for the application
/// </summary>
/// <param name="path">The directory to be searched for DLLs</param>
/// <returns>True if success</returns>
[DllImport("Kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetDllDirectory(String path);
/// <summary>
/// Get the search path used to locate DLLs for the application
/// </summary>
/// <returns>
/// If the function succeeds, the return value is the search path used to locate DLLs for the application
/// If the function fails, the return value is null.To get extended error information, call GetLastError.
/// </returns>
public static String GetDllDirectory()
{
int maxSize = 2048;
IntPtr buffer = Marshal.AllocHGlobal(maxSize);
try
{
bool success = GetDllDirectory((uint) maxSize, buffer);
if (!success)
return null;
return Marshal.PtrToStringUni(buffer);
}
catch (Exception e)
{
Trace.WriteLine("Failed to call into GetDllDirectory:" + Environment.NewLine + e.StackTrace);
return null;
}
finally
{
Marshal.FreeHGlobal(buffer);
}
}
[DllImport("Kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetDllDirectory(uint nBufferLength, IntPtr lpBuffer);
/// <summary>
/// Adds a directory to the search path used to locate DLLs for the application
/// </summary>
/// <param name="path">The directory to be searched for DLLs</param>
/// <returns>True if success</returns>
[DllImport("Kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool AddDllDirectory(String path);
}
}