2015-05-04 16 views
14

Videoyu bir mjpeg akışı veren bir web kamerası üzerinden yakalıyorum. Video çekmeyi bir çalışan iş parçacığında yaptım. Böyle yakalama başlatmak: Kamera Saniyede 20 kare üzerinden akışı besliyorOpenCV VideoCapture, yakalama arabelleği nedeniyle gecikme

const std::string videoStreamAddress = "http://192.168.1.173:80/live/0/mjpeg.jpg?x.mjpeg"; 
qDebug() << "start"; 
cap.open(videoStreamAddress); 
qDebug() << "really started"; 
cap.set(CV_CAP_PROP_FRAME_WIDTH, 720); 
cap.set(CV_CAP_PROP_FRAME_HEIGHT, 576); 

. Ama hiç böyle Saniyede 20 kare içinde okuma yapsam:

if (!cap.isOpened()) return; 

     Mat frame; 
     cap >> frame; // get a new frame from camera 
     mutex.lock(); 

     m_imageFrame = frame; 
     mutex.unlock(); 

Sonra saniye gecikme bir 3+ yoktur. Bunun nedeni, yakalanan videonun ilk önce bir tamponda saklanmasıdır. Kamerayı ilk başlattığımda, arabellek biriktirilir ancak çerçeveleri okumadım. Yani tampondan okursam, bana daima eski çerçeveleri verir. Şu anda sahip olduğum tek çözüm, arabayı 30 fps'de okumaktır, böylece arabelleği hızlı bir şekilde temizler ve daha ciddi bir gecikme olmaz.

Kamerayı her başlattığımda arabayı el ile temizleyebilmem/temizleyebilmem için başka olası bir çözüm var mı?

+1

Neden 20 fps ile sınırlamak istiyorsunuz? İşçi işinde mi bekliyorsun? – mirosval

+1

, kendi bir veya cv :: VideoCapture içindeki bir şey tampon mu? – Micka

+0

@ mirosval, evet, yaptım çünkü çok fazla cpu istemiyorum ... – Nyaruko

cevap

16

this kaynağına göre, cv::VideoCapture nesnesinin arabelleğe alınmasını ayarlayabilirsiniz.

cv::VideoCapture cap; 
cap.set(CV_CAP_PROP_BUFFERSIZE, 3); // internal buffer will now store only 3 frames 

// rest of your code... 

ancak önemli bir sınırlama vardır: iç tampon belleği içinde depolanmış çerçevelerin

CV_CAP_PROP_BUFFERSIZE Miktarı (not: yalnızca şu anda DC1394 v 2.x arka uç tarafından desteklenen)


Çözüm işe yaramazsa, nasıl yapılacağını açıklayan this post numaralı sayfaya bakın. Sorun etrafında ack. Özetle: bir çerçeveyi sorgulamak için gereken süre ölçülür; Çok düşükse, çerçevenin arabellekten okunduğu ve atılabileceği anlamına gelir. Ölçülen süre belirli bir sınırı aşana kadar kareleri sorgulamaya devam edin. Bu olduğunda, tampon boştu ve geri dönen çerçeve güncel.

(bağlantılı sonrası şovlarda cevap: tampon bir kare dönen tarih çerçevesine kadar bir dönme zamanı yaklaşık 1/8th alır Kilometre değişebilir, tabii ki.!)


this postundan esinlenilen farklı bir çözüm, arabelleği boş tutmak için yüksek hızda sürekli olarak kareleri yakalayan üçüncü bir iplik oluşturmaktır. Bu iş parçacığı, yükü önlemek için cv::VideoCapture.grab() kullanmalıdır.

Gerçek çalışan iş parçacığı ile üçüncü iş parçacığı arasındaki okuma çerçevelerini senkronize etmek için basit bir döndürme kilidi kullanabilirsiniz.

+1

Aslında merak ediyorum, zamanın ölçüsünü yerine arabelleğin boş olup olmadığını söylemenin bir yolu var. 'Cv :: VideoCapture' arayüzü Bu bilgiyi elde etmek izin vermez – Nyaruko

+2

... oldukça zahmetli bir iştir. Başka bir çözüm, sürekli olarak kareleri yakalayan farklı bir iş parçacığı oluşturmaktır (['cv :: VideoCapture.grab()' ile] (http://docs.opencv.org/modules/highgui/doc/reading_and_writing_images_and_video.html#videocapture-grab)) yüksek hızda. Bu, gerçek çalışan iş parçacığının bir sonraki çerçeveyi okuduğunda arabelleğin boş olacağını (ve elbette çerçeveleri okurken bu iş parçacığı eşzamanlamayı unutmayın). –

+0

Teşekkürler, şu anda yapıyorum. – Nyaruko

2

Çerçeveyi tutmanın biraz zaman aldığından emin olabilirsiniz. Güvenilmez olsa da, kod için oldukça basittir; potansiyel olarak, bu kod bir kilitlenme yol açabilir.

#include <chrono> 
using clock = std::chrono::high_resolution_clock; 
using duration_float = std::chrono::duration_cast<std::chrono::duration<float>>; 
// ... 
while (1) { 
    TimePoint time_start = clock::now(); 
    camera.grab(); 
    if (duration_float(clock::now() - time_start).count() * camera.get(cv::CAP_PROP_FPS) > 0.5) { 
     break; 
    } 
} 
camera.retrieve(dst_image); 

Bu kod C++ 11'i kullanır.

+0

[docs] (http: // docs. opencv.org/2.4/modules/highgui/doc/reading_and_writing_images_and_video.html) Fonksiyonun birincil kullanımı, özellikle kameraların donanım senkronizasyonu olmadığı durumlarda, çoklu kamera ortamlarında kullanılır. Yani, her kamera için VideoCapture :: grab() yöntemini çağırırsınız ve daha sonra her kameranın kodunu çözmek ve çerçevelemek için daha yavaş bir yöntem olan VideoCapture :: retrieve() yöntemini çağırırsınız. Bu sayede, dinozorlama veya hareket jpeg dekompresyon vb. Ek yükü ortadan kaldırılır ve farklı kameralardan alınan kareler zamanla daha yakın olacaktır. ** Bu düzeltme değil **. Ama ben onu reddettim. – AlexanderVX