<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>More Than Technical &#187; qt</title>
	<atom:link href="http://www.morethantechnical.com/category/qt/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.morethantechnical.com</link>
	<description>On software, code, the internet and more.</description>
	<lastBuildDate>Mon, 06 Feb 2012 23:48:17 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=</generator>
<atom:link rel="hub" href="http://pubsubhubbub.appspot.com"/><atom:link rel="hub" href="http://superfeedr.com/hubbub"/>		<item>
		<title>Qt &amp; OpenCV combined for face detecting QWidgets</title>
		<link>http://www.morethantechnical.com/2009/03/05/qt-opencv-combined-for-face-detecting-qwidgets/</link>
		<comments>http://www.morethantechnical.com/2009/03/05/qt-opencv-combined-for-face-detecting-qwidgets/#comments</comments>
		<pubDate>Thu, 05 Mar 2009 12:19:37 +0000</pubDate>
		<dc:creator>Roy</dc:creator>
				<category><![CDATA[gui]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[qt]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[video]]></category>
		<category><![CDATA[face detection]]></category>
		<category><![CDATA[opencv]]></category>

		<guid isPermaLink="false">http://www.morethantechnical.com/?p=212</guid>
		<description><![CDATA[As my search for the best platform to roll-out my new face detection concept continues, I decided to give ol&#8217; Qt framework a go. I like Qt. It&#8217;s cross-platform, a clear a nice API, straightforward, and remindes me somewhat of Apple&#8217;s Cocoa. My intention is to get some serious face detection going on mobile devices. [...]]]></description>
			<content:encoded><![CDATA[<p>As my search for the best platform to roll-out my new face detection concept continues, I decided to give ol&#8217; Qt framework a go.</p>
<p>I like Qt. It&#8217;s cross-platform, a clear a nice API, straightforward, and remindes me somewhat of Apple&#8217;s Cocoa.</p>
<p>My intention is to get some serious face detection going on mobile devices. So that means either the iPhone, which so far did a crummy job performance-wise, or some other mobile device, preferably linux-based.<br />
This led me to the decision to go with Qt. I believe you can get it to work on any linux-ish platform (limo, moblin, android), and since Nokia baught Trolltech &#8211; it&#8217;s gonna work on Nokia phones soon, awesome!</p>
<p>Lets get to the details, shall we?<br />
<span id="more-212"></span><br />
First thing&#8217;s first: face detection.</p>
<p>I ripped OpenCV&#8217;s facedetect.c sample and extracted only the detect_and_draw() function. Originally the function detects the faces and draws a circle over them, but I needed only the face detection and the result bounding rectangle. So in the end I was left with this:</p>
<pre class="brush: cpp; title: ; notranslate">

CvRect detect_and_draw( IplImage* img, CvMemStorage* storage, CvHaarClassifierCascade* cascade )
{
IplImage *gray, *small_img;
int i = 0;

gray = cvCreateImage( cvSize(img-&gt;width,img-&gt;height), 8, 1 );
small_img = cvCreateImage( cvSize( cvRound (img-&gt;width/scale),
cvRound (img-&gt;height/scale)), 8, 1 );

cvCvtColor( img, gray, CV_RGB2GRAY );
cvResize( gray, small_img, CV_INTER_LINEAR );
cvEqualizeHist( small_img, small_img );
cvClearMemStorage( storage );

CvRect* r = NULL;

if( cascade )
{
double t = (double)cvGetTickCount();
CvSeq* faces = cvHaarDetectObjects( small_img, cascade, storage,
1.1, 2, 0
|CV_HAAR_FIND_BIGGEST_OBJECT
//|CV_HAAR_DO_ROUGH_SEARCH
//|CV_HAAR_DO_CANNY_PRUNING
//|CV_HAAR_SCALE_IMAGE
,
cvSize(30, 30) );
t = (double)cvGetTickCount() - t;

printf( &quot;detection time = %gms\n&quot;, t/((double)cvGetTickFrequency()*1000.) );

r = (CvRect*)cvGetSeqElem( faces, i );

cvReleaseImage( &amp;amp;amp;amp;amp;amp;gray );
cvReleaseImage( &amp;amp;amp;amp;amp;amp;small_img );

if(r) {
return cvRect(r-&gt;x,r-&gt;y,r-&gt;width,r-&gt;height);
} else {
return cvRect(-1,-1,0,0);
}

}
</pre>
<p>This can go anywhere in the code base, as it&#8217;s totally independant (as long as you train the cascade and allocate a MemStorage).Note that I am assuming only one face in the input image, and also that it will be the largest detected object. This bring my benchmark to about 25ms per frame, using the original general detection approach of facedetect.c benchmarked at about 160ms per frame.</p>
<p>OK, done with pure OpenCV, on to Qt.</p>
<p>I subclassed a QWidget, who&#8217;s sole purpose is to show the input video with the detected face. For starters, I needed to have a QImage and an IplImage instances as members, they can also share the same buffer (how awesome is that..). I also need a CvCapture, CvMemStorage and a CvHaarCalssifierCascade:</p>
<pre class="brush: cpp; title: ; notranslate">

class FaceRecognizer : public QWidget
{
Q_OBJECT

public:
FaceRecognizer(QWidget *parent = 0);
~FaceRecognizer();

private:
Ui::FaceRecognizerClass ui;

QImage m_i;

QRect faceLoc;

CvMemStorage* storage;
CvHaarClassifierCascade* cascade;
CvCapture* capture;
IplImage* m_opencvimg;

QTimer* m_timer;

void paintEvent(QPaintEvent* e);

public slots:
void queryFrame();
};
</pre>
<p>You can see that I&#8217;m gonna use a QTimer to query the frames from the CvCapture and also I override paintEvent to paint the frame onto the canvas. In fact in my QWidget I have a QFrame, that the image will painted over it. UI was generated in Qt Designer.</p>
<p>First, some initialization in the constructor:</p>
<pre class="brush: cpp; title: ; notranslate">

FaceRecognizer::FaceRecognizer(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);

capture = cvCaptureFromAVI( &quot;/home/user/Desktop/video.avi&quot; );
//grab one frame to get width and height

IplImage* frame = cvQueryFrame( capture );

m_i = QImage(QSize(frame-&gt;width,frame-&gt;height),QImage::Format_RGB888);
ui.frame-&gt;setMinimumSize(m_i.width(),m_i.height());
ui.frame-&gt;setMaximumSize(ui.frame-&gt;minimumSize());
//create only the header, as the data buffer is shared, and was allocated by QImage

m_opencvimg = cvCreateImageHeader(cvSize(m_i.width(),m_i.height()),8,3);
m_opencvimg-&gt;imageData = (char*)m_i.bits(); // share buffers

if( frame-&gt;origin == IPL_ORIGIN_TL )
cvCopy( frame, m_opencvimg, 0 );
else
cvFlip( frame, m_opencvimg, 0 );

//images from cvQueryFrame come in BGR form and not what Qt expects - RGB

//and since the buffers are shared - format should be consistent
cvCvtColor(m_opencvimg,m_opencvimg,CV_BGR2RGB);

//we need memstorage and a cascade
storage = cvCreateMemStorage(0);
cascade = (CvHaarClassifierCascade*)cvLoad( CASCADE_NAME, 0, 0, 0 );

//set timer for 50ms intervals

m_timer = new QTimer(this);
connect(m_timer,SIGNAL(timeout()),this,SLOT(queryFrame()));
m_timer-&gt;start(50);
}
</pre>
<p>And now, querying the frame: query CvCapture, convert BGR to RGB, detect faces and update faceLoc QRect.</p>
<pre class="brush: cpp; title: ; notranslate">

void FaceRecognizer::queryFrame() {
IplImage* frame = cvQueryFrame( capture );

if( frame-&gt;origin == IPL_ORIGIN_TL )
cvCopy( frame, m_opencvimg, 0 );
else
cvFlip( frame, m_opencvimg, 0 );
cvCvtColor(m_opencvimg,m_opencvimg,CV_BGR2RGB);

CvRect r = detect_and_draw(m_opencvimg,storage,cascade);
faceLoc = QRect(QPoint(r.x,r.y),QSize(r.width,r.height));

this-&gt;update();
}

Finally - painting, which is easy:

void FaceRecognizer::paintEvent(QPaintEvent* e) {
QPainter painter(this);

painter.drawImage(QPoint(ui.frame-&gt;x(),ui.frame-&gt;y()),m_i);

if(faceLoc.x() &gt; 0 &amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp; faceLoc.y() &gt; 0) {
painter.setBrush(Qt::NoBrush);
painter.setPen(QColor(255,0,0));
painter.drawRect(QRect(faceLoc.x()+ui.frame-&gt;x(),faceLoc.y()+ui.frame-&gt;y(),faceLoc.width(),faceLoc.height()));
}
}
</pre>
<p>Looks like it&#8217;s all done&#8230; Here&#8217;s a video:<br />
<object width="425" height="344" data="http://www.youtube.com/v/3eyh-jmAQR0&amp;hl=en&amp;fs=1" type="application/x-shockwave-flash"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube.com/v/3eyh-jmAQR0&amp;hl=en&amp;fs=1" /><param name="allowfullscreen" value="true" /></object></p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.morethantechnical.com%2F2009%2F03%2F05%2Fqt-opencv-combined-for-face-detecting-qwidgets%2F&amp;title=Qt%20%26%23038%3B%20OpenCV%20combined%20for%20face%20detecting%20QWidgets" id="wpa2a_2"><img src="http://www.morethantechnical.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.morethantechnical.com/2009/03/05/qt-opencv-combined-for-face-detecting-qwidgets/feed/</wfw:commentRss>
		<slash:comments>23</slash:comments>
		</item>
		<item>
		<title>Showing video with Qt toolbox and ffmpeg libraries</title>
		<link>http://www.morethantechnical.com/2008/11/02/showing-video-with-qt-toolbox-and-ffmpeg-libraries/</link>
		<comments>http://www.morethantechnical.com/2008/11/02/showing-video-with-qt-toolbox-and-ffmpeg-libraries/#comments</comments>
		<pubDate>Sun, 02 Nov 2008 08:12:00 +0000</pubDate>
		<dc:creator>Roy</dc:creator>
				<category><![CDATA[ffmpeg]]></category>
		<category><![CDATA[graphics]]></category>
		<category><![CDATA[gui]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[qt]]></category>
		<category><![CDATA[video]]></category>
		<category><![CDATA[sdl]]></category>

		<guid isPermaLink="false">http://www.morethantechnical.com/?p=78</guid>
		<description><![CDATA[I recently had to build a demo client that shows short video messages for Ubuntu environment. After checking out GTK+ I decided to go with the more natively OOP Qt toolbox (GTKmm didn&#8217;t look right to me), and I think i made the right choice. So anyway, I have my video files encoded in some [...]]]></description>
			<content:encoded><![CDATA[<p>I recently had to build a demo client that shows short video messages for Ubuntu environment.<br />
After checking out GTK+ I decided to go with the more natively OOP Qt toolbox (GTKmm didn&#8217;t look right to me), and I think i made the right choice.</p>
<p>So anyway, I have my video files encoded in some unknown format and I need my program to show them in a some widget. I went around looking for an exiting example, but i couldn&#8217;t find anything concrete, except for a good tip <a href="http://lists.trolltech.com/qt-interest/2007-09/thread00806-0.html">here</a> that led me <a href="http://www.inb.uni-luebeck.de/%7Eboehme/libavcodec_update.html">here</a> for an example of using ffmpeg&#8217;s libavformat and libavcodec, but no end-to-end example including the Qt code.</p>
<p>The ffmpeg example was simple enough to just copy-paste into my project, but the whole painting over the widget&#8217;s canvas was not covered. Turns out painting video is not as simple as overriding paintEvent()&#8230;</p>
<p>Firstly, you need a separate thread for grabbing frames from the video file, because you won&#8217;t let the GUI event thread do that.<br />
That makes sense, but when the frame-grabbing thread (I called VideoThread) actually grabbed a frame and inserted it somewhere in the memory, I needed to tell the GUI thread to take that buffered pixels and paint them over the widget&#8217;s canvas.</p>
<p>This is the moment where I praise Qt&#8217;s excellent Signals/Slots mechanism. So I&#8217;ll have my VideoThread emit a signal notifying some external entity that a new frame is in the buffer.<br />
Here&#8217;s a little code:</p>
<p><span id="more-78"></span></p>
<pre class="brush: plain; title: ; notranslate">
void VideoThread::run() {
/*
... Initialize libavformat &amp;amp;amp; libavcodec data structures.
You can see it in the example i referred to before
*/
// Open video file
if(av_open_input_file(&amp;amp;amp;pFormatCtx,
&amp;quot;lala.avi&amp;quot;,
NULL, 0, NULL)!=0)
return -1; // Couldn't open file

// Retrieve stream information
if(av_find_stream_info(pFormatCtx)&amp;amp;lt;0)
return -1; // Couldn't find stream information

// Find the first video stream ...

// Get a pointer to the codec context for the video
// stream...

// Find the decoder for the video stream...

// Open codec...

// Allocate video frame
pFrame=avcodec_alloc_frame();

// Allocate an AVFrame structure
pFrameRGB=avcodec_alloc_frame();
if(pFrameRGB==NULL)
return -1;

int dst_fmt = PIX_FMT_RGB24;
int dst_w = 160;
int dst_h = 120;

// Determine required buffer size and allocate buffer
numBytes = avpicture_get_size(dst_fmt, dst_w, dst_h);
buffer = new uint8_t[numBytes + 64];

//put a PPM header on the buffer
int headerlen = sprintf((char *) buffer,
&amp;quot;P6n%d %dn255n&amp;quot;,
dst_w, dst_h);

_v-&amp;amp;gt;buf = (uchar*)buffer;
_v-&amp;amp;gt;len = avpicture_get_size(dst_fmt,dst_w,dst_h) +
headerlen;

// Assign appropriate parts of buffer to image planes
// in pFrameRGB...

// I use libswscale to scale the frames to the required
// size.
// Setup the scaling context:
SwsContext *img_convert_ctx;
img_convert_ctx = sws_getContext(
pCodecCtx-&amp;amp;gt;width, pCodecCtx-&amp;amp;gt;height,
pCodecCtx-&amp;amp;gt;pix_fmt,
dst_w, dst_h, dst_fmt,
SWS_BICUBIC, NULL, NULL, NULL);

// Read frames and notify
i=0;
while(av_read_frame(pFormatCtx, &amp;amp;amp;packet)&amp;amp;gt;=0)
{
// Is this a packet from the video stream?
if(packet.stream_index==videoStream)
{
// Decode video frame
avcodec_decode_video(pCodecCtx,
pFrame,
&amp;amp;amp;frameFinished,
packet.data,
packet.size);

// Did we get a video frame?
if(frameFinished)
{
// Convert the image to RGB
sws_scale(img_convert_ctx,
pFrame-&amp;amp;gt;data,
pFrame-&amp;amp;gt;linesize,
0,
pCodecCtx-&amp;amp;gt;height,
pFrameRGB-&amp;amp;gt;data,
pFrameRGB-&amp;amp;gt;linesize);

emit frameReady();

//My video is 5FPS so sleep for 200ms.
this-&amp;amp;gt;msleep(200);
}
}

// Free the packet that was allocated by
// av_read_frame
av_free_packet(&amp;amp;amp;packet);
}

// Free the RGB image
delete [] buffer;
av_free(pFrameRGB);

// Free the YUV frame
av_free(pFrame);

// Close the codec...

// Close the video file...
} //end VideoThread::run
</pre>
<p>Ok so I have a frame-grabber that emits a frameReady signal everytime the buffer is full and ready for painting.</p>
<p>A couple of things to notice:</p>
<ul style="text-align: left;">
<li>I convert the image format to PIX_FMT_RGB24 (avcodec.h), which is required by Qt&#8217;s QImage::fromData() method.</li>
<li>I scale the image using ffmpeg&#8217;s libswscale. All conversion/scaling methods inside libavcodev are deprecated now.<br />
But it&#8217;s fairly simple, <a href="http://www.dranger.com/ffmpeg/tutorial08.html">here</a>&#8216;s a good example. Just remember you need a sws_getContext and then sws_scale.</li>
<li>I totally disregard actual frame rate here, I just sleep for 200ms because i know my file is 5FPS. For a (far-) more sophisticated way to get the FPS, very important if this is not a constant frame-rate video, you can find <a href="http://www.dranger.com/ffmpeg/tutorial05.html">here</a>.</li>
<li>I don&#8217;t cover audio in this example, although the mechanism to extract it from the file exists&#8230; you just need to grabe the audio stream&#8217;s frame. For playing audio you also need some Qt-external library. In a different project I used SDL very easily, <a href="http://www.dranger.com/ffmpeg/tutorial03.html">here</a>&#8216;s an example online.</li>
</ul>
<p>Now, for painting over the widget.<br />
This is fairly easy:</p>
<pre class="brush: plain; title: ; notranslate">
void VideoWidget::paintEvent(QPaintEvent * e) {
QPainter painter(this);
if(buf) {
QImage i = QImage::fromData(buf,len,&amp;quot;PPM&amp;quot;);
painter.drawImage(QPoint(0,0),i);
}
}
</pre>
<p>Two things to note:</p>
<ul style="text-align: left;">
<li>The widget needs to be given the pointer to the video frame buffer (buf).</li>
<li>The frame buffer needs to be in a PPM format. That means it needs to get a PPM header, which looks something like this: &#8220;P6n320 240n255n&#8221;, and then all the pixels in 3-byte per-pixel format (RGB24). You can see that i take care of that in the previous code block.</li>
</ul>
<p>Finally we need to orchestrate this whole mess.<br />
So in my GUI-screen class I do:</p>
<pre class="brush: plain; title: ; notranslate">
....
vt = new VideoThread();
connect(vt,SIGNAL(frameReady()),this,SLOT(updateVideoWidget()));
vt-&amp;amp;gt;start();
....
</pre>
<p>And:</p>
<pre class="brush: plain; title: ; notranslate">
void playMessage::updateVideoWidget() {
videoWidget-&amp;amp;gt;repaint(); //or update().
}
</pre>
<p>This will make the widget repaint on each frame ready.</p>
<p>Note:</p>
<ul style="text-align: left;">
<li>In this example I don&#8217;t take care of multi-threading issues. Since the GUI and the ffmpeg decoder threads share a memory buffer, I should probably have a mutex to protect it. It&#8217;s a classic producer-consumer problem.</li>
<li>Performance wise, Qt&#8217;s paint mechanism is by far the worst way to go when displaying video&#8230; but it&#8217;s great for a quick-and-dirty solution (I only needed 5fps). A more performance favorable solution will probably be using an overlay block and frame-serving with SDL.</li>
</ul>
<p>Enjoy!<br />
Roy.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.morethantechnical.com%2F2008%2F11%2F02%2Fshowing-video-with-qt-toolbox-and-ffmpeg-libraries%2F&amp;title=Showing%20video%20with%20Qt%20toolbox%20and%20ffmpeg%20libraries" id="wpa2a_4"><img src="http://www.morethantechnical.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.morethantechnical.com/2008/11/02/showing-video-with-qt-toolbox-and-ffmpeg-libraries/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

