Я был измотан этой ошибкой за последние 2 недели. Я много пытался выяснить и пробовал код по-разному, но пока не преуспел. Я думаю, что основная проблема связана с растровым изображением, может быть, я использую его неправильно. Я делюсь своим кодом, чтобы помочь понять, что я делаю.
Сначала я расскажу вам сценарий. В этом приложении я использую камеру dslr для просмотра в реальном времени. Основная область кода из класса камеры приведена ниже:
internal void Run()
{
LVrunning = true;
while (LVrunning)
{
Thread.Sleep(20);
if (LVrunning)
UpdatePicture();
}
}
private void UpdatePicture()
{
try
{
if (err == EDSDK.EDS_ERR_OK && LVrunning)
{
inSide = true;
// Download live view image data
err = EDSDK.EdsDownloadEvfImage(cameraDev, EvfImageRef);
if (err != EDSDK.EDS_ERR_OK)
{
Debug.WriteLine(String.Format("Download of Evf Image: {0:X}", err));
return;
}
IntPtr ipData;
err = EDSDK.EdsGetPointer(MemStreamRef, out ipData);
if (err != EDSDK.EDS_ERR_OK)
{
Debug.WriteLine(String.Format("EdsGetPointer failed: {0:X}", err));
return;
}
uint len;
err = EDSDK.EdsGetLength(MemStreamRef, out len);
if (err != EDSDK.EDS_ERR_OK)
{
Debug.WriteLine(String.Format("EdsGetLength failed:{0:X}", err));
EDSDK.EdsRelease(ipData);
return;
}
Byte[] data = new byte[len];
Marshal.Copy(ipData, data, 0, (int)len);
System.IO.MemoryStream memStream = new System.IO.MemoryStream(data);
// get the bitmap
Bitmap bitmap = null;
try
{
bitmap = new Bitmap(memStream);
}
catch (OutOfMemoryException ex)
{
GC.WaitForPendingFinalizers();
bitmap = new Bitmap(memStream); // sometimes error occur
}
NewFrame(bitmap, null); // this is event call back to form area.
memStream.Dispose();
EDSDK.EdsRelease(ipData);
}
}
catch (Exception ex)
{
}
}
private void getCapturedItem(IntPtr directoryItem)
{
uint err = EDSDK.EDS_ERR_OK;
IntPtr stream = IntPtr.Zero;
EDSDK.EdsDirectoryItemInfo dirItemInfo;
err = EDSDK.EdsGetDirectoryItemInfo(directoryItem, out dirItemInfo);
if (err != EDSDK.EDS_ERR_OK)
{
throw new CameraException("Unable to get captured item info!", err);
}
// Fill the stream with the resulting image
if (err == EDSDK.EDS_ERR_OK)
{
err = EDSDK.EdsCreateMemoryStream((uint)dirItemInfo.Size, out stream);
}
// Copy the stream to a byte[] and
if (err == EDSDK.EDS_ERR_OK)
{
err = EDSDK.EdsDownload(directoryItem, (uint)dirItemInfo.Size, stream);
}
// Create the returned item
//CapturedItem item = new CapturedItem();
if (dirItemInfo.szFileName.ToString().ToLower().Contains("jpg") || dirItemInfo.szFileName.ToString().ToLower().Contains("jpeg"))
{
if (err == EDSDK.EDS_ERR_OK)
{
IntPtr imageRef = IntPtr.Zero;
err = EDSDK.EdsCreateImageRef(stream, out imageRef);
if (err == EDSDK.EDS_ERR_OK)
{
EDSDK.EdsImageInfo info;
err = EDSDK.EdsGetImageInfo(imageRef, EDSDK.EdsImageSource.FullView, out info);
}
}
}
if (err == EDSDK.EDS_ERR_OK)
{
try
{
byte[] buffer = new byte[(int)dirItemInfo.Size];
GCHandle gcHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
IntPtr address = gcHandle.AddrOfPinnedObject();
IntPtr streamPtr = IntPtr.Zero;
err = EDSDK.EdsGetPointer(stream, out streamPtr);
if (err != EDSDK.EDS_ERR_OK)
{
throw new CameraDownloadException("Unable to get resultant image.", err);
}
try
{
Marshal.Copy(streamPtr, buffer, 0, (int)dirItemInfo.Size);//sometimes error comes here
System.IO.MemoryStream memStream = new System.IO.MemoryStream(buffer);
Bitmap bitmap = null;
try
{
bitmap = new Bitmap(memStream);
}
catch (OutOfMemoryException ex)
{
GC.WaitForPendingFinalizers();
Bitmap b = new Bitmap(memStream);//sometimes error comes here
}
if (bitmap != null)
{
PhotoCaptured(bitmap, null);
}
}
catch (AccessViolationException ave)
{
throw new CameraDownloadException("Error copying unmanaged stream to managed byte[].", ave);
}
finally
{
gcHandle.Free();
EDSDK.EdsRelease(stream);
EDSDK.EdsRelease(streamPtr);
}
}
catch (OutOfMemoryException ex)
{
GC.WaitForPendingFinalizers();
IboothmeObject.minimizeMemory();
getCapturedItem(directoryItem);
}
}
else
{
throw new CameraDownloadException("Unable to get resultant image.", err);
}
}
На стороне формы изображение просто обновляется в окне изображения
private void StartLiveView()
{
if (this.liveView.Connected)
{
this.liveView.PhotoCaptured += new EventHandler(liveView_PhotoCaptured);
this.liveView.NewFrame += new EventHandler(liveView_NewFrame);
this.liveView.StartLiveView();
}
}
void liveView_NewFrame(object sender, EventArgs e)
{
this.picMain.Image = sender as Image;
}
void liveView_PhotoCaptured(object sender, EventArgs e)
{
Image img = sender as Image;
// this image is big in size like 5000x3000.
Bitmap tempbitmap = new Bitmap(img.Width, img.Height);// now mostly error comes here
tempbitmap.SetResolution(img.HorizontalResolution, img.VerticalResolution);
using (Graphics g = Graphics.FromImage(tempbitmap))
{
g.DrawImage(img, new Rectangle(0, 0, img.Width, img.Height));
g.Save();
}
picMain.Image = tempbitmap;
tempbitmap.Save(path,ImageFormat.Jpeg);
}
Еще одна область кода, которая использует растровое изображение и просмотр в реальном времени с камеры. Этот код получает кадр с камеры и записывает некоторые объекты в кадр. В моем случае я пишу несколько шариков на кадре.
void liveView_NewFrame(object sender, EventArgs e)
{
using (Image<Bgr, byte> Frame = new Image<Bgr, byte>(new Bitmap(sender as Image)))
{
Frame._SmoothGaussian(3);
IntPtr hsvImage = CvInvoke.cvCreateImage(CvInvoke.cvGetSize(Frame), Emgu.CV.CvEnum.IPL_DEPTH.IPL_DEPTH_8U, 3);
CvInvoke.cvCvtColor(Frame, hsvImage, Emgu.CV.CvEnum.COLOR_CONVERSION.CV_BGR2HSV);
Image<Gray, byte> imgThresh = new Image<Gray, byte>(Frame.Size);
imgThresh.Ptr = GetThresholdedImage(hsvImage);
//CvInvoke.cvSmooth(imgThresh, imgThresh, Emgu.CV.CvEnum.SMOOTH_TYPE.CV_GAUSSIAN, 3, 3, 3, 3);
#region Draw the contours of difference
//this is tasken from the ShapeDetection Example
Rectangle largest = new Rectangle();
try
{
using (MemStorage storage = new MemStorage()) //allocate storage for contour approximation
//detect the contours and loop through each of them
for (Contour<Point> contours = imgThresh.Convert<Gray, Byte>().FindContours(
Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE,
Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_EXTERNAL,
storage);
contours != null;
contours = contours.HNext)
{
//Create a contour for the current variable for us to work with
Contour<Point> currentContour = contours.ApproxPoly(contours.Perimeter * 0.05, storage);
//Draw the detected contour on the image
if (currentContour.Area > ContourThresh) //only consider contours with area greater than 100 as default then take from form control
{
if (currentContour.BoundingRectangle.Width > largest.Width && currentContour.BoundingRectangle.Height > largest.Height)
{
largest = currentContour.BoundingRectangle;
}
}
//storage.Dispose();
}
}
catch (Exception)
{
}
#endregion
#region Draw Object
Random r = new Random();
//Bitmap bb = Frame.Bitmap;
foreach (var item in objectList)
{
using (Graphics g = Graphics.FromImage(Frame.Bitmap))
{
if (DrawAble(item, largest))
{
if (item.Y < 0)
{
if (item.X < picMain.Width)
{
g.DrawImage(item.image, new Rectangle(item.X, 0, item.image.Width, item.image.Height + item.Y),
new Rectangle(), GraphicsUnit.Pixel);
item.X += r.Next(-5, 5);
item.Y += 15;
}
}
else
{
if (item.X < picMain.Width && item.Y < picMain.Height)
{
g.DrawImage(item.image, new Rectangle(item.X, item.Y, item.image.Width, item.image.Height));
item.X += r.Next(-5, 5);
item.Y += 15;
}
else
{
item.X = r.Next(0, picMain.Width - 5);
item.Y = r.Next(-item.image.Height, -5);
}
}
}
else
{
item.X = r.Next(0, picMain.Width - 5);
item.Y = r.Next(-item.image.Height, -5);
}
}
}
#endregion
picMain.Image = Frame.ToBitmap();
}
minimizeMemory();
}
Теперь я подробно расскажу о всей проблеме. Прежде всего, я создал форму для просмотра в реальном времени и, используя библиотеку opencv (Emgu), рисую воздушные шары на кадре. В режиме реального времени эти воздушные шары движутся. Другая форма предназначена для захвата изображения с камеры с высоким разрешением. Я заметил, что память моего приложения увеличивалась с каждым кадром, и после 2 просмотров в реальном времени и захвата 2 изображений она достигает 1+ ГБ. Если я попытался снова показать первую форму для просмотра в реальном времени, в функции UpdatePicture() произошла ошибка. затем я добавляю код, чтобы минимизировать память текущего приложения. Теперь я вызываю эту функцию после каждого кадра в режиме реального времени. После этого решения, когда я проверил память приложения, она не превышала 100 МБ или 200 МБ. Но проблема осталась. После нескольких захватов возникла ошибка в UpdatePicture() при получении растрового изображения из потока ( растровое изображение = новое растровое изображение (memStream);). Ошибка была такой же из-за нехватки памяти. После некоторого поиска я нашел это решение.
// get the bitmap
Bitmap bitmap = null;
try
{
bitmap = new Bitmap(memStream);
}
catch (OutOfMemoryException ex)
{
GC.WaitForPendingFinalizers();
bitmap = new Bitmap(memStream);
}
Но не рабочая ошибка все та же.
Ошибка иногда отображалась в методе UpdatePicture(), иногда возникала в методе liveView_NewFrame. Означает, что проблема связана с растровым изображением, размером растрового изображения или повреждением памяти. Поэтому, пожалуйста, помогите мне. Я беспокоюсь, прошло 2 недели, но я не мог решить эту проблему.
OutOfMemoryException
будет брошен, уже слишком поздно думать о сборщике мусора — он уже сделал все возможное и потерпел неудачу. Каждый раз, когда вы пишете код, который вызывает классGC
(кромеKeepAlive
), вы, вероятно, делаете что-то не так. - person Damien_The_Unbeliever   schedule 10.07.2013