I wanted to make an application which can read data from the webcam. It makes the really bright pixels red (right now). But I can't write it out into an imagebox. So what is the problem?
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
WebCam camera = new WebCam();
if (!camera.IsConnected())
{
camera.Connect();
}
else
{
Application.Exit();
}
// for (int x = 0; x <= 10000; x++)
// {
camera.Update();
MemoryStream ms = new MemoryStream();
camera.CalcBitmap().Save(ms, ImageFormat.Bmp);
byte[] bitmapData = ms.ToArray();
/*
int i = 54;
while (i <= (bitmapData.Length - 2))
{
if ((bitmapData[i] >= 240) & (bitmapData[i + 1] >= 240) & (bitmapData[i + 2] >= 240))
{
bitmapData[i] = 255;
bitmapData[i + 1] = 0;
bitmapData[i + 2] = 0;
i += 3;
}
}*/
MemoryStream stream = new MemoryStream(bitmapData);
pictureBox1.Image = new Bitmap(stream);
// }
}
So after lot of suffering I leaved the picturebox function empty and i wrote everything into a buttonclick function. And it worked! I still don't know what was the problem, but I think the picturebox funtoin tired to connect to the webcam even if it was connected.
public partial class Form1 : Form
{
public static WebCam camera = new WebCam();
private void button1_Click(object sender, EventArgs e)
{
if (!camera.IsConnected())
{
camera.Connect();
camera.Update();
MemoryStream ms = new MemoryStream();
camera.CalcBitmap().Save(ms, ImageFormat.Bmp);
byte[] bitmapData = ms.ToArray();
MemoryStream stream = new MemoryStream(bitmapData);
pictureBox1.Image = new Bitmap(stream);
}
else
{
Application.Exit();
}
}
public void pictureBox1_Paint(object sender, PaintEventArgs e)
{
}
You must call Dispose() on objects that holds unmanaged resources so the memory can be freed.
MemoryStream ms = null
try{
//your code
}
finally{
if(ms != null){
ms.Dispose()
}
}
Related
private void GenerateAnimatedGifs()
{
UnFreezWrapper unfreezWrapper = new UnFreezWrapper();
checkBoxGetImages = false;
checkBoxGetAllImages.Checked = false;
GetImagesFiles();
for (int i = 0; i < filesSatellite.Length; i++)
{
Image img = Image.FromFile(filesSatellite[i]);
img.Save(filesSatellite[i] + "ConvertedToGif.gif", System.Drawing.Imaging.ImageFormat.Gif);
img.Dispose();
File.Delete(filesSatellite[i]);
}
GetImagesFiles();
unfreezWrapper.MakeGIF(filesRadar.ToList(), #"d:\Downloaded Images\Animates Gifs\radanim.gif", 100, true);
unfreezWrapper.MakeGIF(filesSatellite.ToList(), #"d:\Downloaded Images\Animates Gifs\satanim.gif", 100, true);
}
In the loop I convert each image to gif save it in other name and then dispose the original image and then trying to delete the original image so only the ConvertedToGif images will left.
but I'm getting the exception is being used by another process on the delete line
File.Delete(filesSatellite[i]);
but isn't the file disposed already ?
The problem is that in the constructor I'm loading the images to a pictureBox using timer that is why the images are busy with another process.
If I'm not loading the images at the constructor everything will work fine.
But I want to display the images when running the application and also to be able to convert them to other formats and making other manipulations like creating animated gif of them.
I'm stuck here.
This is the constructor code
public Form1()
{
InitializeComponent();
CheckIfImagesExist();
}
And the code of the CheckIfImagesExist method
private void CheckIfImagesExist()
{
GetImagesFiles();
if (filesRadar != null)
{
if (filesRadar.Length > 1)
{
pictureBox1.Image = new Bitmap(filesRadar[0]);
trackBar1.Enabled = true;
timer1.Enabled = true;
}
if (filesRadar.Length == 1)
{
trackBar1.Enabled = false;
pictureBox1.Image = new Bitmap(filesRadar[0]);
}
}
if (filesSatellite != null)
{
if (filesSatellite.Length > 1)
{
pictureBox2.Image = new Bitmap(filesSatellite[0]);
trackBar1.Enabled = true;
timer2.Enabled = true;
}
if (filesSatellite.Length == 1)
{
trackBar1.Enabled = false;
pictureBox2.Image = new Bitmap(filesSatellite[0]);
}
}
}
The timer tick event
int satImagesCount = 0;
private void timer2_Tick(object sender, EventArgs e)
{
satImagesCount++;
if (satImagesCount == filesSatellite.Length)
{
satImagesCount = 0;
}
pictureBox2.Image = new Bitmap(filesSatellite[satImagesCount]);
if (isInsideSat)
{
pb.Image = new Bitmap(filesSatellite[satImagesCount]);
timer2.Interval = trackBar1.Value * 100;
}
}
I want to make a bitmap and save it and display it. I can display it but I cannot save it.
I get this runtime error : System.Runtime.InteropServices.ExternalException: 'A generic error occurred in GDI+.'
I am even using using and I still get that error
private void button1_Click(object sender, EventArgs e)
{
byte[] returndata = new byte[7057600];
for (int x = 0; x < returndata.Length; )
{
returndata[x] = 255;
returndata[x + 1] = 255;
returndata[x + 2] = 0;
returndata[x + 3] = 0;
x = x + 4;
}
using (SaveFileDialog saveFileDialog1 = new SaveFileDialog())
{
saveFileDialog1.Filter = "Bitmaps|*.bmp";
Bitmap temp = null;
temp = InttoBitmap(returndata);
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
string location = saveFileDialog1.FileName;
temp.Save(location, ImageFormat.Bmp);
pictureBox1.Image = temp;
}
}
}
int keepWidth = 3208;
int keepHeight = 2200;
public Bitmap InttoBitmap(byte[] array)
{
unsafe
{
IntPtr pixptr = Marshal.AllocHGlobal(keepWidth * keepHeight * 4);
Marshal.Copy(array, 0, pixptr, keepWidth * keepHeight);
Bitmap bitmap = new Bitmap(keepWidth, keepHeight, 2 * keepWidth, System.Drawing.Imaging.PixelFormat.Format24bppRgb, pixptr);
return bitmap;
}
}
I am attempting to capture a full-page screenshot of any website a user is viewing using the WebBrowser component.
At present, I am able to only able to capture what a user is viewing from within the WebBrowser. However, the screenshot image created is the size of the webpage. For example, below is a (half-sized) screenshot of the BBC website, the black area is actually saved transparent but I've filled it black for visibility.
I have seen solutions where a new WebBrowser instance is used to fetch a fullpage snapshot. However, I need the screenshot to be exactly of the page as the user is viewing it at the time, much like how the full-page screenshot works in Firefox.
My code below that generated the above image:
private void button1_Click(object sender, EventArgs e)
{
while (webBrowser1.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
int scrollWidth = 0;
int scrollHeight = 0;
scrollHeight = webBrowser1.Document.Body.ScrollRectangle.Height;
scrollWidth = webBrowser1.Document.Body.ScrollRectangle.Width;
webBrowser1.Size = new Size(scrollWidth, scrollHeight);
Bitmap bm = new Bitmap(scrollWidth, scrollHeight);
webBrowser1.DrawToBitmap(bm, new Rectangle(0, 0, bm.Width, bm.Height));
bm.Save(#"D:\Screenshots\test.png", ImageFormat.Png);
}
I've got a good working one..
private void button1_Click(object sender, EventArgs e)
{
using (FileDialog fd = new SaveFileDialog())
{
fd.Filter = "Image (*.png)|*.png";
if (fd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
new WebPageSnap(webBrowser1.Url.ToString(), fd.FileName);
//might take 3 or 4 seconds to save cauz it has to load again.
}
}
}
class WebPageSnap
{
WebBrowser wb;
string outFile;
public WebPageSnap(string url, string outputFile)
{
wb = new WebBrowser();
wb.ProgressChanged += wb_ProgressChanged;
outFile = outputFile;
wb.ScriptErrorsSuppressed = true;
wb.ScrollBarsEnabled = false;
wb.Navigate(url);
}
void wb_ProgressChanged(object sender, WebBrowserProgressChangedEventArgs e)
{
if (e.CurrentProgress == e.MaximumProgress)
{
wb.ProgressChanged -= wb_ProgressChanged;
try
{
int scrollWidth = 0;
int scrollHeight = 0;
scrollHeight = wb.Document.Body.ScrollRectangle.Height;
scrollWidth = wb.Document.Body.ScrollRectangle.Width;
wb.Size = new Size(scrollWidth, scrollHeight);
Bitmap bitmap = new Bitmap(wb.Width, wb.Height);
for (int Xcount = 0; Xcount < bitmap.Width; Xcount++)
for (int Ycount = 0; Ycount < bitmap.Height; Ycount++)
bitmap.SetPixel(Xcount, Ycount, Color.Black);
wb.DrawToBitmap(bitmap, new Rectangle(0, 0, wb.Width, wb.Height));
bitmap.Save(outFile, ImageFormat.Png);
}
catch { }
}
}
}
.
;Here's the result
.
I could not fit exactly what I wanted to say in the title, it would be too long. Okay this is a multi-threaded app. What my app does is looks at a picture, find the edges of the picture, and finds the shape of that object from the edges. While it finds the shape, it constantly updates the image so we can get some sort of visual representation. I have created a very short (40 seconds) video demonstrating the issue: http://phstudios.com/projects/Programming/MultiThreadIssue/
As you can see, everything is working fine until the minute I move the window. This is always the case. I ran the program several times without moving the window and it ran fine. However, the minute I move the window, it will come up with that error. As you see, I am locking the specific image I would like to work with. Is the forms OnPaint overriding that somehow? Is there any way I can fix that?
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.Threading;
using System.Drawing.Imaging;
namespace LineRecognition
{
public enum Shape
{
Unknown,
Quadrilateral,
Circle,
Triangle
}
public partial class Form1 : Form
{
Bitmap image, original, shapes;
List<Point> outlines;
Shape shape;
ShapeDetection detector;
public Form1()
{
InitializeComponent();
edgeDetection.WorkerReportsProgress = true;
shapeDetection.WorkerReportsProgress = true;
shape = Shape.Unknown;
}
private void Form1_Load(object sender, EventArgs e)
{
original = new Bitmap("photo1.png");
image = new Bitmap("photo1.png");
shapes = new Bitmap(image.Width, image.Height);
pictureBox1.Image = (Image)original;
}
private void findLines_Click(object sender, EventArgs e)
{
if (edgeDetection.IsBusy != true)
{
lblStatus.Text = "Finding Edges";
edgeDetection.RunWorkerAsync();
}
}
private void justTheOutlines(Bitmap image, List<Point> pixels, BackgroundWorker worker)
{
lock (image)
{
for (int i = 0; i < pixels.Count; i++)
{
image.SetPixel(pixels[i].X, pixels[i].Y, Color.Red);
worker.ReportProgress((int)((float)i * 100 / (float)pixels.Count));
}
}
}
private List<Point> outlineLines(Bitmap image, BackgroundWorker worker)
{
int w = image.Width;
int h = image.Height;
int alpha = 800000;
List<Point> changes = new List<Point>();
lock (image)
{
for (int i = 0; i < w; i++)
{
for (int j = 0; j < h; j++)
{
Color selected = image.GetPixel(i, j);
Color nextRight = selected;
Color nextDown = selected;
if (i < w - 1)
nextRight = image.GetPixel(i + 1, j);
if (j < h - 1)
nextDown = image.GetPixel(i, j + 1);
int iSelected = selected.ToArgb();
int iNextRight = nextRight.ToArgb();
int iNextDown = nextDown.ToArgb();
if (Math.Abs(iSelected - iNextRight) > alpha)
{
if (iSelected < iNextRight)
{
Point p = new Point(i, j);
if(!ContainsPoint(changes, p)) changes.Add(p);
}
else
{
Point p = new Point(i + 1, j);
if (!ContainsPoint(changes, p)) changes.Add(p);
}
}
if (Math.Abs(iSelected - iNextDown) > alpha)
{
if (iSelected < iNextDown)
{
Point p = new Point(i, j);
if (!ContainsPoint(changes, p)) changes.Add(p);
}
else
{
Point p = new Point(i, j + 1);
if (!ContainsPoint(changes, p)) changes.Add(p);
}
}
image.SetPixel(i, j, Color.White);
}
worker.ReportProgress((int)(((float)i / (float)w) * 100));
}
}
return changes;
}
private bool ContainsPoint(List<Point> changes, Point p)
{
foreach (Point n in changes)
{
if (n.Equals(p)) return true;
}
return false;
}
private void edgeDetection_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
outlines = outlineLines(image, worker);
justTheOutlines(image, outlines, worker);
pictureBox2.Image = (Image)image;
Thread.Sleep(100);
image.Save("photo-lines.jpg");
}
private void edgeDetection_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
algorithmProgress.Value = e.ProgressPercentage;
}
private void edgeDetection_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
algorithmProgress.Value = 0;
findLines.Enabled = false;
determineShape.Enabled = true;
lblStatus.Text = "";
}
private void determineShape_Click(object sender, EventArgs e)
{
if (shapeDetection.IsBusy != true)
{
pictureBox1.Image = (Image)image;
lblStatus.Text = "Running Shape Detection: Circle -> Quadrilateral";
shapeDetection.RunWorkerAsync();
}
}
private void ShapeDetection_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
detector = new ShapeDetection(outlines, 40, 10);
detector.Worker = worker;
detector.circleChange += new ShapeDetection.CircleChangeEventHandler(circleChange);
if (detector.IsCircle())
{
MessageBox.Show("Object is a circle");
shape = Shape.Circle;
}
else if (detector.IsQuadrilateral())
{
MessageBox.Show("Object is a quadrilateral", "Number of edges: " + detector.Summits);
shape = Shape.Quadrilateral;
}
else
{
int sides = detector.Summits.Count;
if (sides == 3)
{
MessageBox.Show("Object is a triangle");
shape = Shape.Triangle;
}
else
{
MessageBox.Show("Number of edges: " + detector.Summits.Count, "Unknown");
}
}
BitmapDrawing.DrawLines(detector.Summits, shapes);
BitmapDrawing.DrawSummits(detector.Summits, shapes);
pictureBox2.Image = (Image)shapes;
Thread.Sleep(100);
}
private void ShapeDetection_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (detector != null)
{
lblSummits.Text += detector.Summits.Count;
lblType.Text += shape.ToString();
determineShape.Enabled = false;
lblStatus.Text = "";
}
}
void circleChange(object sender, CircleChangeEventArgs e)
{
lock (shapes)
{
Point p = detector.visited[detector.visited.Count - 1];
shapes.SetPixel(p.X, p.Y, Color.Blue);
pictureBox2.Image = (Image)shapes;
Thread.Sleep(10);
detector.Worker.ReportProgress((int)(e.percent * 100));
}
}
private void shapeDetection_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
algorithmProgress.Value = e.ProgressPercentage;
}
}
}
Update
What Nick said before worked fine. I added that to my CircleChange event and it works. Can somebody explain why the invoke makes it work instead of setting the picturebox2.Image to the shapes image? I mean I call it after I call setpixel, so I should be done modifying the image right?
void circleChange(object sender, CircleChangeEventArgs e)
{
Point p = detector.visited[detector.visited.Count - 1];
shapes.SetPixel(p.X, p.Y, Color.Blue);
Image copyForPictureBox = shapes.Clone() as Image;
BeginInvoke(new Action(() => pictureBox2.Image = copyForPictureBox));
Thread.Sleep(15);
detector.Worker.ReportProgress((int)(e.percent * 100));
}
It appears that you're operating on the shapes bitmap on a thread separate to the GUI thread. When you move the window the OnPaint routine will run which will also access the image.
What you need to do to solve this is operate on a separate bitmap in your worker thread, and then pass a copy of that to the GUI thread using Invoke on the form. That way you're guaranteed only to have one thread accessing the picture box image at a time.
Edit:
void MyThreadFunction( )
{
Bitmap localThreadImage;
...
Image copyForPictureBox = localThreadImage.Clone( ) as Image;
BeginInvoke( new Action( () => pictureBox.Image = copyForPictureBox ) );
....
}
So the idea is that you create a Bitmap on the thread which is only ever accessed by that thread (i.e. your background worker thread). And when you get to a point when you want to update the image in the PictureBox you invoke onto the the GUI thread using BeginInvoke (which doesn't block your worker thread) passing a copy of the Bitmap to the PictureBox.
Locking the shapes object at only one point in your application does not accomplish anything. You also use this bitmap to draw to the window, and my guess is that you are not locking it for drawing. You can either lock it in OnPaint as well, or use a different bitmap for manipulation and display.
Example1
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
pro = new Thread(new ThreadStart(Producer));
con = new Thread(new ThreadStart(Consumer));
}
private AutoResetEvent m_DataAvailableEvent = new AutoResetEvent(false);
Queue<Bitmap> queue = new Queue<Bitmap>();
Thread pro;
Thread con;
public void Producer()
{
MemoryStream[] ms = new MemoryStream[3];
for (int y = 0; y < 3; y++)
{
StreamReader reader = new StreamReader("image" + (y + 1) + ".JPG");
BinaryReader breader = new BinaryReader(reader.BaseStream);
byte[] buffer = new byte[reader.BaseStream.Length];
breader.Read(buffer, 0, buffer.Length);
ms[y] = new MemoryStream(buffer);
}
while (true)
{
for (int x = 0; x < 3; x++)
{
Bitmap bmp = new Bitmap(ms[x]);
queue.Enqueue(bmp);
m_DataAvailableEvent.Set();
Thread.Sleep(6);
}
}
}
public void Consumer()
{
Graphics g = pictureBox1.CreateGraphics();
while (true)
{
m_DataAvailableEvent.WaitOne();
Bitmap bmp = queue.Dequeue();
if (bmp != null)
{
// Bitmap bmp = new Bitmap(ms);
g.DrawImage(bmp, new Point(0, 0));
bmp.Dispose();
}
}
}
private void pictureBox1_Click(object sender, EventArgs e)
{
con.Start();
pro.Start();
}
}
When creating bitmap and drawing to picture box are in seperate thread
then Bitmap bmp = new Bitmap(ms[x]) takes 45.591 millisecond
and g.DrawImage(bmp,new Point(0,0)) takes 41.430 milisecond.
When I make a bitmap from memoryStream and draw it to picture box in one thread then
Bitmap bmp = new Bitmap(ms[x]) takes 29.619 and g.DrawImage(bmp,new Point(0,0)) takes 35.540.
The code is for Example 2 is
public Form1()
{
InitializeComponent();
pro = new Thread(new ThreadStart(Producer));
con = new Thread(new ThreadStart(Consumer));
}
private AutoResetEvent m_DataAvailableEvent = new AutoResetEvent(false);
Queue<MemoryStream> queue = new Queue<MemoryStream>();
Thread pro;
Thread con;
public void Producer()
{
MemoryStream[] ms = new MemoryStream[3];
for (int y = 0; y < 3; y++)
{
StreamReader reader = new StreamReader("image" + (y + 1) + ".JPG");
BinaryReader breader = new BinaryReader(reader.BaseStream);
byte[] buffer = new byte[reader.BaseStream.Length];
breader.Read(buffer, 0, buffer.Length);
ms[y] = new MemoryStream(buffer);
}
while (true)
{
for (int x = 0; x < 3; x++)
{
// Bitmap bmp = new Bitmap(ms[x]);
queue.Enqueue(ms[x]);
m_DataAvailableEvent.Set();
Thread.Sleep(6);
}
}
}
public void Consumer()
{
Graphics g = pictureBox1.CreateGraphics();
while (true)
{
m_DataAvailableEvent.WaitOne();
//Bitmap bmp = queue.Dequeue();
MemoryStream ms = queue.Dequeue();
if (ms != null)
{
Bitmap bmp = new Bitmap(ms);
g.DrawImage(bmp, new Point(0, 0));
bmp.Dispose();
}
}
}
private void pictureBox1_Click(object sender, EventArgs e)
{
con.Start();
pro.Start();
}
Why does it take more time to draw and create a bitmap in seperate thread and how to reduce the time when processing in seperate thread ? I am using ANTS performance profiler 4.3
All UI operations should take place on the same thread. In fact if you want your system to be stable they must all take place on the same thread. I guess that what you're seeing with the slower performance on the multithreaded code is evidence of that instability.
By all means load the images in separate threads, but update the UI in the main thread.
If you search for questions tagged [multithreading] [c#] here on Stack Overflow you'll see many other questions along the same lines as yours.
See here and here for example.