2012-07-23 12 views
6

का उपयोग कर वेबकैम से वीडियो कैप्चर करते समय फ्रीज करता है मैं कुछ वास्तविक समय वीडियो प्रोसेसिंग के लिए ओपनसीवी का उपयोग कर रहा हूं।क्यूटी जीयूआई ओपनसीवी

फ्रंट-एंड के रूप में मैं क्यूटी फ्रेमवर्क का उपयोग कर रहा हूं।

मेरे जीयूआई पर, मेरे पास एक इनपुट छवि विंडो (लेबल में मैप किया गया) और एक आउटपुट छवि विंडो (किसी अन्य लेबल में मैप की गई) और 3 पुश बटन हैं। एक इनपुट इनपुट वीडियो शुरू करने के लिए, वीडियो को संसाधित करने वाला दूसरा (कोड अभी तक लिखा नहीं गया है), और बाहर निकलने के लिए तीसरा।

मैं वर्तमान में अपने वीडियो को स्ट्रीम करने और फ्रंट-एंड पर प्रदर्शित करने में सक्षम हूं। लेकिन यह मेरे जीयूआई को ताला लगा देता है और बाहर निकलने में असमर्थ हूं।

मैंने क्यूटीमर्स (इस और क्यूटी मंच से सुझावों का उपयोग करके) का उपयोग करने की कोशिश की, लेकिन मेरा जीयूआई अभी भी बंद है।

कोई सराहना करेगा अगर कोई मुझे सही दिशा में इंगित कर सकता है। ,

mainwindow.h 

#ifndef MAINWINDOW_H 
#define MAINWINDOW_H 

#include <QMainWindow> 
#include <opencv2/highgui/highgui.hpp> 
#include <opencv2/core/core.hpp> 
#include <opencv2/imgproc/imgproc.hpp> // for cvtColor 
#include <iostream> 
#include <QTimer> 

namespace Ui { 
class MainWindow; 
} 

class MainWindow : public QMainWindow 
{ 
    Q_OBJECT 

public: 
    explicit MainWindow(QWidget *parent = 0); 
    ~MainWindow(); 

private slots: 
    void on_buttonCaptureVideo_clicked(); 

    void on_buttonExit_clicked(); 

public slots: 
    virtual void doNextFrame() {repaint();} 

private: 
    Ui::MainWindow *ui; 
    CvCapture *capture;   // OpenCV Video Capture Variable 
    IplImage *frame;   // Variable to capture a frame of the input video 
    cv::Mat source_image;  // Variable pointing to the same input frame 
    cv::Mat dest_image;  // Variable to output a frame of the processed video 
    QTimer *imageTimer; 
}; 

#endif // MAINWINDOW_H 

mainwindow.cpp

#include "mainwindow.h" 
#include "ui_mainwindow.h" 

MainWindow::MainWindow(QWidget *parent) : 
    QMainWindow(parent), 
    ui(new Ui::MainWindow) 
{ 
    ui->setupUi(this); 
} 

MainWindow::~MainWindow() 
{ 
    delete ui; 
    cvReleaseImage(&frame); 
    cvReleaseCapture(&capture); 
} 

void MainWindow::on_buttonCaptureVideo_clicked() 
{ 
    // Set to 25 frames per second 

    const int imagePeriod = 1000/25; // ms 

    imageTimer = new QTimer(this); 

    imageTimer->setInterval(imagePeriod); 

    connect(imageTimer, SIGNAL(timeout()), this, SLOT(doNextFrame())); 

    // Use the default camera 
    capture = cvCreateCameraCapture(-1); 

    while(capture) 
    { 
    // Capture a frame 
    frame = cvQueryFrame(capture); 

    // Point to the same frame 
    source_image = frame; 

    // Resize Image 
    cv::resize(source_image, source_image, cv::Size(128,128) , 0, 0); 

    // Change to RGB format 
    cv::cvtColor(source_image,source_image,CV_BGR2RGB); 

    // Convert to QImage 
    QImage qimg = QImage((const unsigned char*) source_image.data, source_image.cols, source_image.rows, QImage::Format_RGB888); // convert to QImage 

    // Display on Input Label 
    ui->labelInputVideo->setPixmap(QPixmap::fromImage(qimg)); 

    // Resize the label to fit the image 
    ui->labelInputVideo->resize(ui->labelInputVideo->pixmap()->size()); 

    } 
} 

void MainWindow::on_buttonExit_clicked() 
{ 

    connect(ui->buttonExit, SIGNAL(clicked()), qApp, SLOT(closeAllWindows())); 
} 
+0

सही पर मूल्यांकन करने के लिए 'कैप्चर' कितना समय लगता है? लूप चलाने के दौरान कितना समय लगता है? – jdi

+0

@jdi: जब तक उपयोगकर्ता इनपुट वीडियो स्ट्रीम करना चाहता है, कैप्चर को सत्य का मूल्यांकन करना चाहिए। मुझे क्यूटीमर का उपयोग करके अब प्रतिक्रिया देने के लिए जीयूआई मिल गया है, लेकिन मुझे लगता है कि अगर मैं स्ट्रीमिंग को बहुत लंबे समय तक सक्रिय छोड़ देता हूं, तो मुझे संदेश मिलते हैं "कैमरा गिरावट फ्रेम!", तो मेरा अनुमान है कि आखिरकार मुझे क्यूटीएचड्स में जाने की आवश्यकता होगी। आपके जवाब के लिए धन्यवाद। – Sid

+0

@Sid, क्या आप कोड को काम कर सकते हैं, कृपया? धन्यवाद –

उत्तर

5

जब आप अपने बटन क्लिक करें,

while(capture) { ... } 

पाश हमेशा के लिए चला जाएगा के रूप में capture कभी नहीं होगा:

नीचे कोड है पूर्ण करने के लिए सेट करें। इसका मतलब है कि कोड प्रवाह कभी भी आपके लूप को नहीं छोड़ता है और इस प्रकार मुख्य धागा किसी और चीज को संसाधित नहीं कर सकता है, जैसे उदा। repainting।

क्यूटीमर अपने टाइमआउट() संकेतों को छोड़ देगा, लेकिन उन्हें क्यूटी की घटना कतार में घटनाओं के रूप में रखा जाएगा। जब तक आपकी on_buttonCaptureVideo_clicked() विधि चल रही है, तब तक उन ईवेंट को संसाधित नहीं किया जाएगा।


इस कोड: MainWindow के निर्माता में

// Set to 25 frames per second 
const int imagePeriod = 1000/25; // ms   
imageTimer = new QTimer(this);   
imageTimer->setInterval(imagePeriod);   
connect(imageTimer, SIGNAL(timeout()), this, SLOT(doNextFrame())); 
// Use the default camera    
capture = cvCreateCameraCapture(-1); 

अंतर्गत आता है आपको लगता है कि केवल एक बार सेट अप करना चाहते हैं के रूप में

यहाँ कैसे यह काम करने के लिए अपने सुझाव दिए गए हैं। जब उपयोगकर्ता दूसरे, तीसरे, आदि बटन पर क्लिक करता है तो इसे फिर से करने की आवश्यकता नहीं होती है।

आपके while लूप के भीतर कोड जो doNextFrame() स्लॉट (बिना निर्माण के) में जाना चाहिए।

फिर अपने बटन केवल करेंगे

imageTimer->start(); 

और फिर जैसे

imageTimer->stop(); 

जब इसे फिर से क्लिक किया जाता है।

उदाहरण कोड:

void MainWindow::on_buttonCaptureVideo_clicked() 
{ 
    if(imageTimer->isActive()) 
    { 
     imageTimer->stop(); 
    } 
    else 
    { 
     imageTimer->start(); 
    } 
} 

अगर आप ऐसा कर क्या होगा?

जब आप बटन पर क्लिक करते हैं, तो आपके on_buttonCaptureVideo_clicked() क्लिक किए गए स्लॉट को जीयूआई थ्रेड से बुलाया जाएगा, टाइमर शुरू हो जाएगा, और विधि लगभग तुरंत लौट जाएगी।
अब जीयूआई थ्रेड मुक्त है और पश्चाताप इत्यादि को संभालने में सक्षम है
उस बिंदु से, टाइमर टाइमआउट() प्रत्येक 40ms सिग्नल भेज देगा। जब भी जीयूआई थ्रेड मुक्त होता है, तो यह इस सिग्नल को संभालेगा और आपके doNextFrame स्लॉट को कॉल करेगा।
यह स्लॉट अगले फ्रेम को कैप्चर करेगा और इसे पूरा होने पर वापस कर देगा। जब यह किया जाता है, तो जीयूआई थ्रेड फिर से अन्य घटनाओं (उदा। पुन:) को संसाधित करने में सक्षम होगा।
जैसे ही आप बटन को फिर से क्लिक करते हैं, टाइमर रुक जाएगा, और कोई नया टाइमआउट() ईवेंट नहीं भेजे जाएंगे। यदि बटन पर क्लिक करने के बाद भी आप कुछ फ्रेम देखते हैं, तो इसका मतलब यह हो सकता है कि टाइमर ईवेंट संसाधित किए जाने से तेज़ी से भेजे गए थे।

+0

आपके उत्तर के लिए धन्यवाद। मैं आपके सुझाव के आधार पर जीयूआई जवाब देने में सक्षम था। – Sid

2

प्रस्तावना: मैं सी में मजबूत नहीं कर रहा हूँ तो मैं ++ विशिष्ट कोड प्रदान नहीं कर सकते, लेकिन मैं PyQt

में अनुभवी हूँ यह क्यूटी के लिए नए लोगों के लिए एक आम ख़तरा है। ऐसा लगता है कि आपका on_buttonCaptureVideo_clicked काम करने के लिए आपके मुख्य जीयूआई थ्रेड में लूप में प्रवेश कर रहा है। क्यूटी में, आप अपने मुख्य धागे में व्यस्त कुछ भी करना चाहते हैं। क्यूटी इवेंटलोप को आपके जीयूआई कार्यक्रमों को लगातार संसाधित करने और फ्लश करने में सक्षम होना चाहिए। आप जो कर रहे हैं वह ईवेंट लूप को अवरुद्ध कर रहा है।

यहां दो अलग-अलग चीजें हैं जो आप यहां कर सकते हैं। पहला अधिक बुनियादी दृष्टिकोण है लेकिन आपको अधिक तत्काल परिणाम देखने की अनुमति देता है। आप eventloop "पंप" कर सकते हैं। इस पर निर्भर करता है कि आपके while लूप इटेटेट्स कितनी तेजी से हैं, आप qApp->processEvents(); पर कॉल कर सकते हैं। यह क्यूटी को लंबित जीयूआई कार्यक्रमों को संसाधित करने और आपके ऐप को अधिक उत्तरदायी दिखाई देने की अनुमति देगा। यह मूल रूप से आपके समय लूप और मुख्य पाश के बीच समय साझा कर रहा है। शायद आप इसे हर एनएच फ्रेम पर कॉल करना चाहते हैं। निर्भर करता है कि आप कितनी बार यह सुनिश्चित करना चाहते हैं कि जीयूआई रीफ्रेश हो।

दूसरा विकल्प, जो अधिक बेहतर है, अपने कैप्चर लूप को QThread में रखना है। जब कोई नया फ्रेम उपलब्ध होता है तो आप फ्रेम डेटा के साथ सिग्नल उत्सर्जित कर सकते हैं। सिग्नल क्यूटी इवेंट लूप में बाकी सब कुछ के साथ संसाधित होने के लिए रखा जाएगा और आपके जीयूआई को पकड़ नहीं पाएगा। आम तौर पर यह वह दृष्टिकोण है जिसे आप किसी भी भारी क्रंचिंग या लंबे समय तक चलने वाले कॉलबेल के साथ लेना चाहते हैं।

संपादित

मैं सिर्फ महसूस किया कि आप मुख्य थ्रेड में एक पाश कर के अलावा एक QTimer शुरू करते हैं। यदि आप क्यूटीमर का उपयोग करना चाहते हैं, और आपकी छवि प्रसंस्करण बहुत भारी नहीं है (इसमें प्रति चक्र लंबा नहीं लगता है) तो आपको सबकुछ doNextFrame में ले जाना चाहिए और while लूप को पूरी तरह से हटा देना चाहिए। यदि आपकी doNextFrame एक भारी प्रक्रिया है, तो आपको QThread और सिग्नल का उपयोग करना चाहिए।

संबंधित मुद्दे