|
|
|
|
|
/*! \file CVUtils.h
|
|
|
|
|
|
\brief Some functions extend opencv classes
|
|
|
|
|
|
|
|
|
|
|
|
Created: 2015/06/22, author: Jin Bingwen.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef __CVUtils_h_
|
|
|
|
|
|
#define __CVUtils_h_
|
|
|
|
|
|
|
|
|
|
|
|
#include "StdUtils.h"
|
|
|
|
|
|
#include <opencv2/opencv.hpp>
|
|
|
|
|
|
#include <opencv2/opencv_modules.hpp>
|
|
|
|
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
|
#include <fstream>
|
|
|
|
|
|
#include <map>
|
|
|
|
|
|
#include "pointpair.h"
|
|
|
|
|
|
|
|
|
|
|
|
#if defined(_DEBUG) && defined(_VIEW_INTERNAL_MAT)
|
|
|
|
|
|
#define DEBUG_VIEW_INTERNAL_MAT
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#if defined(_DEBUG) && defined(_DETAIL_LOG)
|
|
|
|
|
|
#define DEBUG_DETAIL_LOG
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#define M_PI CV_PI
|
|
|
|
|
|
|
|
|
|
|
|
#define INTER_POINT_Y(p0x, p0y, p1x, p1y, p2x) ((p1y - p0y)/(p1x - p0x)*(p2x - p0x) + p0y)
|
|
|
|
|
|
#define INTER_POINT_X(p0x, p0y, p1x, p1y, p2y) ((p1x - p0x)/(p1y - p0y)*(p2y - p0y) + p0x)
|
|
|
|
|
|
|
|
|
|
|
|
using std::vector;
|
|
|
|
|
|
using std::pair;
|
|
|
|
|
|
using namespace cv;
|
|
|
|
|
|
|
|
|
|
|
|
typedef Size_<double> Sized;
|
|
|
|
|
|
typedef Size_<float> Sizef;
|
|
|
|
|
|
|
|
|
|
|
|
namespace CyclopsUtils1 {
|
|
|
|
|
|
|
|
|
|
|
|
// Hold an empty dummy mat which is useful when you want to return a Mat() incase of some failure,
|
|
|
|
|
|
// or pass a Mat() as defualt function parameter.
|
|
|
|
|
|
// This will save some computation cost for initialization and deallocation of a local variable.
|
|
|
|
|
|
extern Mat gDummyMat;
|
|
|
|
|
|
|
|
|
|
|
|
// Hold an empty dummy Scalar which is useful when you want to return a Scalar() incase of some failure,
|
|
|
|
|
|
// or pass a Scalar() as defualt function parameter.
|
|
|
|
|
|
// This will save some computation cost for initialization and deallocation of a local variable.
|
|
|
|
|
|
extern Scalar gDummyScalar;
|
|
|
|
|
|
|
|
|
|
|
|
string templateMatchMethod2Str(int method);
|
|
|
|
|
|
|
|
|
|
|
|
// Carmack fast InvSqrt!
|
|
|
|
|
|
inline float InvSqrt(float x)
|
|
|
|
|
|
{
|
|
|
|
|
|
float xhalf = 0.5f*x;
|
|
|
|
|
|
int i = *(int*)&x;
|
|
|
|
|
|
i = 0x5f3759df - (i >> 1); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD>Ƹ<EFBFBD>
|
|
|
|
|
|
x = *(float*)&i;
|
|
|
|
|
|
x = x*(1.5f - xhalf*x*x); // ţ<>ٵ<EFBFBD><D9B5><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
return x;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void printIndent(int indentNum, int indent = 4);
|
|
|
|
|
|
|
|
|
|
|
|
template<typename _Ty>
|
|
|
|
|
|
void printProperty(int indentNum, string label, _Ty val)
|
|
|
|
|
|
{
|
|
|
|
|
|
printIndent(indentNum);
|
|
|
|
|
|
std::cout << label << ": " << val << "; " << std::endl;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void printMatInfo(const Mat& m, int baseIndentNum = 0, int indent = 4);
|
|
|
|
|
|
|
|
|
|
|
|
void alignEachRowRightBound(Mat& img, int tarCen, vector<int>& dxVec,
|
|
|
|
|
|
int gradientKernelWidth = 12,
|
|
|
|
|
|
int smoothBoundaryKernelWidth = 32,
|
|
|
|
|
|
float smoothBoundaryWeight = 3.0,
|
|
|
|
|
|
int backgroundThre = 40);
|
|
|
|
|
|
void autoAlignEachRowGloballyWithIndependentBoundaries(Mat& img);
|
|
|
|
|
|
void autoAlignEachRowWithWeightedXCen(Mat& img, int tarCenX, vector<int>& dxVec);
|
|
|
|
|
|
void autoAlignEachRowWithAutoThreshold(Mat& img, int tarCenX, vector<int>& dxVec);
|
|
|
|
|
|
void alignEachRow(Mat& img, const vector<int>& dxVec);
|
|
|
|
|
|
void autoAlignEachRowGloballyWithWidthConstraint(Mat& img, int tarCenX, vector<int>& dxVec);
|
|
|
|
|
|
void autoAlignEachRowLocally(Mat& img, int searchRadius = 5, int rowWidth = 1, const Mat& preImg = Mat());
|
|
|
|
|
|
|
|
|
|
|
|
void openOper(Mat& img, int w);
|
|
|
|
|
|
void openOper(Mat& img, const Mat& kernel);
|
|
|
|
|
|
void closeOper(Mat& img, int w);
|
|
|
|
|
|
void closeOper(Mat& img, const Mat& kernel);
|
|
|
|
|
|
void localCloseOper(Mat& img, vector< vector<Point> >& contours, float longerScale);
|
|
|
|
|
|
|
|
|
|
|
|
Mat genCircleMask(int rows, int cols, int type,
|
|
|
|
|
|
Point cen, double r,
|
|
|
|
|
|
const Scalar& color, int thickness, int lineType = 8, int shift = 0);
|
|
|
|
|
|
|
|
|
|
|
|
void closeShapesToConvex(const Mat& mask, Mat& closedMask);
|
|
|
|
|
|
|
|
|
|
|
|
double longShortRatio(const Size& s);
|
|
|
|
|
|
|
|
|
|
|
|
float lpContourArea(const vector<Point>& contour);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
float circleDegree(const vector<Point>& contour);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
enum LogicOper
|
|
|
|
|
|
{
|
|
|
|
|
|
LP_LOGIC_LARGER,
|
|
|
|
|
|
LP_LOGIC_SMALLER
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
Mat gridThre(const Mat& img, int gridWidth, int gridHeight, float threStdDevScale, LogicOper oper /*= LP_LOGIC_SMALLER*/, float majority /*= 0.8*/);
|
|
|
|
|
|
Mat gridWhiteThre(const Mat& img, int gridWidth, int gridHeight, float threStdDevScale, float majority /*= 0.8*/);
|
|
|
|
|
|
Mat gridBlackThre(const Mat& img, int gridWidth, int gridHeight, float threStdDevScale, float majority = 0.8);
|
|
|
|
|
|
|
|
|
|
|
|
void converToType(cv::Mat& mat, int mattype);
|
|
|
|
|
|
|
|
|
|
|
|
void genScharrImage(Mat& img);
|
|
|
|
|
|
void genSobelImage(Mat& img, Mat* pSobelx = NULL, Mat* pSobely = NULL);
|
|
|
|
|
|
void genSobelDir(Mat& img);
|
|
|
|
|
|
Mat genSobelDir(const Mat& sobelX, const Mat& sobelY);
|
|
|
|
|
|
Mat genDirColorImg(const Mat& img, Mat* pValueMat = NULL);
|
|
|
|
|
|
|
|
|
|
|
|
template<typename _T>
|
|
|
|
|
|
void histMeanStddev(const Mat& hist, double* pMean, double* pStddev)
|
|
|
|
|
|
{
|
|
|
|
|
|
_T* pData = (_T*)hist.data;
|
|
|
|
|
|
double sum = 0;
|
|
|
|
|
|
int count = 0;
|
|
|
|
|
|
for (int i = 0; i < hist.cols; ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!pData[i])
|
|
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
count += pData[i];
|
|
|
|
|
|
sum += pData[i]*i;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (count == 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (pMean)
|
|
|
|
|
|
{
|
|
|
|
|
|
*pMean = sum;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (pStddev)
|
|
|
|
|
|
{
|
|
|
|
|
|
*pStddev = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
*pMean = sum / (double)count;
|
|
|
|
|
|
sum = 0;
|
|
|
|
|
|
for (int i = 0; i < hist.cols; ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!pData[i])
|
|
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
double d = i - *pMean;
|
|
|
|
|
|
sum += d*d*pData[i];
|
|
|
|
|
|
}
|
|
|
|
|
|
*pStddev = sqrt(sum / (double)(count - 1));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool localMeanVarNorm(const Mat& srcMat, Mat& dstMat, int winRadius, double tarMean = 120, double tarStd = 30);
|
|
|
|
|
|
void meanvarnorm(Mat& src, Mat &dst, double avg, double var, Mat mask = Mat());
|
|
|
|
|
|
Mat genXDeriLineKernel(int w, int type, double absVal);
|
|
|
|
|
|
|
|
|
|
|
|
Mat genXDeriMat(const Mat& img, int w, double absVal);
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************************************/
|
|
|
|
|
|
/* Normalize */
|
|
|
|
|
|
/************************************************************************/
|
|
|
|
|
|
Mat normEachRow(const Mat& img);
|
|
|
|
|
|
|
|
|
|
|
|
enum PixelSelectionMethod
|
|
|
|
|
|
{
|
|
|
|
|
|
LP_PIXEL_SELECT_ALL,
|
|
|
|
|
|
LP_PIXEL_SELECT_MAJORITY,
|
|
|
|
|
|
LP_PIXEL_SELECT_MAJORITY_FAST
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
Mat cocentricNorm(const Mat& img, Point2f center, const Mat& mask, float dstMeanVal);
|
|
|
|
|
|
|
|
|
|
|
|
Mat meanNorm(const Mat& img, const Mat& mask, float dstMeanVal,
|
|
|
|
|
|
float majority = 1.0,
|
|
|
|
|
|
PixelSelectionMethod method = LP_PIXEL_SELECT_ALL);
|
|
|
|
|
|
|
|
|
|
|
|
Mat minMaxNorm(const Mat& img, double tarMin, double tarMax, const Mat& mask = Mat());
|
|
|
|
|
|
|
|
|
|
|
|
Mat normCanvas(const Mat& img);
|
|
|
|
|
|
/**********************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
Mat genGradientDir4EachRow(const Mat& img);
|
|
|
|
|
|
|
|
|
|
|
|
void findMatElementsEquals(const Mat& img, vector<Point>& pointVec, float val, int xPadding);
|
|
|
|
|
|
|
|
|
|
|
|
double localMatSum(const Mat& mat, const Rect& roi);
|
|
|
|
|
|
|
|
|
|
|
|
void findEdgePointsEachRow(const Mat& img, vector<Point>& edgePointVec, int xPadding);
|
|
|
|
|
|
|
|
|
|
|
|
template<typename _Ty>
|
|
|
|
|
|
Mat sumEachRow(const Mat& iMat)
|
|
|
|
|
|
{
|
|
|
|
|
|
_ASSERTE(iMat.channels() == 1);
|
|
|
|
|
|
Mat oVec(iMat.rows, 1, DataType<_Ty>::type);
|
|
|
|
|
|
for (int i = 0; i < iMat.rows; ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
Mat rowVec = iMat.row(i);
|
|
|
|
|
|
Scalar s = cv::sum(rowVec);
|
|
|
|
|
|
oVec.at<_Ty>(i) = s.val[0]/rowVec.cols;
|
|
|
|
|
|
}
|
|
|
|
|
|
return oVec;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<typename _Ty, int cn>
|
|
|
|
|
|
Mat sumEachRowN(const Mat& iMat)
|
|
|
|
|
|
{
|
|
|
|
|
|
_ASSERTE(iMat.channels() == cn);
|
|
|
|
|
|
Mat oVec(iMat.rows, 1, CV_MAKETYPE(DataType<_Ty>::type, cn));
|
|
|
|
|
|
for (int i = 0; i < iMat.rows; ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
Mat rowVec = iMat.row(i);
|
|
|
|
|
|
Scalar s = cv::sum(rowVec);
|
|
|
|
|
|
Vec<_Ty, cn>& d = oVec.at<Vec<_Ty, cn> >(i);
|
|
|
|
|
|
for (int j = 0; j < cn; ++j)
|
|
|
|
|
|
d[j] = s[j] / iMat.cols;
|
|
|
|
|
|
}
|
|
|
|
|
|
return oVec;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Mat sumEachRow2(const Mat& img);
|
|
|
|
|
|
|
|
|
|
|
|
template<typename _Ty>
|
|
|
|
|
|
Mat sumEachCol(const Mat& iMat)
|
|
|
|
|
|
{
|
|
|
|
|
|
_ASSERTE(iMat.channels() == 1);
|
|
|
|
|
|
Mat oVec(1, iMat.cols, DataType<_Ty>::type);
|
|
|
|
|
|
for (int i = 0; i < iMat.cols; ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
Mat colVec = iMat.col(i);
|
|
|
|
|
|
Scalar s = cv::sum(colVec);
|
|
|
|
|
|
oVec.at<_Ty>(i) = s.val[0]/colVec.rows;
|
|
|
|
|
|
}
|
|
|
|
|
|
return oVec;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<typename _Ty, int cn>
|
|
|
|
|
|
Mat sumEachColN(const Mat& iMat)
|
|
|
|
|
|
{
|
|
|
|
|
|
_ASSERTE(iMat.channels() == cn);
|
|
|
|
|
|
Mat oVec(1, iMat.cols, CV_MAKETYPE(DataType<_Ty>::type, cn));
|
|
|
|
|
|
for (int i = 0; i < iMat.cols; ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
Mat colVec = iMat.col(i);
|
|
|
|
|
|
Scalar s = cv::sum(colVec);
|
|
|
|
|
|
Vec<_Ty, cn>& d = oVec.at<Vec<_Ty, cn> >(i);
|
|
|
|
|
|
for (int j = 0; j < cn; ++j)
|
|
|
|
|
|
d[j] = s[j] / colVec.rows;
|
|
|
|
|
|
}
|
|
|
|
|
|
return oVec;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Mat sumEachCol2(const Mat& img);
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************************************/
|
|
|
|
|
|
/* Threshold */
|
|
|
|
|
|
/************************************************************************/
|
|
|
|
|
|
Mat thresholdEachRowLocally(const Mat& img, int localRange = 501, int C = 10);
|
|
|
|
|
|
|
|
|
|
|
|
Mat thresholdEachRow(const Mat& img, float threScale = 0.5);
|
|
|
|
|
|
|
|
|
|
|
|
Mat thresholdEachRow(const Mat& img, const Mat& rowThre, float threScale);
|
|
|
|
|
|
|
|
|
|
|
|
// As OpenCV doesn't provide any API to get automatic threshold value only without actually apply the threshold,
|
|
|
|
|
|
// however in some cases, we need this value only to apply our own threshold type.
|
|
|
|
|
|
// So, copied out the private getThreshVal_Otsu_8u and getThreshVal_Triangle_8u function here,
|
|
|
|
|
|
// and we provide the uniformed getAutoThresValue function to call the above two.
|
|
|
|
|
|
// Pass in THRESH_OTSU for Otsu threshold, and THRESH_TRIANGLE for the other.
|
|
|
|
|
|
double getAutoThresValue(const Mat& img, int type = THRESH_OTSU);
|
|
|
|
|
|
/**********************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
void segEachRow(const Mat& img, vector<PointPair>& pointPairVec, int xPadding);
|
|
|
|
|
|
|
|
|
|
|
|
void fillPointPairVal(const Mat& img, std::string filePath, vector<PointPair>& pointPairVec);
|
|
|
|
|
|
|
|
|
|
|
|
Mat getFirstChannel(const Mat& img);
|
|
|
|
|
|
Mat getChannel(const Mat& img, int i);
|
|
|
|
|
|
void setChannel(Mat& img, int i, Mat chnMat);
|
|
|
|
|
|
|
|
|
|
|
|
void mulEachRow(Mat& img, const Mat& scaleRow);
|
|
|
|
|
|
|
|
|
|
|
|
void genRandomPoints(const Mat& img, vector<Point>& points, RNG rng, int sampleCnt = 1000);
|
|
|
|
|
|
|
|
|
|
|
|
void plot8uVec(const Mat& vec, float scale = 1.0);
|
|
|
|
|
|
|
|
|
|
|
|
void plot32fVec(const Mat& vec, float scale = 1.0);
|
|
|
|
|
|
|
|
|
|
|
|
Mat calcHist(const Mat& img, const Mat& mask, int histSize = 256, int minVal = 0, int maxVal = 256);
|
|
|
|
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
|
|
Mat calcHist(const vector<T>& vals, unsigned int histSize, T* pMinVal = nullptr, T* pMaxVal = nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
_ASSERTE(histSize > 1);
|
|
|
|
|
|
if (histSize <= 1) return gDummyMat;
|
|
|
|
|
|
|
|
|
|
|
|
int minValIdx = -1;
|
|
|
|
|
|
int maxValIdx = -1;
|
|
|
|
|
|
int valSize = vals.size();
|
|
|
|
|
|
if (!pMinVal || !pMaxVal) {
|
|
|
|
|
|
for (int i = 0; i < valSize; ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
const T& v = vals[i];
|
|
|
|
|
|
if (minValIdx < 0 || v < vals[minValIdx]) {
|
|
|
|
|
|
minValIdx = i;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (maxValIdx < 0 || v > vals[maxValIdx]) {
|
|
|
|
|
|
maxValIdx = i;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
T minVal = pMinVal ? *pMinVal : vals[minValIdx];
|
|
|
|
|
|
T maxVal = pMaxVal ? *pMaxVal : vals[maxValIdx];
|
|
|
|
|
|
if (minVal == maxVal) return gDummyMat;
|
|
|
|
|
|
|
|
|
|
|
|
double histStep = (maxVal - minVal) / (histSize-1); // ensure max value is in analysis.
|
|
|
|
|
|
|
|
|
|
|
|
Mat hist(2, histSize, CV_32S, Scalar(0));
|
|
|
|
|
|
int* axis = (int*)hist.ptr(1);
|
|
|
|
|
|
for (int i = 0; i < histSize; ++i)
|
|
|
|
|
|
axis[i] = histStep * i + minVal;
|
|
|
|
|
|
|
|
|
|
|
|
int* data = (int*)hist.ptr(0);
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < valSize; ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
const T& v = vals[i];
|
|
|
|
|
|
int histIdx = (v - minVal) / histStep;
|
|
|
|
|
|
data[histIdx]++;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return hist;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Mat resize(const Mat& img, float s, int interMethod = cv::INTER_LINEAR);
|
|
|
|
|
|
|
|
|
|
|
|
void writeFile(const Mat& mat, std::string filePath, std::string matName = "mat");
|
|
|
|
|
|
|
|
|
|
|
|
Mat readFile(std::string filePath, std::string matName);
|
|
|
|
|
|
|
|
|
|
|
|
void gaussianBlurEachRow(const Mat& src, Mat& dst, int ksize = 3);
|
|
|
|
|
|
|
|
|
|
|
|
void medianBlurEachRow(const Mat& src, Mat& dst, int ksize = 3);
|
|
|
|
|
|
|
|
|
|
|
|
double maxLaplacianX(const Mat& rowMat, float scale = 1.0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
double minLaplacianX(const Mat& rowMat, float scale = 1.0);
|
|
|
|
|
|
|
|
|
|
|
|
void Laplacian1D(const Mat& src, Mat& dst, int ddepth, int ksize = 1);
|
|
|
|
|
|
|
|
|
|
|
|
void filterKeyPointsByNeighborDistance(vector<KeyPoint>& vec, float dis);
|
|
|
|
|
|
|
|
|
|
|
|
void filterKeyPointsByRotationInvariants(vector<KeyPoint>& vec, const Mat& img,
|
|
|
|
|
|
FeatureDetector* pDesExtractor, float tor);
|
|
|
|
|
|
|
|
|
|
|
|
double localIC_Angle(const Mat& img, Point2f center, int patchSize);
|
|
|
|
|
|
double localAngle_WeightedCen(const Mat& img, Point2f center);
|
|
|
|
|
|
double localAngle_(const Mat& img, Point2f center, Mat mask);
|
|
|
|
|
|
|
|
|
|
|
|
class GroupMatcher : public BFMatcher
|
|
|
|
|
|
{
|
|
|
|
|
|
public:
|
|
|
|
|
|
CV_WRAP GroupMatcher(int normType = NORM_L2, bool crossCheck = false);
|
|
|
|
|
|
virtual ~GroupMatcher() {}
|
|
|
|
|
|
|
|
|
|
|
|
virtual bool isMaskSupported() const { return false; }
|
|
|
|
|
|
|
|
|
|
|
|
virtual Ptr<DescriptorMatcher> clone(bool emptyTrainData = false) const;
|
|
|
|
|
|
|
|
|
|
|
|
// no longer supported in opencv3.4.1
|
|
|
|
|
|
#if (CV_MAJOR_VERSION < 3)
|
|
|
|
|
|
AlgorithmInfo* info() const;
|
|
|
|
|
|
#endif
|
|
|
|
|
|
protected:
|
|
|
|
|
|
virtual void knnMatchImpl(const Mat& queryDescriptors, vector<vector<DMatch> >& matches, int k,
|
|
|
|
|
|
const vector<Mat>& masks = vector<Mat>(), bool compactResult = false);
|
|
|
|
|
|
virtual void radiusMatchImpl(const Mat& queryDescriptors, vector<vector<DMatch> >& matches, float maxDistance,
|
|
|
|
|
|
const vector<Mat>& masks = vector<Mat>(), bool compactResult = false);
|
|
|
|
|
|
|
|
|
|
|
|
int normType;
|
|
|
|
|
|
bool crossCheck;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
void upperMajorityMask(const Mat& img, Mat& mask, float majority);
|
|
|
|
|
|
void majorityHistLower(const Mat& img, const Mat& mask, Mat& hist, float majority);
|
|
|
|
|
|
void majorityHistUpper(const Mat& img, const Mat& mask, Mat& hist, float majority);
|
|
|
|
|
|
Mat lowerMajorityMask(const Mat& img, const Mat& mask, float majority);
|
|
|
|
|
|
void meanStdDev(const Mat& img, const Mat& mask, double* pMean, double* pStdDev, float majority, int type = 0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Mat getRoiImg(const Mat& img, Point2i cen, int radius);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Mat getRoiImg(const Mat& img, vector<Point2i> ptVec, int radius);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Mat filterY(const Mat& img, float* kernel, int size, int ddepth = CV_32FC1);
|
|
|
|
|
|
|
|
|
|
|
|
Mat getContourBoundedRoiImg(const Mat& src, const vector<Point>& contour, Rect* pRoiRect = NULL);
|
|
|
|
|
|
|
|
|
|
|
|
void filterContours(Mat hsvColorThresImg,
|
|
|
|
|
|
int minArea, double minLength, double minLongShortRatio,
|
|
|
|
|
|
double maxCircleDegree, vector<Point>* pAreaMaxContour = NULL);
|
|
|
|
|
|
void filterContours(Mat& img, double minArea);
|
|
|
|
|
|
void filterContours(const vector< vector<Point> >& contours, const Mat& srcImg,
|
|
|
|
|
|
vector< vector<Point> >& filteredContours, int minArea, double minLength,
|
|
|
|
|
|
double minLongShortRatio, double maxCircleDegree, vector<Point>* pAreaMaxContour = NULL);
|
|
|
|
|
|
int filterSmallAndFindMaxContours(vector< vector<Point> >& contours, double minArea);
|
|
|
|
|
|
Mat genInRangeMask(const Mat& src, std::map<int, pair<Scalar, Scalar>>& colorRanges);
|
|
|
|
|
|
|
|
|
|
|
|
void genContrastImg(const Mat& img, Mat& contrastImg, const Mat& kernelMat);
|
|
|
|
|
|
void genContrastImg(const Mat& img, Mat& contrastImg, int ksize);
|
|
|
|
|
|
void genYContrastImg(const Mat& img, Mat& constrastImg, int ksize);
|
|
|
|
|
|
|
|
|
|
|
|
void genHalfContrastImg(const Mat& img, Mat& contrastImg, const Mat& kernelMat);
|
|
|
|
|
|
void genHalfContrastImg(const Mat& img, Mat& contrastImg, int ksize);
|
|
|
|
|
|
|
|
|
|
|
|
void cvtColor(Mat& img, int t);
|
|
|
|
|
|
|
|
|
|
|
|
Mat rotateImage(const Mat& img, Point2f cen, float degree);
|
|
|
|
|
|
Mat normAngle(const Mat& img, Mat mask);
|
|
|
|
|
|
|
|
|
|
|
|
Mat genSimpleXGradient(const Mat& m);
|
|
|
|
|
|
|
|
|
|
|
|
void uniformLocalMinExtremas(const Mat& vec, Mat& localExtremaValVec,
|
|
|
|
|
|
vector<int>& idxVec, int n, int refineRange);
|
|
|
|
|
|
|
|
|
|
|
|
void equalizeHist(const Mat& src, Mat& dst, const Mat& mask = gDummyMat);
|
|
|
|
|
|
|
|
|
|
|
|
void removeHighlights(const Mat& src, Mat& dst, float thre);
|
|
|
|
|
|
|
|
|
|
|
|
void genSectorSumVec(const Mat& img, const Mat& weightMat, Mat& hist,
|
|
|
|
|
|
Mat& weightHist, const Point2f& cen, float angleStep,
|
|
|
|
|
|
Mat* pAngMat = NULL, Mat* pMagMat = NULL);
|
|
|
|
|
|
void applySectorScales(Mat& img, const Mat& hist, const Mat& angMat);
|
|
|
|
|
|
void normSectors(Mat& img, Mat weightMat, const Point2f& cen, float angleStep,
|
|
|
|
|
|
float tarVal);
|
|
|
|
|
|
void normSectors_tarImg(Mat& img, Mat weightMat, const Point2f& cen, float angleStep,
|
|
|
|
|
|
const Mat& tarImg);
|
|
|
|
|
|
void normSectorsMeans_tarHist(Mat& img, const Mat& hist, const Point2f& cen,
|
|
|
|
|
|
float angleStep, const Mat& tarHist, const Mat& angMat);
|
|
|
|
|
|
|
|
|
|
|
|
Point2f imgCen(const Mat& img);
|
|
|
|
|
|
|
|
|
|
|
|
class luffyCircle;
|
|
|
|
|
|
cv::Mat findCircleObject(const Mat &src, const Mat& backgroundImg,
|
|
|
|
|
|
int nThres = 20, luffyCircle *pCircle = NULL);
|
|
|
|
|
|
|
|
|
|
|
|
bool ensureGrayImg(const Mat& img, Mat& gray);
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************************************/
|
|
|
|
|
|
/* Color Space */
|
|
|
|
|
|
/************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
double hsvDis(const Vec3b& v0, const Vec3b& v1);
|
|
|
|
|
|
Mat genHSVColorDisMat(const Mat& m0, const Mat& m1);
|
|
|
|
|
|
Mat genHSVColorDisMat(const Mat& m, Vec3b baseColor);
|
|
|
|
|
|
Mat genHSVColorDisMat(const Mat& m);
|
|
|
|
|
|
Mat genBlueGreenRatioMat(const Mat& m, float alpha = 166.32, float beta = -16.414);
|
|
|
|
|
|
Mat genColorFuncDisMat(const Mat& m, float a = 0.001, float b = 0.4061, float c = -5.6845);
|
|
|
|
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
|
|
float validate_diff(T result, T target, float err_tol)
|
|
|
|
|
|
{
|
|
|
|
|
|
T diff = result - target;
|
|
|
|
|
|
float normDiff = cv::norm(diff);
|
|
|
|
|
|
return normDiff <= err_tol ? 0 : normDiff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
|
|
T getImgSubPix(const Mat& img, float x, float y)
|
|
|
|
|
|
{
|
|
|
|
|
|
_ASSERTE(!img.empty());
|
|
|
|
|
|
_ASSERTE(x >= 0 && y >= 0 && x <= img.cols - 1 && y <= img.rows - 1);
|
|
|
|
|
|
|
|
|
|
|
|
int x0 = floor(x);
|
|
|
|
|
|
int y0 = floor(y);
|
|
|
|
|
|
bool noSubX = x0 == x;
|
|
|
|
|
|
bool noSubY = y0 == y;
|
|
|
|
|
|
if (noSubX && noSubY) {
|
|
|
|
|
|
return img.at<T>(y0, x0);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (noSubX) {
|
|
|
|
|
|
int y1 = y0 + 1;
|
|
|
|
|
|
double c = y1 - y;
|
|
|
|
|
|
double d = 1. - c;
|
|
|
|
|
|
|
|
|
|
|
|
const T* p0 = (const T*)img.ptr(y0);
|
|
|
|
|
|
const T* p1 = (const T*)img.ptr(y1);
|
|
|
|
|
|
|
|
|
|
|
|
T ret = p0[x0] * c + p1[x0] * d;
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (noSubY) {
|
|
|
|
|
|
int x1 = x0 + 1;
|
|
|
|
|
|
double a = x1 - x;
|
|
|
|
|
|
double b = 1. - a;
|
|
|
|
|
|
|
|
|
|
|
|
const T* p0 = (const T*)img.ptr(y0);
|
|
|
|
|
|
|
|
|
|
|
|
T ret = a * p0[x0] + b * p0[x1];
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
int x1 = x0 + 1;
|
|
|
|
|
|
int y1 = y0 + 1;
|
|
|
|
|
|
|
|
|
|
|
|
double a = x1 - x;
|
|
|
|
|
|
double b = 1. - a;
|
|
|
|
|
|
double c = y1 - y;
|
|
|
|
|
|
double d = 1. - c;
|
|
|
|
|
|
|
|
|
|
|
|
const T* p0 = (const T*)img.ptr(y0);
|
|
|
|
|
|
const T* p1 = (const T*)img.ptr(y1);
|
|
|
|
|
|
|
|
|
|
|
|
T ret = (a * p0[x0] + b * p0[x1]) * c +
|
|
|
|
|
|
(a * p1[x0] + b * p1[x1]) * d;
|
|
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
|
|
vector<T> cvtMat2Vec(const Mat& img)
|
|
|
|
|
|
{
|
|
|
|
|
|
_ASSERTE(!img.empty());
|
|
|
|
|
|
int count = img.cols * img.rows;
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<T> vals(count);
|
|
|
|
|
|
if (img.isContinuous()) {
|
|
|
|
|
|
memcpy((T*)vals.data(), (T*)img.data, sizeof(T)*count);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
int rows = img.rows;
|
|
|
|
|
|
T* vals_p = vals.data();
|
|
|
|
|
|
size_t rowStep = sizeof(T)*img.cols;
|
|
|
|
|
|
for (int i = 0; i < rows; ++i) {
|
|
|
|
|
|
memcpy(vals_p, img.ptr<T>(i), rowStep);
|
|
|
|
|
|
vals_p += img.cols;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return vals;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<typename T, typename S>
|
|
|
|
|
|
std::list<T> cvtMat2List(const Mat& img)
|
|
|
|
|
|
{
|
|
|
|
|
|
_ASSERTE(!img.empty());
|
|
|
|
|
|
int rows = img.rows;
|
|
|
|
|
|
int cols = img.cols;
|
|
|
|
|
|
int count = cols * rows;
|
|
|
|
|
|
|
|
|
|
|
|
std::list<T> vals;
|
|
|
|
|
|
for (int i = 0; i < rows; ++i) {
|
|
|
|
|
|
const S* img_p = img.ptr<S>(i);
|
|
|
|
|
|
for (int j = 0; j < cols; ++j) {
|
|
|
|
|
|
vals.push_back((S)(img_p[j]));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return vals;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
|
|
T getNthElement(const Mat& img, int n)
|
|
|
|
|
|
{
|
|
|
|
|
|
_ASSERTE(!img.empty());
|
|
|
|
|
|
int count = img.cols * img.rows;
|
|
|
|
|
|
_ASSERTE(n < count);
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<T> vals = cvtMat2Vec<T>(img);
|
|
|
|
|
|
|
|
|
|
|
|
std::nth_element(vals.begin(), vals.begin() + n, vals.end());
|
|
|
|
|
|
|
|
|
|
|
|
return vals[n];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int getLocalMaximun(const Mat& vec, double thres, std::vector<int>* pMaxIdxVec);
|
|
|
|
|
|
int getLocalMinimun(const Mat& vec, double thres, std::vector<int>* pMaxIdxVec);
|
|
|
|
|
|
|
|
|
|
|
|
enum EnumAbnormalType {
|
|
|
|
|
|
AbTypePositive = 0,
|
|
|
|
|
|
AbTypeNegative,
|
|
|
|
|
|
AbTypeBoth
|
|
|
|
|
|
};
|
|
|
|
|
|
int detectAbnormal(const Mat& vec, int kernelSize, EnumAbnormalType abnormalType, double abnormalThreshold,
|
|
|
|
|
|
Mat* pScores = nullptr, std::vector<int>* pAbIdxVec = nullptr);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************************************/
|
|
|
|
|
|
/* Angle */
|
|
|
|
|
|
/************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
inline float normAngle(float x, float y)
|
|
|
|
|
|
{
|
|
|
|
|
|
float angle = atan2f(y, x);
|
|
|
|
|
|
return angle / CV_PI * 180.0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// convert angle to (0, 360)
|
|
|
|
|
|
// inline float normAngle(float angle)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// int c = angle / 360;
|
|
|
|
|
|
// float ret = angle - c * 360;
|
|
|
|
|
|
// return ret < 0 ? ret + 360 : ret;
|
|
|
|
|
|
// }
|
|
|
|
|
|
inline int normAngle(int angle)
|
|
|
|
|
|
{
|
|
|
|
|
|
int c = angle / 360;
|
|
|
|
|
|
int ret = angle - c * 360;
|
|
|
|
|
|
return ret < 0 ? ret + 360 : ret;
|
|
|
|
|
|
}
|
|
|
|
|
|
inline double normAngle(double angle)
|
|
|
|
|
|
{
|
|
|
|
|
|
int c = angle / 360;
|
|
|
|
|
|
double ret = angle - c * 360;
|
|
|
|
|
|
return ret < 0 ? ret + 360 : ret;
|
|
|
|
|
|
}
|
|
|
|
|
|
inline float normAngle180(float angle)
|
|
|
|
|
|
{
|
|
|
|
|
|
int c = angle / 360;
|
|
|
|
|
|
float ret = angle - c * 360;
|
|
|
|
|
|
return ret > 180 ? ret - 360 : (ret < -180 ? ret + 360 : ret);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
inline float diffAngle(float angle1, float angle2)
|
|
|
|
|
|
{
|
|
|
|
|
|
float diff = abs(angle1 - angle2);
|
|
|
|
|
|
return diff > 180 ? 360 - diff : diff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
inline float diffAngle2(float angle1, float angle2)
|
|
|
|
|
|
{
|
|
|
|
|
|
Vec2f vp(cos(angle1 / 180 * CV_PI), sin(angle1 / 180 * CV_PI));
|
|
|
|
|
|
Vec2f vpp(cos(angle2 / 180 * CV_PI), sin(angle2 / 180 * CV_PI));
|
|
|
|
|
|
|
|
|
|
|
|
return vp.dot(vpp);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
inline float diffAngleRaw(float angle1, float angle2)
|
|
|
|
|
|
{
|
|
|
|
|
|
return diffAngle(normAngle(angle1), normAngle(angle2));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
inline float bisectAngle(float angle1, float angle2)
|
|
|
|
|
|
{
|
|
|
|
|
|
float diff = abs(angle1 - angle2);
|
|
|
|
|
|
return diff < 180 ? (angle1 + angle2) / 2 : (angle1 + angle2 + 360) / 2;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************************************/
|
|
|
|
|
|
/* Transform */
|
|
|
|
|
|
/************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
void transPoints(vector<Point2d>& vec, const Mat& mat);
|
|
|
|
|
|
void transPoints(vector<Point2d>& vec, const Matx33d& mat);
|
|
|
|
|
|
void transPoints(const vector<Point2f>& vec, vector<Point2f>& oVec, const Matx23f& mat);
|
|
|
|
|
|
|
|
|
|
|
|
Matx23f getRotationMatrix23f(Point2f center, float angle, float scale,
|
|
|
|
|
|
float xOffset = 0, float yOffset = 0);
|
|
|
|
|
|
|
|
|
|
|
|
void getRigidTransform(const Point2f& cen1, const Point2f& u1, const Point2f& u2,
|
|
|
|
|
|
const Point2f& cen2, const Point2f& v1, const Point2f& v2,
|
|
|
|
|
|
double& x0, double& y0, double& angle, double& scale);
|
|
|
|
|
|
|
|
|
|
|
|
void getRigidTransform(const Point2f& u1, const Point2f& u2, const Point2f& v1, const Point2f& v2,
|
|
|
|
|
|
double& x0, double& y0, double& angle, double& scale);
|
|
|
|
|
|
|
|
|
|
|
|
void getRigidTransform(const Point2f& cen1, const Point2f& u1, float ua,
|
|
|
|
|
|
const Point2f& cen2, const Point2f& v1, float va,
|
|
|
|
|
|
double& x0, double& y0, double& angle, double& scale);
|
|
|
|
|
|
|
|
|
|
|
|
void getRigidTransform(const Point2f& u1, float ua, const Point2f& v1, float va,
|
|
|
|
|
|
double& x0, double& y0, double& angle, double& scale);
|
|
|
|
|
|
|
|
|
|
|
|
void getRigidTransform(const Point2f& cen1, const Point2f& u1, float ua,
|
|
|
|
|
|
const Point2f& cen2, const Point2f& v1, float va, float s,
|
|
|
|
|
|
double& x0, double& y0, double& angle, double& scale);
|
|
|
|
|
|
|
|
|
|
|
|
void getRigidTransform(const Point2f& u1, float ua, const Point2f& v1, float va, float s,
|
|
|
|
|
|
double& x0, double& y0, double& angle, double& scale);
|
|
|
|
|
|
|
|
|
|
|
|
Mat applyPerspectiveTransform(const Mat& img,
|
|
|
|
|
|
std::vector<Point2f>& transVertexes, // in order top-left, top-right, bottom-right, bottom-left
|
|
|
|
|
|
int flags = INTER_LINEAR);
|
|
|
|
|
|
};
|
|
|
|
|
|
using namespace CyclopsUtils1;
|
|
|
|
|
|
|
|
|
|
|
|
#endif // __CVUtils_h_
|
|
|
|
|
|
|