2010-09-12 1 views
2

Я использую этот PictureBox на форме, в это окно изображения Я использую код AForge. Я передаю СПРАВОЧНИК pictureBox в класс веб-камеры, который я создаю, который инициализирует веб-камеру и сообщает ей, где рисовать свои фреймы .... так что он счастливо рисует его фреймами ... нет проблем.Как пополнить безопасный вызов PictureBox.Image в C#, в настоящее время дает одну из 3 ошибок

Но определенное время (когда я хочу, чтобы сделать материал с указанным изображением, если коробка ПРОВ нажата) ... Я начинаю этот таймер с помощью простого кода:

timer1.Enabled = true; 

интервала этого таймера устанавливаются в 33.

Так что теперь его обжиг вместе и каждый раз через петлю мой код имеют следующее:

private void timer1_Tick(object sender, EventArgs e) 
{ 
    ... 
    double value = detector.ProcessFrame(new Bitmap(picCapture.Image)); //errors here 
    ... 

     TimerCallback tc = new TimerCallback(sendDataFast); 
     System.Threading.Timer t = new System.Threading.Timer(tc, null, 2000, Timeout.Infinite); 

} 

эта линия выше имеет один из трех ошибок, которые я видел на нем (Stack следов где Доступны ле):

Object is currently in use elsewhere.

Out of Memory. (A first chance exception of type 'System.OutOfMemoryException' occurred in System.Drawing.dll)

Parameter not valid (A first chance exception of type 'System.ArgumentException' occurred in System.Drawing.dll)

Я уверен, эти вопросы резьб, но я понятия не имею, как иметь дело с ними ... Я полностью потерял. Если программа зависает на этой строке выше, я обычно могу снова запустить прогон в отладчике, и все хорошо. Но я не хочу быть неряшливым и просто ставить волей-неволей попытку поймать, что продолжается. Я хотел бы выяснить корень этой проблемы.

Я видел где-то еще кто-то сказал, что это может быть проблема с резьбой и поставить эту строку: System.Diagnostics.Debug.Assert (! This.InvokeRequired, " InvokeRequired ");

Итак, я сделал это в начале этого метода time1_click, но утверждение, похоже, не происходит, но я не уверен, что это было подходящее место для assert ... is timer1_click в потоке пользовательского интерфейса или нет?

Я подозреваю теперь, что я рассмотрел мой код его что-то с тем, как я инициализирует свой веб-класс:

Или в этом timer1_click я также сделать вызов этого метода:

void sendDataFast(Object stateObject) 
{ 
    EmergencyDelegate delEmergency = 
      new EmergencyDelegate(mic.sendDataEmergency); 

    // call the BeginInvoke function! //sendDataEmergency takes in a picture Image picImage as an argument. 
    delEmergency.BeginInvoke(picCapture.Image, null, null); 
} 

И для полноты это как я инициализировать мой веб-класс:

 webcam = new WebCam(); 
     webcam.InitializeWebCam(ref picCapture, ref picComparator, ref dataObject, this);   //guessing this is calling threading issues   

Те три ошибки, которые случаются не бывает сразу, кажется, происходит случайным образом один из трех .... LEA ds мне думать, что это проблема с потоками, но как еще я могу это исправить? создав делегата по какой-либо причине, который возвращает это двойное значение и вызывается, если invoke required является истинным?

+0

r u все еще получает ошибки? – TalentTuner

ответ

2

is timer1_click в пользовательском интерфейсе или нет?

В зависимости от того, какой таймер вы используете. sendDataFast определенно не потому, что вы использовали System.Threading.Timer.

Если вы посмотрите на документацию MSDN по System.Threading.Timer вы увидите следующее

System.Threading.Timer простой, легкий таймер, который использует обратного вызова методы и обслуживается пулом потоков потоков. Не рекомендуется использовать с Windows Forms, поскольку его обратные вызовы не возникают у пользователя . System.Windows.Forms.Timer - лучший выбор для использования с Windows Forms.choice для использования с Windows Forms.

Это объясняет, почему вы замерзаете.

Метод обратного вызова выполняется с помощью таймера должно быть повторно, потому что она вызывается Threadpool нитей. обратный вызов может быть выполнен одновременно на два пул потоков потоков, если интервал таймера меньше , чем время, необходимое для выполнения обратного вызова, или если все пул потоков нити используется и обратный вызов в очереди несколько раз.

Это означает, что если ваша функция не может быть выполнена менее чем за 33 мс, функция будет вызвана снова. Вероятно, это так, и почему вы получаете исключения, которые видите. Два или более потока пытаются использовать один и тот же файл. У вас может также быть несколько потоков, пытающихся выделить большой блок памяти, и один не может получить блок запрошенного размера. Не знаете, почему вы получаете исключение аргумента, но это может быть из-за предыдущих двух.

По этой причине я предпочитаю System.Timers.Timer. Он имеет свойство AutoReset, которое устанавливает false. Затем в конце моей функции я вызываю Timer.Start. Вы можете сделать то же самое с другими таймерами, но его немного обмануть.

Вот три ссылки вы можете найти полезную

Article on Comparison of the Timer Classes

Jon Skeet Answer on a Begin Invoke Question

Eric Lippert Blog on what an OutOfMemory Exception likely is

+0

Спасибо, я не уверен, что выше было ясно, но что timer1_click, который вызывается, действительно является таймером форм, думаю, я мог бы просто отказаться от этого и заменить его на системный? в основном система может быть «вооружена», а при ее включении таймер вызывается и чтобы не пропустить ничего, что вызывало его вызываемые каждые 33 мс (что, по моему мнению, было близко к моим камерам fps). – Codejoy

+0

, если вы хотите стрелять каждые 33 мс, вам нужно будет убедиться, что рамка процесса повторно активирована. –

1

Я думаю, видя эту линию

double value = detector.ProcessFrame(new Bitmap(picCapture.Image)); 

вы пытаетесь изменить picCapture.Image, который является PictureBox изображение, и вы делаете это каждые 33 миллисекунд.

1-й Что такое этот детектор.ProcessFrame?

2- Вы должны передать фактический URI изображений на New Bitmap, а не использовать изображение, которое является источником PictureBox

3- Почему вы создаете больше таймеров в случае клещевого ????

+0

в основном, если это двойное значение больше некоторого числа, оно обнаруживает движение, и я хочу, чтобы событие срабатывало через * 2 секунды после этого движения. Таким образом, для чего нужен другой таймер, его планировщик ... детектор .ProcessFrame проверяет, есть ли движение между двумя кадрами ... это из библиотеки, которую я использую: 'AForge.Vision.Motion'. Как передать URI изображения вместо самого изображения? – Codejoy

+0

Таймер установлен на 33 __milliseconds__. Он имеет разрешение около 20 миллисекунд. –

1

Для OutOfMemoryException, я предлагаю заменить

double value = detector.ProcessFrame(new Bitmap(picCapture.Image)); 

с

double value; 
using(Bitmap bmp = new Bitmap(picCapture.Image)) { 
    value = detector.ProcessFrame(bmp); 
} 

поэтому ваш временный растровый образ будет таким же, как и должен быть.

+0

Да, выглядит лучше. Но класс Image странный, я помню что-то об этом, бросая OOM по нескольким причинам, не связанным с памятью. –

Смежные вопросы