|
|
/*! \file ImageCompareModel.cpp
|
|
|
|
|
|
Copyright (C) 2014 Hangzhou Leaper.
|
|
|
|
|
|
Created by bang.jin at 2017/02/04.
|
|
|
|
|
|
*/
|
|
|
|
|
|
#include "ImageCompareModel.h"
|
|
|
#include "CVUtils.h"
|
|
|
#include "MultiScaleImageCompareModel.h"
|
|
|
#include <fstream>
|
|
|
#include <iostream>
|
|
|
//#define DEBUG_VIEW_INTERNAL_MAT
|
|
|
#define IMGCMP_STR_NAME "name"
|
|
|
#define IMGCMP_STR_IMAGE_COMPARE_MODEL "imageCompareModel"
|
|
|
#define IMGCMP_STR_ALIGN_BASE_IMAGE "alignBaseImage"
|
|
|
#define IMGCMP_STR_COMPARE_BASE_IMAGE "compareBaseImage"
|
|
|
#define IMGCMP_STR_WEIGHT_MAT "weightMat"
|
|
|
#define IMGCMP_STR_MATCH_VAL_SCALE "matchValScale"
|
|
|
#define IMGCMP_STR_TARGET_MEAN_VAL "targetMeanVal"
|
|
|
#define IMGCMP_STR_TARGET_STDDEV_VAL "targetStddevVal"
|
|
|
#define IMGCMP_STR_REPEAT_NUM "repeatNum"
|
|
|
#define IMGCMP_STR_TRUE_SAMPLE_DIS_MEAN "trueSampleDisMean"
|
|
|
#define IMGCMP_STR_TRUE_SAMPLE_DIS_STDDEV "trueSampleDisStddev"
|
|
|
#define IMGCMP_STR_TRUE_SAMPLE_DIS_MIN "trueSampleDisMin"
|
|
|
#define IMGCMP_STR_TRUE_SAMPLE_DIS_MAX "trueSampleDisMax"
|
|
|
#define IMGCMP_STR_DIS_THRE "disThre"
|
|
|
#define IMGCMP_STR_FALSE_SAMPLE_MIN_DIS "falseSampleMinDis"
|
|
|
#define IMGCMP_STR_TRAIN_DIS "trainDis"
|
|
|
#define IMGCMP_STR_SMALLEST_MATCH_DIS "falseMinDis"
|
|
|
#define IMGCMP_STR_AVER_DIAMETER "averageDiameter"
|
|
|
#define IMGCMP_STR_INSIDE_WEIGHT "insideWeightimage"
|
|
|
#define IMGCMP_STR_INSIDE_AVE_IMAGE "insideBaseimage"
|
|
|
#define IMGCMP_STR_INSIDE_COMP_AVE_IMAGE "insideCompareBaseImage"
|
|
|
#define IMGCMP_STR_INSIDE_RADIUS "insideRadius"
|
|
|
#define IMGCMP_STR_INSIDE_TEMPL "innerTempl"
|
|
|
|
|
|
#define IMGCMP_CACHE_MAX_SIZE 100
|
|
|
|
|
|
#define MIN_CIRCLE_RADII 5
|
|
|
#define MAX_CIRCLE_RADII 110
|
|
|
int ImageCompareModel::m_parallelFlag = 0;
|
|
|
cv::Point2f ImageCompareModel::refineCircleCen(const Mat& img, Point2f cen)
|
|
|
{
|
|
|
int r = 2;
|
|
|
vector<double> vec;
|
|
|
double minDiff = DBL_MAX;
|
|
|
Point2f bestCenter;
|
|
|
vector<float> bestDftVec;
|
|
|
for (float y = cen.y - r; y <= cen.y + r; y += 0.5)
|
|
|
{
|
|
|
for (float x = cen.x - r; x <= cen.x + r; x += 0.5)
|
|
|
{
|
|
|
std::cout << "newCenter: " << x << "-" << y << ", ";
|
|
|
|
|
|
Point2f newCenter(x, y);
|
|
|
|
|
|
vector<float> vec;
|
|
|
selfRotationSimilarityFeature(img, vec, newCenter);
|
|
|
|
|
|
vector<float> dftVec;
|
|
|
dft(vec, dftVec);
|
|
|
|
|
|
// no need to code for plotting in visual studio later than 2017,
|
|
|
// install the ArrayPlotter extension to see the data distribution
|
|
|
#if (_MSC_VER < 1910) // vs2017
|
|
|
CvPlot::plot<float>("refineCenter", &(vec[0]), vec.size());
|
|
|
#endif
|
|
|
|
|
|
float diffVal = sum<float>(vec.begin(), vec.end());
|
|
|
|
|
|
vec.push_back(diffVal);
|
|
|
|
|
|
if (minDiff > diffVal)
|
|
|
{
|
|
|
minDiff = diffVal;
|
|
|
bestCenter = newCenter;
|
|
|
bestDftVec = dftVec;
|
|
|
}
|
|
|
|
|
|
std::cout << "diff: " << diffVal << ", "
|
|
|
" minDiff: " << minDiff << ", "
|
|
|
" bestCenter: " << bestCenter.x << "-" << bestCenter.y <<
|
|
|
std::endl;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return bestCenter;
|
|
|
}
|
|
|
|
|
|
cv::Mat ImageCompareModel::genWeightImage(const Mat& img, Point2f center,
|
|
|
float innerR /*= -1*/, float outterR /*= -1*/)
|
|
|
{
|
|
|
if (innerR == -1)
|
|
|
{
|
|
|
// default is 30
|
|
|
innerR = img.rows*0.175;
|
|
|
}
|
|
|
if (outterR == -1)
|
|
|
{
|
|
|
// default is max radius - 10
|
|
|
outterR = img.rows*0.475;
|
|
|
}
|
|
|
|
|
|
Mat weightImg;
|
|
|
weightImg.create(img.size(), CV_32FC1);
|
|
|
weightImg.setTo(0);
|
|
|
|
|
|
uchar* pData = weightImg.data;
|
|
|
for (int y = 0; y < weightImg.rows; y++)
|
|
|
{
|
|
|
float* pFData = (float*)weightImg.row(y).data;
|
|
|
for (int x = 0; x < weightImg.cols; x++)
|
|
|
{
|
|
|
float& val = pFData[x];
|
|
|
float dx = center.x - x;
|
|
|
float dy = center.y - y;
|
|
|
float r = sqrt(dx*dx + dy*dy);
|
|
|
if (r > outterR || r < innerR)
|
|
|
{
|
|
|
val = 0;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
val = min(outterR - r, r - innerR);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return weightImg;
|
|
|
}
|
|
|
|
|
|
void ImageCompareModel::selfRotationSimilarityFeature(
|
|
|
const Mat& img, vector<float>& vec, Point2f center /*= Point2f(-1, -1)*/)
|
|
|
{
|
|
|
float angleStep = 1.0;
|
|
|
if (center.x < 0 || center.y < 0)
|
|
|
{
|
|
|
center = Point2f(img.cols / 2.0, img.rows / 2.0);
|
|
|
}
|
|
|
|
|
|
double bestVal = DBL_MAX;
|
|
|
Mat bestRImg;
|
|
|
Mat fImg;
|
|
|
img.convertTo(fImg, CV_32FC1);
|
|
|
|
|
|
Mat weightImg = genWeightImage(img, center);
|
|
|
fImg = fImg.mul(weightImg);
|
|
|
|
|
|
double sumVal = sum(weightImg).val[0];
|
|
|
|
|
|
Mat baseImg;
|
|
|
{
|
|
|
Mat t = getRotationMatrix2D(center, 1.0, 1.0);
|
|
|
Mat rImg;
|
|
|
warpAffine(fImg, rImg, t, fImg.size(), CV_INTER_CUBIC);
|
|
|
t = getRotationMatrix2D(center, -1.0, 1.0);
|
|
|
warpAffine(rImg, baseImg, t, rImg.size(), CV_INTER_CUBIC);
|
|
|
}
|
|
|
|
|
|
#ifdef DEBUG_VIEW_INTERNAL_MAT
|
|
|
Mat viewBaseImg = baseImg / 255.0/25.0;
|
|
|
Mat viewfImg = fImg / 255.0/25.0;
|
|
|
#endif
|
|
|
|
|
|
for (float a = 0; a <= 360.0; a += angleStep)
|
|
|
{
|
|
|
Mat t = getRotationMatrix2D(center, a, 1.0);
|
|
|
Mat rImg;
|
|
|
warpAffine(fImg, rImg, t, fImg.size(), CV_INTER_CUBIC);
|
|
|
|
|
|
Mat diffImg = baseImg - rImg;
|
|
|
//diffImg = diffImg.mul(weightImg);
|
|
|
double diffVal = norm(diffImg)/sumVal;
|
|
|
vec.push_back(diffVal);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
cv::Mat ImageCompareModel::genMask(const Mat& img, Point2f center,
|
|
|
float innerR /*= -1*/, float outterR /*= -1*/, int type /*= CV_32FC1*/)
|
|
|
{
|
|
|
Mat mask(img.size(), CV_8UC1);
|
|
|
mask.setTo(0);
|
|
|
if (innerR == -1)
|
|
|
{
|
|
|
// default is 30
|
|
|
innerR = img.rows*0.178;
|
|
|
//innerR = img.rows;
|
|
|
}
|
|
|
if (outterR == -1)
|
|
|
{
|
|
|
// default is max radius - 10
|
|
|
outterR = img.rows*0.425;
|
|
|
//outterR = img.rows;
|
|
|
}
|
|
|
circle(mask, center, outterR, Scalar(255), -1);
|
|
|
circle(mask, center, innerR, Scalar(0), -1);
|
|
|
if (type != CV_8UC1)
|
|
|
{
|
|
|
converToType(mask, type);
|
|
|
mask /= 255;
|
|
|
}
|
|
|
return mask;
|
|
|
}
|
|
|
|
|
|
void ImageCompareModel::genMask()
|
|
|
{
|
|
|
m32fMaskImg = genMask(mAlignBaseImg, Point2f(mAlignBaseImg.cols / 2.0, mAlignBaseImg.rows / 2.0));
|
|
|
m8uMaskImg = genMask(mAlignBaseImg, Point2f(mAlignBaseImg.cols / 2.0, mAlignBaseImg.rows / 2.0),
|
|
|
-1.0, -1.0, CV_8UC1);
|
|
|
m32fInsideMaskImg = genInsideMask(mInSideBaseImg, Point2f(mInSideBaseImg.cols / 2.0, mInSideBaseImg.rows / 2.0));
|
|
|
m8uInsideMaskImg = genInsideMask(mInSideBaseImg, Point2f(mInSideBaseImg.cols / 2.0, mInSideBaseImg.rows / 2.0),
|
|
|
-1.0, -1.0, CV_8UC1);
|
|
|
}
|
|
|
|
|
|
void ImageCompareModel::printInfo()
|
|
|
{
|
|
|
std::cout << IMGCMP_STR_IMAGE_COMPARE_MODEL << ": ";
|
|
|
std::cout << std::endl;
|
|
|
|
|
|
printProperty(1, IMGCMP_STR_NAME, mName);
|
|
|
|
|
|
printIndent(1);
|
|
|
std::cout << IMGCMP_STR_ALIGN_BASE_IMAGE << ": ";
|
|
|
std::cout << std::endl;
|
|
|
printMatInfo(mAlignBaseImg, 2);
|
|
|
std::cout << std::endl;
|
|
|
|
|
|
printIndent(1);
|
|
|
std::cout << IMGCMP_STR_WEIGHT_MAT << ": ";
|
|
|
std::cout << std::endl;
|
|
|
printMatInfo(mWeightMat, 2);
|
|
|
std::cout << std::endl;
|
|
|
|
|
|
printProperty(1, IMGCMP_STR_MATCH_VAL_SCALE, mMatchValScale);
|
|
|
printProperty(1, IMGCMP_STR_TARGET_MEAN_VAL, mTargetMeanVal);
|
|
|
printProperty(1, IMGCMP_STR_TARGET_STDDEV_VAL, mTargetStddevVal);
|
|
|
printProperty(1, IMGCMP_STR_REPEAT_NUM, mRepeatNum);
|
|
|
printProperty(1, IMGCMP_STR_DIS_THRE, mDisThre);
|
|
|
printProperty(1, IMGCMP_STR_TRUE_SAMPLE_DIS_STDDEV, mTrueSampleDisStddev);
|
|
|
printProperty(1, IMGCMP_STR_TRUE_SAMPLE_DIS_MEAN, mTrueSampleDisMean);
|
|
|
printProperty(1, IMGCMP_STR_TRUE_SAMPLE_DIS_MAX, mTrueSampleDisMax);
|
|
|
printProperty(1, IMGCMP_STR_TRUE_SAMPLE_DIS_MIN, mTrueSampleDisMin);
|
|
|
|
|
|
printProperty(1, "filePath", mFilePath);
|
|
|
printProperty(1, "isEnableCache", mIsEnableCache);
|
|
|
}
|
|
|
|
|
|
void ImageCompareModel::saveImages(string dirPath)
|
|
|
{
|
|
|
imwrite(dirPath + "/base.png", mAlignBaseImg);
|
|
|
imwrite(dirPath + "/weight.png", mWeightMat);
|
|
|
}
|
|
|
|
|
|
bool ImageCompareModel::save2file(string filePath)
|
|
|
{
|
|
|
FileStorage fs(filePath, FileStorage::WRITE);
|
|
|
if (!fs.isOpened())
|
|
|
{
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
fs << IMGCMP_STR_NAME << mName <<
|
|
|
IMGCMP_STR_ALIGN_BASE_IMAGE << mAlignBaseImg <<
|
|
|
IMGCMP_STR_COMPARE_BASE_IMAGE << mCompareBaseImg <<
|
|
|
IMGCMP_STR_WEIGHT_MAT << mWeightMat <<
|
|
|
IMGCMP_STR_INSIDE_AVE_IMAGE << mInSideBaseImg <<
|
|
|
IMGCMP_STR_INSIDE_COMP_AVE_IMAGE << mInsideCompareBaseImg <<
|
|
|
IMGCMP_STR_INSIDE_WEIGHT << mInsideWeightMat <<
|
|
|
IMGCMP_STR_INSIDE_TEMPL << innerTempl <<
|
|
|
IMGCMP_STR_MATCH_VAL_SCALE << mMatchValScale <<
|
|
|
IMGCMP_STR_TARGET_MEAN_VAL << mTargetMeanVal <<
|
|
|
IMGCMP_STR_TARGET_STDDEV_VAL << mTargetStddevVal <<
|
|
|
IMGCMP_STR_REPEAT_NUM << mRepeatNum <<
|
|
|
IMGCMP_STR_TRUE_SAMPLE_DIS_MEAN << mTrueSampleDisMean <<
|
|
|
IMGCMP_STR_TRUE_SAMPLE_DIS_STDDEV << mTrueSampleDisStddev <<
|
|
|
IMGCMP_STR_TRUE_SAMPLE_DIS_MIN << mTrueSampleDisMin <<
|
|
|
IMGCMP_STR_TRUE_SAMPLE_DIS_MAX << mTrueSampleDisMax <<
|
|
|
IMGCMP_STR_FALSE_SAMPLE_MIN_DIS << getFalseSampleMinDis() <<
|
|
|
IMGCMP_STR_DIS_THRE << mDisThre <<
|
|
|
IMGCMP_STR_TRAIN_DIS << mDisMat <<
|
|
|
IMGCMP_STR_AVER_DIAMETER << meanDiameter <<
|
|
|
IMGCMP_STR_INSIDE_RADIUS << rInner;
|
|
|
|
|
|
setFilePath(filePath);
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
bool ImageCompareModel::readFromFile(string filePath)
|
|
|
{
|
|
|
FileStorage fs(filePath, FileStorage::READ);
|
|
|
if (!fs.isOpened())
|
|
|
{
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
fs[IMGCMP_STR_ALIGN_BASE_IMAGE] >> mAlignBaseImg;
|
|
|
fs[IMGCMP_STR_COMPARE_BASE_IMAGE] >> mCompareBaseImg;
|
|
|
fs[IMGCMP_STR_WEIGHT_MAT] >> mWeightMat;
|
|
|
fs[IMGCMP_STR_INSIDE_AVE_IMAGE] >> mInSideBaseImg;
|
|
|
fs[IMGCMP_STR_INSIDE_COMP_AVE_IMAGE] >> mInsideCompareBaseImg;
|
|
|
fs[IMGCMP_STR_INSIDE_WEIGHT] >> mInsideWeightMat;
|
|
|
fs[IMGCMP_STR_INSIDE_TEMPL] >> innerTempl;
|
|
|
mMatchValScale = (double)fs[IMGCMP_STR_MATCH_VAL_SCALE];
|
|
|
|
|
|
FileNode fn = fs[IMGCMP_STR_TARGET_MEAN_VAL];
|
|
|
if (!fn.empty())
|
|
|
{
|
|
|
mTargetMeanVal = (int)fn;
|
|
|
}
|
|
|
|
|
|
fn = fs[IMGCMP_STR_TARGET_STDDEV_VAL];
|
|
|
if (!fn.empty())
|
|
|
{
|
|
|
mTargetStddevVal = (int)fn;
|
|
|
}
|
|
|
|
|
|
fn = fs[IMGCMP_STR_REPEAT_NUM];
|
|
|
if (!fn.empty())
|
|
|
{
|
|
|
mRepeatNum = (int)fn;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
//mRepeatNum = computeRepeatNum();
|
|
|
}
|
|
|
|
|
|
fn = fs[IMGCMP_STR_NAME];
|
|
|
if (!fn.empty())
|
|
|
{
|
|
|
mName = (string)fn;
|
|
|
}
|
|
|
|
|
|
fn = fs[IMGCMP_STR_TRUE_SAMPLE_DIS_MEAN];
|
|
|
if (!fn.empty())
|
|
|
{
|
|
|
mTrueSampleDisMean = (double)fn;
|
|
|
}
|
|
|
fn = fs[IMGCMP_STR_TRUE_SAMPLE_DIS_STDDEV];
|
|
|
if (!fn.empty())
|
|
|
{
|
|
|
mTrueSampleDisStddev = (double)fn;
|
|
|
}
|
|
|
fn = fs[IMGCMP_STR_TRUE_SAMPLE_DIS_MIN];
|
|
|
if (!fn.empty())
|
|
|
{
|
|
|
mTrueSampleDisMin = (double)fn;
|
|
|
}
|
|
|
fn = fs[IMGCMP_STR_TRUE_SAMPLE_DIS_MAX];
|
|
|
if (!fn.empty())
|
|
|
{
|
|
|
mTrueSampleDisMax = (double)fn;
|
|
|
}
|
|
|
fn = fs[IMGCMP_STR_FALSE_SAMPLE_MIN_DIS];
|
|
|
if (!fn.empty())
|
|
|
{
|
|
|
setFalseSampleMinDis((double)fn);
|
|
|
}
|
|
|
fn = fs[IMGCMP_STR_DIS_THRE];
|
|
|
if (!fn.empty())
|
|
|
{
|
|
|
mDisThre = (double)fn;
|
|
|
}
|
|
|
|
|
|
fn = fs[IMGCMP_STR_AVER_DIAMETER];
|
|
|
if (!fn.empty())
|
|
|
{
|
|
|
meanDiameter = (int)fn;
|
|
|
}
|
|
|
|
|
|
fn = fs[IMGCMP_STR_INSIDE_RADIUS];
|
|
|
if (!fn.empty())
|
|
|
{
|
|
|
rInner = (float)fn;
|
|
|
}
|
|
|
|
|
|
setFilePath(filePath);
|
|
|
|
|
|
genMask();
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
void ImageCompareModel::preProcessImage(Mat& img, Mat &insideImg) const
|
|
|
{
|
|
|
preProcessImage(img, m8uMaskImg, mTargetMeanVal, mTargetStddevVal, mHighlightsThreshold);
|
|
|
if (insideImg.empty())
|
|
|
{
|
|
|
return;
|
|
|
}
|
|
|
preProcessImage(insideImg, m8uInsideMaskImg, mTargetMeanVal, mTargetStddevVal, mHighlightsThreshold);
|
|
|
}
|
|
|
|
|
|
void ImageCompareModel::preProcessImage(Mat& img, const Mat& mask, double tarMean,
|
|
|
double tarStddev, int highlightsThreshold) const
|
|
|
{
|
|
|
if (img.channels() > 1)
|
|
|
{
|
|
|
img = getFirstChannel(img);
|
|
|
}
|
|
|
if (img.type() != CV_32FC1)
|
|
|
{
|
|
|
converToType(img, CV_32FC1);
|
|
|
}
|
|
|
|
|
|
Mat gaussImg;
|
|
|
GaussianBlur(img, gaussImg, Size(3, 3), 5.0);
|
|
|
img = gaussImg;
|
|
|
|
|
|
Mat dilatedMask;
|
|
|
dilate(mask, dilatedMask, Mat::ones(Size(3, 3), CV_32FC1));
|
|
|
|
|
|
Mat hightlightsMask = img < highlightsThreshold;
|
|
|
Mat imgMask = hightlightsMask & dilatedMask;
|
|
|
|
|
|
Scalar meanScalar, stddevScalar;
|
|
|
meanStdDev(img, meanScalar, stddevScalar, imgMask);
|
|
|
img = (img - meanScalar.val[0]) * tarStddev / stddevScalar.val[0] + tarMean;
|
|
|
|
|
|
converToType(imgMask, CV_32FC1);
|
|
|
imgMask /= 255.0;
|
|
|
Mat imgNorm = cocentricNorm(img, Point2f(img.cols / 2.0, img.rows / 2.0),
|
|
|
imgMask, 125);
|
|
|
#ifdef DEBUG_VIEW_INTERNAL_MAT
|
|
|
Mat vImgNorm = imgNorm / 255.0;
|
|
|
#endif
|
|
|
img = imgNorm;
|
|
|
}
|
|
|
|
|
|
void ImageCompareModel::preProcessImage(Mat& img, const Mat& mask,
|
|
|
const Mat& weightMat, double dstMean, double dstStddev, int highlightsThreshold) const
|
|
|
{
|
|
|
if (img.channels() > 1)
|
|
|
{
|
|
|
img = getFirstChannel(img);
|
|
|
}
|
|
|
if (img.type() != CV_32FC1)
|
|
|
{
|
|
|
converToType(img, CV_32FC1);
|
|
|
}
|
|
|
|
|
|
Mat gaussImg;
|
|
|
GaussianBlur(img, gaussImg, Size(3, 3), 5.0);
|
|
|
img = gaussImg;
|
|
|
|
|
|
Mat hightlightsMask = img < highlightsThreshold;
|
|
|
Mat imgMask = hightlightsMask & mask & (weightMat > 0);
|
|
|
|
|
|
Scalar meanScalar, stddevScalar;
|
|
|
meanStdDev(img, meanScalar, stddevScalar, imgMask);
|
|
|
img = (img - meanScalar.val[0]) * dstStddev / stddevScalar.val[0] + dstMean;
|
|
|
//img.setTo(0, img < 0);
|
|
|
converToType(hightlightsMask, CV_32FC1);
|
|
|
//converToType(imgMask, CV_32FC1);
|
|
|
Mat imgNorm = cocentricNorm(img, Point2f(img.cols / 2.0, img.rows / 2.0),
|
|
|
weightMat.mul(hightlightsMask), 125);
|
|
|
#ifdef DEBUG_VIEW_INTERNAL_MAT
|
|
|
Mat vImgNorm = imgNorm / 255.0;
|
|
|
#endif
|
|
|
img = imgNorm;
|
|
|
}
|
|
|
|
|
|
void ImageCompareModel::preProcessImage0(Mat& img) const
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
double ImageCompareModel::compare(Mat img0, Mat img1, Mat* pRImg0, Mat* pRImg1)
|
|
|
{
|
|
|
if (img0.size() != img1.size() && img0.size() != mAlignBaseImg.size())
|
|
|
{
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
double bestMatchVal = DBL_MAX;
|
|
|
int bestAngle = -1;
|
|
|
Mat bestImg1;
|
|
|
double bestDD = 0;
|
|
|
|
|
|
double w = 0;
|
|
|
|
|
|
Point2f center((float)img1.cols / 2.0, (float)img1.rows / 2.0);
|
|
|
Mat rImg0 = rotateMatch(img0).mBestRImg;
|
|
|
Mat rImg1 = rotateMatch(img1).mBestRImg;
|
|
|
Mat dMat = rImg0 - rImg1;
|
|
|
converToType(dMat, CV_32FC1);
|
|
|
dMat = dMat.mul(mWeightMat);
|
|
|
|
|
|
if (pRImg0)
|
|
|
{
|
|
|
*pRImg0 = rImg0;
|
|
|
}
|
|
|
if (pRImg1)
|
|
|
{
|
|
|
*pRImg1 = rImg1;
|
|
|
}
|
|
|
|
|
|
return genMatchValue(dMat);
|
|
|
}
|
|
|
|
|
|
double ImageCompareModel::compare(Mat srcImage, Mat* pRImg /*= NULL*/, int levelNum /*= 1*/,
|
|
|
bool isFilterSize /*= true*/, int flag, double md_diameter, double md_height)
|
|
|
{
|
|
|
if (mIsEnableCache)
|
|
|
{
|
|
|
auto cacheIter = mDisCache.find(srcImage.data);
|
|
|
if (cacheIter != mDisCache.end())
|
|
|
{
|
|
|
return cacheIter->second;
|
|
|
}
|
|
|
}
|
|
|
/* CircleDetector cd;
|
|
|
cd.setAlgoType(CircleDetector::PeakCircle);
|
|
|
cd.setEdgeWidth(3);
|
|
|
//cd.setPolarity(Polarity::White2Black);
|
|
|
cd.setPolarity(Polarity::Either);
|
|
|
cd.setFindBy(FindBy::Best);
|
|
|
//cd.setFindBy(FindBy::Last);
|
|
|
cd.setRadii(MIN_CIRCLE_RADII, MAX_CIRCLE_RADII);
|
|
|
cd.setACThres(5);
|
|
|
Vec3f bestCircle;
|
|
|
cd.detectBest(srcImage, Point2f(srcImage.cols / 2, srcImage.rows / 2), bestCircle, nullptr);
|
|
|
|
|
|
#ifdef DEBUG_VIEW_INTERNAL_MAT
|
|
|
vector<Mat> vecs;
|
|
|
vecs.push_back(srcImage);
|
|
|
vecs.push_back(srcImage);
|
|
|
vecs.push_back(srcImage);
|
|
|
Mat rr;
|
|
|
merge(vecs, rr);
|
|
|
|
|
|
circle(rr, Point2f(bestCircle[0], bestCircle[1]), bestCircle[2], Scalar(255, 0, 0), 2);
|
|
|
#endif
|
|
|
|
|
|
if (bestCircle[2] < 3 || bestCircle[0] == 0 || bestCircle[1] == 0)
|
|
|
return DBL_MAX;
|
|
|
*/
|
|
|
// int x_Axis = bestCircle[0] - MAX_CIRCLE_RADII;
|
|
|
// int y_Axis = bestCircle[1] - MAX_CIRCLE_RADII;
|
|
|
|
|
|
int x_Axis = srcImage.cols / 2 - MAX_CIRCLE_RADII;
|
|
|
int y_Axis = srcImage.rows / 2 - MAX_CIRCLE_RADII;
|
|
|
|
|
|
int r_Axis = 2 * MAX_CIRCLE_RADII;
|
|
|
|
|
|
if (x_Axis <= 0 || y_Axis <= 0)
|
|
|
return DBL_MAX;
|
|
|
if (r_Axis <= 0)
|
|
|
return DBL_MAX;
|
|
|
if (r_Axis >= srcImage.cols || r_Axis >= srcImage.rows)
|
|
|
return DBL_MAX;
|
|
|
// if (srcImage.cols < (bestCircle[0] + MAX_CIRCLE_RADII) || srcImage.rows < (bestCircle[1] + MAX_CIRCLE_RADII))
|
|
|
// return DBL_MAX;
|
|
|
|
|
|
if (srcImage.cols < (srcImage.cols / 2 + MAX_CIRCLE_RADII) || srcImage.rows < (srcImage.rows / 2 + MAX_CIRCLE_RADII))
|
|
|
return DBL_MAX;
|
|
|
|
|
|
Rect rect(x_Axis, y_Axis, r_Axis, r_Axis);
|
|
|
Mat srcCenterMat;
|
|
|
srcImage(rect).copyTo(srcCenterMat);
|
|
|
Mat img, centerMat;
|
|
|
resizeMat(srcImage, img);
|
|
|
resizeMat(srcCenterMat, centerMat);
|
|
|
Mat rawImg = img.clone();
|
|
|
int nRadiusDiff = 15;
|
|
|
if (mAlignBaseImg.size() != img.size() || mInSideBaseImg.size() !=centerMat.size())
|
|
|
{
|
|
|
if (isFilterSize \
|
|
|
&& abs(mAlignBaseImg.size().width - img.size().width) > nRadiusDiff \
|
|
|
|| abs(mInSideBaseImg.size().width - centerMat.size().width) > 3)
|
|
|
{
|
|
|
return DBL_MAX;
|
|
|
}
|
|
|
resize(img, img, mAlignBaseImg.size());
|
|
|
resize(centerMat, centerMat, mInSideBaseImg.size());
|
|
|
}
|
|
|
|
|
|
Mat matchImg = img.clone();
|
|
|
Mat matchInsideImg = centerMat.clone();
|
|
|
|
|
|
preProcessImage(matchImg, matchInsideImg);
|
|
|
|
|
|
if (!mpMultiScaleModel)
|
|
|
{
|
|
|
initMultiScaleModel();
|
|
|
}
|
|
|
m_parallelFlag = 0;
|
|
|
RotateMatchResult rmr = rotateMatch(matchImg, levelNum);
|
|
|
Mat rImg = rmr.mBestRImg;
|
|
|
m_parallelFlag = 1;
|
|
|
RotateMatchResult rmmInside = rotateMatch(matchInsideImg, 1);
|
|
|
Mat rInsideImg = rmmInside.mBestRImg;
|
|
|
if (rImg.empty() || rInsideImg.empty())
|
|
|
{
|
|
|
return DBL_MAX;
|
|
|
}
|
|
|
|
|
|
#ifdef DEBUG_VIEW_INTERNAL_MAT
|
|
|
Mat vRImg = rImg / 255.0;
|
|
|
Mat vInsideMat = rInsideImg / 255.0;
|
|
|
#endif
|
|
|
|
|
|
double bestAngle = rmr.mBestAngle;
|
|
|
Mat cmpImg = rotateImage(img, Point2f(img.cols / 2.0, img.rows / 2.0),
|
|
|
bestAngle);
|
|
|
|
|
|
// remove highlights
|
|
|
Mat hightlightsMask = cmpImg < mHighlightsThreshold;
|
|
|
converToType(hightlightsMask, CV_32FC1);
|
|
|
hightlightsMask /= 255.0;
|
|
|
|
|
|
Mat unifiedMask = m32fMaskImg.mul(hightlightsMask).mul(mWeightMat);
|
|
|
//Mat ii = mWeightMat / 255.0;
|
|
|
preProcessImage(cmpImg, m8uMaskImg, mWeightMat, mTargetMeanVal,
|
|
|
mTargetStddevVal, mHighlightsThreshold);
|
|
|
|
|
|
cmpImg.setTo(0, cmpImg < 0);
|
|
|
|
|
|
converToType(cmpImg, CV_32FC1);
|
|
|
normSectors_tarImg(cmpImg, unifiedMask, imgCen(cmpImg), 1,
|
|
|
mCompareBaseImg);
|
|
|
|
|
|
double bestInsideAngle = rmmInside.mBestAngle;
|
|
|
Mat camInsideMat = rotateImage(centerMat, Point2f(centerMat.cols / 2.0, centerMat.rows / 2.0),
|
|
|
bestInsideAngle);
|
|
|
|
|
|
// float offset = 5;
|
|
|
// float startX = mAlignBaseImg.cols / 2.0 - rInner - offset;
|
|
|
// float startY = mAlignBaseImg.rows / 2.0 - rInner - offset;
|
|
|
// Rect rect(startX, startY, 2*(rInner + offset), 2*(rInner + offset));
|
|
|
// Mat innerPartMat = camInsideMat(rect);
|
|
|
// Mat rstMat;
|
|
|
// cv::matchTemplate(innerTempl, innerPartMat, rstMat, CV_TM_SQDIFF_NORMED);
|
|
|
// double minVal;
|
|
|
// Point minLoc;
|
|
|
// minMaxLoc(rstMat, &minVal, NULL, &minLoc, NULL);
|
|
|
//#ifdef DEBUG_VIEW_INTERNAL_MAT
|
|
|
// Mat test1 = innerPartMat.clone();
|
|
|
// Mat test2 = innerPartMat.clone();
|
|
|
// vector<Mat> imgs;
|
|
|
// imgs.push_back(test2);
|
|
|
// imgs.push_back(test1);
|
|
|
// imgs.push_back(innerPartMat);
|
|
|
// Mat rst;
|
|
|
// merge(imgs, rst);
|
|
|
// cv::rectangle(rst, Rect(minLoc.x, minLoc.y, innerTempl.cols, innerTempl.rows), Scalar(0, 0, 255));
|
|
|
//#endif
|
|
|
// //debug
|
|
|
//
|
|
|
Mat highLightInsideMask = camInsideMat < mHighlightsThreshold;
|
|
|
converToType(highLightInsideMask, CV_32FC1);
|
|
|
highLightInsideMask /= 255.0;
|
|
|
Mat unifiedInsideMask = m32fInsideMaskImg.mul(highLightInsideMask).mul(mInsideWeightMat);
|
|
|
preProcessImage(camInsideMat, m8uInsideMaskImg, mInsideWeightMat, mTargetMeanVal,
|
|
|
mTargetStddevVal, mHighlightsThreshold);
|
|
|
Mat vcamInside = camInsideMat / 255.0;
|
|
|
camInsideMat.setTo(0, camInsideMat < 0);
|
|
|
//mInsideCompareBaseImg.setTo(0, mInsideCompareBaseImg < 0);
|
|
|
normSectors_tarImg(camInsideMat, unifiedInsideMask, imgCen(camInsideMat), 1, mInsideCompareBaseImg);
|
|
|
//
|
|
|
mInsideCompareBaseImg.setTo(0, mInsideCompareBaseImg < 0);
|
|
|
#ifdef DEBUG_VIEW_INTERNAL_MAT
|
|
|
Mat vRotatedImg0 = cmpImg / 255.0;
|
|
|
Mat vrotatedInsideImage = camInsideMat / 255.0;
|
|
|
cv::imwrite("F:\\temp\\insideAfterSector.png", camInsideMat);
|
|
|
#endif
|
|
|
|
|
|
#ifdef DEBUG_VIEW_INTERNAL_MAT
|
|
|
Mat vRotatedImg1 = mCompareBaseImg / 255.0;
|
|
|
Mat vrotatedInsideBase = mInsideCompareBaseImg / 255.0;
|
|
|
cv::imwrite("F:\\temp\\insideAfterSectorCompareBase.png", mInsideCompareBaseImg);
|
|
|
#endif
|
|
|
|
|
|
cmpImg.setTo(0, cmpImg < 10);
|
|
|
//camInsideMat.setTo(0, camInsideMat < 10);
|
|
|
if (pRImg)
|
|
|
{
|
|
|
*pRImg = cmpImg;
|
|
|
}
|
|
|
m_parallelFlag = 0;
|
|
|
double ret = genMatchValue(cmpImg, mCompareBaseImg, unifiedMask, flag, rawImg.rows, md_diameter, md_height);//<2F>ó<EFBFBD><C3B3><EFBFBD><EFBFBD><EFBFBD>ֵ
|
|
|
|
|
|
m_parallelFlag = 1;
|
|
|
double retInside = genMatchValue(camInsideMat, mInsideCompareBaseImg, unifiedInsideMask, 0, rawImg.rows, md_diameter, md_height);//<2F>ó<EFBFBD><C3B3><EFBFBD><EFBFBD><EFBFBD>ֵ
|
|
|
|
|
|
ret = 0.6*ret + 0.4*retInside;
|
|
|
|
|
|
if (ret > mDisThre)
|
|
|
{
|
|
|
return DBL_MAX;
|
|
|
}
|
|
|
|
|
|
if (mIsEnableCache)
|
|
|
{
|
|
|
mDisCache[img.data] = ret;
|
|
|
if (mDisCache.size() > IMGCMP_CACHE_MAX_SIZE)
|
|
|
{
|
|
|
mDisCache.clear();
|
|
|
}
|
|
|
}
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
void ImageCompareModel::train(const vector<Mat>& vec)
|
|
|
{
|
|
|
#ifdef _DEBUG
|
|
|
std::cout << getName() << std::endl;
|
|
|
#endif _DEBUG
|
|
|
if (0 == vec.size()) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// CircleDetector cd;
|
|
|
// cd.setAlgoType(CircleDetector::PeakCircle);
|
|
|
// cd.setEdgeWidth(3);
|
|
|
// //cd.setPolarity(Polarity::White2Black);
|
|
|
// cd.setPolarity(Polarity::Either);
|
|
|
// cd.setFindBy(FindBy::Best);
|
|
|
// //cd.setFindBy(FindBy::Last);
|
|
|
// cd.setRadii(MIN_CIRCLE_RADII, MAX_CIRCLE_RADII);
|
|
|
// cd.setACThres(5);
|
|
|
vector<Mat> centerMatVec;
|
|
|
vector<Mat> tmpVec;
|
|
|
for (int i = 0; i < vec.size(); i++)
|
|
|
{
|
|
|
Mat originalMat = vec[i];
|
|
|
Vec3f bestCircle;
|
|
|
Point2f p = Point2f(originalMat.cols / 2.0, originalMat.rows / 2.0);
|
|
|
// cd.detectBest(originalMat, Point2f(originalMat.cols / 2.0, originalMat.rows / 2.0), bestCircle, nullptr);
|
|
|
#ifdef DEBUG_VIEW_INTERNAL_MAT
|
|
|
Mat img1 = vec.front().clone();
|
|
|
Mat img2 = vec.front().clone();
|
|
|
vector<Mat> vecs;
|
|
|
vecs.push_back(originalMat);
|
|
|
vecs.push_back(originalMat);
|
|
|
vecs.push_back(originalMat);
|
|
|
Mat rr;
|
|
|
merge(vecs, rr);
|
|
|
|
|
|
circle(rr, Point2f(bestCircle[0], bestCircle[1]), bestCircle[2], Scalar(255, 0, 0), 2);
|
|
|
vector<Mat> imgVec;
|
|
|
resizeVecMat(vec, imgVec);
|
|
|
vector<Mat> vecss;
|
|
|
vecss.push_back(originalMat);
|
|
|
vecss.push_back(originalMat);
|
|
|
vecss.push_back(originalMat);
|
|
|
Mat rrr;
|
|
|
merge(vecss, rrr);
|
|
|
|
|
|
// circle(rrr, Point2f(bestCircle[0] / COLS_SCALE, bestCircle[1] / COLS_SCALE), rInner, Scalar(255, 0, 0), 1);
|
|
|
#endif // DEBUG_VIEW_INTERNAL_MAT
|
|
|
|
|
|
//bob edit
|
|
|
// if (bestCircle[2] > 0.00000001)
|
|
|
// {
|
|
|
// float startX = bestCircle[0] - MAX_CIRCLE_RADII;//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Բ<EFBFBD>⾶<EFBFBD><E2BEB6><EFBFBD>̶<EFBFBD>ֱ<EFBFBD><D6B1>
|
|
|
// float startY = bestCircle[1] - MAX_CIRCLE_RADII;
|
|
|
// Rect rect(startX, startY, MAX_CIRCLE_RADII * 2, MAX_CIRCLE_RADII * 2);
|
|
|
// Mat origianlCenterMat;
|
|
|
// originalMat(rect).copyTo(origianlCenterMat);
|
|
|
// centerMatVec.push_back(origianlCenterMat);
|
|
|
// tmpVec.push_back(vec[i]);
|
|
|
// }
|
|
|
// else
|
|
|
// {
|
|
|
// int a = 0;
|
|
|
// }
|
|
|
|
|
|
float startX = originalMat.cols / 2.0 - MAX_CIRCLE_RADII;//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Բ<EFBFBD>⾶<EFBFBD><E2BEB6><EFBFBD>̶<EFBFBD>ֱ<EFBFBD><D6B1>
|
|
|
float startY = originalMat.rows / 2.0 - MAX_CIRCLE_RADII;
|
|
|
Rect rect(startX, startY, MAX_CIRCLE_RADII * 2, MAX_CIRCLE_RADII * 2);
|
|
|
Mat origianlCenterMat;
|
|
|
originalMat(rect).copyTo(origianlCenterMat);
|
|
|
centerMatVec.push_back(origianlCenterMat);
|
|
|
tmpVec.push_back(vec[i]);
|
|
|
|
|
|
/*bob end edit*/
|
|
|
|
|
|
// if (bestCircle[2] > 0.00000001)
|
|
|
// {
|
|
|
// float startX = bestCircle[0] - bestCircle[2];
|
|
|
// float startY = bestCircle[1] - bestCircle[2];
|
|
|
// Rect rect(startX, startY, bestCircle[2]*2, bestCircle[2]*2);
|
|
|
// Mat origianlCenterMat;
|
|
|
// originalMat(rect).copyTo(origianlCenterMat);
|
|
|
// centerMatVec.push_back(origianlCenterMat);
|
|
|
// }
|
|
|
// else
|
|
|
// {
|
|
|
//
|
|
|
// }
|
|
|
}
|
|
|
vector<Mat> scaledCenterVec;
|
|
|
resizeVecMat(centerMatVec, scaledCenterVec);
|
|
|
if (scaledCenterVec.size() <= 0)
|
|
|
return;
|
|
|
if (tmpVec.size() <= 0)
|
|
|
return;
|
|
|
|
|
|
vector<Mat> imgVec;
|
|
|
resizeVecMat(tmpVec, imgVec);
|
|
|
mAlignBaseImg = imgVec.front();
|
|
|
mInSideBaseImg = scaledCenterVec.front();
|
|
|
genMask();
|
|
|
//Mat baseTempl = imgVec.front();
|
|
|
//float realR = rInner + 2;
|
|
|
//float hf_width = sqrt(realR*realR / 2.0);
|
|
|
//float startx = baseTempl.cols / 2 - hf_width;
|
|
|
//float starty = baseTempl.rows / 2 - hf_width;
|
|
|
//Rect rect(startx, starty, 2*hf_width, 2*hf_width);
|
|
|
//innerTempl = baseTempl(rect);
|
|
|
preProcessImage(mAlignBaseImg, mInSideBaseImg);//Ԥ<><D4A4><EFBFBD><EFBFBD> <20><><EFBFBD>վ<EFBFBD><D5BE><EFBFBD>
|
|
|
Mat sumOutsideMat = Mat::zeros(mAlignBaseImg.size(), CV_32FC1);
|
|
|
Mat sumInsideMat = Mat::zeros(mInSideBaseImg.size(), CV_32FC1);
|
|
|
Mat minOutsideMat(mAlignBaseImg.size(), mAlignBaseImg.type());
|
|
|
Mat minInsideMat(mInSideBaseImg.size(), mInSideBaseImg.type());
|
|
|
minOutsideMat.setTo(FLT_MAX);
|
|
|
minInsideMat.setTo(FLT_MAX);
|
|
|
vector<Mat> rImgVec;
|
|
|
vector<Mat> rInsideImgVec;
|
|
|
vector<RotateMatchResult> rmrVec;
|
|
|
vector<RotateMatchResult> rmrVecInside;
|
|
|
vector<Mat> resizedImgVec;
|
|
|
vector<Mat> resizedCenterVec;
|
|
|
//vector<Mat> resizedWarp;
|
|
|
vector<int> diametersVec;
|
|
|
for (int i = 0; i < imgVec.size(); ++i)
|
|
|
{
|
|
|
diametersVec.push_back(imgVec[i].rows);
|
|
|
Mat img = imgVec[i].clone();
|
|
|
if (img.size() != mAlignBaseImg.size())
|
|
|
{
|
|
|
Mat resizedImg;
|
|
|
resize(img, resizedImg, mAlignBaseImg.size());
|
|
|
//resize(warpImage, warpImage, mAlignBaseImg.size());
|
|
|
img = resizedImg;
|
|
|
}
|
|
|
|
|
|
Mat centerMat = scaledCenterVec[i];
|
|
|
if (centerMat.size() != mInSideBaseImg.size())
|
|
|
{
|
|
|
Mat resizedCenterMat;
|
|
|
resize(centerMat, resizedCenterMat, minInsideMat.size());
|
|
|
centerMat = resizedCenterMat;
|
|
|
}
|
|
|
resizedImgVec.push_back(img);
|
|
|
resizedCenterVec.push_back(centerMat);
|
|
|
//resizedWarp.push_back(warpImage);
|
|
|
//Mat insideImg = img.clone();
|
|
|
preProcessImage(img, centerMat);
|
|
|
m_parallelFlag = 0;
|
|
|
RotateMatchResult rmr = rotateMatch(img);//<2F><>תƥ<D7AA><C6A5> <20><><EFBFBD><EFBFBD>ƥ<EFBFBD><C6A5><EFBFBD><EFBFBD><EFBFBD>ɵĽǶȼ<C7B6>ͼƬ
|
|
|
rmrVec.push_back(rmr);
|
|
|
m_parallelFlag = 1;
|
|
|
RotateMatchResult rmrInside = rotateMatch(centerMat);
|
|
|
rmrVecInside.push_back(rmrInside);
|
|
|
|
|
|
Mat rImg = rmr.mBestRImg;
|
|
|
//rImgVec.push_back(rImg);
|
|
|
|
|
|
Mat rInsideImg = rmrInside.mBestRImg;
|
|
|
rInsideImgVec.push_back(rInsideImg);
|
|
|
//minMat = min(minMat, rImg);
|
|
|
minOutsideMat = min(minOutsideMat, rImg);//<2F><><EFBFBD><EFBFBD>Ȩ<EFBFBD><C8A8>ͼ ȥë<C8A5><C3AB>
|
|
|
sumOutsideMat += rImg;
|
|
|
|
|
|
minInsideMat = min(minInsideMat, rInsideImg);
|
|
|
sumInsideMat += rInsideImg;
|
|
|
|
|
|
#ifdef DEBUG_VIEW_INTERNAL_MAT
|
|
|
Mat viewRImg = rImg / 255.0;
|
|
|
Mat viewRInsideImg = rInsideImg / 255.0;
|
|
|
Mat viewImage = minOutsideMat / 255.0;
|
|
|
Mat viewInside = minInsideMat / 255.0;
|
|
|
#endif
|
|
|
}
|
|
|
meanDiameter = mean(diametersVec)[0];
|
|
|
|
|
|
Mat avgMat = sumOutsideMat / imgVec.size();
|
|
|
mAlignBaseImg = avgMat;
|
|
|
|
|
|
Mat avgInsideMat = sumInsideMat / imgVec.size();
|
|
|
mInSideBaseImg = avgInsideMat;
|
|
|
#ifdef DEBUG_VIEW_INTERNAL_MAT
|
|
|
Mat vAvgMat = avgMat / 255.0;
|
|
|
Mat vAvgInsideMat = avgInsideMat / 255.0;
|
|
|
#endif
|
|
|
//mWeightMat = minMat;
|
|
|
mWeightMat = minOutsideMat;
|
|
|
mWeightMat /= 255.0;
|
|
|
mInsideWeightMat = minInsideMat;
|
|
|
mInsideWeightMat /= 255.0;
|
|
|
/*luffy_base::luffy_imageProc::*/meanvarnorm(mWeightMat, mWeightMat,//<2F><>Ȩ<EFBFBD>ؽ<EFBFBD><D8BD><EFBFBD> <20><>һ<EFBFBD><D2BB>
|
|
|
mTargetMeanVal, 150, m8uMaskImg);
|
|
|
mWeightMat.setTo(0, mWeightMat < 10);
|
|
|
Scalar meanScalar, stddevScalar;
|
|
|
meanStdDev(mInsideWeightMat, meanScalar, stddevScalar, m8uInsideMaskImg);
|
|
|
mInsideWeightMat = mInsideWeightMat* (127 / meanScalar.val[0]);
|
|
|
//luffy_base::luffy_imageProc::meanvarnorm(mInsideWeightMat, mInsideWeightMat,
|
|
|
// mTargetMeanVal, 50, m8uInsideMaskImg);
|
|
|
mInsideWeightMat.setTo(0, mInsideWeightMat < 0);
|
|
|
|
|
|
{
|
|
|
if(mRepeatNum <= 0)
|
|
|
{
|
|
|
mRepeatNum = computeRepeatNum();
|
|
|
}
|
|
|
selfRotateMin(mWeightMat, mWeightMat, mRepeatNum);
|
|
|
}
|
|
|
|
|
|
#ifdef DEBUG_VIEW_INTERNAL_MAT
|
|
|
Mat vWeightMat = mWeightMat / 255.0;
|
|
|
Mat vBaseMat = mAlignBaseImg / 255.0;
|
|
|
// Mat vMinMat = minMat / 255.0;
|
|
|
Mat vMinMat = minOutsideMat / 255.0;
|
|
|
|
|
|
Mat vInsideWeight = mInsideWeightMat / 255.0;
|
|
|
Mat vInsidebaseMat = mInSideBaseImg / 255.0;
|
|
|
Mat vMinInsideMat = minInsideMat / 255.0;
|
|
|
|
|
|
#endif
|
|
|
|
|
|
sumOutsideMat.setTo(0);
|
|
|
sumInsideMat.setTo(0);
|
|
|
for (int i = 0; i < rmrVec.size(); ++i)
|
|
|
{
|
|
|
double bestAngle = rmrVec[i].mBestAngle;
|
|
|
Mat img = resizedImgVec[i];
|
|
|
Mat rotatedImg = rotateImage(img, Point2f(img.cols/2.0, img.rows/2.0),
|
|
|
bestAngle);
|
|
|
|
|
|
preProcessImage(rotatedImg, m8uMaskImg, mWeightMat, mTargetMeanVal,
|
|
|
mTargetStddevVal, mHighlightsThreshold);
|
|
|
|
|
|
double bestInsidePart = rmrVecInside[i].mBestAngle;
|
|
|
//Mat i_Mat = resizedImgVec[i];
|
|
|
Mat centerMat = resizedCenterVec[i];
|
|
|
Mat rotatedInsideMat = rotateImage(centerMat, Point2f(centerMat.cols / 2.0, centerMat.rows / 2.0), bestInsidePart);
|
|
|
|
|
|
preProcessImage(rotatedInsideMat, m8uInsideMaskImg, mInsideWeightMat, mTargetMeanVal,
|
|
|
mTargetStddevVal, mHighlightsThreshold);
|
|
|
|
|
|
sumOutsideMat += rotatedImg;
|
|
|
//rotatedInsideMat.setTo(0, rotatedInsideMat < 0);
|
|
|
sumInsideMat += rotatedInsideMat;
|
|
|
}
|
|
|
mCompareBaseImg = sumOutsideMat / resizedImgVec.size();//<2F>õ<EFBFBD><C3B5><EFBFBD><EFBFBD><EFBFBD>ƥ<EFBFBD><C6A5>ͼ
|
|
|
mInsideCompareBaseImg = sumInsideMat / resizedImgVec.size();
|
|
|
#ifdef DEBUG_VIEW_INTERNAL_MAT
|
|
|
Mat vCompareBaseImg = mCompareBaseImg / 255.0;
|
|
|
vWeightMat = mWeightMat / 255.0;
|
|
|
Mat vcompareInsideBaseImg = mInsideCompareBaseImg / 255.0;
|
|
|
vInsideWeight = mInsideWeightMat / 255.0;
|
|
|
//cv::imwrite("F:\\temp\\insideWeight.png", mInsideWeightMat);
|
|
|
//cv::imwrite("F:\\temp\\insideBase.png", mInSideBaseImg);
|
|
|
//cv::imwrite("F:\\temp\\insideCompareBase.png", mInsideCompareBaseImg);
|
|
|
#endif
|
|
|
|
|
|
trueSampleWeightRecon(resizedImgVec, resizedCenterVec, rmrVec, rmrVecInside);
|
|
|
mWeightMat = falseReConMat.clone();
|
|
|
mInsideWeightMat = insideWeightRecon.clone();
|
|
|
}
|
|
|
|
|
|
void ImageCompareModel::trueSampleWeightRecon(const vector<Mat>& resizedVec,
|
|
|
const vector<Mat>& resizedCenterVec,
|
|
|
vector<RotateMatchResult> rmrVec,
|
|
|
vector<RotateMatchResult> rmrVecInside)
|
|
|
{
|
|
|
falseReConMat = mWeightMat.clone();
|
|
|
insideWeightRecon = mInsideWeightMat.clone();
|
|
|
for (int i = 0; i < resizedVec.size(); i++)
|
|
|
{
|
|
|
const Mat &img = resizedVec[i];
|
|
|
double bestAngle = rmrVec[i].mBestAngle;
|
|
|
//preProcessImage(processedImg, insideMatchImg);
|
|
|
Mat rotatedImg = rotateImage(img, Point2f(img.cols / 2.0, img.rows / 2.0),
|
|
|
bestAngle);
|
|
|
|
|
|
Mat hightlightsMask = rotatedImg < mHighlightsThreshold;
|
|
|
converToType(hightlightsMask, CV_32FC1);
|
|
|
hightlightsMask /= 255.0;
|
|
|
|
|
|
Mat unifiedMask = m32fMaskImg.mul(hightlightsMask).mul(mWeightMat);
|
|
|
|
|
|
preProcessImage(rotatedImg, m8uMaskImg, mWeightMat, mTargetMeanVal,
|
|
|
mTargetStddevVal, mHighlightsThreshold);
|
|
|
|
|
|
rotatedImg.setTo(0, rotatedImg < 0);
|
|
|
converToType(rotatedImg, CV_32FC1);
|
|
|
normSectors_tarImg(rotatedImg, unifiedMask, imgCen(rotatedImg), 1, mCompareBaseImg);
|
|
|
|
|
|
#ifdef DEBUG_VIEW_INTERNAL_MAT
|
|
|
Mat vRotatedImg1 = rotatedImg / 255.0;
|
|
|
#endif
|
|
|
rotatedImg.setTo(0, rotatedImg < 10);
|
|
|
|
|
|
////// FOR INSIDE CIRCLE
|
|
|
double insideBestAngle = rmrVecInside[i].mBestAngle;
|
|
|
const Mat & centerMat = resizedCenterVec[i];
|
|
|
Mat rotatedInsideImg = rotateImage(centerMat, Point2f(centerMat.cols / 2.0, centerMat.rows / 2.0),
|
|
|
insideBestAngle);
|
|
|
|
|
|
Mat highLightInsideMask = rotatedInsideImg < mHighlightsThreshold;
|
|
|
converToType(highLightInsideMask, CV_32FC1);
|
|
|
highLightInsideMask /= 255.0;
|
|
|
Mat unifiedInsideMask = m32fInsideMaskImg.mul(highLightInsideMask).mul(mInsideWeightMat);
|
|
|
preProcessImage(rotatedInsideImg, m8uInsideMaskImg, mInsideWeightMat, mTargetMeanVal,
|
|
|
mTargetStddevVal, mHighlightsThreshold);
|
|
|
Mat vcamInside = rotatedInsideImg / 255.0;
|
|
|
rotatedInsideImg.setTo(0, rotatedInsideImg < 0);
|
|
|
//mInsideCompareBaseImg.setTo(0, mInsideCompareBaseImg < 0);
|
|
|
normSectors_tarImg(rotatedInsideImg, unifiedInsideMask, imgCen(rotatedInsideImg), 1, mInsideCompareBaseImg);
|
|
|
trueWeightRecon(rotatedImg, mCompareBaseImg, rotatedInsideImg, mInsideCompareBaseImg);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void ImageCompareModel::trueWeightRecon(const Mat& rImg, const Mat& baseImg,
|
|
|
const Mat& insideRimg, const Mat& insideBaseImg)
|
|
|
{
|
|
|
Mat dMat = abs(rImg - baseImg);
|
|
|
#ifdef DEBUG_VIEW_INTERNAL_MAT
|
|
|
Mat tt = dMat / 255.0;
|
|
|
Mat m1 = rImg / 255.0;
|
|
|
Mat b1 = baseImg / 255.0;
|
|
|
#endif // DEBUG_VIEW_INTERNAL_MAT
|
|
|
|
|
|
//Mat mData = dMat.mul(m32fMaskImg).mul(mWeightMat);
|
|
|
Mat mData;
|
|
|
dMat.copyTo(mData, dMat > 1000);
|
|
|
|
|
|
double outterVal = sum(mData).val[0];
|
|
|
if (outterVal != 0)
|
|
|
{
|
|
|
mData = minMaxNorm(mData, 0, 255.0);
|
|
|
}
|
|
|
|
|
|
|
|
|
Mat i_dMat = abs(insideRimg - insideBaseImg);
|
|
|
#ifdef DEBUG_VIEW_INTERNAL_MAT
|
|
|
Mat i_tt = i_dMat / 255.0;
|
|
|
Mat i_m1 = insideRimg / 255.0;
|
|
|
Mat i_b1 = insideBaseImg / 255.0;
|
|
|
Mat i_maskR = i_m1.mul(m32fInsideMaskImg);
|
|
|
Mat i_masB = i_b1.mul(m32fInsideMaskImg);
|
|
|
|
|
|
#endif // DEBUG_VIEW_INTERNAL_MAT
|
|
|
Mat i_mData;
|
|
|
i_mData.setTo(0);
|
|
|
//Mat test = i_dMat / 255;
|
|
|
//Mat imgtest = i_dMat.mul(m32fInsideMaskImg) / 255;
|
|
|
Mat innerDmat = i_dMat.mul(m32fInsideMaskImg).mul(mInsideWeightMat);
|
|
|
innerDmat = minMaxNorm(innerDmat, 0, 255.0);
|
|
|
|
|
|
weightMapping(mData, 255.0, innerDmat, 255.0);
|
|
|
}
|
|
|
|
|
|
void ImageCompareModel::weightMapping(const Mat& mData, double maxVal, const Mat& i_mData, double i_maxVal)
|
|
|
{
|
|
|
for (int i = 0; i < mData.rows; i++)
|
|
|
{
|
|
|
float* pData = (float*)mData.row(i).data;
|
|
|
float*pWeight = (float*)falseReConMat.row(i).data;
|
|
|
|
|
|
for (int j = 0; j < mData.cols; j++)
|
|
|
{
|
|
|
double pixVal = pData[j];
|
|
|
|
|
|
if (pixVal != 0)
|
|
|
{
|
|
|
double affineCoeff = descendFunction(pixVal, maxVal);
|
|
|
pWeight[j] *= affineCoeff;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
for (int i = 0; i < i_mData.rows; i++)
|
|
|
{
|
|
|
float* i_pData = (float*)i_mData.row(i).data;
|
|
|
float*i_pWeight = (float*)insideWeightRecon.row(i).data;
|
|
|
|
|
|
for (int j = 0; j < i_mData.cols; j++)
|
|
|
{
|
|
|
double i_pixVal = i_pData[j];
|
|
|
|
|
|
if (i_pixVal != 0)
|
|
|
{
|
|
|
double affineCoeff = descendFunction(i_pixVal, i_maxVal);
|
|
|
i_pWeight[j] *= affineCoeff;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
double ImageCompareModel::descendFunction(double pixVal, double maxVal)
|
|
|
{
|
|
|
return (-1.0 / maxVal)*pixVal + 1.0;
|
|
|
//return -1 * pow(pixVal, 2) + 1;
|
|
|
}
|
|
|
|
|
|
|
|
|
void ImageCompareModel::calculateAllParams(const vector<Mat>& imgVec)
|
|
|
{
|
|
|
mDisThre = DBL_MAX;
|
|
|
Mat disMat(1, imgVec.size(), CV_64FC1);
|
|
|
for (int i = 0; i < imgVec.size(); ++i)
|
|
|
{
|
|
|
const Mat& img = imgVec[i];
|
|
|
double dis = compare(img, NULL, 1, false, 0);
|
|
|
disMat.at<double>(i) = dis;
|
|
|
//disMat.copyTo(mDisMat);
|
|
|
}
|
|
|
|
|
|
if (disMat.cols == 1)
|
|
|
{
|
|
|
mTrueSampleDisStddev = 0;
|
|
|
mTrueSampleDisMean = disMat.at<double>(0);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
Scalar m, s;
|
|
|
meanStdDev(disMat, m, s);
|
|
|
mTrueSampleDisStddev = s.val[0];
|
|
|
mTrueSampleDisMean = m.val[0];
|
|
|
}
|
|
|
disMat.copyTo(mDisMat);
|
|
|
minMaxIdx(disMat, &mTrueSampleDisMin, &mTrueSampleDisMax);
|
|
|
}
|
|
|
|
|
|
void ImageCompareModel::computeDisThre(const vector<Mat>& imgVec, double* pMinDis, double md_diameter, double md_height)
|
|
|
{
|
|
|
if (imgVec.empty())
|
|
|
{
|
|
|
return;
|
|
|
}
|
|
|
mDisThre = DBL_MAX;
|
|
|
vector<double> disVec;
|
|
|
std::map<double, cv::Mat> imgs;
|
|
|
for_each(imgVec.begin(), imgVec.end(), [&](Mat img)
|
|
|
{
|
|
|
double dis = compare(img, NULL, 3, false, 1, md_diameter, md_height);
|
|
|
disVec.push_back(dis);
|
|
|
imgs[dis] = img;
|
|
|
});
|
|
|
double minDis = *(min_element(disVec.begin(), disVec.end()));
|
|
|
setFalseSampleMinDis(minDis);
|
|
|
|
|
|
if (pMinDis)
|
|
|
{
|
|
|
*pMinDis = minDis;
|
|
|
}
|
|
|
if (minDis > mTrueSampleDisMax)
|
|
|
{
|
|
|
mDisThre = mTrueSampleDisMax*0.3 + minDis*0.7;
|
|
|
//mDisThre = mTrueSampleDisMax*0.15 + minDis*0.85 + mTrueSampleDisStddev;
|
|
|
//mDisThre = minDis;
|
|
|
if (mDisThre > mTrueSampleDisMax*1.8)
|
|
|
{
|
|
|
mDisThre = mTrueSampleDisMax*1.8;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
mDisThre = DBL_MAX;
|
|
|
std::cout << "max distance in training > min distance in testing" << std::endl;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void ImageCompareModel::genUniformSepIdx(int num, int startIdx, int endIdx, vector<int>& cenVec)
|
|
|
{
|
|
|
float step = (endIdx - startIdx) / (num);
|
|
|
for (int i = 0; i < num; i++)
|
|
|
{
|
|
|
cenVec.push_back(floorf(step*i + startIdx));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void ImageCompareModel::genAngleRanges(vector<int> cenVec, vector<Range>& rangeVec, int localRange)
|
|
|
{
|
|
|
rangeVec.clear();
|
|
|
for_each(cenVec.begin(), cenVec.end(), [&](int cen)
|
|
|
{
|
|
|
Range r;
|
|
|
r.start = cen - localRange;
|
|
|
r.end = cen + localRange + 1;
|
|
|
rangeVec.push_back(r);
|
|
|
});
|
|
|
}
|
|
|
|
|
|
void ImageCompareModel::genCandidateAngleRanges(vector<float> disVec,
|
|
|
float angleStep, vector<Range>& rangeVec)
|
|
|
{
|
|
|
auto minDisIter = min_element(disVec.begin(), disVec.end());
|
|
|
int startIdx = minDisIter - disVec.begin();
|
|
|
|
|
|
rotate(disVec.begin(), minDisIter, disVec.end());
|
|
|
|
|
|
Mat disVecMat(1, disVec.size(), CV_32FC1, &(disVec[0]));
|
|
|
Mat normDisVecMat;
|
|
|
/*luffy_base::luffy_imageProc::*/meanvarnorm(disVecMat, normDisVecMat, 0, 1.0);
|
|
|
|
|
|
set<unsigned int> canNums;
|
|
|
genCandidateRepeatNums(canNums);
|
|
|
vector<int> cenVec;
|
|
|
int repeatNum = recognizeLowerExtremes(normDisVecMat, canNums, 5, &cenVec);
|
|
|
#ifdef _TEST
|
|
|
if (repeatNum <= 0)
|
|
|
{
|
|
|
std::cout << "repeatNum < 0" << std::endl;
|
|
|
//waitKey();
|
|
|
}
|
|
|
#endif
|
|
|
if (repeatNum < 0)
|
|
|
{
|
|
|
rangeVec.clear();
|
|
|
return;
|
|
|
cenVec.clear();
|
|
|
cenVec.push_back(disVec.size() / 2);
|
|
|
genAngleRanges(cenVec, rangeVec, disVec.size() / 2);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if (cenVec.size() >= 2 && diffAngleRaw(cenVec.front(), cenVec.back()) < 2)
|
|
|
{
|
|
|
cenVec.pop_back();
|
|
|
}
|
|
|
|
|
|
for_each(cenVec.begin(), cenVec.end(), [&](int& cen)
|
|
|
{
|
|
|
cen += startIdx;
|
|
|
cen *= angleStep;
|
|
|
cen = normAngle(cen);
|
|
|
});
|
|
|
for (auto i = cenVec.begin(); i != cenVec.end(); ++i)
|
|
|
{
|
|
|
if (*i < startIdx*angleStep)
|
|
|
{
|
|
|
rotate(cenVec.begin(), i, cenVec.end());
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
#ifdef _TEST
|
|
|
for (int i = 0; i < cenVec.size() - 1; ++i)
|
|
|
{
|
|
|
float curVal = cenVec[i];
|
|
|
float nxtVal = cenVec[i + 1];
|
|
|
if (nxtVal <= curVal)
|
|
|
{
|
|
|
std::cout << "assert nxtVal <= curVal failed" << std::endl;
|
|
|
waitKey();
|
|
|
}
|
|
|
}
|
|
|
#endif
|
|
|
genAngleRanges(cenVec, rangeVec, 10);
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
void ImageCompareModel::genCandidateAngleRanges(const Mat& disMat,
|
|
|
float angleStep, vector<Range>& rangeVec, float rangeScale /*= 1*/)
|
|
|
{
|
|
|
for (int i = 0; i < disMat.rows; ++i)
|
|
|
{
|
|
|
Mat disVec = disMat.row(i);
|
|
|
double minVal, maxVal;
|
|
|
Point minPt, maxPt;
|
|
|
minMaxLoc(disVec, &minVal, &maxVal, &minPt, &maxPt);
|
|
|
Range &r = rangeVec[i];
|
|
|
float cenAngle = r.start + angleStep*minPt.x;
|
|
|
float angleRangeWidth = r.end - r.start;
|
|
|
|
|
|
r.start = floorf(cenAngle - angleRangeWidth * 0.5 * rangeScale);
|
|
|
r.end = floorf(cenAngle + angleRangeWidth * 0.5 * rangeScale);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void ImageCompareModel::selfRotateMin(const Mat& img, Mat& weightMat, int repeatNum)
|
|
|
{
|
|
|
Point2f cen(img.cols / 2.0, img.rows / 2.0);
|
|
|
float angleStep = 360.0 / repeatNum;
|
|
|
Mat dSumMat = Mat::ones(img.size(), img.type()) * 255;
|
|
|
//Mat dSumMat = Mat::ones(img.size(), img.type());
|
|
|
for (int i = 1; i < repeatNum; ++i)
|
|
|
{
|
|
|
Mat rotatedImg = rotateImage(img, cen, i*angleStep);
|
|
|
Mat dilatedImg;
|
|
|
dilate(rotatedImg, dilatedImg, Mat::ones(3, 3, CV_32FC1));
|
|
|
dSumMat = min(dSumMat, dilatedImg);
|
|
|
}
|
|
|
weightMat = dSumMat;
|
|
|
}
|
|
|
|
|
|
double ImageCompareModel::genMatchValue(const Mat& dMat) const
|
|
|
{
|
|
|
double v = norm(dMat, NORM_L2);
|
|
|
|
|
|
double ret = scaleMatchValue(v);
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
double ImageCompareModel::genMatchValue(const Mat& rImg, const Mat& baseImg,
|
|
|
const Mat& maskImg, int flag, int diameter, double md_diameter, double md_height) const
|
|
|
{
|
|
|
Mat dMat = rImg - baseImg;
|
|
|
//Mat testMask = maskImg.mul(m32fMaskImg);
|
|
|
dMat = abs(dMat.mul(maskImg));
|
|
|
//dMat = abs(dMat.mul(testMask));
|
|
|
#ifdef DEBUG_VIEW_INTERNAL_MAT
|
|
|
//Mat vRImg = rImg.mul(m32fMaskImg) / 255.0;
|
|
|
Mat vDMat0 = abs(dMat) / 255.0;
|
|
|
//Mat vBase = baseImg.mul(m32fMaskImg) / 255.0;
|
|
|
Mat vDMat = abs(dMat) / 255.0 / 255.0;
|
|
|
|
|
|
//Mat vinsideImg = rImg.mul(m32fInsideMaskImg) / 255.0;
|
|
|
//Mat vinsideBase = baseImg.mul(m32fInsideMaskImg) / 255.0;
|
|
|
|
|
|
// Mat vMask = maskImg / 255.0;
|
|
|
//Mat vMask = testMask / 255.0;
|
|
|
#endif
|
|
|
Mat minmaxScaleMat;
|
|
|
Mat mMask;
|
|
|
if (m_parallelFlag != 1)
|
|
|
{
|
|
|
minmaxScaleMat = minMaxNorm(dMat, 0, 255, m8uMaskImg);
|
|
|
converToType(minmaxScaleMat, CV_8UC1);
|
|
|
mMask = lowerMajorityMask(minmaxScaleMat, m8uMaskImg, 0.98);
|
|
|
printLog("myLog.txt", "finish outside mMask Part");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
minmaxScaleMat = minMaxNorm(dMat, 0, 255, m8uInsideMaskImg);
|
|
|
converToType(minmaxScaleMat, CV_8UC1);
|
|
|
mMask = lowerMajorityMask(minmaxScaleMat, m8uInsideMaskImg, 0.97);
|
|
|
printLog("myLog.txt", "finish inside mMask Part");
|
|
|
}
|
|
|
|
|
|
converToType(mMask, CV_32FC1);
|
|
|
mMask /= 255.0;
|
|
|
|
|
|
dMat = dMat.mul(mMask);
|
|
|
|
|
|
#ifdef DEBUG_VIEW_INTERNAL_MAT
|
|
|
Mat vDMat1 = abs(dMat) / 255.0 / 255.0;
|
|
|
#endif
|
|
|
Mat vii = mMask.mul(maskImg);
|
|
|
Mat ii = mMask.mul(maskImg) / 255.0;
|
|
|
double s = sum(mMask.mul(maskImg)).val[0];
|
|
|
double ret = genMatchValue(dMat) / s;
|
|
|
|
|
|
if (flag == 1)
|
|
|
{
|
|
|
double matchedVal = ret;
|
|
|
ret = penltyCoeff(matchedVal, meanDiameter, diameter, md_diameter, md_height);//<2F><><EFBFBD>ͷ<EFBFBD>
|
|
|
printf("the matched value %f", ret);
|
|
|
}
|
|
|
printLog("myLog.txt", "finish detect, return val");
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
double ImageCompareModel::scaleMatchValue(double val) const
|
|
|
{
|
|
|
return val*mMatchValScale;
|
|
|
}
|
|
|
|
|
|
|
|
|
ImageCompareModel* ImageCompareModel::scale(float s)
|
|
|
{
|
|
|
Mat baseImage;
|
|
|
resize(mAlignBaseImg, baseImage, Size(), s, s, INTER_CUBIC);
|
|
|
Mat weightMat;
|
|
|
resize(mWeightMat, weightMat, Size(), s, s, INTER_CUBIC);
|
|
|
|
|
|
ImageCompareModel* pRet = new ImageCompareModel;
|
|
|
*pRet = *this;
|
|
|
pRet->setBaseImg(baseImage);
|
|
|
pRet->setWeightMat(weightMat);
|
|
|
|
|
|
//pRet->genMask();
|
|
|
pRet->genOutterMask();
|
|
|
|
|
|
// Mat mask8uImg;
|
|
|
// resize(m8uMaskImg, mask8uImg, Size(), s, s, INTER_NEAREST);
|
|
|
// Mat mask32fImg;
|
|
|
// resize(m32fMaskImg, mask32fImg, Size(), s, s, INTER_NEAREST);
|
|
|
//
|
|
|
// pRet->set8uMaskImg(mask8uImg);
|
|
|
// pRet->set32fMaskImg(mask32fImg);
|
|
|
|
|
|
return pRet;
|
|
|
}
|
|
|
|
|
|
ImageCompareModel::RotateMatchResult ImageCompareModel::rotateMatch(const Mat& img, int levelNum /*= 1*/, float angleStep /*= 1.0*/,
|
|
|
float startAngle /*= 0*/, float endAngle /*= 360*/) const
|
|
|
{
|
|
|
#ifdef _TEST
|
|
|
static int idx = 0;
|
|
|
std::cout << idx << " ";
|
|
|
#endif
|
|
|
RotateData* pData = new RotateData;
|
|
|
vector<Range> angleRangeVec;
|
|
|
if (levelNum > 1)
|
|
|
{
|
|
|
MultiScaleImage msi;
|
|
|
msi.setLevelNum(3);
|
|
|
msi.setBaseLevel(img);
|
|
|
msi.genMultiScale();
|
|
|
ImageCompareData imgCmpData(&msi);
|
|
|
imgCmpData.setStartAngle(startAngle);
|
|
|
imgCmpData.setEndAngle(endAngle);
|
|
|
|
|
|
mpMultiScaleModel->proc(&imgCmpData);
|
|
|
|
|
|
*pData = *imgCmpData.getRotateData();
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
rotateMatchData(img, pData, angleStep, startAngle, endAngle);
|
|
|
}
|
|
|
|
|
|
#ifdef _TEST
|
|
|
if(1)
|
|
|
{
|
|
|
//if (idx == 15)
|
|
|
{
|
|
|
RotateData* pTestData = new RotateData;
|
|
|
rotateMatchData(img, pTestData, angleStep, startAngle, endAngle);
|
|
|
|
|
|
// no need to code for plotting in visual studio later than 2017,
|
|
|
// install the ArrayPlotter extension to see the data distribution
|
|
|
#if (_MSC_VER < 1910) // vs2017
|
|
|
stringstream ss;
|
|
|
ss << "multi_scale_comp_plot";
|
|
|
CvPlot::clear(ss.str());
|
|
|
CvPlot::plot<float>(ss.str(), &(pTestData->mDisValVec[0]),
|
|
|
pTestData->mDisValVec.size());
|
|
|
#endif
|
|
|
|
|
|
float baseAngle = pTestData->bestAngle();
|
|
|
float curAngle = pData->bestAngle();
|
|
|
std::cout << baseAngle << " " << curAngle << " " << baseAngle - curAngle << std::endl;
|
|
|
delete pTestData;
|
|
|
if (abs(diffAngleRaw(baseAngle, curAngle)) > 1)
|
|
|
{
|
|
|
waitKey();
|
|
|
}
|
|
|
}
|
|
|
idx++;
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
RotateMatchResult rmr;
|
|
|
|
|
|
if (pData->mDisValVec.empty())
|
|
|
{
|
|
|
delete pData;
|
|
|
return rmr;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
size_t bestIndex = min_element(pData->mDisValVec.begin(), pData->mDisValVec.end()) - pData->mDisValVec.begin();
|
|
|
|
|
|
Mat ret = pData->mRImgVec[bestIndex];
|
|
|
rmr.mBestRImg = ret;
|
|
|
rmr.mBestAngle = pData->bestAngle();
|
|
|
|
|
|
delete pData;
|
|
|
|
|
|
return rmr;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void ImageCompareModel::rotateMatchData(const Mat& _img, RotateData* pData,
|
|
|
float angleStep /*= 1.0*/, float startAngle /*= 0*/, float endAngle /*= 360*/) const
|
|
|
{
|
|
|
//Mat img = _img.clone();
|
|
|
if (_img.empty())
|
|
|
return;
|
|
|
Point2f center(_img.cols / 2.0, _img.rows / 2.0);
|
|
|
int nNum = (endAngle - startAngle) / angleStep;
|
|
|
RotateData& data = *pData;
|
|
|
data.init(_img.clone(), center, angleStep, nNum);
|
|
|
data.mStartAngle = startAngle;
|
|
|
data.mEndAngle = endAngle;
|
|
|
|
|
|
parallel_for_(Range(0, nNum), ImageCompareModelInvoker(this, pData));
|
|
|
}
|
|
|
|
|
|
void ImageCompareModel::rotateMatchData(const Mat& img, RotateData* pData,
|
|
|
float angleStep /*= 1.0*/, const vector<Range>& angleRangeVec) const
|
|
|
{
|
|
|
float minDis = FLT_MAX;
|
|
|
RotateData bestData;
|
|
|
for_each(angleRangeVec.begin(), angleRangeVec.end(), [&](const Range& r)
|
|
|
{
|
|
|
float startAngle = r.start;
|
|
|
float endAngle = r.end;
|
|
|
rotateMatchData(img, pData, angleStep, startAngle, endAngle);
|
|
|
float localMinDis = *min_element(pData->mDisValVec.begin(), pData->mDisValVec.end());
|
|
|
if (localMinDis < minDis)
|
|
|
{
|
|
|
minDis = localMinDis;
|
|
|
bestData = *pData;
|
|
|
}
|
|
|
});
|
|
|
*pData = bestData;
|
|
|
}
|
|
|
|
|
|
void ImageCompareModel::rotateMatchData(const Mat& img, RotateData* pData,
|
|
|
const vector<Range>& angleRangeVec, float angleStep, Mat& disMat) const
|
|
|
{
|
|
|
if (angleRangeVec.empty())
|
|
|
{
|
|
|
return;
|
|
|
}
|
|
|
disMat.create(angleRangeVec.size(), angleRangeVec.front().size(), CV_32FC1);
|
|
|
pData->mRImgVec.resize(angleRangeVec.size());
|
|
|
pData->mDisValVec.resize(angleRangeVec.size(), FLT_MAX);
|
|
|
double minDis = DBL_MAX;
|
|
|
for (int i = 0; i < angleRangeVec.size(); ++i)
|
|
|
{
|
|
|
Range r = angleRangeVec[i];
|
|
|
Mat disVec = disMat.row(i);
|
|
|
RotateData rotateData;
|
|
|
float startAngle = r.start;
|
|
|
float endAngle = r.end;
|
|
|
rotateMatchData(img, &rotateData, angleStep, startAngle, endAngle);
|
|
|
std::copy(rotateData.mDisValVec.begin(), rotateData.mDisValVec.end(),
|
|
|
(float*)disVec.data);
|
|
|
double localMinDis, localMaxDis;
|
|
|
Point minPt, maxPt;
|
|
|
minMaxLoc(disVec, &localMinDis, &localMaxDis, &minPt, &maxPt);
|
|
|
if (localMinDis < minDis)
|
|
|
{
|
|
|
minDis = localMinDis;
|
|
|
*pData = rotateData;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void ImageCompareModel::genCandidateRepeatNums(set<unsigned int>& canNums)
|
|
|
{
|
|
|
canNums.clear();
|
|
|
|
|
|
for (int i = 4; i < 25; ++i)
|
|
|
{
|
|
|
canNums.insert(i);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
bool isValidExtremas(const Mat& vec, const vector<int>& lessExtremaIdxVec,
|
|
|
const vector<int>& moreExtremaIdxVec)
|
|
|
{
|
|
|
float* pVec = (float*)vec.data;
|
|
|
auto lessIdxIter = lessExtremaIdxVec.begin();
|
|
|
auto moreIdxIter = moreExtremaIdxVec.begin();
|
|
|
while (lessIdxIter != lessExtremaIdxVec.end())
|
|
|
{
|
|
|
auto leftLessIdxIter = lessIdxIter;
|
|
|
auto leftMoreIdxIter = moreIdxIter;
|
|
|
auto rightLessIdxIter = lessIdxIter;
|
|
|
rightLessIdxIter++;
|
|
|
if (rightLessIdxIter == lessExtremaIdxVec.end())
|
|
|
{
|
|
|
break;
|
|
|
}
|
|
|
auto rightMoreIdxIter = leftMoreIdxIter;
|
|
|
while (*rightLessIdxIter > *rightMoreIdxIter)
|
|
|
{
|
|
|
rightMoreIdxIter++;
|
|
|
}
|
|
|
|
|
|
float leftLessExtrema = pVec[*leftLessIdxIter];
|
|
|
float rightLessExtrema = pVec[*rightLessIdxIter];
|
|
|
float localMaxVal = *std::max_element(pVec + *leftLessIdxIter,
|
|
|
pVec + *rightLessIdxIter + 1);
|
|
|
float valRange = localMaxVal - min(leftLessExtrema, rightLessExtrema);
|
|
|
float valTor = valRange*0.05;
|
|
|
float slope = (rightLessExtrema - leftLessExtrema) / (*rightLessIdxIter - *leftLessIdxIter);
|
|
|
|
|
|
leftMoreIdxIter++;
|
|
|
while (leftMoreIdxIter != rightMoreIdxIter)
|
|
|
{
|
|
|
float interVal = leftLessExtrema + slope*(*leftMoreIdxIter - *leftLessIdxIter);
|
|
|
float curExtremaVal = pVec[*leftMoreIdxIter];
|
|
|
if (curExtremaVal < interVal + valTor)
|
|
|
{
|
|
|
return false;
|
|
|
}
|
|
|
leftMoreIdxIter++;
|
|
|
}
|
|
|
|
|
|
lessIdxIter++;
|
|
|
moreIdxIter = rightMoreIdxIter;
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
|
|
|
int ImageCompareModel::recognizeLowerExtremes(const Mat& vec,
|
|
|
set<unsigned int> canNums, int extremeRefineRange /*= 5*/, vector<int> *pExtremaIdxVec /*= 0*/)
|
|
|
{
|
|
|
unsigned int size = vec.cols;
|
|
|
set<unsigned int> validNs;
|
|
|
float* pVec = (float*)vec.data;
|
|
|
|
|
|
double vecMinVal, vecMaxVal;
|
|
|
minMaxIdx(vec, &vecMinVal, &vecMaxVal);
|
|
|
|
|
|
// no need to code for plotting in visual studio later than 2017,
|
|
|
// install the ArrayPlotter extension to see the data distribution
|
|
|
#if (_MSC_VER < 1910) // vs2017
|
|
|
#ifdef DEBUG_VIEW_PLOT
|
|
|
CvPlot::clear("recognizeLowerExtreams");
|
|
|
CvPlot::plot<float>("recognizeLowerExtreams", (float*)vec.data, vec.cols);
|
|
|
#endif
|
|
|
#endif
|
|
|
|
|
|
map<int, vector<int> > repeatNumLocalExtremaIdxMap;
|
|
|
map<int, Mat> repeatNumLocalExtremaValMap;
|
|
|
for (auto iter = canNums.rbegin(); iter != canNums.rend(); ++iter)
|
|
|
{
|
|
|
unsigned int n = *iter;
|
|
|
|
|
|
Mat extremaValVec;
|
|
|
vector<int> extremaIdxVec;
|
|
|
uniformLocalMinExtremas(vec, extremaValVec, extremaIdxVec,
|
|
|
n, extremeRefineRange);
|
|
|
|
|
|
float* pExtremaVecVec = (float*)extremaValVec.data;
|
|
|
|
|
|
float curVal, nxtVal;
|
|
|
bool isValid = true;
|
|
|
|
|
|
Mat preLocalVec;
|
|
|
|
|
|
for (unsigned int i = 0; i < extremaIdxVec.size() - 1; ++i)
|
|
|
{
|
|
|
unsigned int curIdx = extremaIdxVec[i];
|
|
|
unsigned int nxtIdx = extremaIdxVec[i + 1];
|
|
|
curVal = pVec[curIdx];
|
|
|
nxtVal = pVec[nxtIdx];
|
|
|
|
|
|
// no smaller value between two neighbor extremes
|
|
|
if (anyInRange(pVec + curIdx + 1, pVec + nxtIdx,
|
|
|
-FLT_MAX, min(curVal, nxtVal)))
|
|
|
{
|
|
|
isValid = false;
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
if (!preLocalVec.empty())
|
|
|
{
|
|
|
Mat curLocalVec = vec.colRange(curIdx, nxtIdx + 1);
|
|
|
if (curLocalVec.size() != preLocalVec.size())
|
|
|
{
|
|
|
resize(curLocalVec, curLocalVec, preLocalVec.size());
|
|
|
}
|
|
|
float sim = compareHist(curLocalVec, preLocalVec, CV_COMP_CORREL);
|
|
|
if (sim < 0)
|
|
|
{
|
|
|
isValid = false;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
preLocalVec = vec.colRange(curIdx, nxtIdx + 1);
|
|
|
}
|
|
|
if (!isValid)
|
|
|
{
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
set<int> nToBeErased;
|
|
|
for_each(validNs.begin(), validNs.end(), [&](int preN)
|
|
|
{
|
|
|
if (preN % n != 0 || !isValid)
|
|
|
{
|
|
|
return;
|
|
|
}
|
|
|
vector<int> preExtremaIdxVec = repeatNumLocalExtremaIdxMap[preN];
|
|
|
if (isValidExtremas(vec, extremaIdxVec, preExtremaIdxVec))
|
|
|
{
|
|
|
nToBeErased.insert(preN);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
isValid = false;
|
|
|
}
|
|
|
});
|
|
|
if (!isValid)
|
|
|
{
|
|
|
continue;
|
|
|
}
|
|
|
if (nToBeErased.size() == validNs.size())
|
|
|
{
|
|
|
validNs.clear();
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
for_each(nToBeErased.begin(), nToBeErased.end(), [&](int toBeErasedN)
|
|
|
{
|
|
|
validNs.erase(toBeErasedN);
|
|
|
});
|
|
|
}
|
|
|
|
|
|
validNs.insert(n);
|
|
|
repeatNumLocalExtremaIdxMap[n] = extremaIdxVec;
|
|
|
repeatNumLocalExtremaValMap[n] = extremaValVec;
|
|
|
if (pExtremaIdxVec)
|
|
|
{
|
|
|
*pExtremaIdxVec = extremaIdxVec;
|
|
|
}
|
|
|
}
|
|
|
if (validNs.size() == 0)
|
|
|
{
|
|
|
return -1;
|
|
|
}
|
|
|
if (validNs.size() > 1)
|
|
|
{
|
|
|
return -2;
|
|
|
}
|
|
|
|
|
|
return *(validNs.begin());
|
|
|
}
|
|
|
|
|
|
int ImageCompareModel::recognizeRepeatedLocalExtremas(const Mat& vec,
|
|
|
const set<unsigned int>& canNums, int refineRange /*= 5*/,
|
|
|
vector<int> *pIdxVec /*= 0*/)
|
|
|
{
|
|
|
assert(vec.type() == CV_32FC1);
|
|
|
float* pVecData = (float*)vec.data;
|
|
|
|
|
|
for_each(canNums.begin(), canNums.end(), [&](int n)
|
|
|
{
|
|
|
Mat localMinExtremaValVec;
|
|
|
vector<int> localMinExtremaIdxVec;
|
|
|
uniformLocalMinExtremas(vec, localMinExtremaValVec, localMinExtremaIdxVec,
|
|
|
n, refineRange);
|
|
|
|
|
|
float* pExtremaVecVec = (float*)localMinExtremaValVec.data;
|
|
|
|
|
|
// get locally top 10% values
|
|
|
|
|
|
});
|
|
|
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
int ImageCompareModel::computeRepeatNum(const Mat& _img)
|
|
|
{
|
|
|
Mat img;
|
|
|
cv::GaussianBlur(_img, img, Size(3, 3), 5.0);
|
|
|
vector<float> vec;
|
|
|
selfRotationSimilarityFeature(img, vec, Point2f(img.cols / 2.0, img.rows / 2.0));
|
|
|
|
|
|
#ifdef DEBUG_VIEW_INTERNAL_MAT
|
|
|
Mat viewImg = img / 255.0 /255.0;
|
|
|
Mat view_Img = _img / 255.0 /255.0;
|
|
|
#endif
|
|
|
|
|
|
vector<float> normVec(vec);
|
|
|
Mat vecMat(1, vec.size(), CV_32FC1, &(vec[0]));
|
|
|
Mat normVecMat(1, normVec.size(), CV_32FC1, &(normVec[0]));
|
|
|
meanvarnorm(vecMat, normVecMat, 0, 1.0);
|
|
|
|
|
|
#ifdef DEBUG_VIEW_PLOT
|
|
|
Mat dftVec;
|
|
|
dft(normVec, dftVec);
|
|
|
dftVec = abs(dftVec);
|
|
|
|
|
|
Mat dVecMat = normVecMat.clone();
|
|
|
genSobelImage(dVecMat);
|
|
|
Mat dDftVec;
|
|
|
dft(dVecMat, dDftVec);
|
|
|
|
|
|
Mat ddVecMat = dVecMat.clone();
|
|
|
genSobelImage(ddVecMat);
|
|
|
Mat ddDftVec;
|
|
|
dft(ddVecMat, ddDftVec);
|
|
|
|
|
|
// no need to code for plotting in visual studio later than 2017,
|
|
|
// install the ArrayPlotter extension to see the data distribution
|
|
|
#if (_MSC_VER < 1910) // vs2017
|
|
|
CvPlot::plot<float>("normVec", (float*)&(normVec[0]), normVec.size());
|
|
|
CvPlot::plot<float>("dVec", (float*)dVecMat.data, dVecMat.cols);
|
|
|
CvPlot::plot<float>("ddVec", (float*)ddVecMat.data, ddVecMat.cols);
|
|
|
CvPlot::plot<float>("ddft", (float*)dDftVec.data, 50);
|
|
|
CvPlot::plot<float>("dft", (float*)dftVec.data, 50);
|
|
|
CvPlot::plot<float>("dddft", (float*)ddDftVec.data, 50);
|
|
|
#endif
|
|
|
|
|
|
waitKey();
|
|
|
#endif
|
|
|
|
|
|
set<unsigned int> canNums;
|
|
|
genCandidateRepeatNums(canNums);
|
|
|
return recognizeLowerExtremes(normVecMat, canNums);
|
|
|
}
|
|
|
|
|
|
int ImageCompareModel::computeRepeatNum()
|
|
|
{
|
|
|
if (mWeightMat.empty() || mAlignBaseImg.empty())
|
|
|
{
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
Mat img = mAlignBaseImg.mul(mWeightMat);
|
|
|
|
|
|
#ifdef DEBUG_VIEW_INTERNAL_MAT
|
|
|
Mat viewImg = img / 255.0 / 255.0;
|
|
|
#endif
|
|
|
|
|
|
return computeRepeatNum(img);
|
|
|
}
|
|
|
|
|
|
void ImageCompareModel::initMultiScaleModel()
|
|
|
{
|
|
|
if (mpMultiScaleModel)
|
|
|
{
|
|
|
delete mpMultiScaleModel;
|
|
|
}
|
|
|
mpMultiScaleModel = new MultiScaleImageCompareModel;
|
|
|
mpMultiScaleModel->setLevelNum(3);
|
|
|
mpMultiScaleModel->setBaseLevel(this);
|
|
|
mpMultiScaleModel->genMultiScale();
|
|
|
}
|
|
|
|
|
|
void ImageCompareModelInvoker::operator()(const cv::Range& range) const
|
|
|
{
|
|
|
int i0 = range.start;
|
|
|
int i1 = range.end;
|
|
|
assert(abs(i1 - i0) == 1);
|
|
|
m_pModel->parallelDetect(i0, m_pData);
|
|
|
}
|
|
|
|
|
|
void ImageCompareModel::parallelDetect(int index, void *p) const
|
|
|
{
|
|
|
RotateData *pData = (RotateData *)p;
|
|
|
Mat t = getRotationMatrix2D(pData->mCenter, pData->angle(index), 1.0);
|
|
|
Mat rImg;
|
|
|
warpAffine(pData->mImgSrc, rImg, t, pData->mImgSrc.size());
|
|
|
|
|
|
// need add insideImage base image;
|
|
|
|
|
|
// ....
|
|
|
Mat imgRes;
|
|
|
if (m_parallelFlag!=1)
|
|
|
{
|
|
|
if (rImg.size() != mAlignBaseImg.size())
|
|
|
{
|
|
|
resize(rImg, rImg, mAlignBaseImg.size());
|
|
|
}
|
|
|
imgRes = rImg - mAlignBaseImg;
|
|
|
if (!m32fMaskImg.empty())
|
|
|
{
|
|
|
if (m32fMaskImg.size() != imgRes.size())
|
|
|
resize(imgRes, imgRes, m32fMaskImg.size());
|
|
|
imgRes = imgRes.mul(m32fMaskImg);
|
|
|
if (!mWeightMat.empty())
|
|
|
{
|
|
|
if (mWeightMat.size() != imgRes.size())
|
|
|
resize(imgRes, imgRes, mWeightMat.size());
|
|
|
imgRes.mul(mWeightMat);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if (rImg.size() != mInSideBaseImg.size())
|
|
|
{
|
|
|
resize(rImg, rImg, mInSideBaseImg.size());
|
|
|
}
|
|
|
|
|
|
imgRes = rImg - mInSideBaseImg;
|
|
|
if (!m32fInsideMaskImg.empty())
|
|
|
{
|
|
|
if (m32fInsideMaskImg.size() != imgRes.size())
|
|
|
resize(imgRes, imgRes, m32fInsideMaskImg.size());
|
|
|
imgRes = imgRes.mul(m32fInsideMaskImg);
|
|
|
if (!mInsideWeightMat.empty())
|
|
|
{
|
|
|
if (mInsideWeightMat.size() != imgRes.size())
|
|
|
resize(imgRes, imgRes, mInsideWeightMat.size());
|
|
|
imgRes.mul(mInsideWeightMat);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
#ifdef DEBUG_VIEW_INTERNAL_MAT
|
|
|
Mat vRImg, vBaseImg;
|
|
|
vRImg = rImg / 255.0;
|
|
|
vBaseImg = mAlignBaseImg / 255.0;
|
|
|
Mat vImgRes = imgRes / 255.0;
|
|
|
Mat vWeightMat = mWeightMat / 255.0;
|
|
|
Mat viewInsideMat = mInSideBaseImg / 255.0;
|
|
|
#endif
|
|
|
double val = 0;
|
|
|
if(!imgRes.empty())
|
|
|
val = norm(imgRes);
|
|
|
|
|
|
#ifdef DEBUG_VIEW_INTERNAL_MAT
|
|
|
vImgRes = imgRes / 255.0;
|
|
|
#endif
|
|
|
pData->mDisValVec[index] = val;
|
|
|
pData->mRImgVec[index] = rImg;
|
|
|
}
|
|
|
double ImageCompareModel::filterTrainImage(const Mat&img)
|
|
|
{
|
|
|
if (img.empty())
|
|
|
{
|
|
|
return DBL_MAX;
|
|
|
}
|
|
|
mDisThre = DBL_MAX;
|
|
|
double dis = compare(img, NULL, 3, false);
|
|
|
/*if (dis < mTrueSampleDisMax)
|
|
|
{
|
|
|
dis = mTrueSampleDisMax;
|
|
|
}
|
|
|
double absDiff = abs(dis - mTrueSampleDisMax);*/
|
|
|
return dis;
|
|
|
}
|
|
|
void ImageCompareModel::weightOptimization(const vector<Mat>& falseSamples)
|
|
|
{
|
|
|
if (falseSamples.size() <= 0)
|
|
|
return;
|
|
|
reConMat = mWeightMat.clone();
|
|
|
vector<Mat> falseVec;
|
|
|
resizeVecMat(falseSamples, falseVec);
|
|
|
for (int i = 0; i < falseVec.size(); i++)
|
|
|
{
|
|
|
Mat falseSample = falseVec[i].clone();
|
|
|
preWeightReconstruction(falseSample, reConMat);
|
|
|
}
|
|
|
mWeightMat = reConMat;
|
|
|
}
|
|
|
|
|
|
void ImageCompareModel::preWeightReconstruction(Mat img, Mat &reConImg)
|
|
|
{
|
|
|
if (mAlignBaseImg.size().height <= 0 || mAlignBaseImg.size().width <= 0)
|
|
|
{
|
|
|
//mAlignBaseImg = img.clone();
|
|
|
return;
|
|
|
}
|
|
|
if (mAlignBaseImg.size() != img.size())
|
|
|
{
|
|
|
resize(img, img, mAlignBaseImg.size());
|
|
|
}
|
|
|
|
|
|
Mat matchImg = img.clone();
|
|
|
preProcessImage(matchImg, Mat());
|
|
|
|
|
|
if (!mpMultiScaleModel)
|
|
|
{
|
|
|
initMultiScaleModel();
|
|
|
}
|
|
|
RotateMatchResult rmr = rotateMatch(matchImg, 1);
|
|
|
Mat rImg = rmr.mBestRImg;
|
|
|
|
|
|
#ifdef DEBUG_VIEW_INTERNAL_MAT
|
|
|
Mat ttt = mAlignBaseImg / 255.0;
|
|
|
Mat vRImg = rImg / 255.0;
|
|
|
#endif
|
|
|
|
|
|
double bestAngle = rmr.mBestAngle;
|
|
|
Mat cmpImg = rotateImage(img, Point2f(img.cols / 2.0, img.rows / 2.0),
|
|
|
bestAngle);
|
|
|
|
|
|
// remove highlights
|
|
|
Mat hightlightsMask = cmpImg < mHighlightsThreshold;
|
|
|
converToType(hightlightsMask, CV_32FC1);
|
|
|
hightlightsMask /= 255.0;
|
|
|
|
|
|
Mat unifiedMask = m32fMaskImg.mul(hightlightsMask).mul(mWeightMat);
|
|
|
|
|
|
preProcessImage(cmpImg, m8uMaskImg, mWeightMat, mTargetMeanVal,
|
|
|
mTargetStddevVal, mHighlightsThreshold);
|
|
|
|
|
|
cmpImg.setTo(0, cmpImg < 0);
|
|
|
converToType(cmpImg, CV_32FC1);
|
|
|
normSectors_tarImg(cmpImg, unifiedMask, imgCen(cmpImg), 1,
|
|
|
mCompareBaseImg);
|
|
|
|
|
|
#ifdef DEBUG_VIEW_INTERNAL_MAT
|
|
|
Mat vRotatedImg0 = cmpImg / 255.0;
|
|
|
#endif
|
|
|
|
|
|
#ifdef DEBUG_VIEW_INTERNAL_MAT
|
|
|
Mat vRotatedImg1 = mCompareBaseImg / 255.0;
|
|
|
#endif
|
|
|
|
|
|
cmpImg.setTo(0, cmpImg < 10);
|
|
|
|
|
|
weightReconstruction(cmpImg, mCompareBaseImg, unifiedMask, reConImg);
|
|
|
|
|
|
}
|
|
|
|
|
|
void ImageCompareModel::weightReconstruction(const Mat& rImg, const Mat& baseImg, const Mat& maskImg, Mat &reConImg)
|
|
|
{
|
|
|
Mat dMat = abs(rImg - baseImg);
|
|
|
Mat test = dMat / 255.0;
|
|
|
Mat norImg = Mat::ones(dMat.size(), dMat.type()) * 255;
|
|
|
dMat = min(dMat, norImg);
|
|
|
Mat w(dMat.size(), dMat.type(), Scalar::all(0));
|
|
|
dMat.copyTo(w, dMat < 0.5);
|
|
|
w = minMaxNorm(w, 0, 1.0);
|
|
|
for (int i = 0; i < reConImg.rows; i++)
|
|
|
{
|
|
|
float* pData = (float*)reConImg.row(i).data;
|
|
|
float* pWeight = (float*)w.row(i).data;
|
|
|
for (int j = 0; j < reConImg.cols; j++)
|
|
|
{
|
|
|
if (pWeight[j]!=0)
|
|
|
{
|
|
|
//pData[j] *= pWeight[j];
|
|
|
pWeight[j] = -1 * pow(pWeight[j] - 1, 2) + 1;
|
|
|
pData[j] *= pWeight[j];
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
double ImageCompareModel::penltyCoeff(double matchedVal, int diameterMean, int targetDiameter, double modelDiamter, double modelHeight) const
|
|
|
{
|
|
|
int diff = abs(diameterMean - targetDiameter);
|
|
|
double modelDiameterDiff = abs(modelDiamter - realWidth);
|
|
|
double modelHeightDiff = abs(modelHeight - realHeight);
|
|
|
|
|
|
if (diff >=10)
|
|
|
{
|
|
|
return matchedVal*(diff / 100.0 + 1) * (modelHeightDiff / 100.0 + 1) * (modelDiameterDiff / 100.0 + 1);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
return matchedVal;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
cv::Mat ImageCompareModel::genInsideMask(const Mat& img, Point2f center, float innerR /*= -1*/, float outterR /*= -1*/, int type /*= CV_32FC1*/)
|
|
|
{
|
|
|
Mat mask(img.size(), CV_8UC1);
|
|
|
mask.setTo(0);
|
|
|
if (innerR == -1)
|
|
|
{
|
|
|
// default is 30
|
|
|
innerR = img.rows*0.178;
|
|
|
//innerR = img.rows;
|
|
|
}
|
|
|
if (outterR == -1)
|
|
|
{
|
|
|
// default is max radius - 10
|
|
|
outterR = img.rows*0.425;
|
|
|
}
|
|
|
//outterR = r;
|
|
|
/*Mat img1 = img.clone();
|
|
|
|
|
|
img1.convertTo(img1, CV_8UC1);
|
|
|
float r = allocateInnerRadius(img1);
|
|
|
rInner = r;*/
|
|
|
circle(mask, center, outterR, Scalar(255), -1);
|
|
|
circle(mask, center, innerR, Scalar(0), -1);
|
|
|
if (type != CV_8UC1)
|
|
|
{
|
|
|
converToType(mask, type);
|
|
|
mask /= 255;
|
|
|
}
|
|
|
return mask;
|
|
|
}
|
|
|
|
|
|
float ImageCompareModel::allocateInnerRadius(cv::Mat subImage)
|
|
|
{
|
|
|
|
|
|
// //// find global center
|
|
|
// const int &roughRadius = subImage.cols *0.08;
|
|
|
// const Point center(subImage.cols / 2.0, subImage.rows / 2.0);
|
|
|
// Rect rect(center.x - roughRadius, center.y - roughRadius, 2 * roughRadius, 2 * roughRadius);
|
|
|
// Mat centerMat = subImage(rect);
|
|
|
// Mat test = subImage(rect).clone();
|
|
|
// genSobelImage(centerMat);
|
|
|
// centerMat.convertTo(centerMat, CV_8UC1);
|
|
|
// Mat bMat = centerMat > 100;
|
|
|
// //cv::threshold(centerMat, bMat, 0, 255, CV_THRESH_OTSU);
|
|
|
// Mat mask(bMat.size(), CV_8UC1);
|
|
|
// mask.setTo(0);
|
|
|
// //circle(mask, center, roughRadius, Scalar(255), -1);
|
|
|
// //cv::Mat bImage = subImage.mul(mask / 255) > 100;
|
|
|
// Mat dilatedImgBin;
|
|
|
// Mat erodeMat;
|
|
|
// dilate(bMat, dilatedImgBin, Mat::ones(3, 3, CV_32FC1));
|
|
|
// erode(dilatedImgBin, erodeMat, Mat::ones(3, 3, CV_32FC1));
|
|
|
// closeOper(erodeMat, Mat::ones(1, 3, CV_32FC1));
|
|
|
// Mat vMat = erodeMat.clone();
|
|
|
// vector<vector<Point>> contours;
|
|
|
// findContours(erodeMat, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
|
|
|
// for (int i = 0; i < contours.size(); i++) {
|
|
|
// const vector<Point> &pt = contours.at(i);
|
|
|
// if (pt.size() < 10) {
|
|
|
// continue;
|
|
|
// }
|
|
|
// Rect rt = boundingRect(pt);
|
|
|
// if (rt.width < 5 || rt.height < 5) {
|
|
|
// continue;
|
|
|
// }
|
|
|
// drawContours(mask, contours, i, Scalar::all(255), -1);
|
|
|
// }
|
|
|
//
|
|
|
// using namespace luffy_base;
|
|
|
// Mat hit; vector<Point> pts;
|
|
|
// luffy_hit::firstHit4Circle(mask, hit, pts, Point(mask.cols / 2, mask.rows / 2), 0, mask.cols / 2, 360, luffy_hit::emHitOut2In);
|
|
|
// luffy_imageProc::RansacParam rs(0.01, 1, 100, 80, 100);//0421
|
|
|
// vector<Point> pts2 = luffy_imageProc::fitModelbyRansac(pts, luffy_imageProc::emModelCircle, &rs);
|
|
|
// float fRadius;
|
|
|
// Point2f ptCenter;
|
|
|
// bool bFind = luffy_imageProc::lsCircleFit(pts2, fRadius, ptCenter);
|
|
|
//#ifdef _DEBUG
|
|
|
// Mat insideMat(mask.size(), mask.type(), Scalar::all(0));
|
|
|
// int offset = 2;
|
|
|
// cv::circle(insideMat, ptCenter, fRadius, Scalar(1), -1);
|
|
|
// Mat ddst = insideMat.mul(test);
|
|
|
//#endif
|
|
|
// const Point globalCenter(ptCenter.x + center.x - roughRadius, ptCenter.y + center.y - roughRadius);
|
|
|
//
|
|
|
//
|
|
|
//
|
|
|
// //// find minR
|
|
|
// cv::Mat binaryImg = subImage > 25;
|
|
|
// const int innerRadius = binaryImg.rows*0.05;
|
|
|
// const int outterRadius = binaryImg.cols*0.22;
|
|
|
// Mat mmask(binaryImg.size(), CV_8UC1);
|
|
|
// mmask.setTo(0);
|
|
|
// circle(mmask, globalCenter, outterRadius, Scalar(1), -1);
|
|
|
// Mat dilatedImgBin1;
|
|
|
// Mat erodeMat1;
|
|
|
// dilate(binaryImg, dilatedImgBin1, Mat::ones(9, 9, CV_32FC1));
|
|
|
// erode(dilatedImgBin1, erodeMat1, Mat::ones(9, 9, CV_32FC1));
|
|
|
// openOper(erodeMat1, Mat::ones(1, 13, CV_32FC1));
|
|
|
// circle(erodeMat1, globalCenter, innerRadius, Scalar(255), -1);
|
|
|
// Mat tarMat = mmask.mul(erodeMat1) > 0;
|
|
|
//
|
|
|
// vector<Point> maxCon;
|
|
|
// vector<vector<Point>> m_contours;
|
|
|
// findContours(tarMat, m_contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
|
|
|
// maxCon = m_contours.front();
|
|
|
// for (const vector<Point>& contour : m_contours)
|
|
|
// {
|
|
|
// if (contour.size() > maxCon.size())
|
|
|
// {
|
|
|
// maxCon = contour;
|
|
|
// }
|
|
|
// }
|
|
|
// float minDis = FLT_MAX;
|
|
|
// Point initialPoint = maxCon.front();
|
|
|
// for (int i = 0; i < maxCon.size(); i++)
|
|
|
// {
|
|
|
// const Point& p = maxCon[i];
|
|
|
// float dis = pointDis(p, globalCenter);
|
|
|
// if (dis < minDis)
|
|
|
// {
|
|
|
// minDis = dis;
|
|
|
// initialPoint = p;
|
|
|
// }
|
|
|
// }
|
|
|
//#ifdef _DEBUG
|
|
|
// Mat m_Mat(tarMat.size(), tarMat.type(), Scalar::all(0));
|
|
|
// //int offset = 2;
|
|
|
// cv::circle(m_Mat, globalCenter, minDis, Scalar(1), -1);
|
|
|
// Mat d_dst = m_Mat.mul(subImage);
|
|
|
//#endif
|
|
|
// vector<float> rst;
|
|
|
// rst.resize(3);
|
|
|
// rst[0] = minDis - 3;
|
|
|
// rst[1] = globalCenter.x;
|
|
|
// rst[2] = globalCenter.y;
|
|
|
// return rst;
|
|
|
if (subImage.size() != mAlignBaseImg.size())
|
|
|
{
|
|
|
resize(subImage, subImage, mAlignBaseImg.size());
|
|
|
}
|
|
|
|
|
|
cv::Mat binaryImg = subImage > 30;
|
|
|
const int innerRadius = binaryImg.rows*0.05;
|
|
|
const int outterRadius = binaryImg.cols*0.22;
|
|
|
const Point center(binaryImg.cols / 2.0, binaryImg.rows / 2.0);
|
|
|
Mat mask(binaryImg.size(), CV_8UC1);
|
|
|
mask.setTo(0);
|
|
|
circle(mask, center, outterRadius, Scalar(1), -1);
|
|
|
Mat dilatedImgBin;
|
|
|
Mat erodeMat;
|
|
|
dilate(binaryImg, dilatedImgBin, Mat::ones(9, 9, CV_32FC1));
|
|
|
erode(dilatedImgBin, erodeMat, Mat::ones(9, 9, CV_32FC1));
|
|
|
openOper(erodeMat, Mat::ones(1, 13, CV_32FC1));
|
|
|
circle(erodeMat, center, innerRadius, Scalar(255), -1);
|
|
|
Mat tarMat = mask.mul(erodeMat) > 0;
|
|
|
|
|
|
vector<Point> maxCon;
|
|
|
vector<vector<Point>> contours;
|
|
|
findContours(tarMat, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
|
|
|
maxCon = contours.front();
|
|
|
for (const vector<Point>& contour : contours)
|
|
|
{
|
|
|
if (contour.size() > maxCon.size())
|
|
|
{
|
|
|
maxCon = contour;
|
|
|
}
|
|
|
}
|
|
|
float minDis = FLT_MAX;
|
|
|
Point initialPoint = maxCon.front();
|
|
|
for (int i = 0; i < maxCon.size(); i++)
|
|
|
{
|
|
|
const Point& p = maxCon[i];
|
|
|
float dis = pointDis(p, center);
|
|
|
if (dis < minDis)
|
|
|
{
|
|
|
minDis = dis;
|
|
|
initialPoint = p;
|
|
|
}
|
|
|
}
|
|
|
#ifdef _DEBUG
|
|
|
Mat insideMat(tarMat.size(), tarMat.type(), Scalar::all(0));
|
|
|
int offset = 2;
|
|
|
cv::circle(insideMat, center, minDis - offset, Scalar(1), -1);
|
|
|
Mat ddst = insideMat.mul(subImage);
|
|
|
#endif
|
|
|
return minDis - 2;
|
|
|
}
|
|
|
|
|
|
float ImageCompareModel::allocateRadius(cv::Mat subImage)
|
|
|
{
|
|
|
|
|
|
// //// find global center
|
|
|
// const int &roughRadius = subImage.cols *0.08;
|
|
|
// const Point center(subImage.cols / 2.0, subImage.rows / 2.0);
|
|
|
// Rect rect(center.x - roughRadius, center.y - roughRadius, 2 * roughRadius, 2*roughRadius);
|
|
|
// Mat centerMat = subImage(rect);
|
|
|
// Mat test = subImage(rect).clone();
|
|
|
// genSobelImage(centerMat);
|
|
|
// centerMat.convertTo(centerMat, CV_8UC1);
|
|
|
// Mat bMat = centerMat > 100;
|
|
|
// //cv::threshold(centerMat, bMat, 0, 255, CV_THRESH_OTSU);
|
|
|
// Mat mask(bMat.size(), CV_8UC1);
|
|
|
// mask.setTo(0);
|
|
|
// //circle(mask, center, roughRadius, Scalar(255), -1);
|
|
|
// //cv::Mat bImage = subImage.mul(mask / 255) > 100;
|
|
|
// Mat dilatedImgBin;
|
|
|
// Mat erodeMat;
|
|
|
// dilate(bMat, dilatedImgBin, Mat::ones(3, 3, CV_32FC1));
|
|
|
// erode(dilatedImgBin, erodeMat, Mat::ones(3, 3, CV_32FC1));
|
|
|
// closeOper(erodeMat, Mat::ones(1, 3, CV_32FC1));
|
|
|
// Mat vMat = erodeMat.clone();
|
|
|
// vector<vector<Point>> contours;
|
|
|
// findContours(erodeMat, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
|
|
|
// for (int i = 0; i < contours.size(); i++) {
|
|
|
// const vector<Point> &pt = contours.at(i);
|
|
|
// if (pt.size() < 5) {
|
|
|
// continue;
|
|
|
// }
|
|
|
// Rect rt = boundingRect(pt);
|
|
|
// if (rt.width < 5 || rt.height < 5) {
|
|
|
// continue;
|
|
|
// }
|
|
|
// drawContours(mask, contours, i, Scalar::all(255), -1);
|
|
|
// }
|
|
|
//
|
|
|
// using namespace luffy_base;
|
|
|
// Mat hit; vector<Point> pts;
|
|
|
// luffy_hit::firstHit4Circle(mask, hit, pts, Point(mask.cols / 2, mask.rows / 2), 0, mask.cols / 2, 360, luffy_hit::emHitOut2In);
|
|
|
// luffy_imageProc::RansacParam rs(0.01, 1, 100, 80, 100);//0421
|
|
|
// vector<Point> pts2 = luffy_imageProc::fitModelbyRansac(pts, luffy_imageProc::emModelCircle, &rs);
|
|
|
// float fRadius;
|
|
|
// Point2f ptCenter;
|
|
|
// bool bFind = luffy_imageProc::lsCircleFit(pts2, fRadius, ptCenter);
|
|
|
//#ifdef _DEBUG
|
|
|
// Mat insideMat(mask.size(), mask.type(), Scalar::all(0));
|
|
|
// //int offset = 2;
|
|
|
// cv::circle(insideMat, ptCenter, fRadius, Scalar(1), -1);
|
|
|
// Mat ddst = insideMat.mul(test);
|
|
|
//#endif
|
|
|
// const Point globalCenter(ptCenter.x + center.x - roughRadius, ptCenter.y + center.y - roughRadius);
|
|
|
//
|
|
|
//
|
|
|
//
|
|
|
// //// find minR
|
|
|
// cv::Mat binaryImg = subImage > 25;
|
|
|
// const int innerRadius = binaryImg.rows*0.05;
|
|
|
// const int outterRadius = binaryImg.cols*0.22;
|
|
|
// Mat mmask(binaryImg.size(), CV_8UC1);
|
|
|
// mmask.setTo(0);
|
|
|
// circle(mmask, globalCenter, outterRadius, Scalar(1), -1);
|
|
|
// Mat dilatedImgBin1;
|
|
|
// Mat erodeMat1;
|
|
|
// dilate(binaryImg, dilatedImgBin1, Mat::ones(9, 9, CV_32FC1));
|
|
|
// erode(dilatedImgBin1, erodeMat1, Mat::ones(9, 9, CV_32FC1));
|
|
|
// openOper(erodeMat1, Mat::ones(1, 13, CV_32FC1));
|
|
|
// circle(erodeMat1, globalCenter, innerRadius, Scalar(255), -1);
|
|
|
// Mat tarMat =mmask.mul(erodeMat1) > 0;
|
|
|
//
|
|
|
// vector<Point> maxCon;
|
|
|
// vector<vector<Point>> m_contours;
|
|
|
// findContours(tarMat, m_contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
|
|
|
// maxCon = m_contours.front();
|
|
|
// for (const vector<Point>& contour : m_contours)
|
|
|
// {
|
|
|
// if (contour.size() > maxCon.size())
|
|
|
// {
|
|
|
// maxCon = contour;
|
|
|
// }
|
|
|
// }
|
|
|
// float minDis = FLT_MAX;
|
|
|
// Point initialPoint = maxCon.front();
|
|
|
// for (int i = 0; i < maxCon.size(); i++)
|
|
|
// {
|
|
|
// const Point& p = maxCon[i];
|
|
|
// float dis = pointDis(p, globalCenter);
|
|
|
// if (dis < minDis)
|
|
|
// {
|
|
|
// minDis = dis;
|
|
|
// initialPoint = p;
|
|
|
// }
|
|
|
// }
|
|
|
//#ifdef _DEBUG
|
|
|
// Mat m_Mat(tarMat.size(), tarMat.type(), Scalar::all(0));
|
|
|
// //int offset = 2;
|
|
|
// cv::circle(m_Mat, globalCenter, minDis, Scalar(1), -1);
|
|
|
// Mat d_dst = m_Mat.mul(subImage);
|
|
|
//#endif
|
|
|
// //return minDis - 2;
|
|
|
// vector<float> rst;
|
|
|
// rst.resize(3);
|
|
|
// rst[0] = minDis - 3;
|
|
|
// rst[1] = globalCenter.x;
|
|
|
// rst[2] = globalCenter.y;
|
|
|
// return rst;
|
|
|
|
|
|
if (subImage.size() != mAlignBaseImg.size())
|
|
|
{
|
|
|
resize(subImage, subImage, mAlignBaseImg.size());
|
|
|
}
|
|
|
cv::Mat binaryImg = subImage > 30;
|
|
|
const int innerRadius = binaryImg.rows*0.05;
|
|
|
const int outterRadius = binaryImg.cols*0.22;
|
|
|
const Point center(binaryImg.cols / 2.0, binaryImg.rows / 2.0);
|
|
|
Mat mask(binaryImg.size(), CV_8UC1);
|
|
|
mask.setTo(0);
|
|
|
circle(mask, center, outterRadius, Scalar(1), -1);
|
|
|
Mat dilatedImgBin;
|
|
|
Mat erodeMat;
|
|
|
dilate(binaryImg, dilatedImgBin, Mat::ones(9, 9, CV_32FC1));
|
|
|
erode(dilatedImgBin, erodeMat, Mat::ones(9, 9, CV_32FC1));
|
|
|
openOper(erodeMat, Mat::ones(1, 13, CV_32FC1));
|
|
|
circle(erodeMat, center, innerRadius, Scalar(255), -1);
|
|
|
Mat tarMat = mask.mul(erodeMat) > 0;
|
|
|
|
|
|
vector<Point> maxCon;
|
|
|
vector<vector<Point>> contours;
|
|
|
findContours(tarMat, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
|
|
|
maxCon = contours.front();
|
|
|
for (const vector<Point>& contour : contours)
|
|
|
{
|
|
|
if (contour.size() > maxCon.size())
|
|
|
{
|
|
|
maxCon = contour;
|
|
|
}
|
|
|
}
|
|
|
float minDis = FLT_MAX;
|
|
|
Point initialPoint = maxCon.front();
|
|
|
for (int i = 0; i < maxCon.size(); i++)
|
|
|
{
|
|
|
const Point& p = maxCon[i];
|
|
|
float dis = pointDis(p, center);
|
|
|
if (dis < minDis)
|
|
|
{
|
|
|
minDis = dis;
|
|
|
initialPoint = p;
|
|
|
}
|
|
|
}
|
|
|
#ifdef _DEBUG
|
|
|
Mat insideMat(tarMat.size(), tarMat.type(), Scalar::all(0));
|
|
|
int offset = 2;
|
|
|
cv::circle(insideMat, center, minDis - offset, Scalar(1), -1);
|
|
|
Mat ddst = insideMat.mul(subImage);
|
|
|
#endif
|
|
|
return minDis - 2;
|
|
|
}
|
|
|
|
|
|
void ImageCompareModel::genOutterMask()
|
|
|
{
|
|
|
m32fMaskImg = genMask(mAlignBaseImg, Point2f(mAlignBaseImg.cols / 2.0, mAlignBaseImg.rows / 2.0));
|
|
|
m8uMaskImg = genMask(mAlignBaseImg, Point2f(mAlignBaseImg.cols / 2.0, mAlignBaseImg.rows / 2.0),
|
|
|
-1.0, -1.0, CV_8UC1);
|
|
|
}
|
|
|
|
|
|
void ImageCompareModel::resizeVecMat(vector<Mat> srcVec, vector<Mat> &dstVec)
|
|
|
{
|
|
|
if (srcVec.size() <= 0)
|
|
|
return;
|
|
|
dstVec.resize(srcVec.size());
|
|
|
int nWidth = ((int)((float)srcVec.front().cols / COLS_SCALE / 4)) * 4;
|
|
|
for (int i = 0; i < srcVec.size(); i++)
|
|
|
{
|
|
|
const Mat& mat = srcVec[i];
|
|
|
Mat dstMat;
|
|
|
cv::resize(mat, dstMat, cv::Size(nWidth, nWidth));
|
|
|
dstVec[i] = dstMat;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void ImageCompareModel::resizeMat(Mat src, Mat &dst)
|
|
|
{
|
|
|
int nWidth = ((int)((float)src.cols / COLS_SCALE / 4)) * 4;
|
|
|
cv::resize(src, dst, cv::Size(nWidth, nWidth));
|
|
|
}
|
|
|
|
|
|
void ImageCompareModel::printLog(string root, string log, double n) const
|
|
|
{
|
|
|
#ifdef DEBUG_VIEW_INTERNAL_MAT
|
|
|
ofstream write;
|
|
|
write.open(root, ios::app);
|
|
|
time_t seconds = time(NULL);
|
|
|
struct tm *p;
|
|
|
p = localtime(&seconds);
|
|
|
char strTime[100] = { 0 };
|
|
|
sprintf(strTime, "%02d-%02d %02d:%02d:%02d:", 1 + p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);
|
|
|
std::ostringstream str;
|
|
|
str << log;
|
|
|
if (n != 0)
|
|
|
{
|
|
|
str << n;
|
|
|
}
|
|
|
write << "time:" << string(strTime);
|
|
|
write << str.str() << "\n";
|
|
|
write.close();
|
|
|
#endif
|
|
|
}
|
|
|
|