Commit 909ad7a031135ca8ae05bfc1c94d46486f33fec5

Authored by caotto
2 parents fabf7784 96384bbc

Merge pull request #294 from biometrics/stream_galleries

Refactor video handling in stream
openbr/core/qtutils.cpp
@@ -484,5 +484,22 @@ float overlap(const QRectF &r, const QRectF &s) { @@ -484,5 +484,22 @@ float overlap(const QRectF &r, const QRectF &s) {
484 return (intersection.width()*intersection.height())/(r.width()*r.height()); 484 return (intersection.width()*intersection.height())/(r.width()*r.height());
485 } 485 }
486 486
  487 +
  488 +QString getAbsolutePath(const QString &filename)
  489 +{
  490 + // Try adding the global path, if present
  491 + QString withPath = (Globals->path.isEmpty() ? "" : Globals->path + "/") + filename;
  492 +
  493 + // we weren't necessarily using it to begin with, so see if that file
  494 + // exists
  495 + QFileInfo wpInfo(withPath);
  496 + if (wpInfo.exists() )
  497 + return wpInfo.absoluteFilePath();
  498 +
  499 + // If no, just use the nominal filename
  500 + return QFileInfo(filename).absoluteFilePath();
  501 +}
  502 +
  503 +
487 } // namespace QtUtils 504 } // namespace QtUtils
488 505
openbr/core/qtutils.h
@@ -50,6 +50,7 @@ namespace QtUtils @@ -50,6 +50,7 @@ namespace QtUtils
50 void emptyDir(QDir &dir); 50 void emptyDir(QDir &dir);
51 void deleteDir(QDir &dir); 51 void deleteDir(QDir &dir);
52 QString find(const QString &file, const QString &alt); 52 QString find(const QString &file, const QString &alt);
  53 + QString getAbsolutePath(const QString &filename);
53 54
54 /**** String Utilities ****/ 55 /**** String Utilities ****/
55 bool toBool(const QString &string); 56 bool toBool(const QString &string);
openbr/plugins/algorithms.cpp
@@ -48,12 +48,12 @@ class AlgorithmsInitializer : public Initializer @@ -48,12 +48,12 @@ class AlgorithmsInitializer : public Initializer
48 Globals->abbreviations.insert("4SF", "Open+Cvt(Gray)+Cascade(FrontalFace)+ASEFEyes+Affine(128,128,0.33,0.45)+(Grid(10,10)+SIFTDescriptor(12)+ByRow)/(Blur(1.1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)+LBP(1,2)+RectRegions(8,8,6,6)+Hist(59))+PCA(0.95)+Cat+Normalize(L2)+Dup(12)+RndSubspace(0.05,1)+LDA(0.98)+Cat+PCA(0.95)+Normalize(L1)+Quantize:NegativeLogPlusOne(ByteL1)"); 48 Globals->abbreviations.insert("4SF", "Open+Cvt(Gray)+Cascade(FrontalFace)+ASEFEyes+Affine(128,128,0.33,0.45)+(Grid(10,10)+SIFTDescriptor(12)+ByRow)/(Blur(1.1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)+LBP(1,2)+RectRegions(8,8,6,6)+Hist(59))+PCA(0.95)+Cat+Normalize(L2)+Dup(12)+RndSubspace(0.05,1)+LDA(0.98)+Cat+PCA(0.95)+Normalize(L1)+Quantize:NegativeLogPlusOne(ByteL1)");
49 49
50 // Video 50 // Video
51 - Globals->abbreviations.insert("DisplayVideo", "Stream(FPSLimit(30)+Show(false,[FrameNumber])+Discard)");  
52 - Globals->abbreviations.insert("PerFrameDetection", "Stream(SaveMat(original)+Cvt(Gray)+Cascade(FrontalFace)+ASEFEyes+RestoreMat(original)+Draw(inPlace=true)+Show(false,[FrameNumber])+Discard)");  
53 - Globals->abbreviations.insert("AgeGenderDemo", "Stream(SaveMat(original)+Cvt(Gray)+Cascade(FrontalFace)+Expand+<FaceClassificationRegistration>+<FaceClassificationExtraction>+<AgeRegressor>/<GenderClassifier>+Discard+RestoreMat(original)+Draw(inPlace=true)+DrawPropertiesPoint([Age,Gender],Affine_0,inPlace=true)+SaveMat(original)+Discard+Contract+RestoreMat(original)+FPSCalc+Show(false,[AvgFPS,Age,Gender])+Discard)");  
54 - Globals->abbreviations.insert("ShowOpticalFlowField", "Stream(SaveMat(original)+AggregateFrames(2)+OpticalFlow(useMagnitude=false)+Grid(100,100)+DrawOpticalFlow+FPSLimit(30)+Show(false)+Discard)");  
55 - Globals->abbreviations.insert("ShowOpticalFlowMagnitude", "Stream(AggregateFrames(2)+OpticalFlow+Normalize(Range,false,0,255)+Cvt(Color)+Draw+FPSLimit(30)+Show(false)+Discard)");  
56 - Globals->abbreviations.insert("ShowMotionSegmentation", "Stream(DropFrames(5)+AggregateFrames(2)+OpticalFlow+CvtUChar+WatershedSegmentation+DrawSegmentation+Draw+FPSLimit(30)+Show(false)+Discard)"); 51 + Globals->abbreviations.insert("DisplayVideo", "FPSLimit(30)+Show(false,[FrameNumber])+Discard");
  52 + Globals->abbreviations.insert("PerFrameDetection", "SaveMat(original)+Cvt(Gray)+Cascade(FrontalFace)+ASEFEyes+RestoreMat(original)+Draw(inPlace=true)+Show(false,[FrameNumber])+Discard");
  53 + Globals->abbreviations.insert("AgeGenderDemo", "SaveMat(original)+Cvt(Gray)+Cascade(FrontalFace)+Expand+<FaceClassificationRegistration>+<FaceClassificationExtraction>+<AgeRegressor>/<GenderClassifier>+Discard+RestoreMat(original)+Draw(inPlace=true)+DrawPropertiesPoint([Age,Gender],Affine_0,inPlace=true)+SaveMat(original)+Discard+Contract+RestoreMat(original)+FPSCalc+Show(false,[AvgFPS,Age,Gender])+Discard");
  54 + Globals->abbreviations.insert("ShowOpticalFlowField", "SaveMat(original)+AggregateFrames(2)+OpticalFlow(useMagnitude=false)+Grid(100,100)+DrawOpticalFlow+FPSLimit(30)+Show(false)+Discard");
  55 + Globals->abbreviations.insert("ShowOpticalFlowMagnitude", "AggregateFrames(2)+OpticalFlow+Normalize(Range,false,0,255)+Cvt(Color)+Draw+FPSLimit(30)+Show(false)+Discard");
  56 + Globals->abbreviations.insert("ShowMotionSegmentation", "DropFrames(5)+AggregateFrames(2)+OpticalFlow+CvtUChar+WatershedSegmentation+DrawSegmentation+Draw+FPSLimit(30)+Show(false)+Discard");
57 57
58 Globals->abbreviations.insert("HOGVideo", "Stream(DropFrames(5)+Cvt(Gray)+Grid(5,5)+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat)+Contract+CatRows+KMeans(500)+Hist(500)+SVM"); 58 Globals->abbreviations.insert("HOGVideo", "Stream(DropFrames(5)+Cvt(Gray)+Grid(5,5)+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat)+Contract+CatRows+KMeans(500)+Hist(500)+SVM");
59 Globals->abbreviations.insert("HOFVideo", "Stream(DropFrames(5)+Grid(5,5)+AggregateFrames(2)+OpticalFlow+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat)+Contract+CatRows+KMeans(500)+Hist(500)"); 59 Globals->abbreviations.insert("HOFVideo", "Stream(DropFrames(5)+Grid(5,5)+AggregateFrames(2)+OpticalFlow+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat)+Contract+CatRows+KMeans(500)+Hist(500)");
openbr/plugins/gallery.cpp
@@ -34,6 +34,8 @@ @@ -34,6 +34,8 @@
34 #include "openbr/core/opencvutils.h" 34 #include "openbr/core/opencvutils.h"
35 #include "openbr/core/qtutils.h" 35 #include "openbr/core/qtutils.h"
36 36
  37 +#include <fstream>
  38 +
37 #ifdef CVMATIO 39 #ifdef CVMATIO
38 #include "MatlabIO.hpp" 40 #include "MatlabIO.hpp"
39 #include "MatlabIOContainer.hpp" 41 #include "MatlabIOContainer.hpp"
@@ -1743,6 +1745,330 @@ BR_REGISTER(Gallery, vbbGallery) @@ -1743,6 +1745,330 @@ BR_REGISTER(Gallery, vbbGallery)
1743 1745
1744 #endif 1746 #endif
1745 1747
  1748 +
  1749 +// Read a video frame by frame using cv::VideoCapture
  1750 +class videoGallery : public Gallery
  1751 +{
  1752 + Q_OBJECT
  1753 +public:
  1754 + qint64 idx;
  1755 + ~videoGallery()
  1756 + {
  1757 + video.release();
  1758 + }
  1759 +
  1760 + static QMutex openLock;
  1761 +
  1762 + virtual void deferredInit()
  1763 + {
  1764 + bool status = video.open(QtUtils::getAbsolutePath(file.name).toStdString());
  1765 +
  1766 + if (!status)
  1767 + qFatal("Failed to open file %s with path %s", qPrintable(file.name), qPrintable(QtUtils::getAbsolutePath(file.name)));
  1768 + }
  1769 +
  1770 + TemplateList readBlock(bool *done)
  1771 + {
  1772 + if (!video.isOpened()) {
  1773 + // opening videos appears to not be thread safe on windows
  1774 + QMutexLocker lock(&openLock);
  1775 +
  1776 + deferredInit();
  1777 + idx = 0;
  1778 + }
  1779 +
  1780 + Template output;
  1781 + output.file = file;
  1782 + output.m() = cv::Mat();
  1783 +
  1784 + cv::Mat temp;
  1785 + bool res = video.read(temp);
  1786 +
  1787 + if (!res) {
  1788 + // The video capture broke, return an empty list.
  1789 + output.m() = cv::Mat();
  1790 + video.release();
  1791 + *done = true;
  1792 + return TemplateList();
  1793 + }
  1794 +
  1795 + // This clone is critical, if we don't do it then the output matrix will
  1796 + // be an alias of an internal buffer of the video source, leading to various
  1797 + // problems later.
  1798 + output.m() = temp.clone();
  1799 +
  1800 + output.file.set("progress", idx);
  1801 + idx++;
  1802 +
  1803 + TemplateList rVal;
  1804 + rVal.append(temp);
  1805 + *done = false;
  1806 + return rVal;
  1807 + }
  1808 +
  1809 + void write(const Template &t)
  1810 + {
  1811 + (void)t; qFatal("Not implemented");
  1812 + }
  1813 +
  1814 +protected:
  1815 + cv::VideoCapture video;
  1816 +};
  1817 +BR_REGISTER(Gallery,videoGallery)
  1818 +
  1819 +QMutex videoGallery::openLock;
  1820 +
  1821 +class aviGallery : public videoGallery
  1822 +{
  1823 + Q_OBJECT
  1824 +};
  1825 +BR_REGISTER(Gallery, aviGallery)
  1826 +
  1827 +class wmvGallery : public videoGallery
  1828 +{
  1829 + Q_OBJECT
  1830 +};
  1831 +BR_REGISTER(Gallery, wmvGallery)
  1832 +
  1833 +// Mostly the same as videoGallery, but we open the VideoCapture with an integer index
  1834 +// rather than file name/web address
  1835 +class webcamGallery : public videoGallery
  1836 +{
  1837 +public:
  1838 + Q_OBJECT
  1839 +
  1840 + void deferredInit()
  1841 + {
  1842 + bool intOK = false;
  1843 + int anInt = file.baseName().toInt(&intOK);
  1844 +
  1845 + if (!intOK)
  1846 + qFatal("Expected integer basename, got %s", qPrintable(file.baseName()));
  1847 +
  1848 + bool rc = video.open(anInt);
  1849 +
  1850 + if (!rc)
  1851 + qFatal("Failed to open webcam with index: %s", qPrintable(file.baseName()));
  1852 + }
  1853 +
  1854 +};
  1855 +BR_REGISTER(Gallery,webcamGallery)
  1856 +
  1857 +class seqGallery : public Gallery
  1858 +{
  1859 +public:
  1860 + Q_OBJECT
  1861 +
  1862 + bool open()
  1863 + {
  1864 + seqFile.open(QtUtils::getAbsolutePath(file.name).toStdString().c_str(), std::ios::in | std::ios::binary | std::ios::ate);
  1865 + if (!isOpen()) {
  1866 + qDebug("Failed to open file %s for reading", qPrintable(file.name));
  1867 + return false;
  1868 + }
  1869 +
  1870 + int headSize = 1024;
  1871 + // start at end of file to get full size
  1872 + int fileSize = seqFile.tellg();
  1873 + if (fileSize < headSize) {
  1874 + qDebug("No header in seq file");
  1875 + return false;
  1876 + }
  1877 +
  1878 + // first 4 bytes store 0xEDFE, next 24 store 'Norpix seq '
  1879 + char firstFour[4];
  1880 + seqFile.seekg(0, std::ios::beg);
  1881 + seqFile.read(firstFour, 4);
  1882 + char nextTwentyFour[24];
  1883 + readText(24, nextTwentyFour);
  1884 + if (firstFour[0] != (char)0xED || firstFour[1] != (char)0xFE || strncmp(nextTwentyFour, "Norpix seq", 10) != 0) {
  1885 + qDebug("Invalid header in seq file");
  1886 + return false;
  1887 + }
  1888 +
  1889 + // next 8 bytes for version (skipped below) and header size (1024), then 512 for descr
  1890 + seqFile.seekg(4, std::ios::cur);
  1891 + int hSize = readInt();
  1892 + if (hSize != headSize) {
  1893 + qDebug("Invalid header size");
  1894 + return false;
  1895 + }
  1896 + char desc[512];
  1897 + readText(512, desc);
  1898 + file.set("Description", QString(desc));
  1899 +
  1900 + width = readInt();
  1901 + height = readInt();
  1902 + // get # channels from bit depth
  1903 + numChan = readInt()/8;
  1904 + int imageBitDepthReal = readInt();
  1905 + if (imageBitDepthReal != 8) {
  1906 + qDebug("Invalid bit depth");
  1907 + return false;
  1908 + }
  1909 + // the size of just the image part of a raw img
  1910 + imgSizeBytes = readInt();
  1911 +
  1912 + int imgFormatInt = readInt();
  1913 + if (imgFormatInt == 100 || imgFormatInt == 200 || imgFormatInt == 101) {
  1914 + imgFormat = "raw";
  1915 + } else if (imgFormatInt == 102 || imgFormatInt == 201 || imgFormatInt == 103 ||
  1916 + imgFormatInt == 1 || imgFormatInt == 2) {
  1917 + imgFormat = "compressed";
  1918 + } else {
  1919 + qFatal("unsupported image format");
  1920 + }
  1921 +
  1922 + numFrames = readInt();
  1923 + // skip empty int
  1924 + seqFile.seekg(4, std::ios::cur);
  1925 + // the size of a full raw file, with extra crap after img data
  1926 + trueImgSizeBytes = readInt();
  1927 +
  1928 + // gather all the frame positions in an array
  1929 + seekPos.reserve(numFrames);
  1930 + // start at end of header
  1931 + seekPos.append(headSize);
  1932 + // extra 8 bytes at end of img
  1933 + int extra = 8;
  1934 + for (int i=1; i<numFrames; i++) {
  1935 + int s;
  1936 + // compressed images have different sizes
  1937 + // the first byte at the beginning of the file
  1938 + // says how big the current img is
  1939 + if (imgFormat == "compressed") {
  1940 + int lastPos = seekPos[i-1];
  1941 + seqFile.seekg(lastPos, std::ios::beg);
  1942 + int currSize = readInt();
  1943 + s = lastPos + currSize + extra;
  1944 +
  1945 + // but there might be 16 extra bytes instead of 8...
  1946 + if (i == 1) {
  1947 + seqFile.seekg(s, std::ios::beg);
  1948 + char zero;
  1949 + seqFile.read(&zero, 1);
  1950 + if (zero == 0) {
  1951 + s += 8;
  1952 + extra += 8;
  1953 + }
  1954 + }
  1955 + }
  1956 + // raw images are all the same size
  1957 + else {
  1958 + s = headSize + (i*trueImgSizeBytes);
  1959 + }
  1960 +
  1961 + seekPos.enqueue(s);
  1962 + }
  1963 +
  1964 +#ifdef CVMATIO
  1965 + if (basis.file.contains("vbb")) {
  1966 + QString vbb = basis.file.get<QString>("vbb");
  1967 + annotations = TemplateList::fromGallery(File(vbb));
  1968 + }
  1969 +#else
  1970 + qWarning("cvmatio not installed, bounding boxes will not be available. Add -DBR_WITH_CVMATIO cmake flag to install.");
  1971 +#endif
  1972 +
  1973 + return true;
  1974 + }
  1975 +
  1976 + bool isOpen()
  1977 + {
  1978 + return seqFile.is_open();
  1979 + }
  1980 +
  1981 + void close()
  1982 + {
  1983 + seqFile.close();
  1984 + }
  1985 +
  1986 + TemplateList readBlock(bool *done)
  1987 + {
  1988 + if (!isOpen()) {
  1989 + if (!open())
  1990 + qFatal("Failed to open file %s for reading", qPrintable(file.name));
  1991 + else
  1992 + idx = 0;
  1993 + }
  1994 +
  1995 + // if we've reached the last frame, we're done
  1996 + if (seekPos.size() == 0) {
  1997 + *done = true;
  1998 + return TemplateList();
  1999 + }
  2000 +
  2001 + seqFile.seekg(seekPos.dequeue(), std::ios::beg);
  2002 +
  2003 + cv::Mat temp;
  2004 + // let imdecode do all the work to decode the compressed img
  2005 + if (imgFormat == "compressed") {
  2006 + int imgSize = readInt() - 4;
  2007 + std::vector<char> imgBuf(imgSize);
  2008 + seqFile.read(&imgBuf[0], imgSize);
  2009 + // flags < 0 means load image as-is (keep color info if available)
  2010 + cv::imdecode(imgBuf, -1, &temp);
  2011 + }
  2012 + // raw images can be loaded straight into a Mat
  2013 + else {
  2014 + char *imgBuf = new char[imgSizeBytes];
  2015 + seqFile.read(imgBuf, imgSizeBytes);
  2016 + int type = (numChan == 1 ? CV_8UC1 : CV_8UC3);
  2017 + temp = cv::Mat(height, width, type, imgBuf);
  2018 + }
  2019 + Template output;
  2020 + output.file = file;
  2021 + if (!annotations.empty()) {
  2022 + output.file.setRects(annotations.first().file.rects());
  2023 + annotations.removeFirst();
  2024 + }
  2025 + output.m() = temp;
  2026 + output.file.set("position",idx);
  2027 + idx++;
  2028 +
  2029 + *done = false;
  2030 + TemplateList rVal;
  2031 + rVal.append(output);
  2032 +
  2033 + return rVal;
  2034 + }
  2035 +
  2036 + void write(const Template &t)
  2037 + {
  2038 + (void) t;
  2039 + qFatal("Not implemented.");
  2040 + }
  2041 +
  2042 +private:
  2043 + qint64 idx;
  2044 + int readInt()
  2045 + {
  2046 + int num;
  2047 + seqFile.read((char*)&num, 4);
  2048 + return num;
  2049 + }
  2050 +
  2051 + // apparently the text in seq files is 16 bit characters (UTF-16?)
  2052 + // since we don't really need the last byte, snad since it gets interpreted as
  2053 + // a terminating char, let's just grab the first byte for storage
  2054 + void readText(int bytes, char *buffer)
  2055 + {
  2056 + seqFile.read(buffer, bytes);
  2057 + for (int i=0; i<bytes; i+=2) {
  2058 + buffer[i/2] = buffer[i];
  2059 + }
  2060 + buffer[bytes/2] = '\0';
  2061 + }
  2062 +
  2063 +protected:
  2064 + std::ifstream seqFile;
  2065 + QQueue<int> seekPos;
  2066 + int width, height, numChan, imgSizeBytes, trueImgSizeBytes, numFrames;
  2067 + QString imgFormat;
  2068 + TemplateList annotations;
  2069 +};
  2070 +BR_REGISTER(Gallery, seqGallery)
  2071 +
1746 void FileGallery::init() 2072 void FileGallery::init()
1747 { 2073 {
1748 f.setFileName(file); 2074 f.setFileName(file);
openbr/plugins/stream.cpp
@@ -23,10 +23,9 @@ class Idiocy : public QObject @@ -23,10 +23,9 @@ class Idiocy : public QObject
23 { 23 {
24 Q_OBJECT 24 Q_OBJECT
25 public: 25 public:
26 - enum StreamModes { StreamVideo,  
27 - DistributeFrames,  
28 - StreamGallery,  
29 - Auto}; 26 + enum StreamModes { DistributeFrames,
  27 + StreamGallery
  28 + };
30 29
31 Q_ENUMS(StreamModes) 30 Q_ENUMS(StreamModes)
32 }; 31 };
@@ -207,88 +206,8 @@ public: @@ -207,88 +206,8 @@ public:
207 virtual bool getNextTemplate(Template &output)=0; 206 virtual bool getNextTemplate(Template &output)=0;
208 protected: 207 protected:
209 Template basis; 208 Template basis;
210 - string getAbsolutePath(QString filename)  
211 - {  
212 - // Yes, we should specify absolute path:  
213 - // http://stackoverflow.com/questions/9396459/loading-a-video-in-opencv-in-python  
214 - QString fileName = (Globals->path.isEmpty() ? "" : Globals->path + "/") + filename;  
215 - return QFileInfo(fileName).absoluteFilePath().toStdString();  
216 - }  
217 }; 209 };
218 210
219 -static QMutex openLock;  
220 -  
221 -// Read a video frame by frame using cv::VideoCapture  
222 -class VideoReader : public TemplateProcessor  
223 -{  
224 -public:  
225 - VideoReader() {}  
226 -  
227 - bool open(Template &input)  
228 - {  
229 - basis = input;  
230 -  
231 - // We can open either files (well actually this includes addresses of ip cameras  
232 - // through ffmpeg), or webcams. Webcam VideoCaptures are created through a separate  
233 - // overload of open that takes an integer, not a string.  
234 - // So, does this look like an integer?  
235 - bool is_int = false;  
236 - int anInt = input.file.name.toInt(&is_int);  
237 - if (is_int)  
238 - {  
239 - bool rc = video.open(anInt);  
240 -  
241 - if (!rc)  
242 - {  
243 - qDebug("open failed!");  
244 - }  
245 - if (!video.isOpened())  
246 - {  
247 - qDebug("Video not open!");  
248 - }  
249 - } else {  
250 - // On windows, this appears to not be thread-safe  
251 - QMutexLocker lock(&openLock);  
252 - video.open(getAbsolutePath(input.file.name));  
253 - }  
254 -  
255 - return video.isOpened();  
256 - }  
257 -  
258 - bool isOpen() { return video.isOpened(); }  
259 -  
260 - void close() { video.release(); }  
261 -  
262 - bool getNextTemplate(Template &output)  
263 - {  
264 - if (!isOpen()) {  
265 - qDebug("video source is not open");  
266 - return false;  
267 - }  
268 - output.file = basis.file;  
269 - output.m() = cv::Mat();  
270 -  
271 - cv::Mat temp;  
272 - bool res = video.read(temp);  
273 -  
274 - if (!res) {  
275 - // The video capture broke, return false.  
276 - output.m() = cv::Mat();  
277 - close();  
278 - return false;  
279 - }  
280 -  
281 - // This clone is critical, if we don't do it then the matrix will  
282 - // be an alias of an internal buffer of the video source, leading  
283 - // to various problems later.  
284 - output.m() = temp.clone();  
285 - return true;  
286 - }  
287 -protected:  
288 - cv::VideoCapture video;  
289 -};  
290 -  
291 -  
292 struct StreamGallery : public TemplateProcessor 211 struct StreamGallery : public TemplateProcessor
293 { 212 {
294 bool open(Template &input) 213 bool open(Template &input)
@@ -387,199 +306,6 @@ protected: @@ -387,199 +306,6 @@ protected:
387 bool data_ok; 306 bool data_ok;
388 }; 307 };
389 308
390 -class SeqReader : public TemplateProcessor  
391 -{  
392 -public:  
393 - SeqReader() {}  
394 -  
395 - bool open(Template &input)  
396 - {  
397 - basis = input;  
398 -  
399 - seqFile.open(getAbsolutePath(input.file.name).c_str(), ios::in | ios::binary | ios::ate);  
400 - if (!isOpen()) return false;  
401 -  
402 - int headSize = 1024;  
403 - // start at end of file to get full size  
404 - int fileSize = seqFile.tellg();  
405 - if (fileSize < headSize) {  
406 - qDebug("No header in seq file");  
407 - return false;  
408 - }  
409 -  
410 - // first 4 bytes store 0xEDFE, next 24 store 'Norpix seq '  
411 - char firstFour[4];  
412 - seqFile.seekg(0, ios::beg);  
413 - seqFile.read(firstFour, 4);  
414 - char nextTwentyFour[24];  
415 - readText(24, nextTwentyFour);  
416 - if (firstFour[0] != (char)0xED || firstFour[1] != (char)0xFE || strncmp(nextTwentyFour, "Norpix seq", 10) != 0) {  
417 - qDebug("Invalid header in seq file");  
418 - return false;  
419 - }  
420 -  
421 - // next 8 bytes for version (skipped below) and header size (1024), then 512 for descr  
422 - seqFile.seekg(4, ios::cur);  
423 - int hSize = readInt();  
424 - if (hSize != headSize) {  
425 - qDebug("Invalid header size");  
426 - return false;  
427 - }  
428 - char desc[512];  
429 - readText(512, desc);  
430 - basis.file.set("Description", QString(desc));  
431 -  
432 - width = readInt();  
433 - height = readInt();  
434 - // get # channels from bit depth  
435 - numChan = readInt()/8;  
436 - int imageBitDepthReal = readInt();  
437 - if (imageBitDepthReal != 8) {  
438 - qDebug("Invalid bit depth");  
439 - return false;  
440 - }  
441 - // the size of just the image part of a raw img  
442 - imgSizeBytes = readInt();  
443 -  
444 - int imgFormatInt = readInt();  
445 - if (imgFormatInt == 100 || imgFormatInt == 200 || imgFormatInt == 101) {  
446 - imgFormat = "raw";  
447 - } else if (imgFormatInt == 102 || imgFormatInt == 201 || imgFormatInt == 103 ||  
448 - imgFormatInt == 1 || imgFormatInt == 2) {  
449 - imgFormat = "compressed";  
450 - } else {  
451 - qFatal("unsupported image format");  
452 - }  
453 -  
454 - numFrames = readInt();  
455 - // skip empty int  
456 - seqFile.seekg(4, ios::cur);  
457 - // the size of a full raw file, with extra crap after img data  
458 - trueImgSizeBytes = readInt();  
459 -  
460 - // gather all the frame positions in an array  
461 - seekPos.reserve(numFrames);  
462 - // start at end of header  
463 - seekPos.append(headSize);  
464 - // extra 8 bytes at end of img  
465 - int extra = 8;  
466 - for (int i=1; i<numFrames; i++) {  
467 - int s;  
468 - // compressed images have different sizes  
469 - // the first byte at the beginning of the file  
470 - // says how big the current img is  
471 - if (imgFormat == "compressed") {  
472 - int lastPos = seekPos[i-1];  
473 - seqFile.seekg(lastPos, ios::beg);  
474 - int currSize = readInt();  
475 - s = lastPos + currSize + extra;  
476 -  
477 - // but there might be 16 extra bytes instead of 8...  
478 - if (i == 1) {  
479 - seqFile.seekg(s, ios::beg);  
480 - char zero;  
481 - seqFile.read(&zero, 1);  
482 - if (zero == 0) {  
483 - s += 8;  
484 - extra += 8;  
485 - }  
486 - }  
487 - }  
488 - // raw images are all the same size  
489 - else {  
490 - s = headSize + (i*trueImgSizeBytes);  
491 - }  
492 -  
493 - seekPos.enqueue(s);  
494 - }  
495 -  
496 -#ifdef CVMATIO  
497 - if (basis.file.contains("vbb")) {  
498 - QString vbb = basis.file.get<QString>("vbb");  
499 - annotations = TemplateList::fromGallery(File(vbb));  
500 - }  
501 -#else  
502 - qWarning("cvmatio not installed, bounding boxes will not be available. Add -DBR_WITH_CVMATIO cmake flag to install.");  
503 -#endif  
504 -  
505 - return true;  
506 - }  
507 -  
508 - bool isOpen()  
509 - {  
510 - return seqFile.is_open();  
511 - }  
512 -  
513 - void close()  
514 - {  
515 - seqFile.close();  
516 - }  
517 -  
518 - bool getNextTemplate(Template &output)  
519 - {  
520 - if (!isOpen()) {  
521 - qDebug("Seq not open");  
522 - return false;  
523 - }  
524 - // if we've reached the last frame, we're done  
525 - if (seekPos.size() == 0) return false;  
526 -  
527 - seqFile.seekg(seekPos.dequeue(), ios::beg);  
528 -  
529 - Mat temp;  
530 - // let imdecode do all the work to decode the compressed img  
531 - if (imgFormat == "compressed") {  
532 - int imgSize = readInt() - 4;  
533 - vector<char> imgBuf(imgSize);  
534 - seqFile.read(&imgBuf[0], imgSize);  
535 - // flags < 0 means load image as-is (keep color info if available)  
536 - imdecode(imgBuf, -1, &temp);  
537 - }  
538 - // raw images can be loaded straight into a Mat  
539 - else {  
540 - char *imgBuf = new char[imgSizeBytes];  
541 - seqFile.read(imgBuf, imgSizeBytes);  
542 - int type = (numChan == 1 ? CV_8UC1 : CV_8UC3);  
543 - temp = Mat(height, width, type, imgBuf);  
544 - }  
545 -  
546 - output.file = basis.file;  
547 - if (!annotations.empty()) {  
548 - output.file.setRects(annotations.first().file.rects());  
549 - annotations.removeFirst();  
550 - }  
551 - output.m() = temp;  
552 -  
553 - return true;  
554 - }  
555 -private:  
556 - int readInt()  
557 - {  
558 - int num;  
559 - seqFile.read((char*)&num, 4);  
560 - return num;  
561 - }  
562 -  
563 - // apparently the text in seq files is 16 bit characters (UTF-16?)  
564 - // since we don't really need the last byte, snad since it gets interpreted as  
565 - // a terminating char, let's just grab the first byte for storage  
566 - void readText(int bytes, char *buffer)  
567 - {  
568 - seqFile.read(buffer, bytes);  
569 - for (int i=0; i<bytes; i+=2) {  
570 - buffer[i/2] = buffer[i];  
571 - }  
572 - buffer[bytes/2] = '\0';  
573 - }  
574 -  
575 -protected:  
576 - ifstream seqFile;  
577 - QQueue<int> seekPos;  
578 - int width, height, numChan, imgSizeBytes, trueImgSizeBytes, numFrames;  
579 - QString imgFormat;  
580 - TemplateList annotations;  
581 -};  
582 -  
583 // Interface for sequentially getting data from some data source. 309 // Interface for sequentially getting data from some data source.
584 // Given a TemplateList, return single template frames sequentially by applying a TemplateProcessor 310 // Given a TemplateList, return single template frames sequentially by applying a TemplateProcessor
585 // to each individual template. 311 // to each individual template.
@@ -650,7 +376,6 @@ public: @@ -650,7 +376,6 @@ public:
650 return true; 376 return true;
651 } 377 }
652 378
653 -  
654 // non-blocking version of getFrame 379 // non-blocking version of getFrame
655 // Returns a NULL FrameData if too many frames are out, or the 380 // Returns a NULL FrameData if too many frames are out, or the
656 // data source is broken. Sets last_frame to true iff the FrameData 381 // data source is broken. Sets last_frame to true iff the FrameData
@@ -744,19 +469,7 @@ protected: @@ -744,19 +469,7 @@ protected:
744 frameSource->close(); 469 frameSource->close();
745 470
746 Template curr = this->templates[current_template_idx]; 471 Template curr = this->templates[current_template_idx];
747 - if (mode == br::Idiocy::Auto)  
748 - {  
749 - delete frameSource;  
750 - if (curr.empty()) {  
751 - if (curr.file.name.right(3) == "seq")  
752 - frameSource = new SeqReader();  
753 - else  
754 - frameSource = new VideoReader();  
755 - }  
756 - else  
757 - frameSource = new DirectReturn();  
758 - }  
759 - else if (mode == br::Idiocy::DistributeFrames) 472 + if (mode == br::Idiocy::DistributeFrames)
760 { 473 {
761 if (!frameSource) 474 if (!frameSource)
762 frameSource = new DirectReturn(); 475 frameSource = new DirectReturn();
@@ -766,15 +479,6 @@ protected: @@ -766,15 +479,6 @@ protected:
766 if (!frameSource) 479 if (!frameSource)
767 frameSource = new StreamGallery(); 480 frameSource = new StreamGallery();
768 } 481 }
769 - else if (mode == br::Idiocy::StreamVideo)  
770 - {  
771 - if (!frameSource) {  
772 - if (curr.file.name.right(3) == "seq")  
773 - frameSource = new SeqReader();  
774 - else  
775 - frameSource = new VideoReader();  
776 - }  
777 - }  
778 open_res = frameSource->open(curr); 482 open_res = frameSource->open(curr);
779 if (!open_res) 483 if (!open_res)
780 { 484 {
@@ -1271,7 +975,7 @@ public: @@ -1271,7 +975,7 @@ public:
1271 Q_PROPERTY(br::Idiocy::StreamModes readMode READ get_readMode WRITE set_readMode RESET reset_readMode) 975 Q_PROPERTY(br::Idiocy::StreamModes readMode READ get_readMode WRITE set_readMode RESET reset_readMode)
1272 Q_PROPERTY(br::Transform* endPoint READ get_endPoint WRITE set_endPoint RESET reset_endPoint STORED true) 976 Q_PROPERTY(br::Transform* endPoint READ get_endPoint WRITE set_endPoint RESET reset_endPoint STORED true)
1273 BR_PROPERTY(int, activeFrames, 100) 977 BR_PROPERTY(int, activeFrames, 100)
1274 - BR_PROPERTY(br::Idiocy::StreamModes, readMode, br::Idiocy::Auto) 978 + BR_PROPERTY(br::Idiocy::StreamModes, readMode, br::Idiocy::StreamGallery)
1275 BR_PROPERTY(br::Transform*, endPoint, make("CollectOutput")) 979 BR_PROPERTY(br::Transform*, endPoint, make("CollectOutput"))
1276 980
1277 friend class StreamTransfrom; 981 friend class StreamTransfrom;
@@ -1589,7 +1293,7 @@ public: @@ -1589,7 +1293,7 @@ public:
1589 Q_PROPERTY(br::Idiocy::StreamModes readMode READ get_readMode WRITE set_readMode RESET reset_readMode) 1293 Q_PROPERTY(br::Idiocy::StreamModes readMode READ get_readMode WRITE set_readMode RESET reset_readMode)
1590 1294
1591 BR_PROPERTY(int, activeFrames, 100) 1295 BR_PROPERTY(int, activeFrames, 100)
1592 - BR_PROPERTY(br::Idiocy::StreamModes, readMode, br::Idiocy::Auto) 1296 + BR_PROPERTY(br::Idiocy::StreamModes, readMode, br::Idiocy::StreamGallery)
1593 BR_PROPERTY(br::Transform*, endPoint, make("CollectOutput")) 1297 BR_PROPERTY(br::Transform*, endPoint, make("CollectOutput"))
1594 1298
1595 bool timeVarying() const { return true; } 1299 bool timeVarying() const { return true; }