Преобразование изображения в c#

Edit: решено! пожалуйста, смотрите мой ответ ниже для деталей. Я не смог найти ответа на исходный вопрос, но я нашел альтернативное решение

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

вопрос: мне нужно преобразовать "поток" в " изображение (bgr, байт)" за один раз, есть ли способ / команда для преобразования непосредственно из Система.Рисунок.Изображение.FromStream в Эмгу.Резюме.Образ(Бгр байт) без конверсии поток to изображения to точечный to изображение (bgr, байт)?

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

(Я знаю, что мой текущий метод чрезвычайно неэффективен, поэтому я здесь, я фактически конвертирую изображение в 5 раз (даже серое масштабирование тоже), фактически используя только половину памяти моих процессоров (i7, 8GB RAM)). Он должен be image (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>();

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

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

3 ответов


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

один из способов обойти это-полностью обойти образ .NET. Это будет включать в себя попытку использовать libjpeg напрямую. Есть Свободный порт здесь В C# и IIRC вы можете подключиться к нему, чтобы получить вызов на основе каждой строки для заполнения буфер.

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

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


Я считаю, что нашел ответ на мою проблему. Я баловался, используя Майсурадзеидея обработки в памяти, которая улучшила fps крошечный запас (не сразу заметный без тестирования). А также благодаря цоколи ответ у меня есть понимание многопоточности, и я могу оптимизировать это по мере продвижения, поскольку я могу разделить алгоритмы на работу параллельно.

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

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

вывод:

  • многопоточность для оптимизации
  • обработка в памяти вместо преобразования постоянно
  • лучшие сетевые решения (более высокая пропускная способность и скорость)

Edit: код для извлечения изображения и процесса в памяти для тех, кто находит это ищет помогите!--5-->

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

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

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

//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...
    }
}

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