3030
3131#include < Client/Client.h>
3232
33- #ifndef DLIB_JPEG_SUPPORT
34- #error "DLIB must have built-in libjpeg support enabled!"
35- #endif
36-
3733#include < dlib/clustering.h>
3834#include < dlib/image_io.h>
3935
36+ #ifdef TURBOJPEG_AVAILABLE
37+ #include < turbojpeg.h>
38+ #endif
39+
4040#include " config.h"
4141
4242using namespace dlib ;
@@ -94,6 +94,104 @@ DLIBWorker::DLIBWorker(class QSettings* config, const Settings *settings)
9494 }
9595 }
9696 }
97+
98+ #ifdef TURBOJPEG_AVAILABLE
99+ QMetaObject::invokeMethod (this , [this ]() {
100+ m_tjHandle = tjInitDecompress ();
101+ }, Qt::QueuedConnection);
102+ #endif
103+ }
104+
105+ DLIBWorker::~DLIBWorker ()
106+ {
107+ #ifdef TURBOJPEG_AVAILABLE
108+ if (m_tjHandle)
109+ tjDestroy (m_tjHandle);
110+ #endif
111+ }
112+
113+ dlib::array2d<rgb_pixel> DLIBWorker::decodeJPEG (const QByteArray &jpegBuffer, void *tjHandle)
114+ {
115+ array2d<rgb_pixel> img;
116+
117+ #ifdef TURBOJPEG_AVAILABLE
118+ bool destroyHandle = false ;
119+
120+ if (tjHandle == nullptr )
121+ {
122+ tjHandle = tjInitDecompress ();
123+ destroyHandle = true ;
124+ }
125+
126+ assert (tjHandle);
127+
128+ int width, height;
129+ int jpegSubsamp, jpegColorspace;
130+
131+ int ret;
132+
133+ auto ptrBuffer = reinterpret_cast <const unsigned char *>(jpegBuffer.constData ());
134+
135+ ret = tjDecompressHeader3 (tjHandle,
136+ ptrBuffer,
137+ jpegBuffer.size (),
138+ &width, &height,
139+ &jpegSubsamp, &jpegColorspace);
140+
141+ if (ret || width <= 0 || height <= 0 )
142+ {
143+ if (destroyHandle)
144+ tjDestroy (tjHandle);
145+
146+ return img;
147+ }
148+
149+ img.set_size (height, width);
150+
151+ tjDecompress2 (tjHandle,
152+ ptrBuffer,
153+ jpegBuffer.size (),
154+ static_cast <unsigned char *>(image_data (img)),
155+ width, 0 , height,
156+ TJPF_RGB,
157+ TJFLAG_FASTDCT);
158+
159+ if (destroyHandle)
160+ tjDestroy (tjHandle);
161+ #else
162+ Q_UNUSED (tjHandle);
163+
164+ try
165+ {
166+ load_jpeg (img, buffer.constData (), buffer.size ());
167+ }
168+ catch (...)
169+ {
170+
171+ }
172+ #endif
173+
174+ return img;
175+ }
176+
177+ dlib::array2d<rgb_pixel> DLIBWorker::decodeJPEG (const QByteArray &jpegBuffer)
178+ {
179+ auto decoded = decodeJPEG (jpegBuffer,
180+ #ifdef TURBOJPEG_AVAILABLE
181+ m_tjHandle
182+ #else
183+ nullptr
184+ #endif
185+ );
186+
187+ if (decoded.size () <= 0 )
188+ #ifdef TURBOJPEG_AVAILABLE
189+ emit log (QString (" libjpeg-turbo error code: %1" ).arg (tjGetErrorStr2 (m_tjHandle)));
190+ #else
191+ emit log (" dlib::load_jpeg failed!" );
192+ #endif
193+
194+ return decoded;
97195}
98196
99197std::vector<Face> DLIBWorker::findFaces (const array2d<rgb_pixel>& img)
@@ -260,26 +358,14 @@ void DLIBWorker::process(const QByteArray& buffer)
260358
261359 try
262360 {
263- if (referenceFaces.size () == 0 )
264- {
265- if (m_refPhotoFileList.size () == 0 )
266- {
267- throwException (std::exception (" Reference face list is empty!" ));
268- }
269- else
270- {
271- detector = get_frontal_face_detector ();
272- string landmarkModel = m_faceLandmarkModelFile.toStdString ();
273- string recogModel = m_faceRecognitionModelFile.toStdString ();
274- deserialize (landmarkModel) >> sp;
275- deserialize (recogModel) >> net;
361+ auto img = decodeJPEG (buffer);
276362
277- setupReference (m_refPhotoFileList);
278- }
363+ if (img.size () <= 0 )
364+ {
365+ m_busy = false ;
366+ return ;
279367 }
280368
281- auto img = constructImgFromBuffer (buffer);
282-
283369 if (m_settings->objectDetectionEnabled )
284370 {
285371 if (labels.empty ())
@@ -312,30 +398,51 @@ void DLIBWorker::process(const QByteArray& buffer)
312398
313399 if (m_settings->faceRecognitionEnabled )
314400 {
401+ if (referenceFaces.size () == 0 )
402+ {
403+ if (m_refPhotoFileList.size () == 0 )
404+ {
405+ throwException (std::exception (" Reference face list is empty!" ));
406+ }
407+ else
408+ {
409+ detector = get_frontal_face_detector ();
410+ string landmarkModel = m_faceLandmarkModelFile.toStdString ();
411+ string recogModel = m_faceRecognitionModelFile.toStdString ();
412+ deserialize (landmarkModel) >> sp;
413+ deserialize (recogModel) >> net;
414+
415+ setupReference (m_refPhotoFileList);
416+ }
417+ }
418+
315419 auto faces = findFaces (img);
316420
317- rectangle rect;
318- for (const auto & face : referenceFaces)
421+ if (faces.size () > 0 )
319422 {
320- faces.push_back (make_tuple (get<0 >(face), rect, get<2 >(face)));
321- }
423+ rectangle rect;
424+ for (const auto & face : referenceFaces)
425+ {
426+ faces.push_back (make_tuple (get<0 >(face), rect, get<2 >(face)));
427+ }
322428
323- auto graph = createGraph (faces, m_threshold);
429+ auto graph = createGraph (faces, m_threshold);
324430
325- auto clusters = cluster (graph, faces);
431+ auto clusters = cluster (graph, faces);
326432
327- QVector<QPair<QRect, QString>> linearFaces;
433+ QVector<QPair<QRect, QString>> linearFaces;
328434
329- for (const auto & it : clusters)
330- {
331- QString str = it.first ;
332- for (const auto & it2 : it.second )
435+ for (const auto & it : clusters)
333436 {
334- linearFaces.push_back (qMakePair (QRect (it2.left (), it2.top (), it2.width (), it2.height ()), str));
437+ QString str = it.first ;
438+ for (const auto & it2 : it.second )
439+ {
440+ linearFaces.push_back (qMakePair (QRect (it2.left (), it2.top (), it2.width (), it2.height ()), str));
441+ }
335442 }
336- }
337443
338- emit doneFace (linearFaces);
444+ emit doneFace (linearFaces);
445+ }
339446 }
340447
341448 m_busy = false ;
@@ -346,9 +453,3 @@ void DLIBWorker::process(const QByteArray& buffer)
346453 }
347454}
348455
349- dlib::array2d<dlib::rgb_pixel> DLIBWorker::constructImgFromBuffer (const QByteArray& buffer)
350- {
351- array2d<rgb_pixel> img;
352- load_jpeg (img, buffer.constData (), buffer.size ());
353- return img;
354- }
0 commit comments