Speeding Up Image Handling - c#

This is a follow on to my question How To Handle Image as Background to CAD Application
I applied the resizing/resampling code but it is not making any difference. I am sure I do not know enough about GDI+ etc so please excuse me if I seem muddled.
I am using a third party graphics library (Piccolo). I do not know enough to be sure what it is doing under the hood other than it evenually wraps GDI+.
My test is to rotate the display at different zoom levels - this is the process that causes the worst performance hit. I know I am rotating the camera view. At zoom levels up to 1.0 there is no performance degradation and rotation is smooth using the mouse wheel. The image has to be scaled to the CAD units of 1m per pixel at a zoom level of 1.0. I have resized/ resampled the image to match that. I have tried different ways to speed this up based on the code given me in the last question:
public static Bitmap ResampleImage(Image img, Size size) {
using (logger.VerboseCall()) {
var bmp = new Bitmap(size.Width, size.Height, PixelFormat.Format32bppPArgb);
using (var gr = Graphics.FromImage(bmp)) {
gr.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Low;
gr.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighSpeed;
gr.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed;
gr.DrawImage(img, new Rectangle(Point.Empty, size));
}
return bmp;
}
}
I guess this speeds up the resample but as far as I can tell has no effect on the performance when trying to rotate the display at high zoom levels. User a performance profiler (ANTS) I am able to find the code that is causing the performance hit:
protected override void Paint(PPaintContext paintContext) {
using (PUtil.logger.DebugCall()) {
try {
if (Image != null) {
RectangleF b = Bounds;
Graphics g = paintContext.Graphics;
g.DrawImage(image, b);
}
}
catch (Exception ex) {
PUtil.logger.Error(string.Format("{0}\r\n{1}", ex.Message, ex.StackTrace));
//----catch GDI OOM exceptions
}
}
}
The performance hit is entirely in g.DrawImage(image, b);
Bounds is the bounds of the image of course. The catch block is there to catch GDI+ OOM exceptions which seem worse at high zoom levels also.
The number of times this is called seems to increase as the zoom level increases....
There is another hit in the code painting the camera view but I have not enough information to explain that yet except that this seems to paint all the layers attached to the camera - and all the objects on them I assume - when when the cameras view matrix and clip are applied to the paintContext (whatever that means).
So is there some other call to g.DrawImage(image, b); that I could use? Or am I at the mercy of the graphics engine? Unfortunately it is so embedded that it would be very hard to change for me
Thanks again

I think you you use,if I'm not mistake, PImageNode object form Piccolo. The quantity of calls to that method could increase because Piccolo engine traces "real" drawing area on the user screen, based on zoom level (kind of Culling) and draws only the nodes which are Visible ones. If you have a lot of PImageNode objects on your scene and make ZoomOut it will increase the quantity of PImageNode objects need to be drawn, so the calls to that method.
What about the performance:
1) Try to use SetStyle(ControlStyles.DoubleBuffer,true); of the PCanvas (if it's not yet setted up)
2) look here CodeProject
Regards.

Related

Problem with disposing Graphics in C# running on mono [duplicate]

I have a Windows Application project that deals with Image editing (Cropping & Resizing). Unfortunately these image processings consume a lot of Memory and CPU resources (easily reaches 600MB or 50% cpu) and it is all about cropping and resizing just one gif image that weighs 2.5MB (2300*5400px). More than that, due to large resource consumption, the program gets stuck while resizing...
public static Image Resize(Image imgToResize, Size size)
{
Bitmap b = new Bitmap(size.Width, size.Height);
Graphics g = Graphics.FromImage((Image)b);
g.InterpolationMode = InterpolationMode.Default;
g.SmoothingMode = SmoothingMode.HighSpeed;
g.PixelOffsetMode = PixelOffsetMode.Default;
g.DrawImage(imgToResize, 0, 0, size.Width, size.Height);
g.Dispose();
return (Image)b;
}
public static Image Crop(Image img, Point p1, Point p2)
{
Rectangle cropArea = new Rectangle(p1.X, p1.Y, p2.X - p1.X, p2.Y - p1.Y);
return (img as Bitmap).Clone(cropArea, img.PixelFormat);
}
What methods should I use to avoid this?
I've already tried compressing it to memory stream in several formats but it didn't help (even made it worse)
NOTE: I use the standard .NET Drawing libraries: System.Drawing, System.Drawing.Imaging
Your code is creating copies of the image so you should expect unmanaged memory usage to rise when you call these methods. What matters a great deal is what you do with the original. You would be wise to get rid of it so it no longer takes up memory. You have to call its Dispose() method to do so. Waiting for the garbage collector to do it takes too long. The Bitmap class takes very little managed memory but oodles of unmanaged memory.
From an earlier version of this question: http://snippets.dzone.com/posts/show/4336
Also, AForge.net has several resize functions
This is a tricky one, and one I've run into before. You could split the image into x pieces, depending on the size of the file, then save each one to disk to ensure that the memory is clean.
Next, you resize the component images one at a time, each time, ensuring that the component is disposed before proceeding to the next one. Once you're all done, you stitch them back together, and then crop.
A MAJOR PROBLEM with this approach - if you're resizing upward, this approach will put seams in your image, as the interpolation won't have the surrounding pixels to guess at. But I would think that this approach would work well with resizing downward.
HTH.
Another hint again:
For example in resize, like #Hans pointed out, you create a new Bitmap, which one is your bottlenecks.
But, what if you just draw image resized, the same image which was loaded originally (obviously you made a backup file of original image before on the disk).
After crop what if you just draw a portion of a bitmap that user cropped, so user will see only that rectangle. ?
I mean in general, operate over image you already have, and try (as much as it possible) do not initialize new object for it.
Regards.
write Application.DoEvents(); in your functions, at least it wont get stuck

C# How to Improve Efficiency in Direct2D Drawing

Good morning,
I have been teaching myself a bit of Direct2D programming in C#, utilizing native wrappers that are available (currently using d2dSharp, but have also tried SharpDX). I'm running into problems with efficiency, though, where the basic drawing Direct2D drawing methods are taking approximately 250 ms to draw 45,000 basic polygons. The performance I am seeing is on par, or even slower than, Windows GDI+. I'm hoping that someone can take a look at what I've done and propose a way(s) that I can dramatically improve the time it takes to draw.
The background to this is that I have a personal project in which I am developing a basic but functional CAD interface capable of performing a variety of tasks, including 2D finite element analysis. In order to make it at all useful, the interface needs to be able to display tens-of-thousands of primitive elements (polygons, circles, rectangles, points, arcs, etc.).
I initially wrote the drawing methods using Windows GDI+ (System.Drawing), and performance is pretty good until I reach about 3,000 elements on screen at any given time. The screen must be updated any time the user pans, zooms, draws new elements, deletes elements, moves, rotates, etc. Now, in order to improve efficiency, I utilize a quad tree data structure to store my elements, and I only draw elements that actually fall within the bounds of the control window. This helped significantly when zoomed in, but obviously, when fully zoomed out and displaying all elements, it makes no difference. I also use a timer and tick events to update the screen at the refresh rate (60 Hz), so I'm not trying to update thousands of times per second or on every mouse event.
This is my first time programming with DirectX and Direct2D, so I'm definitely learning here. That being said, I've spent days reviewing tutorials, examples, and forums, and could not find much that helped. I've tried a dozen different methods of drawing, pre-processing, multi-threading, etc. My code is below
Code to Loop Through and Draw Elements
List<IDrawingElement> elementsInBounds = GetElementsInDraftingWindow();
_d2dContainer.Target.BeginDraw();
_d2dContainer.Target.Clear(ColorD2D.FromKnown(Colors.White, 1));
if (elementsInBounds.Count > 0)
{
Stopwatch watch = new Stopwatch();
watch.Start();
#region Using Drawing Element DrawDX Method
foreach (IDrawingElement elem in elementsInBounds)
{
elem.DrawDX(ref _d2dContainer.Target, ref _d2dContainer.Factory, ZeroPoint, DrawingScale, _selectedElementBrush, _selectedElementPointBrush);
}
#endregion
watch.Stop();
double drawingTime = watch.ElapsedMilliseconds;
Console.WriteLine("DirectX drawing time = " + drawingTime);
watch.Reset();
watch.Start();
Matrix3x2 scale = Matrix3x2.Scale(new SizeFD2D((float)DrawingScale, (float)DrawingScale), new PointFD2D(0, 0));
Matrix3x2 translate = Matrix3x2.Translation((float)ZeroPoint.X, (float)ZeroPoint.Y);
_d2dContainer.Target.Transform = scale * translate;
watch.Stop();
double transformTime = watch.ElapsedMilliseconds;
Console.WriteLine("DirectX transform time = " + transformTime);
}
DrawDX Function for Polygon
public override void DrawDX(ref WindowRenderTarget rt, ref Direct2DFactory fac, Point zeroPoint, double drawingScale, SolidColorBrush selectedLineBrush, SolidColorBrush selectedPointBrush)
{
if (_pathGeometry == null)
{
CreatePathGeometry(ref fac);
}
float brushWidth = (float)(Layer.Width / (drawingScale));
brushWidth = (float)(brushWidth * 2);
if (Selected == false)
{
rt.DrawGeometry(Layer.Direct2DBrush, brushWidth, _pathGeometry);
//Note that _pathGeometry is a PathGeometry
}
else
{
rt.DrawGeometry(selectedLineBrush, brushWidth, _pathGeometry);
}
}
Code to Create Direct2D Factory & Render Target
private void CreateD2DResources(float dpiX, float dpiY)
{
Factory = Direct2DFactory.CreateFactory(FactoryType.SingleThreaded, DebugLevel.None, FactoryVersion.Auto);
RenderTargetProperties props = new RenderTargetProperties(
RenderTargetType.Default, new PixelFormat(DxgiFormat.B8G8R8A8_UNORM,
AlphaMode.Premultiplied), dpiX, dpiY, RenderTargetUsage.None, FeatureLevel.Default);
Target = Factory.CreateWindowRenderTarget(_targetPanel, PresentOptions.None, props);
Target.AntialiasMode = AntialiasMode.Aliased;
if (_selectionBoxLeftStrokeStyle != null)
{
_selectionBoxLeftStrokeStyle.Dispose();
}
_selectionBoxLeftStrokeStyle = Factory.CreateStrokeStyle(new StrokeStyleProperties1(LineCapStyle.Flat,
LineCapStyle.Flat, LineCapStyle.Flat, LineJoin.Bevel, 10, DashStyle.Dash, 0, StrokeTransformType.Normal), null);
}
I create a Direct2D factory and render target once and keep references to them at all times (that way I'm not recreating each time). I also create all of the brushes when the drawing layer (which describes color, width, etc.) is created. As such, I am not creating a new brush every time I draw, simply referencing a brush that already exists. Same with the geometry, as can be seen in the second code-snippet. I create the geometry once, and only update the geometry if the element itself is moved or rotated. Otherwise, I simply apply a transform to the render target after drawing.
Based on my stopwatches, the time taken to loop through and call the elem.DrawDX methods takes about 225-250 ms (for 45,000 polygons). The time taken to apply the transform is 0-1 ms, so it appears that the bottleneck is in the RenderTarget.DrawGeometry() function.
I've done the same tests with RenderTarget.DrawEllipse() or RenderTarget.DrawRectangle(), as I've read that using DrawGeometry is slower than DrawRectangle or DrawEllipse as the rectangle / ellipse geometry is known beforehand. However, in all of my tests, it hasn't mattered which draw function I use, the time for the same number of elements is always about equal.
I've tried building a multi-threaded Direct2D factory and running the draw functions through tasks, but that is much slower (about two times slower). The Direct2D methods appear to be utilizing my graphics card (hardware accelerated is enabled), as when I monitor my graphics card usage, it spikes when the screen is updating (my laptop has an NVIDIA Quadro mobile graphics card).
Apologies for the long-winded post. I hope this was enough background and description of things I've tried. Thanks in advance for any help!
Edit #1
So changed the code from iterating over a list using foreach to iterating over an array using for and that cut the drawing time down by half! I hadn't realized how much slower lists were than arrays (I knew there was some performance advantage, but didn't realize this much!). It still, however, takes 125 ms to draw. This is much better, but still not smooth. Any other suggestions?
Direct2D can be used with P/Invoke
See the sample "VB Direct2D Pixel Perfect Collision"
from https://social.msdn.microsoft.com/Forums/en-US/cea42526-4b82-454d-9d79-2e1d94083552/collisions?forum=vbgeneral
the animation is perfect, even done in VB

Best way to draw text in MonoGame without using a SpriteFont?

Alright, so I'm working on a game in MonoGame which is set in a computer operating system. As expected, it does a lot of text rendering. The in-game OS allows users to customize almost every aspect of the operating system - people have made skins for the OS that make it look like Mac OS Sierra, almost every najor Windows release since 95, Xubuntu, Ubuntu, and way more.
This game used to be written in Windows Forms however there are features I want to implement that simply are not possible in WinForms. So, we decided to move from WinForms to MonoGame, and we are faced with one huge problem.
The skin format we've made allows the user to select any font installed on their computer to use for various elements like titlebar text, main UI text, terminal text etc. This was fine in WinForms because we could use System.Drawing to render text and that allows the use of any TrueType font on the system. If it can be loaded into a System.Drawing.Font, it can be rendered.
But, MonoGame uses a different technology for rendering text on-screen. SpriteFont objects. The problem is, there seems to be no way at all to dynamically generate a SpriteFont from the same data used to generate System.Drawing.Fonts (family, size, style, etc) in code.
So, since I seemingly can't create SpriteFonts dynamically, in my graphics helper class (which deals with drawing textures etc onto the current graphics device without needing copy-pasted code everywhere), I have my own DrawString and MeasureString methods which use System.Drawing.Graphics to composite text onto a bitmap and use that bitmap as a texture to draw onto the screen.
And, here's my code for doing exactly that.
public Vector2 MeasureString(string text, System.Drawing.Font font, int wrapWidth = int.MaxValue)
{
using(var gfx = System.Drawing.Graphics.FromImage(new System.Drawing.Bitmap(1, 1)))
{
var s = gfx.SmartMeasureString(text, font, wrapWidth); //SmartMeasureString is an extension method I made for System.Drawing.Graphics which applies text rendering hints and formatting rules that I need to make text rendering and measurement accurate and usable without copy-pasting the same code.
return new Vector2((float)Math.Ceiling(s.Width), (float)Math.Ceiling(s.Height)); //Better to round up the values returned by SmartMeasureString - it's just easier math-wise to deal with whole numbers
}
}
public void DrawString(string text, int x, int y, Color color, System.Drawing.Font font, int wrapWidth = 0)
{
x += _startx;
y += _starty;
//_startx and _starty are used for making sure coordinates are relative to the clip bounds of the current context
Vector2 measure;
if (wrapWidth == 0)
measure = MeasureString(text, font);
else
measure = MeasureString(text, font, wrapWidth);
using (var bmp = new System.Drawing.Bitmap((int)measure.X, (int)measure.Y))
{
using (var gfx = System.Drawing.Graphics.FromImage(bmp))
{
var textformat = new System.Drawing.StringFormat(System.Drawing.StringFormat.GenericTypographic);
textformat.FormatFlags = System.Drawing.StringFormatFlags.MeasureTrailingSpaces;
textformat.Trimming = System.Drawing.StringTrimming.None;
textformat.FormatFlags |= System.Drawing.StringFormatFlags.NoClip; //without this, text gets cut off near the right edge of the string bounds
gfx.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixel; //Anything but this and performance takes a dive.
gfx.DrawString(text, font, new System.Drawing.SolidBrush(System.Drawing.Color.FromArgb(color.A, color.R, color.G, color.B)), 0, 0, textformat);
}
var lck = bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); //Lock the bitmap in memory and give us the ability to extract data from it so we can load it into a Texture2D
var data = new byte[Math.Abs(lck.Stride) * lck.Height]; //destination array for bitmap data, source for texture data
System.Runtime.InteropServices.Marshal.Copy(lck.Scan0, data, 0, data.Length); //cool, data's in the destination array
bmp.UnlockBits(lck); //Unlock the bits. We don't need 'em.
using (var tex2 = new Texture2D(_graphicsDevice, bmp.Width, bmp.Height))
{
for (int i = 0; i < data.Length; i += 4)
{
byte r = data[i];
byte b = data[i + 2];
data[i] = b;
data[i + 2] = r;
} //This code swaps the red and blue values of each pixel in the bitmap so that they are arranged as BGRA. If we don't do this, we get weird rendering glitches where red text is blue etc.
tex2.SetData<byte>(data); //Load the data into the texture
_spritebatch.Draw(tex2, new Rectangle(x, y, bmp.Width, bmp.Height), Color.White); //...and draw it!
}
}
}
I'm already caching heaps of textures created dynamically - window buffers for in-game programs, skin textures, etc, so those don't hit the performance hard if at all, but this text rendering code hits it hard. I have trouble even getting the game above 29 FPS!
So, is there a better way of doing text rendering without SpriteFonts, and if not, is there any way at all to create a spritefont dynamically in code simply by specifying a font family, font size and style (bold, italic, strikeout etc)?
I'd say I'm intermediate with MonoGame now but I have a hard enough time getting RenderTargets to work - so if you want to answer this question please answer it as if you were talking to a kindergarten student.
Any help would be greatly appreciated, and as this is a major hot-buttin' issue in my game's development team you may see yourself mentioned in the game's credits as a major help :P
You could create a custom spritefont using System.Drawing and use this one. It is basically every character that can be used, stored in a Dictionary with the corresponding Texture2D.
When you want to draw a text, you just draw every char next to eachother.
This is still slow (because drawing text without vector graphics is always slow) but at least you do not have to parse everything every frame.
Just specify somewhere what characters can be used and import them. Dictionaries are very fast in C# when it comes to indexing, so this shouldn't be a problem at all.
Hope this helps. Good luck.

Game engine sprite sheet performance issues - DrawImage srcRectangle performance issues

I'm trying to make a game engine, with a sprite sheet loading system. Originally it was based upon single images but I ran into huge memory issues which ultimately led to me using a sprite sheet system.
Before the change the engine was getting around 300+ frames per second rendering, with a render time of around 2ms. Now the render time is 16 - 20ms and the fps about 40. I've tried optimizing my code by reducing the amount of calculations being ran but it has barely improved it at all.
What could I do to optimize this, the source of my problem seems to be using a srcRectangle to select the area of the sprite sheet to display, with the DrawImage method.
Draw method:
public virtual void Draw(Graphics g)
{
g.DrawImage(this.SpriteController.SpriteSheet,this.GetBoundingBox(), this.SpriteController.GetSpriteRectangle(),GraphicsUnit.Pixel);
}
GetBoundingBox method:
public Rectangle GetBoundingBox()
{
return new Rectangle((int)this.X, (int)this.Y, this.SpriteController.Width, this.SpriteController.Height);
}
GetSpriteRectangle method:
public RectangleF GetSpriteRectangle()
{
return new RectangleF(this.SpriteX, this.SpriteY, this.Width, this.Height);
}
That's all that is ran on render.

C#: How to reduce memory and CPU consumption when working with Bitmaps?

I have a Windows Application project that deals with Image editing (Cropping & Resizing). Unfortunately these image processings consume a lot of Memory and CPU resources (easily reaches 600MB or 50% cpu) and it is all about cropping and resizing just one gif image that weighs 2.5MB (2300*5400px). More than that, due to large resource consumption, the program gets stuck while resizing...
public static Image Resize(Image imgToResize, Size size)
{
Bitmap b = new Bitmap(size.Width, size.Height);
Graphics g = Graphics.FromImage((Image)b);
g.InterpolationMode = InterpolationMode.Default;
g.SmoothingMode = SmoothingMode.HighSpeed;
g.PixelOffsetMode = PixelOffsetMode.Default;
g.DrawImage(imgToResize, 0, 0, size.Width, size.Height);
g.Dispose();
return (Image)b;
}
public static Image Crop(Image img, Point p1, Point p2)
{
Rectangle cropArea = new Rectangle(p1.X, p1.Y, p2.X - p1.X, p2.Y - p1.Y);
return (img as Bitmap).Clone(cropArea, img.PixelFormat);
}
What methods should I use to avoid this?
I've already tried compressing it to memory stream in several formats but it didn't help (even made it worse)
NOTE: I use the standard .NET Drawing libraries: System.Drawing, System.Drawing.Imaging
Your code is creating copies of the image so you should expect unmanaged memory usage to rise when you call these methods. What matters a great deal is what you do with the original. You would be wise to get rid of it so it no longer takes up memory. You have to call its Dispose() method to do so. Waiting for the garbage collector to do it takes too long. The Bitmap class takes very little managed memory but oodles of unmanaged memory.
From an earlier version of this question: http://snippets.dzone.com/posts/show/4336
Also, AForge.net has several resize functions
This is a tricky one, and one I've run into before. You could split the image into x pieces, depending on the size of the file, then save each one to disk to ensure that the memory is clean.
Next, you resize the component images one at a time, each time, ensuring that the component is disposed before proceeding to the next one. Once you're all done, you stitch them back together, and then crop.
A MAJOR PROBLEM with this approach - if you're resizing upward, this approach will put seams in your image, as the interpolation won't have the surrounding pixels to guess at. But I would think that this approach would work well with resizing downward.
HTH.
Another hint again:
For example in resize, like #Hans pointed out, you create a new Bitmap, which one is your bottlenecks.
But, what if you just draw image resized, the same image which was loaded originally (obviously you made a backup file of original image before on the disk).
After crop what if you just draw a portion of a bitmap that user cropped, so user will see only that rectangle. ?
I mean in general, operate over image you already have, and try (as much as it possible) do not initialize new object for it.
Regards.
write Application.DoEvents(); in your functions, at least it wont get stuck

Categories