mirror of
https://github.com/riegera2412/UVtools.git
synced 2026-07-08 17:42:31 +02:00
5fdac82dd6
* (Add) Settings & Issues: Enable or disable Empty Layers * (Add) PrusaSlicer Printer: Nova Bene4 Mono * (Add) CWS: Support the GRAY2RGB and RBG2GRAY encoding for Bene Mono * (Add) Layer issue Z map paired with layer navigation tracker bar * (Change) Shortcuts: + and - to go up and down on layers were change to W and S keys. Reason: + and - are bound to zoom and can lead to problems * (Upgrade) OpenCV from 4.2 to 4.3 * (Fix) CWS: Add missing Platform X,Y,Z size when converting from SL1 * (Fix) CWS: Invert XY resolution when converting from SL1
698 lines
28 KiB
C#
698 lines
28 KiB
C#
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 < TColor, TDepth > 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<Gray, Byte>, Image<Bgr, Byte> and Image<Bgra, Byte> 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<Gray, Byte>, Image<Bgr, Byte> and Image<Bgra, Byte>, 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<Gray, Byte> and Image<Bgr, Byte>, 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;
|
|
}
|
|
}
|
|
}
|
|
} |