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.
wheeldetect/molunCar/ImageCompareModel.h

380 lines
13 KiB
C

/*! \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"
#include "CircleDetector.h"
#define COLS_SCALE (float)(1200.0/ 416.0)
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));
Mat genMask(const Mat& img, Point2f center, float innerR = -1,
float outterR = -1,
int type = CV_32FC1);
Mat genInsideMask (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);
float allocateInnerRadius(cv::Mat subImage);
float allocateRadius(cv::Mat subImage);
void resizeVecMat(vector<Mat> srcVec, vector<Mat> &dstVec);
void resizeMat(Mat src, Mat &dst);
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),
realWidth(0),
realHeight(0),
rInner(DBL_MAX)
{};
ImageCompareModel(const ImageCompareModel& model)
: mAlignBaseImg(model.getBaseImg().clone())
, mWeightMat(model.getWeightMat().clone())
, mMatchValScale(model.getMatchValScale())
, mInSideBaseImg(model.getInsideBaseImg().clone())
, mInsideWeightMat(model.getInsideWeightImg().clone())
{
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();
mInSideBaseImg = model.getInsideBaseImg().clone();
mInsideWeightMat = model.getInsideWeightImg().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();
rInner = model.getInnerR();
}
void genMask();
void genOutterMask();
void preProcessImage(Mat& img, Mat &insideImg) 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 <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ<EFBFBD><EFBFBD>
\param Mat * pRImg <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>תƥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
\param bool isFilterSize <EFBFBD>Ƿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ<EFBFBD><EFBFBD><EFBFBD>ߴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
\return double <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
\see compare(Mat, Mat, Mat*, Mat*)
*/
double compare(Mat srcImage, Mat* pRImg = NULL, int levelNum = 1, bool isFilterSize = true, int flag = 0,
double md_diameter = 0, double md_height = 0);
//! ѵ<><D1B5><EFBFBD>õ<EFBFBD><C3B5><EFBFBD>׼ͼ<D7BC><CDBC>mBaseImg
/*!
\param const vector<Mat> & imgVec <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͬ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ
\return void
*/
void train(const vector<Mat>& vec);
void calculateAllParams(const vector<Mat>& imgVec);
void trueSampleWeightRecon(const vector<Mat>& resizedVec, const vector<Mat>& resizedCenterVec, vector<RotateMatchResult> rmrVec,
vector<RotateMatchResult> rmrVecInside);
void trueWeightRecon(const Mat& rImg, const Mat& baseImg, const Mat& insideRimg, const Mat& insideBaseImg);
void weightMapping(const Mat& weight, double maxVal, const Mat& i_mData, double i_maxVal);
//void falseWeightmapping(Mat &img);
double descendFunction(double pixVal, double maxVal);
double penltyCoeff(double matchedVal, int diameterMean, int targetDiameterm, double modelDiamter, double modelHeight) 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 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڸ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ
\return void
*/
void computeDisThre(const vector<Mat>& imgVec, double* pMinDis = NULL, double md_diameter = 0, double md_height = 0);
double filterTrainImage(const Mat &img);
//! <20><><EFBFBD>м<EFBFBD><D0BC><EFBFBD>rotate
/*!
\param int index <EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>index
\param void *p <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD>
*/
void parallelDetect(int index, void *p) const;
//! <20><>ȡ<EFBFBD><C8A1>׼ͼ<D7BC><CDBC>
/*!
\return cv::Mat <EFBFBD><EFBFBD>׼ͼ<EFBFBD><EFBFBD>
*/
Mat getInsideBaseImg() const{ return mInSideBaseImg; }
Mat getInsideWeightImg() const{ return mInsideWeightMat; }
float getInnerR() const { return rInner; }
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 <EFBFBD>ļ<EFBFBD>·<EFBFBD><EFBFBD>
*/
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();
void setRealWidth(int val){ realWidth = val; }
void setRealHeight(int val){ realHeight = val; }
int getRealWidth(){ return realWidth; }
int getRealHeight(){ return realHeight; }
void printLog(string root, string log, double n = 0) const;
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 <EFBFBD><EFBFBD><EFBFBD>Ƚϵ<EFBFBD>ͼ<EFBFBD><EFBFBD>img0
\param Mat img1 <EFBFBD><EFBFBD><EFBFBD>Ƚϵ<EFBFBD>ͼ<EFBFBD><EFBFBD>img1
\param Mat * pRImg0 <EFBFBD><EFBFBD>img0<EFBFBD>ͱ<EFBFBD>׼ͼmBaseImg<EFBFBD><EFBFBD>תƥ<EFBFBD><EFBFBD><EFBFBD>Ľ<EFBFBD><EFBFBD><EFBFBD>rimg0
\param Mat * pRImg1 <EFBFBD><EFBFBD>img1<EFBFBD>ͱ<EFBFBD>׼ͼmBaseImg<EFBFBD><EFBFBD>תƥ<EFBFBD><EFBFBD><EFBFBD>Ľ<EFBFBD><EFBFBD><EFBFBD>rimg1
\return double <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><EFBFBD>ȡֵ<EFBFBD><EFBFBD>СΪ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, double md_diameter, double md_height) 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;
Mat insideWeightRecon;
Mat innerTempl;
double mDisThre{ DBL_MAX };
string mName;
double falseMinDis;
int meanDiameter;
int realWidth;
int realHeight;
// INSIDE PART
Mat mInSideBaseImg, mInsideCompareBaseImg;
Mat mInsideWeightMat;
Mat m32fInsideMaskImg, m8uInsideMaskImg;
float rInner;
float x_aix;
float y_aix;
// some training data
double mTrueSampleDisStddev, mTrueSampleDisMean, mTrueSampleDisMax{DBL_MAX}, mTrueSampleDisMin;
double mFalseSampleMinDis;
// temp data
string mFilePath;
void initMultiScaleModel();
MultiScaleImageCompareModel* mpMultiScaleModel;
// cache
bool mIsEnableCache;
map<uchar*, double> mDisCache;
public:
static int m_parallelFlag;
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;
};