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

373 lines
12 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"
#include "ICompareModel.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 ICompareModel
{
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);
virtual 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 <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 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 <20><><EFBFBD><EFBFBD>ͬ<EFBFBD><CDAC><EFBFBD><EFBFBD>ѵ<EFBFBD><D1B5><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 <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 md_diameter = 0, double md_height = 0);
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 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 <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();
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 <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, 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;
};