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.
newValue/3part/Cyclops/include/ImageCompareModel.h

339 lines
11 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*! \file ImageCompareModel.h
Copyright (C) 2014 Hangzhou Leaper.
Created by bang.jin at 2017/02/04.
*/
#pragma once
#include <opencv2/opencv.hpp>
#include <opencv2/opencv_modules.hpp>
#include <string>
#include <map>
#include <set>
#include <fstream>
#include "MultiScaleObj.h"
using std::set;
using std::map;
using std::fstream;
using std::string;
using namespace cv;
class MultiScaleImageCompareModel;
class ImageCompareModel
{
public:
class RotateMatchResult
{
public:
Mat mBestRImg;
double mBestAngle;
};
class RotateData
{
public:
RotateData() {};
RotateData(const Mat &img, Point pt, double dAngleStep, int size)
: mImgSrc(img)
, mStartAngle(0)
, mEndAngle(360)
{
init(img, pt, dAngleStep, size);
};
void init(const Mat& img, Point pt, double dAngleStep, int size)
{
mImgSrc = img;
mStartAngle = 0;
mEndAngle = 360.0;
mRImgVec.clear();
mRImgVec.resize(size);
mDisValVec.clear();
mDisValVec.resize(size, FLT_MAX);
mCenter = pt;
mAngleStep = dAngleStep;
}
double angle(int index)
{
return index*mAngleStep + mStartAngle;
}
double bestAngle()
{
if (mDisValVec.empty())
{
return -DBL_MAX;
}
size_t bestIndex = min_element(mDisValVec.begin(),
mDisValVec.end()) - mDisValVec.begin();
double bestAngle = angle(bestIndex);
return bestAngle;
}
Mat bestRImg()
{
if (mRImgVec.empty())
{
return Mat();
}
size_t bestIndex = min_element(mDisValVec.begin(),
mDisValVec.end()) - mDisValVec.begin();
return mRImgVec[bestIndex];
}
double mAngleStep;
Mat mImgSrc;
Point mCenter;
vector<Mat> mRImgVec;
vector<float> mDisValVec;
float mStartAngle, mEndAngle;
};
public:
static cv::Point2f refineCircleCen(const Mat& img, Point2f cen);
static Mat genWeightImage(const Mat& img, Point2f center, float innerR = -1,
float outterR = -1);
static void selfRotationSimilarityFeature(const Mat& img,
vector<float>& vec, Point2f cen = Point2f(-1, -1));
static Mat genMask(const Mat& img, Point2f center, float innerR = -1,
float outterR = -1,
int type = CV_32FC1);
static void genCandidateRepeatNums(set<unsigned int>& canNums);
static int computeRepeatNum(const Mat& img);
static int recognizeLowerExtremes(const Mat& vec, set<unsigned int> canNums, int extremeRefineRange = 5, vector<int> *pExtemeIdxVec = 0);
static int recognizeRepeatedLocalExtremas(const Mat& vec, const set<unsigned int>& canNums, int extremeRefineRange = 5, vector<int> *pExtremeIdxVec = 0);
static void genUniformSepIdx(int num, int startIdx, int endIdx, vector<int>& cenVec);
static void genAngleRanges(vector<int> cenVec, vector<Range>& rangeVec, int localRange);
static void genCandidateAngleRanges(vector<float> disVec,
float angleStep, vector<Range>& rangeVec);
static void genCandidateAngleRanges(const Mat& disMat, float angleStep,
vector<Range>& rangeVec, float rangeScale = 1);
static void selfRotateMin(const Mat& img, Mat& weightMat, int repeatNum);
public:
ImageCompareModel() :
mMatchValScale(1.0),
mTargetMeanVal(127),
mTargetStddevVal(50),
mHighlightsThreshold(256),
mRepeatNum(0),
mName("unnamed"),
mDisThre(DBL_MAX),
mTrueSampleDisMin(DBL_MAX),
mTrueSampleDisMax(DBL_MIN),
mTrueSampleDisMean(-1),
mTrueSampleDisStddev(-1),
mIsEnableCache(false),
mpMultiScaleModel(NULL),
meanDiameter(0)
{};
ImageCompareModel(const ImageCompareModel& model)
: mAlignBaseImg(model.getBaseImg().clone())
, mWeightMat(model.getWeightMat().clone())
, mMatchValScale(model.getMatchValScale())
{
genMask();
}
~ImageCompareModel() {};
void printInfo();
void saveImages(string dirPath);
bool save2file(string filePath);
bool readFromFile(string filePath);
void operator = (const ImageCompareModel& model)
{
mAlignBaseImg = model.getBaseImg().clone();
mWeightMat = model.getWeightMat().clone();
mMatchValScale = model.getMatchValScale();
mTargetMeanVal = model.getTargetMeanVal();
mTargetStddevVal = model.getTargetStddevVal();
mName = model.getName();
mTrueSampleDisStddev = model.getDisStdDev();
mTrueSampleDisMean = model.getDisMean();
mTrueSampleDisMax = model.getDisMax();
mTrueSampleDisMin = model.getDisMin();
meanDiameter = model.getMeanDiamter();
}
void genMask();
void preProcessImage(Mat& img) const;
void preProcessImage(Mat& img, const Mat& mask, double dstMean, double dstStddev, int highlightsThreshold) const;
void preProcessImage(Mat& img, const Mat& mask, const Mat& weightMat, double dstMean,
double dstStddev, int highlightsThreshold) const;
void preProcessImage0(Mat& img) const;
void weightOptimization(const vector<Mat>& falseSamples);
//! <20><>һ<EFBFBD><D2BB>ͼ<EFBFBD><CDBC><EFBFBD>ͱ<EFBFBD>׼ͼmBaseImg<6D><67><EFBFBD><EFBFBD><EFBFBD><EFBFBD>תƥ<D7AA><EFBFBD><E4A3AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ò<EFBFBD><C3B2><EFBFBD>ֵ
/*!
\param Mat img <20><><EFBFBD><EFBFBD>ͼ<EFBFBD><CDBC>
\param Mat * pRImg <20><><EFBFBD><EFBFBD>ͼ<EFBFBD><CDBC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>תƥ<D7AA><C6A5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
\param bool isFilterSize <20>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD><EFBFBD>ͼ<EFBFBD><CDBC><EFBFBD>ߴ<EFBFBD><DFB4><EFBFBD><EFBFBD><EFBFBD>
\return double <20><><EFBFBD><EFBFBD>ֵ
\see compare(Mat, Mat, Mat*, Mat*)
*/
double compare(Mat img, Mat* pRImg = NULL, int levelNum = 1, bool isFilterSize = true, int flag = 0);
//! ѵ<><D1B5><EFBFBD>õ<EFBFBD><C3B5><EFBFBD>׼ͼ<D7BC><CDBC>mBaseImg
/*!
\param const vector<Mat> & imgVec <20><><EFBFBD><EFBFBD>ͬ<EFBFBD><CDAC><EFBFBD><EFBFBD>ѵ<EFBFBD><D1B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ
\return void
*/
void train(const vector<Mat>& imgVec);
void calculateAllParams(const vector<Mat>& imgVec);
void trueSampleWeightRecon(const vector<Mat>& resizedVec, vector<RotateMatchResult> rmrVec);
void trueWeightRecon(const Mat& rImg, const Mat& baseImg);
void weightMapping(const Mat& weight, double maxVal);
//void falseWeightmapping(Mat &img);
double descendFunction(double pixVal, double maxVal);
double penltyCoeff(double matchedVal, int diameterMean, int targetDiameter) const;
//! <20><><EFBFBD>ݸ<EFBFBD><DDB8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD><D0B6><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>µ<EFBFBD>ͼ<EFBFBD><CDBC><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD>ڸ<EFBFBD><DAB8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/*!
\param const vector<Mat> & imgVec <20><><EFBFBD><EFBFBD><EFBFBD>ڸ<EFBFBD><DAB8><EFBFBD><EFBFBD><EFBFBD>ѵ<EFBFBD><D1B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ
\return void
*/
void computeDisThre(const vector<Mat>& imgVec, double* pMinDis = NULL);
double filterTrainImage(const Mat &img);
//! <20><><EFBFBD>м<EFBFBD><D0BC><EFBFBD>rotate
/*!
\param int index <20><>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD>index
\param void *p <20><><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8>
*/
void parallelDetect(int index, void *p) const;
//! <20><>ȡ<EFBFBD><C8A1>׼ͼ<D7BC><CDBC>
/*!
\return cv::Mat <20><>׼ͼ<D7BC><CDBC>
*/
Mat getBaseImg() const { return mAlignBaseImg; }
void setBaseImg(const Mat& img) { mAlignBaseImg = img; }
Mat getWeightMat() const { return mWeightMat; }
void setWeightMat(Mat val) { mWeightMat = val; }
double getMatchValScale() const { return mMatchValScale; }
void setMatchValScale(double val) { mMatchValScale = val; }
int getTargetStddevVal() const { return mTargetStddevVal; }
void setTargetStddevVal(int val) { mTargetStddevVal = val; }
int getTargetMeanVal() const { return mTargetMeanVal; }
void setTargetMeanVal(int val) { mTargetMeanVal = val; }
int getRepeatNum() const { return mRepeatNum; }
void setRepeatNum(int val) { mRepeatNum = val; }
string getName() const { return mName; }
void setName(string val) { mName = val; }
double getDisStdDev() const { return mTrueSampleDisStddev; }
double getDisMean() const { return mTrueSampleDisMean; }
double getDisMin() const { return mTrueSampleDisMin; }
double getDisMax() const { return mTrueSampleDisMax; }
double getFalseSampleMinDis() const { return mFalseSampleMinDis; }
double getMeanDiamter() const { return meanDiameter; }
//! <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>ִ<EFBFBD><D6B4>readFromFileʱ<65><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>·<EFBFBD><C2B7>
/*!
\return string <20>ļ<EFBFBD>·<EFBFBD><C2B7>
*/
string getFilePath() const { return mFilePath; }
double getDisThre() const { return mDisThre; }
void setDisThre(double val) { mDisThre = val; }
//! <20><><EFBFBD>û<EFBFBD><C3BB><EFBFBD><E6A1A3><EFBFBD><EFBFBD><EFBFBD>Ὣÿ<E1BDAB>ε<EFBFBD><CEB5><EFBFBD>compare<72>ӿ<EFBFBD><D3BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>img<6D><67><EFBFBD><EFBFBD><EFBFBD><EFBFBD>dataָ<61><D6B8><EFBFBD><EFBFBD>Ϊkey<65>
// <20><><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5>
/*!
\return void
*/
void setIsEnableCache(bool val) { mIsEnableCache = val; }
bool getIsEnableCache() const { return mIsEnableCache; }
void clearDisCache() { mDisCache.clear(); }
ImageCompareModel* scale(float s);
RotateMatchResult rotateMatch(const Mat& img, int levelNum = 1, float angleStep = 1.0,
float startAngle = 0, float endAngle = 360) const;
void rotateMatchData(const Mat& img, RotateData* pData, const vector<Range>& angleRangeVec, float angleStep,
Mat& disMat) const;
void rotateMatchData(const Mat& img, RotateData* pData, float angleStep = 1.0,
float startAngle = 0, float endAngle = 360) const;
void rotateMatchData(const Mat& img, RotateData* pData, float angleStep,
const vector<Range>& angleRangeVec) const;
cv::Mat getM8uMaskImg() const { return m8uMaskImg; }
void setM8uMaskImg(cv::Mat val) { m8uMaskImg = val; }
cv::Mat getM32fMaskImg() const { return m32fMaskImg; }
void setM32fMaskImg(cv::Mat val) { m32fMaskImg = val; }
int computeRepeatNum();
protected:
//! <20><><EFBFBD><EFBFBD>δ<EFBFBD><CEB4><EFBFBD>ɣ<EFBFBD><C9A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ<EFBFBD><CDBC><EFBFBD>ֱ<EFBFBD><D6B1>ͱ<EFBFBD>׼ͼmBaseImg<6D><67><EFBFBD><EFBFBD><EFBFBD><EFBFBD>תƥ<D7AA><EFBFBD><E4A3AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ò<EFBFBD><C3B2><EFBFBD>ֵ
/*!
\param Mat img0 <20><><EFBFBD>Ƚϵ<C8BD>ͼ<EFBFBD><CDBC>img0
\param Mat img1 <20><><EFBFBD>Ƚϵ<C8BD>ͼ<EFBFBD><CDBC>img1
\param Mat * pRImg0 <20><>img0<67>ͱ<EFBFBD>׼ͼmBaseImg<6D><67>תƥ<D7AA><C6A5><EFBFBD>Ľ<EFBFBD><C4BD><EFBFBD>rimg0
\param Mat * pRImg1 <20><>img1<67>ͱ<EFBFBD>׼ͼmBaseImg<6D><67>תƥ<D7AA><C6A5><EFBFBD>Ľ<EFBFBD><C4BD><EFBFBD>rimg1
\return double <20><><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5>ȡֵ<C8A1><D6B5>СΪmMatchValScale*norm(rimg0 - rimg1)/(cols*rows)
*/
double compare(Mat img0, Mat img1, Mat* pRImg0 = NULL, Mat* pRImg1 = NULL);
void setFilePath(string val) { mFilePath = val; }
double genMatchValue(const Mat& rImg, const Mat& baseImg, const Mat& maskImg, int flag, int diameter) const;
double genMatchValue(const Mat& dMat) const;
double scaleMatchValue(double val) const;
void weightReconstruction(const Mat& rImg, const Mat& baseImg, const Mat& maskImg, Mat &reConImg);
void preWeightReconstruction(Mat img, Mat &reConImg);
void setFalseSampleMinDis(double iVal) { mFalseSampleMinDis = iVal; }
double mMatchValScale;
int mTargetMeanVal, mTargetStddevVal, mHighlightsThreshold;
int mRepeatNum;
Mat mAlignBaseImg, mCompareBaseImg;
Mat mWeightMat;
Mat m32fMaskImg, m8uMaskImg;
Mat mDisMat;
Mat reConMat;
Mat falseReConMat;
double mDisThre;
string mName;
double falseMinDis;
int meanDiameter;
// some training data
double mTrueSampleDisStddev, mTrueSampleDisMean, mTrueSampleDisMax, mTrueSampleDisMin;
double mFalseSampleMinDis;
// temp data
string mFilePath;
void initMultiScaleModel();
MultiScaleImageCompareModel* mpMultiScaleModel;
// cache
bool mIsEnableCache;
map<uchar*, double> mDisCache;
private:
};
class ImageCompareModelInvoker : public cv::ParallelLoopBody
{
public:
ImageCompareModelInvoker(const ImageCompareModel *pModel, void* pData)
: m_pModel(pModel), m_pData(pData)
{}
private:
const ImageCompareModel *m_pModel;
void *m_pData;
virtual void operator() (const cv::Range& range) const;
};