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

835 lines
25 KiB
C++

/*! \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 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); // 计算第一个近似根
x = *(float*)&i;
x = x*(1.5f - xhalf*x*x); // 牛顿迭代法
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);
using namespace cv;
/************************************************************************/
/* Miscellaneous */
/************************************************************************/
inline double distance(float x0, float y0, float x1, float y1)
{
return sqrt(pow(x0 - x1, 2) + pow(y0 - y1, 2));
}
inline double distance(Point2f p1, Point2f p2)
{
return distance(p1.x, p1.y, p2.x, p2.y);
}
/************************************************************************/
/* Rect */
/************************************************************************/
typedef Rect_<double> Rectd;
typedef Rect_<float> Rectf;
template<typename _Ty>
bool isImageRoiRectValid(const Rect_<_Ty>& rect)
{
return rect.x >= 0 && rect.y >= 0 && rect.width > 0 && rect.height > 0;
}
template<typename _Ty>
string rect2str(const Rect_<_Ty>& rect)
{
stringstream ss;
ss << rect.x << ", " << rect.y << ", " << rect.width << ", " << rect.height;
return ss.str();
}
template<typename _Ty>
Rect_<_Ty> rectFromVec(vector<_Ty>& vec)
{
if (vec.size() < 4)
{
return Rect_<_Ty>();
}
Rect_<_Ty> rect;
rect.x = vec[0];
rect.y = vec[1];
rect.width = vec[2];
rect.height = vec[3];
return rect;
}
template<typename _Point>
Rect genRectCenRadius(_Point cen, int radius)
{
return Rect(cen.x - radius,
cen.y - radius,
radius * 2 + 1,
radius * 2 + 1);
}
template<typename _Point>
Rect genRectLeftTopRadius(_Point p, int radius)
{
return Rect(p.x,
p.y,
radius * 2,
radius * 2);
}
template<typename _Point>
Rect genRectCenRadius(const vector<_Point>& ptVec, int radius)
{
Rect br = cv::boundingRect(ptVec);
return Rect(br.x - radius, br.y - radius, br.width + 2 * radius, br.height + 2 * radius);
}
Rect loadRect(std::string filepath);
Rect rectInImage(const Mat& img, const Point& pt, const Size& rectSize,
int xPadding = 0, int yPadding = 0);
Rect extRectTopLeftFix(const Rect& r, int w);
Rect extRectCenFix(const Rect& r, int w);
inline void rotatedRect2PtVec(const RotatedRect& rr, vector<Point2f>& ptVec)
{
ptVec.resize(4);
rr.points(&ptVec[0]);
}
bool isPntInRotatedRect(const RotatedRect& rr, const Point2f& pnt);
/************************************************************************/
/* Intersection */
/************************************************************************/
bool intersection(Point2f o1, Point2f p1, Point2f o2, Point2f p2,
Point2f &r, bool bounded = false);
bool intersection(const Vec4f& l0, const Vec4f& l1, Point2f& r,
bool bounded = false);
bool intersection(const Vec4f& l, const vector<Point2f>& vertexes, vector<Point2f>& interPtVec,
bool bounded = false);
int intersection(const Vec4f& line, const Vec3f& circle, Point2f& r1, Point2f& r2);
int intersection(const Vec4d& line, const Vec3d& circle, Point2d& r1, Point2d& r2);
Point2f getNearestIntersectionOfMultiLines(const vector<Vec4f>& lines);
Point2f getNearestIntersectionOfMultiLines(const vector<Point2f>& linePnts, const vector<Vec2f>& lineNorms);
Point2f getNearestIntersectionOfMultiLines(const vector<Point2f>& linePnts, const vector<float>& lineAngles, bool useDegree = true);
/************************************************************************/
/* 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);
/************************************************************************/
/* Shape */
/************************************************************************/
float isSameDir(Vec4f& l1, Vec4f& l2, float err_tol = 1e-9);
float isCollinear(Vec4f& l1, Vec4f& l2, float err_tol = 1e-9);
bool isLikeArch(const Mat& vec, double tor);
bool isLikeHorizontalLine(const Mat& vec, double tor);
};
using namespace CyclopsUtils;
#endif // __CVUtils_h_