Commit d871472165bf9cbac099cfd5d2a0bedd02d84cf5

Authored by Scott Klum
2 parents 1bb6c063 da24109c

Merge branch 'master' of https://github.com/biometrics/openbr

.gitignore
... ... @@ -39,4 +39,5 @@ scripts/results
39 39 ### autogenerated sigsets ###
40 40 data/INRIAPerson/sigset
41 41 data/KTH/sigset
  42 +data/CaltechPedestrians/annotations
42 43  
... ...
data/CaltechPedestrians/README.md 0 → 100644
  1 +## Caltech Pedestrians Dataset
  2 +The Caltech Pedestrian Dataset consists of approximately 10 hours of 640x480 30Hz video taken from a vehicle driving through regular traffic in an urban environment. About 250,000 frames (in 137 approximately minute long segments) with a total of 350,000 bounding boxes and 2300 unique pedestrians were annotated. The annotation includes temporal correspondence between bounding boxes and detailed occlusion labels.
  3 +* [Website](http://www.vision.caltech.edu/Image_Datasets/CaltechPedestrians/)
... ...
openbr/plugins/stream.cpp
  1 +#include <fstream>
1 2 #include <QReadWriteLock>
2 3 #include <QWaitCondition>
3 4 #include <QThreadPool>
4 5 #include <QSemaphore>
5 6 #include <QMap>
6   -#include <opencv/highgui.h>
  7 +#include <QQueue>
7 8 #include <QtConcurrent>
  9 +#include <opencv/highgui.h>
8 10 #include "openbr_internal.h"
9   -
10 11 #include "openbr/core/common.h"
11 12 #include "openbr/core/opencvutils.h"
12 13 #include "openbr/core/qtutils.h"
13 14  
14 15 using namespace cv;
  16 +using namespace std;
15 17  
16 18 namespace br
17 19 {
... ... @@ -203,6 +205,13 @@ public:
203 205 virtual bool getNextTemplate(Template & output)=0;
204 206 protected:
205 207 Template basis;
  208 + string getAbsolutePath(QString filename)
  209 + {
  210 + // Yes, we should specify absolute path:
  211 + // http://stackoverflow.com/questions/9396459/loading-a-video-in-opencv-in-python
  212 + QString fileName = (Globals->path.isEmpty() ? "" : Globals->path + "/") + filename;
  213 + return QFileInfo(fileName).absoluteFilePath().toStdString();
  214 + }
206 215 };
207 216  
208 217 static QMutex openLock;
... ... @@ -236,12 +245,9 @@ public:
236 245 qDebug("Video not open!");
237 246 }
238 247 } else {
239   - // Yes, we should specify absolute path:
240   - // http://stackoverflow.com/questions/9396459/loading-a-video-in-opencv-in-python
241   - QString fileName = (Globals->path.isEmpty() ? "" : Globals->path + "/") + input.file.name;
242 248 // On windows, this appears to not be thread-safe
243 249 QMutexLocker lock(&openLock);
244   - video.open(QFileInfo(fileName).absoluteFilePath().toStdString());
  250 + video.open(getAbsolutePath(input.file.name));
245 251 }
246 252  
247 253 return video.isOpened();
... ... @@ -319,6 +325,182 @@ protected:
319 325 bool data_ok;
320 326 };
321 327  
  328 +class SeqReader : public TemplateProcessor
  329 +{
  330 +public:
  331 + SeqReader() {}
  332 +
  333 + bool open(Template &input)
  334 + {
  335 + basis = input;
  336 +
  337 + seqFile.open(getAbsolutePath(input.file.name).c_str(), ios::in | ios::binary | ios::ate);
  338 + if (!isOpen()) return false;
  339 +
  340 + int headSize = 1024;
  341 + // start at end of file to get full size
  342 + int fileSize = seqFile.tellg();
  343 + if (fileSize < headSize) {
  344 + qDebug("No header in seq file");
  345 + return false;
  346 + }
  347 +
  348 + // first 4 bytes store 0xEDFE, next 24 store 'Norpix seq '
  349 + char *firstFour = new char[4], *nextTwentyFour;
  350 + seqFile.seekg(0, ios::beg);
  351 + seqFile.read(firstFour, 4);
  352 + nextTwentyFour = readText(24);
  353 + if (firstFour[0] != (char)0xED || firstFour[1] != (char)0xFE || strncmp(nextTwentyFour, "Norpix seq", 10) != 0) {
  354 + qDebug("Invalid header in seq file");
  355 + return false;
  356 + }
  357 +
  358 + // next 8 bytes for version (skipped below) and header size (1024), then 512 for descr
  359 + seqFile.seekg(4, ios::cur);
  360 + int hSize = readInt();
  361 + if (hSize != headSize) {
  362 + qDebug("Invalid header size");
  363 + return false;
  364 + }
  365 + char *desc = readText(512);
  366 + basis.file.set("Description", QString(desc));
  367 +
  368 + width = readInt();
  369 + height = readInt();
  370 + // get # channels from bit depth
  371 + numChan = readInt()/8;
  372 + int imageBitDepthReal = readInt();
  373 + if (imageBitDepthReal != 8) {
  374 + qDebug("Invalid bit depth");
  375 + return false;
  376 + }
  377 + // the size of just the image part of a raw img
  378 + imgSizeBytes = readInt();
  379 +
  380 + int imgFormatInt = readInt();
  381 + if (imgFormatInt == 100 || imgFormatInt == 200 || imgFormatInt == 101) {
  382 + imgFormat = "raw";
  383 + } else if (imgFormatInt == 102 || imgFormatInt == 201 || imgFormatInt == 103 ||
  384 + imgFormatInt == 1 || imgFormatInt == 2) {
  385 + imgFormat = "compressed";
  386 + } else {
  387 + qFatal("unsupported image format");
  388 + }
  389 +
  390 + numFrames = readInt();
  391 + // skip empty int
  392 + seqFile.seekg(4, ios::cur);
  393 + // the size of a full raw file, with extra crap after img data
  394 + trueImgSizeBytes = readInt();
  395 +
  396 + // gather all the frame positions in an array
  397 + seekPos.reserve(numFrames);
  398 + // start at end of header
  399 + seekPos.append(headSize);
  400 + // extra 8 bytes at end of img
  401 + int extra = 8;
  402 + for (int i=1; i<numFrames; i++) {
  403 + int s;
  404 + // compressed images have different sizes
  405 + // the first byte at the beginning of the file
  406 + // says how big the current img is
  407 + if (imgFormat == "compressed") {
  408 + int lastPos = seekPos[i-1];
  409 + seqFile.seekg(lastPos, ios::beg);
  410 + int currSize = readInt();
  411 + s = lastPos + currSize + extra;
  412 +
  413 + // but there might be 16 extra bytes instead of 8...
  414 + if (i == 1) {
  415 + seqFile.seekg(s, ios::beg);
  416 + char *zero = new char[1];
  417 + seqFile.read(zero, 1);
  418 + if (zero[0] == 0) {
  419 + s += 8;
  420 + extra += 8;
  421 + }
  422 + }
  423 + }
  424 + // raw images are all the same size
  425 + else {
  426 + s = headSize + (i*trueImgSizeBytes);
  427 + }
  428 +
  429 + seekPos.enqueue(s);
  430 + }
  431 +
  432 + return true;
  433 + }
  434 +
  435 + bool isOpen()
  436 + {
  437 + return seqFile.is_open();
  438 + }
  439 +
  440 + void close()
  441 + {
  442 + seqFile.close();
  443 + }
  444 +
  445 + bool getNextTemplate(Template &output)
  446 + {
  447 + if (!isOpen()) {
  448 + qDebug("Seq not open");
  449 + return false;
  450 + }
  451 + // if we've reached the last frame, we're done
  452 + if (seekPos.size() == 0) return false;
  453 +
  454 + seqFile.seekg(seekPos.dequeue(), ios::beg);
  455 +
  456 + Mat temp;
  457 + // let imdecode do all the work to decode the compressed img
  458 + if (imgFormat == "compressed") {
  459 + int imgSize = readInt() - 4;
  460 + vector<char> imgBuf(imgSize);
  461 + seqFile.read(&imgBuf[0], imgSize);
  462 + // flags < 0 means load image as-is (keep color info if available)
  463 + imdecode(imgBuf, -1, &temp);
  464 + }
  465 + // raw images can be loaded straight into a Mat
  466 + else {
  467 + char *imgBuf = new char[imgSizeBytes];
  468 + seqFile.read(imgBuf, imgSizeBytes);
  469 + int type = (numChan == 1 ? CV_8UC1 : CV_8UC3);
  470 + temp = Mat(height, width, type, imgBuf);
  471 + }
  472 +
  473 + output.file = basis.file;
  474 + output.m() = temp;
  475 + return true;
  476 + }
  477 +private:
  478 + int readInt()
  479 + {
  480 + int num;
  481 + seqFile.read((char*)&num, 4);
  482 + return num;
  483 + }
  484 +
  485 + // apparently the text in seq files is 16 bit characters (UTF-16?)
  486 + // since we don't really need the last byte, snad since it gets interpreted as
  487 + // a terminating char, let's just grab the first byte for storage
  488 + char* readText(int bytes)
  489 + {
  490 + char *text = new char[bytes], *ret = new char[bytes/2];
  491 + seqFile.read(text, bytes);
  492 + for (int i=0; i<bytes; i+=2) {
  493 + ret[i/2] = text[i];
  494 + }
  495 + return ret;
  496 + }
  497 +
  498 +protected:
  499 + ifstream seqFile;
  500 + QQueue<int> seekPos;
  501 + int width, height, numChan, imgSizeBytes, trueImgSizeBytes, numFrames;
  502 + QString imgFormat;
  503 +};
322 504  
323 505 // Interface for sequentially getting data from some data source.
324 506 // Given a TemplateList, return single template frames sequentially by applying a TemplateProcessor
... ... @@ -514,11 +696,16 @@ protected:
514 696 if (frameSource)
515 697 frameSource->close();
516 698  
  699 + Template curr = this->templates[current_template_idx];
517 700 if (mode == br::Idiocy::Auto)
518 701 {
519 702 delete frameSource;
520   - if (this->templates[this->current_template_idx].empty())
521   - frameSource = new VideoReader();
  703 + if (curr.empty()) {
  704 + if (curr.file.name.right(3) == "seq")
  705 + frameSource = new SeqReader();
  706 + else
  707 + frameSource = new VideoReader();
  708 + }
522 709 else
523 710 frameSource = new DirectReturn();
524 711 }
... ... @@ -529,11 +716,15 @@ protected:
529 716 }
530 717 else if (mode == br::Idiocy::StreamVideo)
531 718 {
532   - if (!frameSource)
533   - frameSource = new VideoReader();
  719 + if (!frameSource) {
  720 + if (curr.file.name.right(3) == "seq")
  721 + frameSource = new SeqReader();
  722 + else
  723 + frameSource = new VideoReader();
  724 + }
534 725 }
535 726  
536   - open_res = frameSource->open(this->templates[current_template_idx]);
  727 + open_res = frameSource->open(curr);
537 728 if (!open_res)
538 729 {
539 730 current_template_idx++;
... ...
scripts/downloadDatasets.sh
... ... @@ -35,6 +35,33 @@ if [ ! -d ../data/BioID/img ]; then
35 35 rm *.eye description.txt BioID-FaceDatabase-V1.2.zip
36 36 fi
37 37  
  38 +# Caltech Pedestrian
  39 +if [ ! -d ../data/CaltechPedestrians/vid ]; then
  40 + mkdir ../data/CaltechPedestrians/vid
  41 + echo "Downloading Caltech Pedestrians dataset..."
  42 + prefix="http://www.vision.caltech.edu/Image_Datasets/CaltechPedestrians/datasets/USA"
  43 + for seq in {0..10}; do
  44 + fname=`printf "set%02d.tar" $seq`
  45 + dlpath="$prefix/$fname"
  46 + if hash curl 2>/dev/null; then
  47 + curl -OL $dlpath
  48 + else
  49 + wget $dlpath
  50 + fi
  51 + tar -xf $fname
  52 + done
  53 + rm *.tar
  54 + mv set* ../data/CaltechPedestrians/vid
  55 + if hash curl 2>/dev/null; then
  56 + curl -OL "$prefix/annotations.zip"
  57 + else
  58 + wget "$prefix/annotations.zip"
  59 + fi
  60 + unzip annotations.zip
  61 + rm annotations.zip
  62 + mv annotations ../data/CaltechPedestrians
  63 +fi
  64 +
38 65 # INRIA person
39 66 if [ ! -d ../data/INRIAPerson/img ]; then
40 67 echo "Downloading INRIA person dataset..."
... ... @@ -66,7 +93,7 @@ if [ ! -d ../data/KTH/vid ]; then
66 93 fi
67 94 mkdir ../data/KTH/vid/${vidclass}
68 95 unzip ${vidclass}.zip -d ../data/KTH/vid/${vidclass}
69   - rm ${vidclass}.zip
  96 + rm ${vidclass}.zip
70 97 done
71 98 # this file is corrupted
72 99 rm -f ../data/KTH/vid/boxing/person01_boxing_d4_uncomp.avi
... ...