2015-03-24 4 views
6

Редактировать: SOLVED! Подробнее см. Мой ответ ниже. Мне не удалось найти ответ на исходный вопрос, но я нашел альтернативное решениеПреобразование изображения в C#

Этот вопрос может быть задан где-то в другом месте, но я искал дни и не могу найти ничего, что поможет.

Вопрос: мне нужно преобразовать «поток» на «изображение (BGR, байты)» на одном дыхании, есть ли способ/команда для преобразования непосредственно из System.Drawing.Image.FromStream в Emgu. CV.Image (BGR, байт) без преобразования из потока к изображения к растровый к изображения (БГР, байт)?

Информация: Я кодирования в C# в Visual Studio 2010 как часть моей диссертации проекта. Я беру поток изображений с IP-камеры в сети и применяю много алгоритмов для обнаружения лиц/экстрактов лицевых функций и распознавания лиц. На моем ноутбуке локальная камера я могу достичь FPS около 25 ~ (дать или взять), включая алгоритмы, потому что мне не нужно преобразовывать изображение. Для потока IP-камеры мне нужно многократно преобразовать его для достижения желаемого формата, а результат - около 5-8 кадров в секунду.

(Я знаю, что мой текущий метод чрезвычайно неэффективен, поэтому я здесь, я фактически конвертирую изображение в 5 раз (даже серое масштабирование), на самом деле только половину памяти моего процессора (i7, 8gb ОЗУ)). Это должно быть изображение (bgr, byte), так как это единственный формат, с которым будут работать алгоритмы.

код, я использую, чтобы получить изображение:

//headers 
using System.IO 
using System.Threading; 
using System.Net; 
//request a connection 
req = (HttpWebRequest)HttpWebRequest.Create(cameraUrl); 
//gives chance for timeout for errors to occur or loss of connection 
req.AllowWriteStreamBuffering = true; 
req.Timeout = 20000; 
//retrieve response (if successfull) 
res = req.GetResponse(); 
//image returned 
stream = res.GetResponseStream(); 

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

//Convert stream to image then to bitmap 
Bitmap bmpImage = new Bitmap(System.Drawing.Image.FromStream(stream));      
//Convert to emgu image (desired goal) 
currentFrame = new Emgu.CV.Image<Bgr, Byte>(bmpImage); 
//gray scale for other uses 
gray = currentFrame.Convert<Gray, Byte>(); 

Я понимаю, есть способ, чтобы сохранить изображение на месте временно, но я должен был бы избежать, что в целях безопасности. Я ищу больше для прямого преобразования, чтобы помочь сохранить вычислительную мощность. Я что-то пропускаю? Вся помощь приветствуется.

Спасибо за чтение. (Я уточню это, если кто-нибудь запросит более подробную информацию) -Dave

+0

Можете ли вы использовать класс секундомера для измерения производительности каждой линии? (для последних 3 строк) –

+0

Я не использовал это для измерения производительности, но если вы дадите мне некоторое время, я удалю что-нибудь вместе и прокомментирую. Последние 3 строки замедляют его, когда он делает 5 преобразований, обращаясь к выводам изображений и выводам алгоритма рендеринга при получении следующего кадра. – Hughsie28

+0

@VanoMaisuradze. Секундомер показывает, что для завершения задачи для завершения задачи было выполнено 00: 00: 00: 0343616. эти 3 строки в частности (подумайте, что в миллисекундах). – Hughsie28

ответ

3

Я считаю, что нашел ответ на мою проблему. Я пробовал использовать Идея обработки Vano Maisuradze в памяти, которая улучшила fps крошечный запас (не сразу заметный без тестирования). А также благодаря Плинтус Ответ: У меня есть понимание многопоточности, и я могу оптимизировать это, пока я прогрессирую, поскольку я могу разделить алгоритмы на параллельную работу.

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

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

Вывод:

  • Многопоточность оптимизировать
  • Обработка в памяти вместо того, чтобы постоянно преобразовывать
  • Лучшие сетевые решения (более высокую пропускную способность и скорость)

Edit: Код для получения изображения и обработки в памяти для тех, кто находит это в поисках помощи

public void getFrames(object sender, EventArgs e) 
{//Gets a frame from the IP cam 
    //Replace "IPADDRESS", "USERNAME", "PASSWORD" 
    //with respective data for your camera 
    string sourceURL = "http://IPADDRESS/snapshot.cgi?user=USERNAME&pwd=PASSWORD"; 
    //used to store the image retrieved in memory 
    byte[] buffer = new byte[640 * 480]; 
    int read, total = 0; 

    //Send a request to the peripheral via HTTP 
    HttpWebRequest req = (HttpWebRequest)WebRequest.Create(sourceURL); 
    WebResponse resp = req.GetResponse(); 

    //Get the image capture after recieving a request 
    //Note: just a screenshot not a steady stream 
    Stream stream = resp.GetResponseStream(); 
    while ((read = stream.Read(buffer, total, 1000)) != 0) 
    { 
     total += read; 
    }//While End 

    //Convert memory (byte) to bitmap and store in a picturebox  
    pictureBox1.Image = (Bitmap)Bitmap.FromStream(new MemoryStream(buffer, 0, total)); 
}//getFrames End 

private void button1_Click(object sender, EventArgs e) 
{//Trigger an event to start running the function when possible 
    Application.Idle += new EventHandler(getFrames); 
}//Button1_Click End 
2

Вы можете сохранить несколько изображений в памяти (буфере), а затем начать обработку из буфера.

Что-то вроде этого:

//Convert stream to image then to bitmap 
Bitmap bmpImage = new Bitmap(System.Drawing.Image.FromStream(stream));      
//Convert to emgu image (desired goal) 
currentFrame = new Emgu.CV.Image<Bgr, Byte>(bmpImage); 

//gray scale for later use 
gray = currentFrame.Convert<Gray, Byte>(); 
SaveToBuffer(gray); 

Queue<Emgu.CV.Image<Gray, Byte>> buffer = new Queue<Emgu.CV.Image<Gray, Byte>>(); 
bool canProcess = false; 

// ... 

private void SaveToBuffer(Emgu.CV.Image<Gray, Byte> img) 
{ 
    buffer.Enqueue(img); 
    canProcess = buffer.Count > 100; 
} 

private void Process() 
{ 
    if(canProcess) 
    { 
     buffer.Dequeue(); 
     // Processing logic goes here... 
    } 
    else 
    { 
     // Buffer is still loading... 
    } 
} 

Но обратите внимание, что вам потребуется достаточно оперативной памяти для хранения изображений в памяти, а также вы должны настроить размер буфера к мясу требованиям.

+0

Это достойная идея, я буду исследовать методы преобразования памяти. У меня есть хорошие характеристики ОЗУ, поэтому я должен попробовать этот метод. – Hughsie28

3

У вас есть пара потенциальных узких мест, и не в последнюю очередь это то, что вы, вероятно, jpeg, декодируете поток в изображение, а затем преобразуете его в растровое изображение, а затем в изображение openCV.

Один из способов обойти это полностью. Это будет связано с попыткой напрямую использовать libjpeg. В C# есть free port of it here, а IIRC вы можете подключиться к нему, чтобы получить вызов на основе сканирования для заполнения буфера.

Недостатком является то, что вы дешифрируете данные JPEG в управляемом коде, который будет работать как минимум на 1,5X медленнее, чем эквивалент C, хотя, честно говоря, я ожидал бы, что скорость сети значительно изменится.

OpenCV должен иметь возможность непосредственно просматривать jpeg-изображения (хотите угадать, что они используют под капотом? Survey говорит: libjpeg), что означает, что вы можете буферизовать весь поток и передать его OpenCV и обходить слой .NET полностью.

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