/*! \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 #include //#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 vec; double minDiff = DBL_MAX; Point2f bestCenter; vector 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 vec; selfRotationSimilarityFeature(img, vec, newCenter); vector 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("refineCenter", &(vec[0]), vec.size()); #endif float diffVal = sum(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& 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 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 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);//得出相似值 m_parallelFlag = 1; double retInside = genMatchValue(camInsideMat, mInsideCompareBaseImg, unifiedInsideMask, 0, rawImg.rows, md_diameter, md_height);//得出相似值 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& 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 centerMatVec; vector 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 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 imgVec; resizeVecMat(vec, imgVec); vector 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;//找最大圆外径,固定直径 // 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;//找最大圆外径,固定直径 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 scaledCenterVec; resizeVecMat(centerMatVec, scaledCenterVec); if (scaledCenterVec.size() <= 0) return; if (tmpVec.size() <= 0) return; vector 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);//预处理 光照均衡 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 rImgVec; vector rInsideImgVec; vector rmrVec; vector rmrVecInside; vector resizedImgVec; vector resizedCenterVec; //vector resizedWarp; vector 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);//旋转匹配 输出匹配完成的角度及图片 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);//生成权重图 去毛刺 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,//对权重进行 归一化 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();//得到最终匹配图 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& resizedVec, const vector& resizedCenterVec, vector rmrVec, vector 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& 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(i) = dis; //disMat.copyTo(mDisMat); } if (disMat.cols == 1) { mTrueSampleDisStddev = 0; mTrueSampleDisMean = disMat.at(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& imgVec, double* pMinDis, double md_diameter, double md_height) { if (imgVec.empty()) { return; } mDisThre = DBL_MAX; vector disVec; std::map 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& cenVec) { float step = (endIdx - startIdx) / (num); for (int i = 0; i < num; i++) { cenVec.push_back(floorf(step*i + startIdx)); } } void ImageCompareModel::genAngleRanges(vector cenVec, vector& 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 disVec, float angleStep, vector& 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 canNums; genCandidateRepeatNums(canNums); vector 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& 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);//做惩罚 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 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(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& 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& 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& canNums) { canNums.clear(); for (int i = 4; i < 25; ++i) { canNums.insert(i); } } bool isValidExtremas(const Mat& vec, const vector& lessExtremaIdxVec, const vector& 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 canNums, int extremeRefineRange /*= 5*/, vector *pExtremaIdxVec /*= 0*/) { unsigned int size = vec.cols; set 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("recognizeLowerExtreams", (float*)vec.data, vec.cols); #endif #endif map > repeatNumLocalExtremaIdxMap; map repeatNumLocalExtremaValMap; for (auto iter = canNums.rbegin(); iter != canNums.rend(); ++iter) { unsigned int n = *iter; Mat extremaValVec; vector 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 nToBeErased; for_each(validNs.begin(), validNs.end(), [&](int preN) { if (preN % n != 0 || !isValid) { return; } vector 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& canNums, int refineRange /*= 5*/, vector *pIdxVec /*= 0*/) { assert(vec.type() == CV_32FC1); float* pVecData = (float*)vec.data; for_each(canNums.begin(), canNums.end(), [&](int n) { Mat localMinExtremaValVec; vector 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 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 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("normVec", (float*)&(normVec[0]), normVec.size()); CvPlot::plot("dVec", (float*)dVecMat.data, dVecMat.cols); CvPlot::plot("ddVec", (float*)ddVecMat.data, ddVecMat.cols); CvPlot::plot("ddft", (float*)dDftVec.data, 50); CvPlot::plot("dft", (float*)dftVec.data, 50); CvPlot::plot("dddft", (float*)ddDftVec.data, 50); #endif waitKey(); #endif set 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& falseSamples) { if (falseSamples.size() <= 0) return; reConMat = mWeightMat.clone(); vector 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> contours; // findContours(erodeMat, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE); // for (int i = 0; i < contours.size(); i++) { // const vector &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 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 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 maxCon; // vector> m_contours; // findContours(tarMat, m_contours, RETR_EXTERNAL, CHAIN_APPROX_NONE); // maxCon = m_contours.front(); // for (const vector& 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 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 maxCon; vector> contours; findContours(tarMat, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE); maxCon = contours.front(); for (const vector& 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> contours; // findContours(erodeMat, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE); // for (int i = 0; i < contours.size(); i++) { // const vector &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 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 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 maxCon; // vector> m_contours; // findContours(tarMat, m_contours, RETR_EXTERNAL, CHAIN_APPROX_NONE); // maxCon = m_contours.front(); // for (const vector& 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 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 maxCon; vector> contours; findContours(tarMat, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE); maxCon = contours.front(); for (const vector& 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 srcVec, vector &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 }