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.cpp

2441 lines
70 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.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
}