|
Hi all,
I'm creating an application that will allow me to draw lines with the mouse and then save them to a file in a graphical format. By dint of trying and trying I have come to the code.
The last problem that I can not solve is that I can only save the 'background' of the image but not the drawed shape.
The program consists of a PictureBox1 and a button1, drawing with the left mouse button, closes the shape with the right button and save the.
Thanks in advance to those who want to give me a tip.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
Bitmap bm;
Graphics g;
GraphicsPath path = new GraphicsPath();
Pen redPen;
Pen blackPen1;
Pen blackPen2;
Pen orangePen;
public Form1()
{
InitializeComponent();
g = pictureBox1.CreateGraphics();
redPen = new Pen(Color.Red, 2);
blackPen1 = new Pen(Color.Black, 1);
blackPen2 = new Pen(Color.Black, 2);
orangePen = new Pen(Color.Orange, 1);
bm = new Bitmap(pictureBox1.Width, pictureBox1.Height);
}
private void Form1_Load(object sender, EventArgs e)
{
pictureBox1.Paint += new System.Windows.Forms.PaintEventHandler(this.pictureBox1_Paint);
pictureBox1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.pictureBox1_MouseDown);
Shown += Form1_Shown;
}
private void Form1_Shown(Object sender, EventArgs e)
{
}
private List<Point> polygonPoints = new List<Point>();
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
switch (e.Button)
{
case MouseButtons.Left:
polygonPoints.Add(new Point(e.X, e.Y));
if (polygonPoints.Count > 1)
{
path.AddLine(polygonPoints[polygonPoints.Count - 2], polygonPoints[polygonPoints.Count - 1]);
g.DrawPath(redPen, path);
}
break;
case MouseButtons.Right:
if (polygonPoints.Count > 2)
{
path.CloseAllFigures();
g.DrawPath(redPen, path);
g.FillPath(new SolidBrush(Color.Orange), path);
}
break;
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Graphics g = Graphics.FromImage(bm);
for (int i = 0; i < pictureBox1.Width; i += 10) g.DrawLine(blackPen1, i, pictureBox1.Height, i, 0);
for (int i = 0; i < pictureBox1.Height; i += 10) g.DrawLine(blackPen1, 0, i, pictureBox1.Width, i);
g.DrawLine(blackPen2, 0, pictureBox1.Height - 90, pictureBox1.Width, pictureBox1.Height - 90);
e.Graphics.DrawImageUnscaled(bm, 0, 0);
}
private void button1_Click(object sender, EventArgs e)
{
bm.Save("c:\\test.png", ImageFormat.Png);
}
}
}
|
|
|
|
|
Member 7921268 wrote: Thanks in advance to those who want to give me a tip.
Declared on top of the code;
Graphics g; A bit confusing, as you're also painting on "g" in the "_Paint" method. Are you drawing on the correct graphics-object? The reason I ask, is because there's two of them;
g = pictureBox1.CreateGraphics();
Graphics g = Graphics.FromImage(bm);
Bastard Programmer from Hell
If you can't read my code, try converting it here[^]
|
|
|
|
|
You are right!, I'll investigate about it.
Thanks
|
|
|
|
|
If you want to save the drawing for later edits, it is usually better to save the points to a file, and not the image. Its more of a suggestion than anser but...
|
|
|
|
|
Thanks for your reply but I need to save the shape in image format for a successive 'shape matching' process.
Regards.
Lenny
|
|
|
|
|
Member 7921268 wrote: Thanks in advance to those who want to give me a tip.
Solved!, thanks all
Working release:
using System.Collections.Generic;
using System.Text;
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Drawing.Imaging;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
bool flgDraw = false;
Pen redPen;
Pen blackPen1;
Pen blackPen2;
Pen orangePen;
Bitmap drawing;
GraphicsPath path = new GraphicsPath();
private List<Point> polygonPoints = new List<Point>();
public Form1()
{
InitializeComponent();
redPen = new Pen(Color.Red, 2);
blackPen1 = new Pen(Color.Black, 1);
blackPen2 = new Pen(Color.Black, 2);
orangePen = new Pen(Color.Orange, 1);
panel1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.panel1_MouseMove);
panel1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.panel1_MouseDown);
panel1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.panel1_MouseUp);
panel1.Paint += new System.Windows.Forms.PaintEventHandler(this.panel1_Paint);
Shown += Form1_Shown;
drawing = new Bitmap(panel1.Width, panel1.Height, panel1.CreateGraphics());
Graphics.FromImage(drawing).Clear(Color.White);
}
private void Form1_Shown(Object sender, EventArgs e)
{
Grid();
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (flgDraw)
{
Graphics Gpanel = Graphics.FromImage(drawing);
panel1.CreateGraphics().DrawImageUnscaled(drawing, new Point(0, 0));
}
}
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
flgDraw = true;
Graphics Gpanel = Graphics.FromImage(drawing);
switch (e.Button)
{
case MouseButtons.Left:
polygonPoints.Add(new Point(e.X, e.Y));
if (polygonPoints.Count > 1)
{
path.AddLine(polygonPoints[polygonPoints.Count - 2], polygonPoints[polygonPoints.Count - 1]);
Gpanel.DrawPath(redPen, path);
}
break;
case MouseButtons.Right:
if (polygonPoints.Count > 2)
{
path.CloseAllFigures();
Gpanel.DrawPath(redPen, path);
Gpanel.FillPath(new SolidBrush(Color.Orange), path);
}
break;
}
panel1.CreateGraphics().DrawImageUnscaled(drawing, new Point(0, 0));
}
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
flgDraw = false;
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawImageUnscaled(drawing, new Point(0, 0));
}
private void Grid()
{
Graphics Gpanel = Graphics.FromImage(drawing);
for (int i = 0; i < panel1.Width; i += 10)
Gpanel.DrawLine(blackPen1, i, panel1.Height, i, 0);
for (int i = 0; i < panel1.Height; i += 10)
Gpanel.DrawLine(blackPen1, 0, i, panel1.Width, i);
Gpanel.DrawLine(blackPen2, 0, panel1.Height - 90, panel1.Width, panel1.Height - 90);
panel1.CreateGraphics().DrawImageUnscaled(drawing, new Point(0, 0));
}
private void btnSave_Click(object sender, EventArgs e)
{
drawing.Save("c:\\test.png", ImageFormat.Png);
}
}
}
|
|
|
|
|
Here's a program which creates 100 million random numbers, then counts how many are divisible by seven using three different methods:
static void Main(string[] args)
{
Random r = new Random(Environment.TickCount);
int[] numbers = new int[100000000];
for (int index = 0; index < numbers.Length; index++)
{
numbers[index] = r.Next();
}
Stopwatch sw = Stopwatch.StartNew();
int count = 0;
foreach (int number in numbers) if (number % 7 == 0) count++;
Console.WriteLine("Simple Iteration {0} : {1}", count, sw.ElapsedMilliseconds);
sw = Stopwatch.StartNew();
var x = from g in numbers where g % 7 == 0 select g;
count = x.Count();
Console.WriteLine("LINQ Query {0} : {1}", count, sw.ElapsedMilliseconds);
sw = Stopwatch.StartNew();
int z = numbers.Count(g => g % 7 == 0);
Console.WriteLine("Count Query {0} : {1}", z, sw.ElapsedMilliseconds);
Console.ReadLine();
}
If you run it, you'll find that the Select query(2nd) takes almost exactly twice as long as basic iteration (1st), the count method (3rd) takes about three times as long.
This is a similar program to one I wrote when LINQ came out, and it rather put me off. Not only did the LINQ look more confusing, but it took twice as long to execute. It's also harder to debug, of course.
So, interested in views on this. Can anyone adjust the app so the performance becomes similar? Because, unless I'm missing something, half the performance is a serious issue in a real-time system and something to avoid everywhere else.
Regards,
Rob Philpott.
|
|
|
|
|
Rob Philpott wrote: If you run it, you'll find that the Select query(2nd) takes almost exactly twice as long as basic iteration (1st)
I'm not surprised. LINQ sacrifices speed for convenience. I'm using it a lot in my apps, and unless we're talking about a thight loop, it's not noticeable.
Rob Philpott wrote: half the performance is a serious issue in a real-time system One does not build real-time systems in a managed language. If speed is that much of an issue, you'd be better served with C++ or Delphi. Do an IntToStr in Delphi and in C#, and you'll have an equally large "problem".
Bastard Programmer from Hell
If you can't read my code, try converting it here[^]
|
|
|
|
|
Eddy Vluggen wrote: One does not build real-time systems in a managed language
I can assure you they do, I've worked on several such systems. And why not? Once the JIT is out the way calculations can be sometimes quicker than native code (I once had this in a C# vs C++ battle calculating prime numbers. The JIT can optimise for the installed processor, in my case an AMD chip and the managed code was quicker). The impact of things like array checking and garbage collection are usually negligible.
Regards,
Rob Philpott.
|
|
|
|
|
Rob Philpott wrote: The JIT can optimise for the installed processor It can, but it doesn't. Ok it does (it uses FISTTP and MOVQ), but not nearly enough.
Also, so can native code, although not as fully because it's not at runtime (it takes a lot of space and it will be frozen in time): CPU dispatch is a very common technique.
Rob Philpott wrote: the managed code was quicker) That just means the native code wasn't compiled right or the compiler sucked (MSVC sucks, except maybe the 2012 version) or both. There is no excuse for it otherwise.
|
|
|
|
|
Possibly so, and you can argue the finer points but the central point is that managed languages/environments are capable.
Regards,
Rob Philpott.
|
|
|
|
|
Ok, fair enough. It's just, that "JIT can optimize for installed process"-meme that keeps going around. It's technically true and all, but if it can do something and then it doesn't do it, well..
|
|
|
|
|
Rob Philpott wrote: And why not? Because the way Windows multitasks. You're not even guaranteed to get CPU-time.
What do you define as "real-time"? If you cannot guarantee a reaction within milliseconds, we'd be talking about "instant", not "real-time". As in "instant messaging"
Bastard Programmer from Hell
If you can't read my code, try converting it here[^]
|
|
|
|
|
I have found that sometimes LinQ is slower than traditional for loops, with your example being on that I have seen first Hand too.
But recently I compared doing a product of calculation of a series of decimal numbers both with LinQ and a for loop for a project that I am working on. The LinQ for me out performed the
List<int> data = new List<int>();
for (int i = 0; i < 100; i++) data.Add(i);
Stopwatch sw = Stopwatch.StartNew();
int value = 1;
for (int i = 0; i < 99; i++)
{
value *= data[i];
}
Console.WriteLine(";Simple Iteration time {0}", sw.Elapsed.TotalMilliseconds);
sw = Stopwatch.StartNew();
int linqAgg = data.Aggregate((first, second) =>; first * second);
Console.WriteLine("Linq Iteration time {0}", sw.Elapsed.TotalMilliseconds );
Console.ReadLine();
my results are as follow
Simple Iteration time 1.7021
Linq Iteration time 0.6478
My personal feeling for the use of LinQ is to use with caution when speed is the most important factor.
Every day, thousands of innocent plants are killed by vegetarians.
Help end the violence EAT BACON
|
|
|
|
|
There's a few things I think you need to take into acccunt there. Firstly, if you up the 100 to 100 million, the simple iteration is three times as quick (on my computer). When you time a small loop with 100 items in it, really you're just timing the JIT compilation time, not the actual execution time which will be super sub-millisecond. The LINQ has been pre-jitted as its part of the .NET framework so you'd expect that (the first time). Also, timers aren't that accurate so really I think you need large numbers of iterations to be able to draw comparisons, and when you do that, again, LINQ is several times slower.
Regards,
Rob Philpott.
|
|
|
|
|
Thanks (no really) I'm off to expand my learning, I like it when things like this happen
Every day, thousands of innocent plants are killed by vegetarians.
Help end the violence EAT BACON
|
|
|
|
|
Hope I didn't sound argumentative.
Regards,
Rob Philpott.
|
|
|
|
|
Hmm Interesting subject the performance of LinQ and I don't really know or understand it until now, glad I butted in on this thread
Quote: LINQ-to-Objects generally is going to add some marginal overheads (multiple iterators, etc). It still has to do the loops, and has delegate invokes, and will generally have to do some extra dereferencing to get at captured variables etc. In most code this will be virtually undetectable, and more than afforded by the simpler to understand code.
which I read on this LinQ statement faster than foreach loop[^]
But in another article LinQ performance faq[^]. It goes on to say that doing certain operations in LinQ has an impact on memory such as the OrderBy() extension as it creates a new copy of the list / array in memory as well as the original, but you can improve performance by utilizing chaining and Lazy evaluation.
Every day, thousands of innocent plants are killed by vegetarians.
Help end the violence EAT BACON
|
|
|
|
|
We did similar tests about a year or two ago and also inlcuded unmanaged C++, which was still several times faster than the simple managed loop.
|
|
|
|
|
Windows is not a "real-time" operating system so I don't know what you expect to get out of the code.
|
|
|
|
|
What no one has mentioned is where the actual issue is here. It's not in the line of code that you probably think it is. As a hint, put a sw.Stop(); just before the line count = x.Count(); . This should show you what the actual hold up is (as a hint - the first part of that statement doesn't actually return a concrete list. As LINQ utilizes lazy evaluation and deferred execution, you effectively end up with the actual iteration being done twice (the second time in the Count() method).
|
|
|
|
|
Yep, I appreciate that which is why the way the code is (timer after count). Just another wonderful aspect of LINQ. I don't see why the iteration is being done twice though. The query sets up an enumerator and the count enumerates it. Where are the two iterations? And most importantly, can you suggest a change which will make the LINQ execution speed similar (presumably get it down to just one iteration)?
EDIT: corrected some of the jargon, got two kids running around the place and so first part was rushed and incoherent.
Regards,
Rob Philpott.
modified 30-Apr-13 13:04pm.
|
|
|
|
|
Its been a fun bit of learning, but I have worked out why it is significantly slower.
The Count() method uses eager evaluation, from reading various sources, this means that the collection is iterated in full when in this case count() is called.
so
var x = from g in numbers where g % 7 == 0 select g;
count = x.Count();
This block uses lazy evaluation to create x, but it is not evaluated until you call Count() which uses eager evaluation.
and
int Count = numbers.Count(p => p % 7 ==0);
this block causes the entire 10 million records to be evaluated.
Every day, thousands of innocent plants are killed by vegetarians.
Help end the violence EAT BACON
|
|
|
|
|
Strange - I'm not seeing the same results, and my computer isn't exactly new. Running in LinqPad, I get:
- Release mode:
- Simple Iteration : 2107
- LINQ Query : 2168
- Count Query : 2255
- Debug mode:
- Simple Iteration : 2273
- LINQ Query : 2281
- Count Query : 2758
Yes, there's a small difference, but at worst it's less than a 20% hit. It's certainly not taking three times as long.
If you add PLINQ into the picture, your loop starts to look pretty slow:
count = numbers.AsParallel().Count(g => g % 7 == 0);
- Simple Iteration : 2218
- PLINQ Query : 1749
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Yes! I was missing something - I hadn't tried it in release. What an idiot.
I get about the same as you with that change, it drops from 100% longer to about 20% which is a lot more palatable. And like you, if I make it parallel its actually quicker.
This requires a recalibration of my attitude to LINQ. 20% still makes me feel uncomfortable but is much better than I thought.
Regards,
Rob Philpott.
|
|
|
|
|