Arrange files, add dependencies

This commit is contained in:
Tiago Conceição
2020-09-25 01:46:37 +01:00
parent 9051d61f9a
commit 9b2ed7a343
55 changed files with 2056 additions and 733 deletions
-698
View File
@@ -1,698 +0,0 @@
using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using Emgu.CV;
using Emgu.CV.Cuda;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Emgu.CV.Util;
using Emgu.Util;
namespace UVtools.GUI.Extensions
{
/// <summary>
/// Provide extension method to convert IInputArray to and from Bitmap
/// </summary>
public static class BitmapExtension
{
#region Color Palette
/// <summary>
/// The ColorPalette of Grayscale for Bitmap Format8bppIndexed
/// </summary>
public static readonly ColorPalette GrayscalePalette = GenerateGrayscalePalette();
private static ColorPalette GenerateGrayscalePalette()
{
using (Bitmap image = new Bitmap(1, 1, PixelFormat.Format8bppIndexed))
{
ColorPalette palette = image.Palette;
for (int i = 0; i < 256; i++)
{
palette.Entries[i] = Color.FromArgb(i, i, i);
}
return palette;
}
}
/// <summary>
/// Convert the color palette to four lookup tables
/// </summary>
/// <param name="palette">The color palette to transform</param>
/// <param name="bTable">Lookup table for the B channel</param>
/// <param name="gTable">Lookup table for the G channel</param>
/// <param name="rTable">Lookup table for the R channel</param>
/// <param name="aTable">Lookup table for the A channel</param>
public static void ColorPaletteToLookupTable(ColorPalette palette, out Matrix<Byte> bTable,
out Matrix<Byte> gTable, out Matrix<Byte> rTable, out Matrix<Byte> aTable)
{
bTable = new Matrix<byte>(256, 1);
gTable = new Matrix<byte>(256, 1);
rTable = new Matrix<byte>(256, 1);
aTable = new Matrix<byte>(256, 1);
byte[,] bData = bTable.Data;
byte[,] gData = gTable.Data;
byte[,] rData = rTable.Data;
byte[,] aData = aTable.Data;
Color[] colors = palette.Entries;
for (int i = 0; i < colors.Length; i++)
{
Color c = colors[i];
bData[i, 0] = c.B;
gData[i, 0] = c.G;
rData[i, 0] = c.R;
aData[i, 0] = c.A;
}
}
#endregion
/// <summary>
/// Convert raw data to bitmap
/// </summary>
/// <param name="scan0">The pointer to the raw data</param>
/// <param name="step">The step</param>
/// <param name="size">The size of the image</param>
/// <param name="srcColorType">The source image color type</param>
/// <param name="numberOfChannels">The number of channels</param>
/// <param name="srcDepthType">The source image depth type</param>
/// <param name="tryDataSharing">Try to create Bitmap that shares the data with the image</param>
/// <returns>The Bitmap</returns>
public static Bitmap RawDataToBitmap(IntPtr scan0, int step, Size size, Type srcColorType, int numberOfChannels,
Type srcDepthType, bool tryDataSharing = false)
{
if (tryDataSharing)
{
if (srcColorType == typeof(Gray) && srcDepthType == typeof(Byte))
{
//Grayscale of Bytes
Bitmap bmpGray = new Bitmap(
size.Width,
size.Height,
step,
PixelFormat.Format8bppIndexed,
scan0
) {Palette = GrayscalePalette};
return bmpGray;
}
// Mono in Linux doesn't support scan0 constructor with Format24bppRgb, use ToBitmap instead
// See https://bugzilla.novell.com/show_bug.cgi?id=363431
// TODO: check mono buzilla Bug 363431 to see when it will be fixed
if (
Platform.OperationSystem == Platform.OS.Windows &&
Platform.ClrType == Platform.Clr.DotNet &&
srcColorType == typeof(Bgr) && srcDepthType == typeof(Byte)
&& (step & 3) == 0)
{
//Bgr byte
return new Bitmap(
size.Width,
size.Height,
step,
PixelFormat.Format24bppRgb,
scan0);
}
if (srcColorType == typeof(Bgra) && srcDepthType == typeof(Byte))
{
//Bgra byte
return new Bitmap(
size.Width,
size.Height,
step,
PixelFormat.Format32bppArgb,
scan0);
}
//PixelFormat.Format16bppGrayScale is not supported in .NET
//else if (typeof(TColor) == typeof(Gray) && typeof(TDepth) == typeof(UInt16))
//{
// return new Bitmap(
// size.width,
// size.height,
// step,
// PixelFormat.Format16bppGrayScale;
// scan0);
//}
}
PixelFormat format; //= System.Drawing.Imaging.PixelFormat.Undefined;
if (srcColorType == typeof(Gray)) // if this is a gray scale image
{
format = PixelFormat.Format8bppIndexed;
}
else if (srcColorType == typeof(Bgra)) //if this is Bgra image
{
format = PixelFormat.Format32bppArgb;
}
else if (srcColorType == typeof(Bgr)) //if this is a Bgr Byte image
{
format = PixelFormat.Format24bppRgb;
}
else
{
using (Mat m = new Mat(size.Height, size.Width, CvInvoke.GetDepthType(srcDepthType), numberOfChannels,
scan0, step))
using (Mat m2 = new Mat())
{
CvInvoke.CvtColor(m, m2, srcColorType, typeof(Bgr));
return RawDataToBitmap(m2.DataPointer, m2.Step, m2.Size, typeof(Bgr), 3, srcDepthType);
}
}
Bitmap bmp = new Bitmap(size.Width, size.Height, format);
BitmapData data = bmp.LockBits(
new Rectangle(Point.Empty, size),
ImageLockMode.WriteOnly,
format);
using (Mat bmpMat = new Mat(size.Height, size.Width, DepthType.Cv8U, numberOfChannels, data.Scan0,
data.Stride))
using (Mat dataMat = new Mat(size.Height, size.Width, CvInvoke.GetDepthType(srcDepthType), numberOfChannels,
scan0, step))
{
if (srcDepthType == typeof(Byte))
dataMat.CopyTo(bmpMat);
else
{
double scale = 1.0, shift = 0.0;
RangeF range = dataMat.GetValueRange();
if (range.Max > 255.0 || range.Min < 0)
{
scale = range.Max.Equals(range.Min) ? 0.0 : 255.0 / (range.Max - range.Min);
shift = scale.Equals(0) ? range.Min : -range.Min * scale;
}
CvInvoke.ConvertScaleAbs(dataMat, bmpMat, scale, shift);
}
}
bmp.UnlockBits(data);
if (format == PixelFormat.Format8bppIndexed)
bmp.Palette = GrayscalePalette;
return bmp;
}
/// <summary>
/// Convert the mat into Bitmap, the pixel values are copied over to the Bitmap
/// </summary>
public static Bitmap ToBitmap(this Mat mat)
{
if (mat.Dims > 3)
return null;
int channels = mat.NumberOfChannels;
Size s = mat.Size;
Type colorType;
switch (channels)
{
case 1:
colorType = typeof(Gray);
if (s.Equals(Size.Empty))
return null;
if ((s.Width | 3) != 0) //handle the special case where width is not a multiple of 4
{
Bitmap bmp = new Bitmap(s.Width, s.Height, PixelFormat.Format8bppIndexed)
{
Palette = GrayscalePalette
};
BitmapData bitmapData = bmp.LockBits(new Rectangle(Point.Empty, s), ImageLockMode.WriteOnly,
PixelFormat.Format8bppIndexed);
using (Mat m = new Mat(s.Height, s.Width, DepthType.Cv8U, 1, bitmapData.Scan0,
bitmapData.Stride))
{
mat.CopyTo(m);
}
bmp.UnlockBits(bitmapData);
return bmp;
}
break;
case 3:
colorType = typeof(Bgr);
break;
case 4:
colorType = typeof(Bgra);
break;
default:
throw new Exception("Unknown color type");
}
return RawDataToBitmap(mat.DataPointer, mat.Step, s, colorType, mat.NumberOfChannels,
CvInvoke.GetDepthType(mat.Depth), true);
}
/// <summary>
/// Convert the umat into Bitmap, the pixel values are copied over to the Bitmap
/// </summary>
public static Bitmap ToBitmap(this UMat umat)
{
using (Mat tmp = umat.GetMat(AccessType.Read))
{
return tmp.ToBitmap();
}
}
/// <summary>
/// Convert the gpuMat into Bitmap, the pixel values are copied over to the Bitmap
/// </summary>
public static Bitmap ToBitmap(this GpuMat gpuMat)
{
using (Mat tmp = new Mat())
{
gpuMat.Download(tmp);
return tmp.ToBitmap();
}
}
/// <summary>
/// Create an Image &lt; TColor, TDepth &gt; from Bitmap
/// </summary>
public static Image<TColor, TDepth> ToImage<TColor, TDepth>(this Bitmap bitmap) where
TColor : struct, IColor
where TDepth : new()
{
Size size = bitmap.Size;
Image<TColor, TDepth> image = new Image<TColor, TDepth>(size);
switch (bitmap.PixelFormat)
{
case PixelFormat.Format32bppRgb:
if (typeof(TColor) == typeof(Bgr) && typeof(TDepth) == typeof(Byte))
{
BitmapData data = bitmap.LockBits(
new Rectangle(Point.Empty, size),
ImageLockMode.ReadOnly,
bitmap.PixelFormat);
using (Image<Bgra, Byte> mat =
new Image<Bgra, Byte>(size.Width, size.Height, data.Stride, data.Scan0))
{
CvInvoke.MixChannels(mat, image, new[] {0, 0, 1, 1, 2, 2});
}
bitmap.UnlockBits(data);
}
else
{
using (Image<Bgr, Byte> tmp = bitmap.ToImage<Bgr, byte>())
image.ConvertFrom(tmp);
}
break;
case PixelFormat.Format32bppArgb:
if (typeof(TColor) == typeof(Bgra) && typeof(TDepth) == typeof(Byte))
image.CopyFromBitmap(bitmap);
else
{
BitmapData data = bitmap.LockBits(
new Rectangle(Point.Empty, size),
ImageLockMode.ReadOnly,
bitmap.PixelFormat);
using (Image<Bgra, Byte> tmp =
new Image<Bgra, byte>(size.Width, size.Height, data.Stride, data.Scan0))
image.ConvertFrom(tmp);
bitmap.UnlockBits(data);
}
break;
case PixelFormat.Format8bppIndexed:
if (typeof(TColor) == typeof(Bgra) && typeof(TDepth) == typeof(Byte))
{
Matrix<Byte> bTable, gTable, rTable, aTable;
ColorPaletteToLookupTable(bitmap.Palette, out bTable, out gTable, out rTable, out aTable);
BitmapData data = bitmap.LockBits(
new Rectangle(Point.Empty, size),
ImageLockMode.ReadOnly,
bitmap.PixelFormat);
using (Image<Gray, Byte> indexValue =
new Image<Gray, byte>(size.Width, size.Height, data.Stride, data.Scan0))
{
using (Mat b = new Mat())
using (Mat g = new Mat())
using (Mat r = new Mat())
using (Mat a = new Mat())
{
CvInvoke.LUT(indexValue, bTable, b);
CvInvoke.LUT(indexValue, gTable, g);
CvInvoke.LUT(indexValue, rTable, r);
CvInvoke.LUT(indexValue, aTable, a);
using (VectorOfMat mv = new VectorOfMat(b, g, r, a))
{
CvInvoke.Merge(mv, image);
}
}
}
bitmap.UnlockBits(data);
bTable.Dispose();
gTable.Dispose();
rTable.Dispose();
aTable.Dispose();
}
else
{
using (Image<Bgra, Byte> tmp = bitmap.ToImage<Bgra, Byte>())
image.ConvertFrom(tmp);
}
break;
case PixelFormat.Format24bppRgb:
if (typeof(TColor) == typeof(Bgr) && typeof(TDepth) == typeof(Byte))
image.CopyFromBitmap(bitmap);
else
{
BitmapData data = bitmap.LockBits(
new Rectangle(Point.Empty, size),
ImageLockMode.ReadOnly,
bitmap.PixelFormat);
using (Image<Bgr, Byte> tmp =
new Image<Bgr, byte>(size.Width, size.Height, data.Stride, data.Scan0))
image.ConvertFrom(tmp);
bitmap.UnlockBits(data);
}
break;
case PixelFormat.Format1bppIndexed:
if (typeof(TColor) == typeof(Gray) && typeof(TDepth) == typeof(Byte))
{
int rows = size.Height;
int cols = size.Width;
BitmapData data = bitmap.LockBits(
new Rectangle(Point.Empty, size),
ImageLockMode.ReadOnly,
bitmap.PixelFormat);
int fullByteCount = cols >> 3;
int partialBitCount = cols & 7;
int mask = 1 << 7;
Int64 srcAddress = data.Scan0.ToInt64();
Byte[,,] imagedata = image.Data as Byte[,,];
Byte[] row = new byte[fullByteCount + (partialBitCount == 0 ? 0 : 1)];
int v = 0;
for (int i = 0; i < rows; i++, srcAddress += data.Stride)
{
Marshal.Copy((IntPtr) srcAddress, row, 0, row.Length);
for (int j = 0; j < cols; j++, v <<= 1)
{
if ((j & 7) == 0)
{
//fetch the next byte
v = row[j >> 3];
}
imagedata[i, j, 0] = (v & mask) == 0 ? (Byte) 0 : (Byte) 255;
}
}
}
else
{
using (Image<Gray, Byte> tmp = bitmap.ToImage<Gray, Byte>())
image.ConvertFrom(tmp);
}
break;
default:
#region Handle other image type
// Bitmap bgraImage = new Bitmap(value.Width, value.Height, PixelFormat.Format32bppArgb);
// using (Graphics g = Graphics.FromImage(bgraImage))
// {
// g.DrawImageUnscaled(value, 0, 0, value.Width, value.Height);
// }
// Bitmap = bgraImage;
using (Image<Bgra, Byte> tmp1 = new Image<Bgra, Byte>(size))
{
Byte[,,] data = tmp1.Data;
for (int i = 0; i < size.Width; i++)
for (int j = 0; j < size.Height; j++)
{
Color color = bitmap.GetPixel(i, j);
data[j, i, 0] = color.B;
data[j, i, 1] = color.G;
data[j, i, 2] = color.R;
data[j, i, 3] = color.A;
}
image.ConvertFrom(tmp1);
}
#endregion
break;
}
return image;
}
/// <summary>
/// Utility function for converting Bitmap to Image
/// </summary>
/// <param name="bmp">the bitmap to copy data from</param>
/// <param name="image">The image to copy data to</param>
private static void CopyFromBitmap<TColor, TDepth>(this Image<TColor, TDepth> image, Bitmap bmp) where
TColor : struct, IColor
where TDepth : new()
{
BitmapData data = bmp.LockBits(
new Rectangle(Point.Empty, bmp.Size),
ImageLockMode.ReadOnly,
bmp.PixelFormat);
using (Matrix<TDepth> mat =
new Matrix<TDepth>(bmp.Height, bmp.Width, image.NumberOfChannels, data.Scan0, data.Stride))
CvInvoke.cvCopy(mat.Ptr, image.Ptr, IntPtr.Zero);
bmp.UnlockBits(data);
}
/// <summary>
/// Provide a more efficient way to convert Image&lt;Gray, Byte&gt;, Image&lt;Bgr, Byte&gt; and Image&lt;Bgra, Byte&gt; into Bitmap
/// such that the image data is <b>shared</b> with Bitmap.
/// If you change the pixel value on the Bitmap, you change the pixel values on the Image object as well!
/// For other types of image this property has the same effect as ToBitmap()
/// <b>Take extra caution not to use the Bitmap after the Image object is disposed</b>
/// </summary>
/// <typeparam name="TColor">The color of the image</typeparam>
/// <typeparam name="TDepth">The depth of the image</typeparam>
/// <param name="image">The image to create Bitmap from</param>
/// <returns>A bitmap representation of the image. In the cases of Image&lt;Gray, Byte&gt;, Image&lt;Bgr, Byte&gt; and Image&lt;Bgra, Byte&gt;, the image data is shared between the Bitmap and the Image object.</returns>
public static Bitmap AsBitmap<TColor, TDepth>(this Image<TColor, TDepth> image) where
TColor : struct, IColor
where TDepth : new()
{
IntPtr scan0;
int step;
Size size;
CvInvoke.cvGetRawData(image.Ptr, out scan0, out step, out size);
return RawDataToBitmap(scan0, step, size, typeof(TColor), image.NumberOfChannels, typeof(TDepth), true);
}
/// <summary>
/// Convert this image into Bitmap, the pixel values are copied over to the Bitmap
/// </summary>
/// <remarks> For better performance on Image&lt;Gray, Byte&gt; and Image&lt;Bgr, Byte&gt;, consider using the Bitmap property </remarks>
/// <returns> This image in Bitmap format, the pixel data are copied over to the Bitmap</returns>
public static Bitmap ToBitmap<TColor, TDepth>(this Image<TColor, TDepth> image) where
TColor : struct, IColor
where TDepth : new()
{
Type typeOfColor = typeof(TColor);
Type typeofDepth = typeof(TDepth);
PixelFormat format = PixelFormat.Undefined;
if (typeOfColor == typeof(Gray)) // if this is a gray scale image
{
format = PixelFormat.Format8bppIndexed;
}
else if (typeOfColor == typeof(Bgra)) //if this is Bgra image
{
format = PixelFormat.Format32bppArgb;
}
else if (typeOfColor == typeof(Bgr)) //if this is a Bgr Byte image
{
format = PixelFormat.Format24bppRgb;
}
else
{
using (Image<Bgr, Byte> temp = image.Convert<Bgr, Byte>())
return ToBitmap(temp);
}
if (typeof(TDepth) == typeof(Byte))
{
Size size = image.Size;
Bitmap bmp = new Bitmap(size.Width, size.Height, format);
BitmapData data = bmp.LockBits(
new Rectangle(Point.Empty, size),
ImageLockMode.WriteOnly,
format);
//using (Matrix<Byte> m = new Matrix<byte>(size.Height, size.Width, data.Scan0, data.Stride))
using (Mat mat = new Mat(size.Height, size.Width, DepthType.Cv8U, image.NumberOfChannels,
data.Scan0, data.Stride))
{
image.Mat.CopyTo(mat);
}
bmp.UnlockBits(data);
if (format == PixelFormat.Format8bppIndexed)
bmp.Palette = GrayscalePalette;
return bmp;
}
using (Image<TColor, Byte> temp = image.Convert<TColor, Byte>())
return temp.ToBitmap();
}
/// <summary> Create a Bitmap image of certain size</summary>
/// <param name="image">The image to be converted to Bitmap</param>
/// <param name="width">The width of the bitmap</param>
/// <param name="height"> The height of the bitmap</param>
/// <returns> This image in Bitmap format of the specific size</returns>
public static Bitmap ToBitmap<TColor, TDepth>(this Image<TColor, TDepth> image, int width, int height) where
TColor : struct, IColor
where TDepth : new()
{
using (Image<TColor, TDepth> scaledImage = image.Resize(width, height, Inter.Linear))
return scaledImage.ToBitmap();
}
/// <summary>
/// Convert the CudaImage to its equivalent Bitmap representation
/// </summary>
public static Bitmap ToBitmap<TColor, TDepth>(this CudaImage<TColor, TDepth> cudaImage) where
TColor : struct, IColor
where TDepth : new()
{
if (typeof(TColor) == typeof(Bgr) && typeof(TDepth) == typeof(Byte))
{
Size s = cudaImage.Size;
Bitmap result = new Bitmap(s.Width, s.Height, PixelFormat.Format24bppRgb);
BitmapData data = result.LockBits(new Rectangle(Point.Empty, result.Size),
ImageLockMode.WriteOnly, result.PixelFormat);
using (Image<TColor, TDepth> tmp = new Image<TColor, TDepth>(s.Width, s.Height, data.Stride, data.Scan0)
)
{
cudaImage.Download(tmp);
}
result.UnlockBits(data);
return result;
}
using (Image<TColor, TDepth> tmp = cudaImage.ToImage())
{
return tmp.ToBitmap();
}
}
}
/// <summary>
/// Class that can be used to read file into Mat
/// </summary>
public class BitmapFileReaderMat : IFileReaderMat
{
/// <summary>
/// Read the file into a Mat
/// </summary>
/// <param name="fileName">The name of the image file</param>
/// <param name="mat">The Mat to read into</param>
/// <param name="loadType">Image load type.</param>
/// <returns>True if the file can be read into the Mat</returns>
public bool ReadFile(String fileName, Mat mat, ImreadModes loadType)
{
try
{
using (Bitmap bmp = new Bitmap(fileName))
using (Image<Bgr, Byte> image = bmp.ToImage<Bgr, Byte>())
image.Mat.CopyTo(mat);
return true;
}
catch (Exception e)
{
Debug.WriteLine(e);
//throw;
return false;
}
}
}
/// <summary>
/// Class that can be used to write the Mat to a file
/// </summary>
public class BitmapFileWriterMat : IFileWriterMat
{
/// <summary>
/// Write the Mat into the file
/// </summary>
/// <param name="mat">The Mat to write</param>
/// <param name="fileName">The name of the file to be written into</param>
/// <returns>True if the file has been written into Mat</returns>
public bool WriteFile(Mat mat, String fileName)
{
try
{
//Try to save the image using .NET's Bitmap class
String extension = Path.GetExtension(fileName);
if (!String.IsNullOrEmpty(extension))
using (Bitmap bmp = mat.ToBitmap())
{
switch (extension.ToLower())
{
case ".jpg":
case ".jpeg":
bmp.Save(fileName, ImageFormat.Jpeg);
break;
case ".bmp":
bmp.Save(fileName, ImageFormat.Bmp);
break;
case ".png":
bmp.Save(fileName, ImageFormat.Png);
break;
case ".tiff":
case ".tif":
bmp.Save(fileName, ImageFormat.Tiff);
break;
case ".gif":
bmp.Save(fileName, ImageFormat.Gif);
break;
default:
throw new NotImplementedException(String.Format("Saving to {0} format is not supported", extension));
}
}
return true;
}
catch (Exception e)
{
Debug.WriteLine(e);
//throw;
return false;
}
}
}
}
+6 -1
View File
@@ -95,6 +95,9 @@
<Reference Include="Cyotek.Windows.Forms.ImageBox, Version=1.2.0.0, Culture=neutral, PublicKeyToken=58daa28b0b2de221, processorArchitecture=MSIL">
<HintPath>..\packages\CyotekImageBox.1.3.0-Alpha1\lib\net20\Cyotek.Windows.Forms.ImageBox.dll</HintPath>
</Reference>
<Reference Include="Emgu.CV.Bitmap, Version=4.4.0.4061, Culture=neutral, PublicKeyToken=7281126722ab4438, processorArchitecture=MSIL">
<HintPath>..\packages\Emgu.CV.Bitmap.4.4.0.4061\lib\netstandard2.0\Emgu.CV.Bitmap.dll</HintPath>
</Reference>
<Reference Include="Emgu.CV.Platform.NetStandard, Version=4.4.0.4061, Culture=neutral, PublicKeyToken=7281126722ab4438, processorArchitecture=MSIL">
<HintPath>..\packages\Emgu.CV.4.4.0.4061\lib\netstandard2.0\Emgu.CV.Platform.NetStandard.dll</HintPath>
</Reference>
@@ -108,6 +111,9 @@
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Core" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing.Common, Version=4.0.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Drawing.Common.4.7.0\lib\net461\System.Drawing.Common.dll</HintPath>
</Reference>
<Reference Include="System.Drawing.Primitives, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Drawing.Primitives.4.3.0\lib\net45\System.Drawing.Primitives.dll</HintPath>
<Private>True</Private>
@@ -288,7 +294,6 @@
<Compile Include="Controls\TransparentLabel.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Extensions\BitmapExtension.cs" />
<Compile Include="Extensions\ControlExtensions.cs" />
<Compile Include="Extensions\CursorExtensions.cs" />
<Compile Include="Extensions\GUIExtensions.cs" />
+2
View File
@@ -2,9 +2,11 @@
<packages>
<package id="CyotekImageBox" version="1.3.0-Alpha1" targetFramework="net48" />
<package id="Emgu.CV" version="4.4.0.4061" targetFramework="net48" />
<package id="Emgu.CV.Bitmap" version="4.4.0.4061" targetFramework="net48" />
<package id="Emgu.CV.runtime.windows" version="4.4.0.4061" targetFramework="net48" />
<package id="ObjectListView.Official" version="2.9.2-alpha2" targetFramework="net48" />
<package id="System.Buffers" version="4.5.1" targetFramework="net48" />
<package id="System.Drawing.Common" version="4.7.0" targetFramework="net48" />
<package id="System.Drawing.Primitives" version="4.3.0" targetFramework="net48" />
<package id="System.IO" version="4.3.0" targetFramework="net48" />
<package id="System.Memory" version="4.5.4" targetFramework="net48" />