You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
262 lines
8.8 KiB
C
262 lines
8.8 KiB
C
|
4 years ago
|
/*!
|
||
|
|
* \file SampleDBManager.h
|
||
|
|
* \date 2019/10/17
|
||
|
|
*
|
||
|
|
* \author Lin, Chi
|
||
|
|
* Contact: lin.chi@hzleaper.com
|
||
|
|
*
|
||
|
|
*
|
||
|
|
* \note
|
||
|
|
*/
|
||
|
|
|
||
|
|
#ifndef __SampleDBManager_h_
|
||
|
|
#define __SampleDBManager_h_
|
||
|
|
|
||
|
|
#include "CyclopsCommon.h"
|
||
|
|
#include "StdUtils.h"
|
||
|
|
#include "DetectRoi.h"
|
||
|
|
#include <list>
|
||
|
|
#include "CyclopsModules.h"
|
||
|
|
#include "SampleInstance.h"
|
||
|
|
|
||
|
|
/*! \brief Manager for sample database
|
||
|
|
* Support add/delete/query operations, could be in-memory or persistent
|
||
|
|
* Example:
|
||
|
|
* \code{.cpp}
|
||
|
|
* SampleDBManager sdbMgr; // or create via global factory SampleDBManager::getInstance()
|
||
|
|
* bool ret= sdbMgr.init("my_new_db", "z:/db_folder_name"); // or pass in empty folder path indicating an in-memory database
|
||
|
|
* if (ret) {
|
||
|
|
* sdbMgr.add(sampleImg, SampleDBManager::TrainSet);
|
||
|
|
* // ... and more
|
||
|
|
* sdbMgr.add(testImg, SampleDBManager::TestSet);
|
||
|
|
* // ... and more
|
||
|
|
* }
|
||
|
|
* \endcode
|
||
|
|
* To get sample instances for browsing/modification and other usage, use getIterator
|
||
|
|
*
|
||
|
|
*/
|
||
|
|
class SampleDBManager : public ICyclopsModuleInstance
|
||
|
|
{
|
||
|
|
/*! \fn getClassLabel
|
||
|
|
* Get class label of this sample database, see also load()
|
||
|
|
*/
|
||
|
|
DECLARE_PARAMETER_GET(std::string, ClassLabel)
|
||
|
|
|
||
|
|
/*! \fn setCacheImage
|
||
|
|
* Define whether we'll cache image in sample instance, default to false, see also getCacheImage()
|
||
|
|
* \fn getCacheImage
|
||
|
|
* Get value of whether we'll cache image in sample instance, see also setCacheImage()
|
||
|
|
*/
|
||
|
|
DECLARE_PARAMETER(bool, CacheImage)
|
||
|
|
|
||
|
|
/*! \fn setUseAutoSize
|
||
|
|
* Define whether use auto generated uniformed size as sample size, or use customized size, default to true, see also getCacheImage()
|
||
|
|
* \fn getUseAutoSize
|
||
|
|
* Get whether use auto generated uniformed size as sample size, or use customized size, see also setUseAutoSize()
|
||
|
|
*/
|
||
|
|
DECLARE_PARAMETER(bool, UseAutoSize)
|
||
|
|
|
||
|
|
/*! \fn setCustomSize
|
||
|
|
* Define customized sample size, used when UseAutoSize = false, default to (64, 64)
|
||
|
|
*/
|
||
|
|
DECLARE_PARAMETER_SET(Size, CustomSize)
|
||
|
|
|
||
|
|
public:
|
||
|
|
enum SampleDBType {
|
||
|
|
All = 0, TrainSet, TestSet
|
||
|
|
};
|
||
|
|
|
||
|
|
public:
|
||
|
|
SampleDBManager()
|
||
|
|
: mInited(false), mInMemory(false), mCacheImage(false), mUseAutoSize(true), mCustomSize(64, 64),
|
||
|
|
mAutoSize(0, 0), mAutoSizeCount(0)
|
||
|
|
{}
|
||
|
|
virtual ~SampleDBManager() {}
|
||
|
|
|
||
|
|
typedef std::shared_ptr<SampleDBManager> Ptr;
|
||
|
|
DECL_GET_INSTANCE(SampleDBManager::Ptr)
|
||
|
|
|
||
|
|
/*! initialize the whole sample database
|
||
|
|
* @param classLabel string label of class
|
||
|
|
* @param rootPath working directory, where the dbinfo file locates, empty for in-memory mode
|
||
|
|
* @return true if everything is fine
|
||
|
|
*/
|
||
|
|
virtual bool init(const std::string& classLabel, const std::string& rootPath);
|
||
|
|
|
||
|
|
/*! return whether this is a well initialized */
|
||
|
|
bool hasInit() const { return mInited; }
|
||
|
|
|
||
|
|
/*! change class label */
|
||
|
|
virtual void setClassLabel(const std::string& classLabel);
|
||
|
|
|
||
|
|
/*! refresh the whole sample database, add new sample instance from disk and remove legacy
|
||
|
|
* @return true if everything is fine
|
||
|
|
*/
|
||
|
|
virtual bool refresh(bool force = false);
|
||
|
|
|
||
|
|
/*! \fn serializeToMemory
|
||
|
|
* Serialize information of this sample database into a in-memory string, see also deserializeFromMemory()
|
||
|
|
* @param str used to take the output serialization result
|
||
|
|
* @return true for succeed, false for fail
|
||
|
|
* \fn serializeToFile
|
||
|
|
* Serialize information of this sample database into a text file, see also deserializeFromFile()
|
||
|
|
* @param filename file name (full path) where we will write the data
|
||
|
|
* @return true for succeed, false for fail
|
||
|
|
* \fn deserializeFromMemory
|
||
|
|
* Deserialize the sample database from in-memory string, see also serializeToMemory()
|
||
|
|
* @param str in-memory string
|
||
|
|
* @return true for succeed, false for fail
|
||
|
|
* \fn deserializeFromFile
|
||
|
|
* Deserialize the sample database from a text file, see also serializeToFile()
|
||
|
|
* @param filename file name (full path) where we will read the data
|
||
|
|
* @return true for succeed, false for fail
|
||
|
|
*/
|
||
|
|
DECL_SERIALIZE_FUNCS
|
||
|
|
|
||
|
|
/*! get train set size */
|
||
|
|
std::size_t trainSetCount() const { return mTrainSet.size(); }
|
||
|
|
|
||
|
|
/*! get test set size */
|
||
|
|
std::size_t testSetCount() const { return mTestSet.size(); }
|
||
|
|
|
||
|
|
/*! Add image to train or test set. We'll save image to disk under current working directory
|
||
|
|
* @param img input image
|
||
|
|
* @param dbType train or test dataset
|
||
|
|
* @param droi roi
|
||
|
|
* @param pUserData optional user data map
|
||
|
|
* @param pNewName return name of the new added
|
||
|
|
* @return true if everything works fine
|
||
|
|
*/
|
||
|
|
virtual bool addToDB(const Mat& img, DetectRoi& droi, SampleDBType dbType,
|
||
|
|
SampleInstance::UserDataMap* pUserData = nullptr, std::string* pNewName = nullptr);
|
||
|
|
|
||
|
|
/** @overload */
|
||
|
|
virtual bool addToDB(const Mat& img, SampleDBType dbType,
|
||
|
|
SampleInstance::UserDataMap* pUserData = nullptr, std::string* pNewName = nullptr);
|
||
|
|
|
||
|
|
/** @overload */
|
||
|
|
virtual bool addToDB(const Mat& img, const vector<Point2f>& roi, SampleDBType dbType,
|
||
|
|
SampleInstance::UserDataMap* pUserData = nullptr, std::string* pNewName = nullptr);
|
||
|
|
|
||
|
|
/** @overload */
|
||
|
|
virtual bool addToDB(const Mat& img, const Mat& mask, SampleDBType dbType,
|
||
|
|
SampleInstance::UserDataMap* pUserData = nullptr, std::string* pNewName = nullptr);
|
||
|
|
|
||
|
|
/*! Add a new data folder to train or test set, and perform incremental refresh immediately
|
||
|
|
* @param path path to the new data folder
|
||
|
|
* @param dbType train or test dataset
|
||
|
|
* @return true if everything works fine
|
||
|
|
*/
|
||
|
|
virtual bool addFolderToDB(const std::string& path, SampleDBType dbType);
|
||
|
|
|
||
|
|
/*! Remove sample instance from train or test set, permanently remove image and roi file from disk
|
||
|
|
* @param instName sample instance name to remove
|
||
|
|
* @param dbType train or test dataset
|
||
|
|
* @return true if everything works fine
|
||
|
|
*/
|
||
|
|
virtual bool removeFromDB(const std::string& instName, SampleDBType dbType);
|
||
|
|
|
||
|
|
/*! Remove existing data folder from train or test set
|
||
|
|
* @param path path to the new data folder
|
||
|
|
* @param dbType train or test dataset
|
||
|
|
* @return true if everything works fine
|
||
|
|
*/
|
||
|
|
virtual bool removeFolderFromDB(const std::string& path, SampleDBType dbType);
|
||
|
|
|
||
|
|
/*! Query sample instance in this database
|
||
|
|
* @param instName sample instance name to remove
|
||
|
|
* @param dbType train or test dataset
|
||
|
|
* @return pointer to sample instance
|
||
|
|
*/
|
||
|
|
virtual SampleInstPtr queryDB(const std::string& instName, SampleDBType dbType);
|
||
|
|
|
||
|
|
/*! Get iterator to visit corresponding dataset(or subset of it) in specific order maybe
|
||
|
|
* Example:
|
||
|
|
* \code{.cpp}
|
||
|
|
* SampleInstIterator it = sdbMgrPtr->getIterator(SampleDBManager::TrainSet, SortBy::Date);
|
||
|
|
* while (it.hasNext()) {
|
||
|
|
* SampleInstPtr& siPtr = it.next();
|
||
|
|
* // do stuff to sample instance
|
||
|
|
* }
|
||
|
|
* \endcode
|
||
|
|
* @param dbType train, test or from all datasets
|
||
|
|
* @return iterator
|
||
|
|
*/
|
||
|
|
virtual SampleInstIterator getIterator(SampleDBType dbType, SortBy sortBy = SortBy::None, int topN = -1);
|
||
|
|
|
||
|
|
/*! Remove entire database, including train and test set */
|
||
|
|
virtual bool removeEntireDB();
|
||
|
|
|
||
|
|
/*! Get working directory */
|
||
|
|
virtual std::string getWorkDir() const;
|
||
|
|
|
||
|
|
/*! Get default dataset folder */
|
||
|
|
virtual const std::string& getDefaultDataFolder(SampleDBType dbType) const;
|
||
|
|
|
||
|
|
/*! Get all dataset folder */
|
||
|
|
const std::list<std::string>& getDataFolder(SampleDBType dbType) const {
|
||
|
|
return dbType == SampleDBType::TrainSet ? mTrainSetPaths : mTestSetPaths;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*! Get uniformed sample size, either auto-generated or customized */
|
||
|
|
Size getSampleSize() const {
|
||
|
|
if (mUseAutoSize) {
|
||
|
|
return mAutoSizeCount > 0 ? Size(mAutoSize.width / mAutoSizeCount, mAutoSize.height / mAutoSizeCount) : Size(64, 64);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
return mCustomSize;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*! cleanup all cached data in sample instances as it's invalid */
|
||
|
|
virtual void cleanupSampleCache();
|
||
|
|
|
||
|
|
/*! Parameter pack for how to generate more samples */
|
||
|
|
struct MoreSamplePack {
|
||
|
|
Rangef shiftRng = Rangef(0, 0);
|
||
|
|
Rangef rotateRng = Rangef(0, 0);
|
||
|
|
Rangef resizeRng = Rangef(1, 1);
|
||
|
|
Rangef grayRng = Rangef(0, 0);
|
||
|
|
float shiftStep = 0.5;
|
||
|
|
float rotateStep = 0.5;
|
||
|
|
float resizeStep = 0.1;
|
||
|
|
float grayStep = 10;
|
||
|
|
};
|
||
|
|
/*! generate more samples by shifting, rotation, resizing, gray offset
|
||
|
|
* @param dbType train or test dataset
|
||
|
|
* @param samplePack how to generate more samples
|
||
|
|
* @param 0 to take all, otherwise we'll randomly pick some
|
||
|
|
* @return true if everything works fine
|
||
|
|
*/
|
||
|
|
virtual bool generateMoreSamples(SampleDBType dbType, const MoreSamplePack& samplePack, int moreCount = 0);
|
||
|
|
|
||
|
|
private:
|
||
|
|
bool serialize(FileStorage& fs);
|
||
|
|
bool deserialize(const FileNode& fs);
|
||
|
|
bool ensureDefaultDataFolder(SampleDBType dbType);
|
||
|
|
SampleInstMap& getDataSet(SampleDBType dbType) {
|
||
|
|
return dbType == SampleDBType::TrainSet ? mTrainSet : mTestSet;
|
||
|
|
}
|
||
|
|
|
||
|
|
void refreshDataset(SampleInstMap& dataset, SampleInstMap& newDataset, const std::string& dirPath,
|
||
|
|
bool calcAutoSize = false);
|
||
|
|
|
||
|
|
private:
|
||
|
|
bool mInited;
|
||
|
|
bool mInMemory;
|
||
|
|
std::string mDBInfoPath;
|
||
|
|
std::list<std::string> mTrainSetPaths;
|
||
|
|
std::list<std::string> mTestSetPaths;
|
||
|
|
std::string mTrainGenSetPath;
|
||
|
|
std::string mTestGenSetPath;
|
||
|
|
|
||
|
|
SampleInstMap mTrainSet;
|
||
|
|
SampleInstMap mTestSet;
|
||
|
|
|
||
|
|
Size2d mAutoSize;
|
||
|
|
int mAutoSizeCount;
|
||
|
|
};
|
||
|
|
|
||
|
|
#endif // SampleDBManager_h_
|
||
|
|
|