Files
marketdata/MarketDataLib/CNNProcessing/ImageHelper.cs

319 lines
10 KiB
C#

using System;
using System.Drawing;
using System.IO;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Drawing.Drawing2D;
using System.Security.Permissions;
namespace MarketData.CNNProcessing
{
public class ImageHelper : IDisposable
{
private Bitmap bitmap = null;
private Graphics graphics=null;
private PointMapping pointMapping;
private int width;
private int height;
public ImageHelper()
{
}
public void Dispose()
{
if(null!=bitmap)
{
bitmap.Dispose();
bitmap=null;
}
if(null!=graphics)
{
graphics.Dispose();
graphics=null;
}
}
public bool LoadImage(string pathFileName)
{
Stream bitmapStream = null;
try
{
bitmapStream = File.Open(pathFileName,FileMode.Open);
Image image = Image.FromStream(bitmapStream);
bitmap=new Bitmap(image);
width=bitmap.Width;
height=bitmap.Height;
return true;
}
catch(Exception)
{
return false;
}
finally
{
if(null!=bitmapStream)
{
bitmapStream.Close();
bitmapStream.Dispose();
bitmapStream.Dispose();
}
}
}
/// <summary>
/// Resize image to given width maintaining aspect ration for height.
/// If aspect ration is used for CNN then you will need to introduce padding. For instance 640,640 image and then paste the aspect
/// mainained image onto that. The CNN will then have to learn that black means nothing. Resizing is the recommended way to go.
/// </summary>
public bool Resize(int newWidth)
{
double aspectRatio=(double)bitmap.Width/(double)bitmap.Height;
int newHeight=(int)(((double)newWidth)/aspectRatio);
if(0!=newHeight%2)newHeight++;
return Resize(newWidth,newHeight);
}
/// <summary>
/// Resize image to given width and height. The documenation on CNN's indicates that resizing will work better than maintaining apsect
/// ration with padding
/// </summary>
public bool Resize(int newWidth, int newHeight)
{
Graphics graphics = null;
ImageAttributes imageAttributes = null;
try
{
Validate();
Rectangle destRect=new Rectangle(0,0,newWidth,newHeight);
Bitmap destBitmap = new Bitmap(newWidth,newHeight);
destBitmap.SetResolution(bitmap.HorizontalResolution,bitmap.VerticalResolution);
graphics = Graphics.FromImage(destBitmap);
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
imageAttributes = new ImageAttributes();
imageAttributes.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(bitmap, destRect, 0,0, bitmap.Width, bitmap.Height, GraphicsUnit.Pixel, imageAttributes);
bitmap.Dispose();
bitmap=destBitmap;
imageAttributes.Dispose();
graphics.Dispose();
return true;
}
catch(Exception)
{
return false;
}
finally
{
if(null!=graphics)
{
graphics.Dispose();
graphics=null;
}
if(null!=imageAttributes)
{
imageAttributes.Dispose();
imageAttributes=null;
}
}
}
/// <summary>
/// Resize the image to the specified width and height.
/// </summary>
/// <param name="image">The image to resize.</param>
/// <param name="width">The width to resize to.</param>
/// <param name="height">The height to resize to.</param>
/// <returns>The resized image.</returns>
//public static Bitmap ResizeImage(Image image, int width, int height)
//{
// var destRect = new Rectangle(0, 0, width, height);
// var destImage = new Bitmap(width, height);
// destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
// using (var graphics = Graphics.FromImage(destImage))
// {
// graphics.CompositingMode = CompositingMode.SourceCopy;
// graphics.CompositingQuality = CompositingQuality.HighQuality;
// graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
// graphics.SmoothingMode = SmoothingMode.HighQuality;
// graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
// using (var wrapMode = new ImageAttributes())
// {
// wrapMode.SetWrapMode(WrapMode.TileFlipXY);
// graphics.DrawImage(image, destRect, 0, 0, image.Width,image.Height, GraphicsUnit.Pixel, wrapMode);
// }
// }
// return destImage;
//}
public void CreateImage(int width, int height,PointMapping pointMapping)
{
this.width=width;
this.height=height;
this.pointMapping=pointMapping;
bitmap=new Bitmap(width,height,System.Drawing.Imaging.PixelFormat.Format24bppRgb);
Validate();
graphics=Graphics.FromImage(bitmap);
}
public Stream SaveBlackAndWhiteJPG()
{
Validate();
Bitmap bwBitmap=ToBlackAndWhite(bitmap);
Stream memoryStream=new MemoryStream();
BitmapExtensions.SaveJPG100(bwBitmap,memoryStream);
memoryStream.Position=0;
bwBitmap.Dispose();
return memoryStream;
}
public void SaveGrayScaleJPG(String pathFileName)
{
Validate();
Bitmap bwBitmap=ToBlackAndWhite(bitmap);
Save(pathFileName,bwBitmap);
bwBitmap.Dispose();
}
public void SaveBlackAndWhiteJPG(String pathFileName)
{
Validate();
Bitmap bwBitmap=ToBlackAndWhite(bitmap);
Save(pathFileName,bwBitmap);
bwBitmap.Dispose();
}
public void Save(String pathFileName)
{
Save(pathFileName,null);
}
private void Save(String pathFileName,Bitmap altBitmap=null)
{
Validate();
if(null==altBitmap)BitmapExtensions.SaveJPG100(bitmap,pathFileName);
else BitmapExtensions.SaveJPG100(altBitmap,pathFileName);
}
// Convert to 8 bits per pixel black and white
private Bitmap ToBlackAndWhite(Bitmap bmp)
{
var result = new Bitmap(bmp.Width, bmp.Height, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
BitmapData data = result.LockBits(new Rectangle(0, 0, result.Width, result.Height), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
byte[] bytes = new byte[data.Height * data.Stride];
Marshal.Copy(data.Scan0, bytes, 0, bytes.Length);
for (int y = 0; y < bmp.Height; y++)
{
for (int x = 0; x < bmp.Width; x++)
{
Color color = bmp.GetPixel(x, y);
byte rgb = (byte)((color.R + color.G + color.B) / 3);
if(rgb>0)rgb=255;
bytes[y * data.Stride + x] = rgb;
}
}
Marshal.Copy(bytes, 0, data.Scan0, bytes.Length);
result.UnlockBits(data);
return result;
}
// Convert to 8 bits per pixel gray scale
private Bitmap ToGrayScale(Bitmap bmp)
{
var result = new Bitmap(bmp.Width, bmp.Height, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
BitmapData data = result.LockBits(new Rectangle(0, 0, result.Width, result.Height), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
byte[] bytes = new byte[data.Height * data.Stride];
Marshal.Copy(data.Scan0, bytes, 0, bytes.Length);
for (int y = 0; y < bmp.Height; y++)
{
for (int x = 0; x < bmp.Width; x++)
{
Color color = bmp.GetPixel(x, y);
byte rgb = (byte)((color.R + color.G + color.B) / 3);
bytes[y * data.Stride + x] = rgb;
}
}
Marshal.Copy(bytes, 0, data.Scan0, bytes.Length);
result.UnlockBits(data);
return result;
}
public Color GetPixel(int x,int y)
{
return bitmap.GetPixel(x,y);
}
public void SetPixel(int x, int y,Color color)
{
bitmap.SetPixel(x,y,color);
}
public Point TranslatePoint(Point point)
{
return pointMapping.TranslatePoint(point);
}
public void Validate()
{
if(null==bitmap)throw new InvalidDataException("The image has not been initialized");
}
public int Width
{
get{return width;}
}
public int Height
{
get{return height;}
}
public void Fill(Brush brush)
{
Validate();
Region region=new Region(new Rectangle(0,0,bitmap.Width,bitmap.Height));
graphics.FillRegion(brush,region);
}
public void DrawPoint(Pen pen,Point drawPoint)
{
Validate();
Point txPoint=pointMapping.MapPoint(drawPoint);
graphics.DrawImage(bitmap,txPoint);
}
public void AddNoise(Color color,double percentDecimal)
{
Random random=new Random();
int amount=(int)(percentDecimal*(Width*Height));
for(int index=0;index<amount;index++)
{
int row=random.Next(Height-1);
int col=random.Next(Width-1);
SetPixel(row,col,color);
}
}
public void DrawLine(Pen pen,Point srcPoint,Point dstPoint)
{
Validate();
Point txSrcPoint=pointMapping.MapPoint(srcPoint);
Point txDstPoint=pointMapping.MapPoint(dstPoint);
graphics.DrawLine(pen,txSrcPoint,txDstPoint);
}
public void DrawPath(Pen pen,LineSegments lineSegments)
{
GraphicsPath graphicsPath=new GraphicsPath();
foreach(LineSegment lineSegment in lineSegments)
{
graphicsPath.AddLine(pointMapping.MapPoint(lineSegment.P1),pointMapping.MapPoint(lineSegment.P2));
}
graphics.DrawPath(pen,graphicsPath);
}
public void DrawCircle(Brush brush,Point pt,float size=1.00f)
{
Validate();
Point txPoint=pointMapping.MapPoint(pt);
txPoint.X-=(int)(size/2f);
txPoint.Y-=(int)(size/2F);
Rectangle boundingRectangle=new Rectangle();
boundingRectangle.X=txPoint.X;
boundingRectangle.Y=txPoint.Y;
boundingRectangle.Width=(int)size;
boundingRectangle.Height=(int)size;
graphics.FillEllipse(brush,boundingRectangle);
}
}
}