You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1051 lines
32 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*! \file CVUtils.h
\brief Some functions extend opencv classes
Created: 2015/06/22, author: Jin Bingwen.
*/
#ifndef __CVUtils_h_
#define __CVUtils_h_
#include "CyclopsVersion.h"
#include "StdUtils.h"
#include <opencv2/opencv.hpp>
#include <opencv2/opencv_modules.hpp>
#include <memory>
#include <vector>
#include <iostream>
#include <fstream>
#include <map>
#if defined(_DEBUG) && defined(_VIEW_INTERNAL_MAT)
#define DEBUG_VIEW_INTERNAL_MAT
#endif
#if defined(_DEBUG) && defined(_DETAIL_LOG)
#define DEBUG_DETAIL_LOG
#endif
#ifndef M_PI
#define M_PI CV_PI
#endif
#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 CyclopsUtils {
// 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;
}
inline bool isPow2(int n)
{
return (n & (n - 1)) == 0;
}
inline unsigned int makePow2(unsigned int n)
{
return n <= 2 ? n : pow(2, cvFloor(std::log2(n)));
}
template<typename T>
bool isEyeMat(const Mat& m) {
for (int j = 0; j < m.rows; ++j) {
const T* p = m.ptr<T>(j);
if (j < m.cols && p[j] != 1) return false;
for (int i = 0; i < j; ++i) {
if (p[i] != 0) return false;
}
for (int i = j + 1; i < m.cols; ++i) {
if (p[i] != 0) return false;
}
}
return true;
}
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 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);
void magnitude_16s32f(const Mat& sobelX, const Mat& sobelY, Mat& magMat);
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);
Mat genXDeriLineKernel(int w, int type, double absVal);
Mat genXDeriMat(const Mat& img, int w, double absVal);
Mat GaussianDownSamplerWithBox(Mat in, Rect bbox, float scaleX, float scaleY = -1);
bool PoolingByReduce(const Mat& src, Mat& des,const Size& BlockSize, ReduceTypes emReducedtype);
//Precisely line-interpolation: {1,3,5,7}=>{1,2,3,4,5,6,7}
Mat interpMat(const Mat& src);
/************************************************************************/
/* Normalize */
/************************************************************************/
bool zsorceNorm(const cv::Mat &mtSrc, cv::Mat &mtDst, int rtype = -1, const Mat& mask= Mat::Mat());
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 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;
}
CYCLOPS_UTILS_DLLSPEC 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;
}
CYCLOPS_UTILS_DLLSPEC 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);
/**********************************************************************/
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);
CYCLOPS_UTILS_DLLSPEC Mat calcHist(const Mat& img, const Mat& mask, int histSize = 256, int minVal = 0, int maxVal = 256);
Mat resizeSum(const Mat& img, const Size& s);
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);
CYCLOPS_UTILS_DLLSPEC float getMajor(const Mat& img, Mat mask, float tfactor = 0.8);
float getMajor(const Mat& img, Mat mask, Range binSize, Range binCount, int binCountExpect,
double* pMajorMean, double* pMajorStdDev);
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);
CYCLOPS_UTILS_DLLSPEC Mat cropImage(const Mat& img, const Rect& roi);
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);
CYCLOPS_UTILS_DLLSPEC bool ensureGrayImg(const Mat& img, Mat& gray);
CYCLOPS_UTILS_DLLSPEC bool ensureColorImg(const Mat& img, Mat& color);
Scalar ensureScalarRng(const Scalar& c, int min, int max);
CYCLOPS_UTILS_DLLSPEC void gradiant(const Mat& img, Mat& orResult, int dx, int dy, bool ignoreSign = false, int ddepth = -1);
CYCLOPS_UTILS_DLLSPEC double sharpness(const Mat& img, Mat const* pMask = nullptr, Mat* pRetMat = nullptr);
/************************************************************************/
/* 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);
CYCLOPS_UTILS_DLLSPEC void addColorRngToLUT(const Scalar& c1, const Scalar& c2, Mat& lut, uchar val);
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, typename S>
inline S _bilinear(const T* p0, const T* p1, int x0, int x1,
double a, double b, double c, double d)
{
return (a * (S)(p0[x0]) + b * (S)(p0[x1])) * c +
(a * (S)(p1[x0]) + b * (S)(p1[x1])) * d;
}
template<typename T, typename S>
S getImgSubPixBilinear(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 = x;
int y0 = y;
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 = img.ptr<T>(y0);
const T* p1 = img.ptr<T>(y1);
return _bilinear<T, S>(p0, p1, x0, x1, a, b, c, d);
}
template<typename T, typename S>
void getImgSubPixBilinear2(const Mat& img1, const Mat& img2, float x, float y, S& ret1, S& ret2)
{
_ASSERTE(!img1.empty() && !img2.empty());
_ASSERTE(x >= 0 && y >= 0 && x < img1.cols - 1 && y < img1.rows - 1);
_ASSERTE(img1.size == img2.size);
int x0 = x;
int y0 = y;
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 = img1.ptr<T>(y0);
size_t rstep = img1.step.p[0] / sizeof(T);
const T* p1 = p0 + rstep;
ret1 = _bilinear<T, S>(p0, p1, x0, x1, a, b, c, d);
p0 = img2.ptr<T>(y0);
p1 = p0 + rstep;
ret2 = _bilinear<T, S>(p0, p1, x0, x1, a, b, c, d);
}
template<typename T, typename S>
S getImgSubPixBilinearSafeBorder(const Mat& img, float x, float y)
{
_ASSERTE(!img.empty());
_ASSERTE(x >= 0 && y >= 0 && x < img.cols && y < img.rows);
int x0 = x;
int y0 = y;
int x1 = x0 + 1;
int y1 = y0 + 1;
double a = x1 - x;
double b = 1. - a;
double c = y1 - y;
double d = 1. - c;
if (x0 < 0) x0 = x1;
if (x1 > img.cols - 1) x1 = x0;
if (y0 < 0) y0 = y1;
if (y1 > img.rows - 1) y1 = y0;
const T* p0 = img.ptr<T>(y0);
const T* p1 = img.ptr<T>(y1);
return _bilinear<T, S>(p0, p1, x0, x1, a, b, c, d);
}
template<typename T>
inline T __cubicHermite(T A, T B, T C, T D, double t3, double t2, double t)
{
T A2 = -A / 2.0f;
T D2 = D / 2.0f;
T a = A2 + 1.5f * B - 1.5f * C + D2;
T b = A - 2.5f * B + 2.0f * C - D2;
T c = A2 + C / 2.0f;
return a * t3 + b * t2 + c * t + B;
}
template<typename T, typename S>
inline S _cubicHermite(const T* p0, const T* p1, const T* p2, const T* p3,
int x0_1, int x0, int x1, int x2,
double dx3, double dx2, double dx, double dy3, double dy2, double dy)
{
S col0 = __cubicHermite<S>(p0[x0_1], p0[x0], p0[x1], p0[x2], dx3, dx2, dx);
S col1 = __cubicHermite<S>(p1[x0_1], p1[x0], p1[x1], p1[x2], dx3, dx2, dx);
S col2 = __cubicHermite<S>(p2[x0_1], p2[x0], p2[x1], p2[x2], dx3, dx2, dx);
S col3 = __cubicHermite<S>(p3[x0_1], p3[x0], p3[x1], p3[x2], dx3, dx2, dx);
return __cubicHermite<S>(col0, col1, col2, col3, dy3, dy2, dy);
}
template<typename T, typename S>
S getImgSubPixCubic(const Mat& img, float x, float y)
{
_ASSERTE(!img.empty());
_ASSERTE(x >= 1 && y >= 1 && x < img.cols - 2 && y < img.rows - 2);
int x0 = x;
int y0 = y;
double dx = x - x0;
double dy = y - y0;
size_t rstep = img.step.p[0];
const T* p1 = (const T*)(img.data + rstep * y0);
const T* p0 = (const T*)((const uchar*)(p1) - rstep);
const T* p2 = (const T*)((const uchar*)(p1) + rstep);
const T* p3 = (const T*)((const uchar*)(p2) + rstep);
double dx2 = dx * dx;
double dx3 = dx2 * dx;
double dy2 = dy * dy;
double dy3 = dy2 * dy;
int x0_1 = x0 - 1;
int x1 = x0 + 1;
int x2 = x0 + 2;
return _cubicHermite<T, S>(p0, p1, p2, p3, x0_1, x0, x1, x2, dx3, dx2, dx, dy3, dy2, dy);
}
template<typename T, typename S>
void getImgSubPixCubic2(const Mat& img1, const Mat& img2, float x, float y, S& ret1, S& ret2)
{
_ASSERTE(!img1.empty() && !img2.empty());
_ASSERTE(x >= 1 && y >= 1 && x < img1.cols - 2 && y < img1.rows - 2);
_ASSERTE(img1.size == img2.size);
int x0 = x;
int y0 = y;
double dx = x - x0;
double dy = y - y0;
size_t rstep = img1.step.p[0];
const T* p1 = (const T*)(img1.data + rstep * y0);
const T* p0 = (const T*)((const uchar*)(p1)-rstep);
const T* p2 = (const T*)((const uchar*)(p1)+rstep);
const T* p3 = (const T*)((const uchar*)(p2)+rstep);
double dx2 = dx * dx;
double dx3 = dx2 * dx;
double dy2 = dy * dy;
double dy3 = dy2 * dy;
int x0_1 = x0 - 1;
int x1 = x0 + 1;
int x2 = x0 + 2;
ret1 = _cubicHermite<T, S>(p0, p1, p2, p3, x0_1, x0, x1, x2, dx3, dx2, dx, dy3, dy2, dy);
p1 = (const T*)(img2.data + rstep * y0);
p0 = (const T*)((const uchar*)(p1)-rstep);
p2 = (const T*)((const uchar*)(p1)+rstep);
p3 = (const T*)((const uchar*)(p2)+rstep);
ret2 = _cubicHermite<T, S>(p0, p1, p2, p3, x0_1, x0, x1, x2, dx3, dx2, dx, dy3, dy2, dy);
}
template<typename T, typename S>
S getVecSubPixBilinear(const std::vector<T>& vec, float x)
{
_ASSERTE(x >= 0 && x < vec.size() - 1);
int x0 = x;
double dx = x - x0;
return saturate_cast<S>(dx * vec[x0 + 1] + (1 - dx) * vec[x0]);
}
template<typename T>
double interpolatePoly2(T v, T v0, T v1)
{
// y = ax^2 + bx + c, y -> v,
// x represent the position of the pixel point and its neighbor, x - 1 and x + 1
float c = v;
float a = (v0 + v1) / 2.f - c;
float b = (v1 - v0) / 2.f;
return abs(a) < FLT_EPSILON ? 0 : -b / (2.f * a); // -b/2a
}
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>
vector<T> cvtMat2Vec(const Mat& img, const Mat& mask)
{
_ASSERTE(!img.empty());
int count = img.cols * img.rows;
std::vector<T> vals;
vals.reserve(count);
for (int i = 0; i < img.rows; ++i) {
const T* img_p = img.ptr<T>(i);
const uchar* mask_p = mask.ptr<uchar>(i);
for (int j = 0; j < img.cols; ++j) {
if (mask_p[j]) {
vals.push_back(saturate_cast<T>(img_p[j]));
}
}
}
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(saturate_cast<T>(img_p[j]));
}
}
return vals;
}
template<typename T>
Mat cvtVec2Mat(const vector<T>& vec)
{
_ASSERTE(vec.size());
return Mat(1, vec.size(), DataType<T>::type, (T*)vec.data());
}
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);
int getLocalMaximun(const Mat& vec, const Mat& mask, std::vector<int>* pMaxIdxVec);
int getLocalMinimun(const Mat& vec, const Mat& mask, std::vector<int>* pMaxIdxVec);
// naive method for finding local extremes
int getLocalMaximun(const Mat& vec, std::vector<int>* pMaxIdxVec);
int getLocalMinimun(const Mat& vec, std::vector<int>* pMaxIdxVec);
enum EnumAbnormalType {
AbTypePositive = 0,
AbTypeNegative,
AbTypeBoth
};
CYCLOPS_UTILS_DLLSPEC int detectAbnormal(const Mat& vec, int kernelSize, EnumAbnormalType abnormalType, double abnormalThreshold,
Mat* pScores = nullptr, std::vector<int>* pAbIdxVec = nullptr);
typedef std::vector<Point> PointVec;
typedef std::vector<Point2f> Point2fVec;
typedef std::vector<Point3f> Point3fVec;
typedef std::vector<Point2d> Point2dVec;
typedef std::vector<Point3d> Point3dVec;
Point2fVec toPoint2fVec(const Point3fVec& pnts3d);
void toPoint2fVec(const Point3fVec& pnts3d, Point2fVec& pnts2d);
Point3fVec toPoint3fVec(const Point2fVec& pnts2d, float z = 0);
void toPoint3fVec(const Point2fVec& pnts2d, Point3fVec& pnts3d, float z = 0);
CYCLOPS_UTILS_DLLSPEC Point2f detectValley(const Mat& mask);
void filterWithMask(const Mat& src, Mat& dst, const Mat& mask, int ddepth, Size kSize);
CYCLOPS_UTILS_DLLSPEC Point2f findMaskCenter(const Mat& mask);
CYCLOPS_UTILS_DLLSPEC void createMaskByContour(Mat& mask,
const PointVec& contour, const vector<PointVec>& holes, const Point& offset = Point(0, 0), bool isDense = true);
vector<double> resampleVec(const vector<double>& v, float start, float end, int expectSize);
// add new helper functions above
};
using namespace CyclopsUtils;
#include "GeomUtils.h"
// This macro provide 4 functions for serialization:
// serializeToMemory, serializeToFile, deserializeFromMemory, deserializeFromFile
// It does the error case handling and FileStorage initialization for you,
// you only need to write serialize() and deserialize() to do the real job.
// see CameraCalibrator and BlobDetector for example
#define DECL_SERIALIZE_FUNCS public:\
bool serializeToMemory(std::string& str, bool base64 = true) {\
try {\
int writeFlag = base64 ? FileStorage::WRITE_BASE64 : FileStorage::WRITE;\
FileStorage fs(".json", writeFlag + FileStorage::MEMORY + FileStorage::FORMAT_JSON);\
if (!fs.isOpened()) return false;\
bool ret = serialize(fs);\
if (!ret) return false;\
str = fs.releaseAndGetString();\
}\
catch (const cv::Exception& exc) {\
std::cout << cvErrorStr(exc.code) << std::endl;\
return false;\
}\
catch (...) {\
return false;\
}\
return true;\
}\
bool serializeToFile(const char* filename, bool base64 = true) {\
if (!filename || strlen(filename) == 0) return false;\
try {\
int writeFlag = base64 ? FileStorage::WRITE_BASE64 : FileStorage::WRITE;\
FileStorage fs(filename, writeFlag + FileStorage::FORMAT_JSON);\
if (!fs.isOpened()) return false;\
bool ret = serialize(fs);\
if (!ret) return false;\
}\
catch (const cv::Exception& exc) {\
std::cout << cvErrorStr(exc.code) << std::endl;\
return false;\
}\
catch (...) {\
return false;\
}\
return true;\
}\
bool serializeToFile(const std::string& filename, bool base64 = true) { return serializeToFile(filename.c_str(), base64); }\
bool deserializeFromMemory(const std::string& str) {\
if (str.empty()) return false;\
try {\
FileStorage fs(str, FileStorage::READ + FileStorage::MEMORY + FileStorage::FORMAT_JSON);\
if (!fs.isOpened()) return false;\
bool ret = deserialize(fs.root());\
if (!ret) return false;\
}\
catch (const cv::Exception& exc) {\
std::cout << cvErrorStr(exc.code) << std::endl;\
return false;\
}\
catch (...) {\
return false;\
}\
return true;\
}\
bool deserializeFromFile(const char* filename) {\
if (!filename || strlen(filename) == 0) return false;\
try {\
FileStorage fs(filename, FileStorage::READ + FileStorage::FORMAT_JSON);\
if (!fs.isOpened()) return false;\
bool ret = deserialize(fs.root());\
if (!ret) return false;\
}\
catch (const cv::Exception& exc) {\
std::cout << cvErrorStr(exc.code) << std::endl;\
return false;\
}\
catch (...) {\
return false;\
}\
return true;\
}\
bool deserializeFromFile(const std::string& filename) { return deserializeFromFile(filename.c_str()); }\
// more implementation of serialization
template<typename _Tp>
void serializeList(FileStorage& fs, const std::list<_Tp>& vec, const char* n) {
fs << n << "[";
for (const _Tp& v : vec) {
fs << v;
}
fs << "]";
}
template<typename _Tp> static inline
void deserializeList(const FileNode& node, std::list<_Tp>& vec, const char* n) {
FileNode lNode = node[n];
vec.clear();
if (!lNode.isNone()) {
_Tp val;
for (FileNodeIterator it = lNode.begin(); it != lNode.end(); ++it) {
*it >> val;
vec.push_back(std::move(val));
}
}
}
template<typename _T, typename _S>
void serializeMap(FileStorage& fs, const std::map<_T, _S>& m, const char* n) {
fs << n << "{";
fs << "keys" << "[";
for (auto it = m.begin(); it != m.end(); ++it) {
fs << it->first;
}
fs << "]";
fs << "values" << "[";
for (auto it = m.begin(); it != m.end(); ++it) {
fs << it->second;
}
fs << "]";
fs << "}";
}
template<typename _T, typename _S>
void deserializeMap(const FileNode& node, std::map<_T, _S>& m, const char* n) {
FileNode mNode = node[n];
m.clear();
if (!mNode.isNone()) {
_T k; _S v;
FileNode kNode = mNode["keys"];
FileNode vNode = mNode["values"];
_ASSERTE(kNode.size() == vNode.size());
FileNodeIterator itValue = vNode.begin();
for (FileNodeIterator itKey = kNode.begin(); itKey != kNode.end() && itValue != vNode.end();
++itKey, ++itValue)
{
*itKey >> k;
*itValue >> v;
m[k] = v;
}
}
}
// more implementation of saturate_cast
namespace cv {
template<> inline float saturate_cast<float>(double v) { return v > FLT_MAX ? FLT_MAX : (v < -FLT_MAX ? -FLT_MAX : v); }
}
template<typename T, typename S> inline Point_<T> saturate_cast_point(const Point_<S>& pnt) {
return Point_<T>(saturate_cast<T>(pnt.x), saturate_cast<T>(pnt.y));
}
template<typename T, typename S> inline std::vector<Point_<T> > saturate_cast_points(const std::vector<Point_<S> >& pnts) {
size_t n = pnts.size();
std::vector<Point_<T> > ret; ret.reserve(n);
for (size_t i = 0; i < n; ++i) {
ret.push_back(saturate_cast_point<T, S>(pnts[i]));
}
return std::move(ret);
}
template<typename T, typename S> inline Point_<T> saturate_cast_point(const Point_<S>& pnt,
const Point_<S>& scale, const Point_<S>& shift)
{
return Point_<T>(saturate_cast<T>(pnt.x * scale.x + shift.x), saturate_cast<T>(pnt.y * scale.y + shift.y));
}
template<typename T, typename S> inline std::vector<Point_<T> > saturate_cast_points(const std::vector<Point_<S> >& pnts,
const Point_<S>& scale, const Point_<S>& shift)
{
size_t n = pnts.size();
std::vector<Point_<T> > ret; ret.reserve(n);
for (size_t i = 0; i < n; ++i) {
ret.push_back(saturate_cast_point<T, S>(pnts[i], scale, shift));
}
return std::move(ret);
}
// more implementation of cv structure's operation
namespace cv {
static inline bool operator!= (const Size& s1, const Size& s2) { return s1.width != s2.width || s1.height != s2.height; }
static inline bool operator>= (const Size& s1, const Size& s2) { return s1.width >= s2.width && s1.height >= s2.height; }
static inline bool operator> (const Size& s1, const Size& s2) { return s1.width > s2.width && s1.height > s2.height; }
static inline bool operator<= (const Size& s1, const Size& s2) { return s1.width <= s2.width && s1.height <= s2.height; }
static inline bool operator< (const Size& s1, const Size& s2) { return s1.width < s2.width && s1.height < s2.height; }
}
// implementation of float range
namespace cv {
class Rangef
{
public:
Rangef() : start(0), end(0) {}
Rangef(float _start, float _end) : start(_start), end(_end) {}
float size() const { return empty() ? 0 : end - start; }
float empty() const { return start >= end; }
void add(float v) {
start = std::min<float>(v, start);
end = std::max<float>(v, end);
}
void add(const Rangef& other) {
start = std::min<float>(other.start, start);
end = std::max<float>(other.end, end);
}
Rangef extend(float dstart, float dend) const {
return Rangef(start + dstart, end + dend);
}
Rangef merge(const Rangef& other) const {
return Rangef(std::min<float>(other.start, start), std::max<float>(other.end, end));
}
Rangef overlap(const Rangef& other) const {
if (start > other.start) return other.overlap(*this);
else if (end > other.start) return Rangef(other.start, std::min<float>(other.end, end));
else return Rangef();
}
bool equal(const Rangef& other, float tol = FLT_EPSILON) const {
return abs(other.start - start) < tol && abs(other.end - end) < tol;
}
float mid() const { return (start + end) / 2.; }
bool contain(float v) const { return v >= start && v <= end; }
static Rangef all() { return Rangef(-FLT_MAX, FLT_MAX); }
static Rangef none() { return Rangef(FLT_MAX, -FLT_MAX); }
float start, end;
};
template<> class DataType<Rangef>
{
public:
typedef Rangef value_type;
typedef value_type work_type;
typedef float channel_type;
enum {
generic_type = 0,
channels = 2,
fmt = traits::SafeFmt<channel_type>::fmt + ((channels - 1) << 8)
#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED
, depth = DataType<channel_type>::depth
, type = CV_MAKETYPE(depth, channels)
#endif
};
typedef Vec<channel_type, channels> vec_type;
};
namespace traits {
template<>
struct Depth< Rangef > { enum { value = Depth<float>::value }; };
template<>
struct Type< Rangef > { enum { value = CV_MAKETYPE(Depth<float>::value, 2) }; };
}
}
#endif // __CVUtils_h_