diff --git a/MarketData/MarketDataLib/CNNProcessing/BitmapExtensions.cs b/MarketData/MarketDataLib/CNNProcessing/BitmapExtensions.cs index cdbeca2..80edf0f 100755 --- a/MarketData/MarketDataLib/CNNProcessing/BitmapExtensions.cs +++ b/MarketData/MarketDataLib/CNNProcessing/BitmapExtensions.cs @@ -10,9 +10,14 @@ namespace MarketData.CNNProcessing { public static class BitmapExtensions { -// This call is used to generate the training, test, and validation bitmaps.. +// This call is used to generate the CNN training, test, and validation bitmaps.. // I noticed a large difference in the accuracy or the model when the quality parameter is 100. // I therefore intentionally not using EncoderParameters to specify quality but instead taking the default quality. + /// + /// Save JPG encoded bitmap + /// + /// + /// public static void SaveJPG100(this SKBitmap bitmap, string filename) { if(File.Exists(filename))File.Delete(filename); @@ -22,11 +27,42 @@ namespace MarketData.CNNProcessing encodedImage.SaveTo(stream); } + /// + /// Save JPG encoded bitmap + /// + /// + /// public static void SaveJPG100(this SKBitmap bitmap, Stream stream) { using SKImage image = SKImage.FromBitmap(bitmap); using SKData encodedImage = image.Encode(SKEncodedImageFormat.Jpeg,100); encodedImage.SaveTo(stream); } + + /// + /// Save PNG encoded bitmap + /// + /// + /// + public static void SavePNG100(this SKBitmap bitmap, string filename) + { + if(File.Exists(filename))File.Delete(filename); + using FileStream stream = new FileStream(filename, FileMode.Create, FileAccess.Write); + using SKImage image = SKImage.FromBitmap(bitmap); + using SKData encodedImage = image.Encode(SKEncodedImageFormat.Png,100); + encodedImage.SaveTo(stream); + } + + /// + /// Save PNG encoded bitmap + /// + /// + /// + public static void SavePNG100(this SKBitmap bitmap, Stream stream) + { + using SKImage image = SKImage.FromBitmap(bitmap); + using SKData encodedImage = image.Encode(SKEncodedImageFormat.Png,100); + encodedImage.SaveTo(stream); + } } } diff --git a/MarketData/MarketDataLib/CNNProcessing/ImageHelper.cs b/MarketData/MarketDataLib/CNNProcessing/ImageHelper.cs index 03c7e97..10d2143 100644 --- a/MarketData/MarketDataLib/CNNProcessing/ImageHelper.cs +++ b/MarketData/MarketDataLib/CNNProcessing/ImageHelper.cs @@ -47,7 +47,7 @@ namespace MarketData.CNNProcessing /// public bool LoadImage(string pathFileName) { - FileStream stream = new FileStream(pathFileName, FileMode.Open); + using FileStream stream = new FileStream(pathFileName, FileMode.Open); return LoadImage(stream); } @@ -220,6 +220,19 @@ namespace MarketData.CNNProcessing else BitmapExtensions.SaveJPG100(altBitmap,pathFileName); } + /// + /// Save the bitmap in PNG format. Note: PNG files support alpha channels, JPG files do not + /// + /// + /// + public void SavePng(String pathFileName,SKBitmap altBitmap=null) + { + Validate(); + if(null==altBitmap)BitmapExtensions.SavePNG100(bitmap,pathFileName); + else BitmapExtensions.SavePNG100(altBitmap,pathFileName); + } + + // Convert to 8 bits per pixel black and white private SKBitmap ToBlackAndWhite(SKBitmap bitmap) { @@ -420,7 +433,7 @@ namespace MarketData.CNNProcessing } /// - /// Make the bitmap transparent + /// Make the bitmap transparent. Note: PNG format preserves alpha channel while JPG format does not.. so save as PNG if using transparency /// public void Transparent(SKColor color) { @@ -613,27 +626,50 @@ namespace MarketData.CNNProcessing } /// - /// Draw a triangle centered inside the bounded area defined by imageWidth, imageHeight + /// Draw a triangle centered inside the bounded area defined by the width and height of the bitmap. /// - /// The width of the bounded area - /// The height of the bounded area /// The paint stroke to to use to outline the triangle /// The paint stroke to use to fill the triangle - public void DrawTriangle(int imageWidth, int imageHeight, SKPaint paintStroke, SKPaint paintFill) + public void DrawTriangle(SKPaint paintStroke, SKPaint paintFill) { + Validate(); using SKPath path = new SKPath(); - float hLength = (float)imageWidth / 2f; - CreateImage(imageWidth,imageHeight); - Transparent(SKColors.White); - SKPoint txOrigin = pointMapping.MapPoint(new SKPoint(imageWidth/2.0f,imageHeight)); + float hLength = (float)Width / 2f; + SKPoint txOrigin = pointMapping.MapPoint(new SKPoint(hLength,Height)); using SKCanvas canvas = new SKCanvas(bitmap); path.MoveTo(txOrigin.X, txOrigin.Y); - path.LineTo(txOrigin.X - hLength, (txOrigin.Y + imageHeight)-1f); - path.LineTo((txOrigin.X + hLength)-1f, (txOrigin.Y + imageHeight)-1f); + path.LineTo(txOrigin.X - hLength, txOrigin.Y + Height - 1f); + path.LineTo(txOrigin.X + hLength - 1f, txOrigin.Y + Height - 1f); path.LineTo(txOrigin.X, txOrigin.Y); path.Close(); canvas.DrawPath(path, paintStroke); canvas.DrawPath(path, paintFill); } + + /// + /// Draw a triangle centered at the specified 'origin' and being 'length' width at it's base + /// + /// The point origin + /// The length of the base of the triangle + /// The paint stroke to to use to outline the triangle + /// The paint stroke to use to fill the triangle + public void DrawTriangle(SKPoint origin, int length, SKPaint paintStroke, SKPaint paintFill) + { + Validate(); + SKPath path = new SKPath(); + SKPoint txOrigin = pointMapping.MapPoint(origin); + float lengthF = (float)length; + float hLength = lengthF / 2f; + float height = (float)Math.Sqrt(Math.Pow(lengthF, 2) - Math.Pow(hLength, 2)); + height/=1.15f; // reduce the height by 15% + path.MoveTo(txOrigin.X, txOrigin.Y); + path.LineTo(txOrigin.X - hLength, txOrigin.Y + height); + path.LineTo(txOrigin.X + hLength, txOrigin.Y + height); + path.LineTo(txOrigin.X, txOrigin.Y); + path.Close(); + using SKCanvas canvas = new SKCanvas(bitmap); + canvas.DrawPath(path, paintStroke); + canvas.DrawPath(path, paintFill); + } } } \ No newline at end of file