|
|
|
|
|
#ifndef _Luffy_Process_h_
|
|
|
|
|
|
#define _Luffy_Process_h_
|
|
|
|
|
|
|
|
|
|
|
|
#include "CVUtils.h"
|
|
|
|
|
|
#include "stdio.h"
|
|
|
|
|
|
#include <list>
|
|
|
|
|
|
#include <map>
|
|
|
|
|
|
using namespace cv;
|
|
|
|
|
|
using std::vector;
|
|
|
|
|
|
|
|
|
|
|
|
namespace luffy_base
|
|
|
|
|
|
{
|
|
|
|
|
|
#define LP_MAX_ANGLE 360
|
|
|
|
|
|
#define LP_GRAY_LEVEL 256
|
|
|
|
|
|
#define LP_MAX_GRAY_VALUE 255
|
|
|
|
|
|
|
|
|
|
|
|
#define LP_COLOR_GREEN Scalar(0, 255, 0)
|
|
|
|
|
|
#define LP_COLOR_RED Scalar(0, 0, 255)
|
|
|
|
|
|
#define LP_COLOR_BLUE Scalar(255, 0, 0)
|
|
|
|
|
|
#define LP_COLOR_WHITE Scalar(255, 255, 255)
|
|
|
|
|
|
#define LP_COLOR_BLACK Scalar(0, 0, 0)
|
|
|
|
|
|
|
|
|
|
|
|
#define LuffyMax(a, b) ((a)>(b) ? (a) : (b))
|
|
|
|
|
|
#define LuffyMin(a, b) ((a)<(b) ? (a) : (b))
|
|
|
|
|
|
|
|
|
|
|
|
#define LP_SINGLE_LINE 1
|
|
|
|
|
|
|
|
|
|
|
|
class luffyCircle
|
|
|
|
|
|
{
|
|
|
|
|
|
public:
|
|
|
|
|
|
luffyCircle() :ptCenter(0,0), fRadius(0){}
|
|
|
|
|
|
public:
|
|
|
|
|
|
Point2f ptCenter;
|
|
|
|
|
|
float fRadius;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class luffyObject
|
|
|
|
|
|
{
|
|
|
|
|
|
public:
|
|
|
|
|
|
luffyObject();
|
|
|
|
|
|
|
|
|
|
|
|
Rect rtPos;
|
|
|
|
|
|
|
|
|
|
|
|
float getRadius() { return (rtPos.width / 2.0); }
|
|
|
|
|
|
//Rect
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
typedef int LP_NORM_METHOD;
|
|
|
|
|
|
|
|
|
|
|
|
class luffyPos
|
|
|
|
|
|
{
|
|
|
|
|
|
public:
|
|
|
|
|
|
Point m_ptInPic; //圆在大图中的圆心位置
|
|
|
|
|
|
Point m_ptInROI; //圆在ROI中的圆心位置
|
|
|
|
|
|
Rect m_rtROI; //ROI区域
|
|
|
|
|
|
float m_fRadiusAvg; //半径
|
|
|
|
|
|
};
|
|
|
|
|
|
/*
|
|
|
|
|
|
阈值分割算法汇总
|
|
|
|
|
|
emThresMethodDefault 按照param1作为阈值分割
|
|
|
|
|
|
emThresMethodInv 按照param1作为阈值
|
|
|
|
|
|
emThresMethodRatio 按照灰度总数的前百分比emThresMethodRatio计算值作为阈值
|
|
|
|
|
|
emThresMethodNum 按照灰度总数的前emThresMethodNum个灰度数量作为阈值
|
|
|
|
|
|
emThresMethodOtsu 最大间方差得到的阈值
|
|
|
|
|
|
emThresMethodIteration 迭代法
|
|
|
|
|
|
emThresMethodBasicGlobal 基本全局阈值法
|
|
|
|
|
|
emThresMethodMaxEntropy 最大熵阈值分割
|
|
|
|
|
|
emThresMethodHuangFuzzy
|
|
|
|
|
|
*/
|
|
|
|
|
|
namespace luffy_threshold {
|
|
|
|
|
|
enum EmThresMethod {
|
|
|
|
|
|
emThresMethodDefault = 000, emThresMethodInv = 100, emThresMethodRatio = 2, emThresMethodNum = 3, emThresMethodOtsu = 4,
|
|
|
|
|
|
emThresMethodIteration= 5, emThresMethodBasicGlobal = 6, emThresMethodMaxEntropy = 7, emThresMethodHuangFuzzy = 8, emThresMethod2 = 9
|
|
|
|
|
|
};
|
|
|
|
|
|
void calcuHist(const Mat &src, Mat &matHist, int &nTotal, Mat &mask = gDummyMat);
|
|
|
|
|
|
int getThresValue(Mat &matHist, int nTotal, double dRatio, EmThresMethod emMethod = emThresMethodRatio);
|
|
|
|
|
|
int Threshold(const Mat &src, Mat &dst, double param1, int nThresMethod = emThresMethodDefault, Mat mask = Mat());
|
|
|
|
|
|
int Threshold(const Mat &src, Mat &dst, vector<double> param, int nThresMethod = emThresMethodDefault, Mat mask = Mat());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
投影计数:直角坐标与极坐标投影
|
|
|
|
|
|
*/
|
|
|
|
|
|
namespace luffy_projection {
|
|
|
|
|
|
enum EmProjectionDirect { emProjX = 0, emProjY = 1 };
|
|
|
|
|
|
|
|
|
|
|
|
void project2point(const Mat & src, Mat & projDst, Point ptCenter, int nAngleCount, LP_NORM_METHOD normType = 0);
|
|
|
|
|
|
void project2axis(const Mat & src, Mat & projDst, EmProjectionDirect param1 = emProjX, LP_NORM_METHOD normType = 0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//<! 基本的图像处理方法
|
|
|
|
|
|
namespace luffy_imageProc {
|
|
|
|
|
|
void meanvarnorm(Mat& src, Mat &dst, double avg, double var, Mat mask = Mat()); //<! 此函数由大饼提供
|
|
|
|
|
|
bool lsCircleFit(vector<Point> &points, float &fRadius, Point2f ¢er); //<! 最小二乘法圆拟合
|
|
|
|
|
|
bool lsLineFit(vector<Point> &points, float& a, float &b); //<! 最小二乘法直线拟合 y = a + b * x
|
|
|
|
|
|
|
|
|
|
|
|
void rotateImage(Mat &src, Mat &dst, float angle, Point ptCenter = Point(), int clockWise = 1);
|
|
|
|
|
|
void RemoveSmallRegion(Mat &Src, Mat &Dst, int AreaLimit, int CheckMode, int NeihborMode);
|
|
|
|
|
|
int judgeCircle(const vector<Point> &vec, Point2f ptCenter, float radius, float dDiff);
|
|
|
|
|
|
enum EmCreateMode{
|
|
|
|
|
|
emCreateDefault, emCreateGray, emCreateColor, emCreateCopy, emCreateNull
|
|
|
|
|
|
};
|
|
|
|
|
|
void createImage(Mat & src, Mat & dst, EmCreateMode emMode = emCreateDefault, Scalar color = Scalar::all(0));
|
|
|
|
|
|
void sobel(Mat &src, Mat *pDst = NULL, Mat *pSobelX = NULL, Mat *pSobelY = NULL, int iBlockSize = 3);
|
|
|
|
|
|
|
|
|
|
|
|
enum EmGradientMethod {
|
|
|
|
|
|
emGradient1
|
|
|
|
|
|
};
|
|
|
|
|
|
void ComputeGradient(Mat & src, EmGradientMethod method = emGradient1, Mat *pAngle = nullptr, Mat *pMag = NULL);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//<! fit model by Ransac
|
|
|
|
|
|
enum EmModel {
|
|
|
|
|
|
emModelCircle, emModelLine
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct RansacParam {
|
|
|
|
|
|
RansacParam(float fProb, float fErrorDis, int nMaxItCount, int nMinFitNum, int nBreakCondit) {
|
|
|
|
|
|
m_fProb = fProb; m_fErrorDis = fErrorDis; m_nMinFitNum = nMinFitNum; m_nMaxItCount = nMaxItCount; m_nBreakCondit = nBreakCondit;
|
|
|
|
|
|
}
|
|
|
|
|
|
float m_fProb;
|
|
|
|
|
|
float m_fErrorDis;
|
|
|
|
|
|
int m_nMaxItCount;
|
|
|
|
|
|
int m_nMinFitNum;
|
|
|
|
|
|
int m_nBreakCondit;
|
|
|
|
|
|
};
|
|
|
|
|
|
vector<Point> genRandPoints(vector<Point> & vecPoints, float fProb, int prec = 100);
|
|
|
|
|
|
vector <Point> fitModelbyRansac(vector<Point> &vecPoints, EmModel emModel, float fProb, float errorDis, int nMaxItNum, int minFitNum, int breakCondi);
|
|
|
|
|
|
vector <Point> fitModelbyRansac(vector<Point> &vecPoints, EmModel emModel, RansacParam *pParam);
|
|
|
|
|
|
bool fitModel(vector<Point> &vecPoints, vector<double> &vecRes, EmModel emModel);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
数学类操作:几何+代数
|
|
|
|
|
|
*/
|
|
|
|
|
|
namespace luffy_math {
|
|
|
|
|
|
int mod(int index, int total, int periodNum = 1); //<! 取余
|
|
|
|
|
|
float getVectorsAngle(float angle1, float angle2, const int nMaxAngle = 360); //<! 求夹角中心
|
|
|
|
|
|
float caculAngle(Point ptCenter, Point ptTarget); //<! 角度计算
|
|
|
|
|
|
|
|
|
|
|
|
template<typename T1, typename T2> //<! 点之间距离
|
|
|
|
|
|
float disofPoints(T1 pt1, T2 pt2) {
|
|
|
|
|
|
float dx = pt1.x - pt2.x;
|
|
|
|
|
|
float dy = pt1.y - pt2.y;
|
|
|
|
|
|
return (float)sqrtf(dx*dx + dy*dy);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
|
float disofPoint2Line(T pt, float a, float b) { //<! 点与直线间的距离, y=a+bx
|
|
|
|
|
|
return fabs(pt.x * b + a - pt.y) / sqrtf(a*a + b*b);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
|
|
bool sort2Data(T &minData, T &maxData) { //<! 2数据排序
|
|
|
|
|
|
if (minData <= maxData) return true;
|
|
|
|
|
|
else {
|
|
|
|
|
|
T tmp = minData; minData = maxData; maxData = tmp;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
bool isOutRange(Point pt, Size size);
|
|
|
|
|
|
bool checkPoint(Point &pt, Rect rt);
|
|
|
|
|
|
bool checkData(int &nData, int nMax, int nMin);
|
|
|
|
|
|
bool checkRoiRect(Size imgSize, Rect & rtRoi);
|
|
|
|
|
|
bool checkSquare(Rect rect, int nMinWidth, int nMaxWidth, int nMaxDiff = 20);
|
|
|
|
|
|
bool checkSquare(RotatedRect rect, float nMinWidth, float nMaxWidth, float nMaxDiff = 20);
|
|
|
|
|
|
bool checkSquare(Size2f size, float nMinWidth, float nMaxWidth, float nMaxDiff = 20);
|
|
|
|
|
|
void LeastSquare1d(const cv::Mat & mat1d, cv::Mat &Basemat, cv::Mat &Residualmat);
|
|
|
|
|
|
double rotateRectIntersects(const cv::RotatedRect &rRect1, const cv::RotatedRect& rRect2, bool ifDis = true);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
enum EmDataMinMax{ emDataMax, emDataMin };
|
|
|
|
|
|
double getMinMaxData(const Mat & src, EmDataMinMax emData = emDataMax, Point *pIndex = NULL);
|
|
|
|
|
|
Point polar2rect(Point2f ptCenter, float radius, float dCos, float dSin);
|
|
|
|
|
|
void polar2rect(const Mat &src, Mat &dst, Point ptCenter, int nRadiusIn, int nRadiusOut, int nAngleMax);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CheckMatEqu(const cv::Mat &mask1, const cv::Mat &mask2, bool ifcheckType=false);
|
|
|
|
|
|
bool CheckMatLogical(const cv::Mat &src);
|
|
|
|
|
|
|
|
|
|
|
|
//<! 一位数组数据可视化
|
|
|
|
|
|
void drawCurveUsingArray(const Mat &src, Mat &dst, LP_NORM_METHOD normType = 0, Scalar bgColor = Scalar::all(255), Scalar curveColor = Scalar::all(0));
|
|
|
|
|
|
|
|
|
|
|
|
//<! 大小端
|
|
|
|
|
|
void swapBigEndian(unsigned short &data);
|
|
|
|
|
|
/*
|
|
|
|
|
|
图像匹配
|
|
|
|
|
|
1、图像模板匹配(广义上的图像,不单单指灰度图本身)
|
|
|
|
|
|
2、轮廓线匹配
|
|
|
|
|
|
*/
|
|
|
|
|
|
namespace luffy_match {
|
|
|
|
|
|
enum EmLoopMatchDirect { emLoopMatchCol = 0, emLoopMatX = 0, emLoopMatchRow = 1, emLoopMatY = 1 };
|
|
|
|
|
|
bool LoopMatMatch(Mat & src, Mat &temp, EmLoopMatchDirect direct, Mat &result, int method = CV_TM_CCORR_NORMED);
|
|
|
|
|
|
void LoopMatShift(Mat & src, Mat & dst, EmLoopMatchDirect direct, int clockwiseShift = 0); //<! 顺时针偏移 偏移量为clockwiseShift
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
blob分析
|
|
|
|
|
|
0906:可以取每一取blob的像素面积(个数)
|
|
|
|
|
|
*/
|
|
|
|
|
|
namespace luffy_blob {
|
|
|
|
|
|
struct PolyEdge{
|
|
|
|
|
|
PolyEdge() : y0(0), y1(0), x(0), dx(0), next(0) {}
|
|
|
|
|
|
|
|
|
|
|
|
int y0, y1;
|
|
|
|
|
|
int x, dx;
|
|
|
|
|
|
PolyEdge *next;
|
|
|
|
|
|
};
|
|
|
|
|
|
static const int CodeDeltas[8][2] =
|
|
|
|
|
|
{ { 1, 0 }, { 1, -1 }, { 0, -1 }, { -1, -1 }, { -1, 0 }, { -1, 1 }, { 0, 1 }, { 1, 1 } };
|
|
|
|
|
|
|
|
|
|
|
|
struct CmpEdges
|
|
|
|
|
|
{
|
|
|
|
|
|
bool operator ()(const PolyEdge& e1, const PolyEdge& e2)
|
|
|
|
|
|
{
|
|
|
|
|
|
return e1.y0 - e2.y0 ? e1.y0 < e2.y0 :
|
|
|
|
|
|
e1.x - e2.x ? e1.x < e2.x : e1.dx < e2.dx;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
enum { XY_SHIFT = 16, XY_ONE = 1 << XY_SHIFT, DRAWING_STORAGE_BLOCK = (1 << 12) - 256 };
|
|
|
|
|
|
|
|
|
|
|
|
//20150906 当前版本只能计算每个blob的面积
|
|
|
|
|
|
|
|
|
|
|
|
//获取面积
|
|
|
|
|
|
//std::list<int> getArea(Size imgSize, vector< vector<Point> > &contours);
|
|
|
|
|
|
int getArea(const Size imgSize, const vector<Point> & contours);
|
|
|
|
|
|
|
|
|
|
|
|
//获取长度
|
|
|
|
|
|
std::list<int> getLeng(Size imgSize, vector< vector<Point> > contours, int contourIdx);
|
|
|
|
|
|
|
|
|
|
|
|
std::list<int> cvProcessContours(Size imgSize, CvSeq* contour, int max_level);
|
|
|
|
|
|
|
|
|
|
|
|
void CollectPolyEdges(const Point* v, int count, vector<PolyEdge>& edges, int shift);
|
|
|
|
|
|
int CaculCollectionArea(Size imgSize, vector<PolyEdge>& edges);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
三角函数值的快速索引
|
|
|
|
|
|
1、先初始化createNewTrigValue,其中total表示将360°进行total份等分,
|
|
|
|
|
|
2、创建完成之后,即可使用getCos/Sin与getCosPtr/SinPtr索引相关参数,index为total等分下的索引
|
|
|
|
|
|
*/
|
|
|
|
|
|
namespace luffy_triangle {
|
|
|
|
|
|
bool createNewTrigValue(int total);
|
|
|
|
|
|
bool releaseTrigValue(int total);
|
|
|
|
|
|
double getCos(int total, int index);
|
|
|
|
|
|
double getSin(int total, int index);
|
|
|
|
|
|
double *getCosPtr(int total);
|
|
|
|
|
|
double *getSinPtr(int total);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
碰击计算:记录从起点到终点,第一次遇见白点时候的坐标,分为极坐标与直角坐标
|
|
|
|
|
|
*/
|
|
|
|
|
|
namespace luffy_hit {
|
|
|
|
|
|
enum EmHitDirectParam {
|
|
|
|
|
|
emHitIn2Out = 0, emHitOut2In = 1,
|
|
|
|
|
|
emHitUp2Down = 0, emHitDown2Up = 1,
|
|
|
|
|
|
emHitLeft2Right = 2, emRight2Left = 3
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class MoutainClamp {
|
|
|
|
|
|
public:
|
|
|
|
|
|
MoutainClamp(int iTotal = 360, bool bLoop = false) {
|
|
|
|
|
|
left = 0; right = 0; total = iTotal; m_bLoop = bLoop;
|
|
|
|
|
|
}
|
|
|
|
|
|
int left;
|
|
|
|
|
|
int right;
|
|
|
|
|
|
int total;
|
|
|
|
|
|
bool m_bLoop;
|
|
|
|
|
|
|
|
|
|
|
|
int getLen() {
|
|
|
|
|
|
return (m_bLoop == false) ? (right - left + 1) : luffy_math::mod(right - left + 1, total);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
vector<Rect> getRect(int nRow, int nCols) {
|
|
|
|
|
|
vector<Rect> vecRect;
|
|
|
|
|
|
if (1 != nCols) {
|
|
|
|
|
|
if (left <= right) {
|
|
|
|
|
|
vecRect.push_back(Rect(left, 0, getLen(), LP_SINGLE_LINE));
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
vecRect.push_back(Rect(left, 0, nCols - left + 1, LP_SINGLE_LINE));
|
|
|
|
|
|
vecRect.push_back(Rect(0, 0, right, LP_SINGLE_LINE));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
if (left <= right) {
|
|
|
|
|
|
vecRect.push_back(Rect(0, left, LP_SINGLE_LINE, getLen()));
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
vecRect.push_back(Rect(0, left, LP_SINGLE_LINE, nRow - left + 1));
|
|
|
|
|
|
vecRect.push_back(Rect(0, 0, LP_SINGLE_LINE, right));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return vecRect;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
double getSum(Mat & src){
|
|
|
|
|
|
double dSum = 0.0;
|
|
|
|
|
|
vector<Rect> vecRect = getRect(src.rows, src.cols);
|
|
|
|
|
|
for (int i = 0; i < vecRect.size(); i++) {
|
|
|
|
|
|
dSum += cv::sum(src(vecRect[i]))[0];
|
|
|
|
|
|
}
|
|
|
|
|
|
return dSum;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
int getMid(){
|
|
|
|
|
|
return luffy_math::getVectorsAngle(left, right, total);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool judgeLen(int nMin = 0, int nMax = 360, bool bLoop = false) {
|
|
|
|
|
|
int nLen = getLen();
|
|
|
|
|
|
return luffy_math::checkData(nLen, nMax, nMin);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
void firstHit4Circle(Mat &binary, Mat &hit, vector<Point> &vecHit, Point ptCenter, int nIn, int nOut, int nHitCount = 360, EmHitDirectParam emHit = emHitOut2In);
|
|
|
|
|
|
void firstHit4Axis(Mat &binary, Mat &hit, int nMin, int nMax, EmHitDirectParam emHit = emHitUp2Down);
|
|
|
|
|
|
void hit2Moutain(Mat & src, std::vector<MoutainClamp> &vecMouts, float thresValue, int nWidth);
|
|
|
|
|
|
void filterMoutain(std::vector<MoutainClamp> & vecMouts, int nTotal, int minSpace, int minWidth, bool bLoop = false);
|
|
|
|
|
|
MoutainClamp getMaxWidthMoutain(std::vector<MoutainClamp> & vecMouts, bool bLoop = false);
|
|
|
|
|
|
MoutainClamp getMaxDensityMoutain(Mat &src, std::vector<MoutainClamp> & vecMouts, bool bLoop = false);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endif //_Luffy_Process_h_
|