add molun car code
parent
f518d476b5
commit
3d2a85cf60
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,610 @@
|
||||
/*! \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);
|
||||
|
||||
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 CyclopsUtils;
|
||||
|
||||
#include "GeomUtils.h"
|
||||
|
||||
#endif // __CVUtils_h_
|
||||
|
||||
@ -0,0 +1,243 @@
|
||||
#include "DynamicProgramSearch.h"
|
||||
#include <list>
|
||||
|
||||
using std::list;
|
||||
|
||||
void dynamicProgramY(Mat& disMat, int n /*= 2*/)
|
||||
{
|
||||
for (int y = 1; y < disMat.rows; ++y)
|
||||
{
|
||||
for (int x = 0; x < disMat.cols; ++x)
|
||||
{
|
||||
// find max neighbor
|
||||
int sy = y - 1;
|
||||
float maxVal = -1;
|
||||
int sj = x - n >= 0 ? x - n : 0;
|
||||
int ej = x + n <= disMat.cols - 1 ? x + n : disMat.cols - 1;
|
||||
for (int j = sj; j <= ej; j++)
|
||||
{
|
||||
float val = disMat.at<float>(sy, j);
|
||||
if (maxVal < val)
|
||||
{
|
||||
maxVal = val;
|
||||
}
|
||||
}
|
||||
|
||||
disMat.at<float>(y, x) += maxVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dynamicProgramX(Mat& disMat, int n /*= 2*/)
|
||||
{
|
||||
for (int x = 1; x < disMat.cols; ++x)
|
||||
{
|
||||
int sx = x - 1;
|
||||
for (int y = 0; y < disMat.rows; ++y)
|
||||
{
|
||||
// find max neighbor
|
||||
float maxVal = -1;
|
||||
int si = max(y - n, 0);
|
||||
int ei = min(y + n, disMat.rows - 1);
|
||||
for (int i = si; i <= ei; i++)
|
||||
{
|
||||
float val = disMat.at<float>(i, sx);
|
||||
if (maxVal < val)
|
||||
{
|
||||
maxVal = val;
|
||||
}
|
||||
}
|
||||
|
||||
disMat.at<float>(y, x) += maxVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void findMaxXPath(const Mat& disMat, vector<int>& vec, vector<float>& energyVec,
|
||||
int n /*= 2*/)
|
||||
{
|
||||
int sy = 0;
|
||||
int ey = disMat.rows - 1;
|
||||
vec.resize(disMat.cols, -1);
|
||||
energyVec.resize(disMat.cols, -1);
|
||||
for (int x = disMat.cols - 1; x >= 0; --x)
|
||||
{
|
||||
float maxVal = -1;
|
||||
int maxIdx = -1;
|
||||
for (int y = sy; y <= ey; ++y)
|
||||
{
|
||||
float val = disMat.at<float>(y, x);
|
||||
if (maxVal < val)
|
||||
{
|
||||
maxVal = val;
|
||||
maxIdx = y;
|
||||
}
|
||||
}
|
||||
vec[x] = maxIdx;
|
||||
energyVec[x] = maxVal;
|
||||
sy = maxIdx - n;
|
||||
ey = maxIdx + n;
|
||||
sy = (sy >= 0 ? sy : 0);
|
||||
ey = (ey < disMat.rows ? ey : disMat.rows - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void findMaxYPath(const Mat& disMat, vector<int>& vec, vector<float>& energyVec, int n /*= 2*/)
|
||||
{
|
||||
int sx = 0;
|
||||
int ex = disMat.cols - 1;
|
||||
vec.resize(disMat.rows, -1);
|
||||
energyVec.resize(disMat.rows, -1);
|
||||
for (int y = disMat.rows - 1; y >= 0; --y)
|
||||
{
|
||||
float maxVal = -1;
|
||||
int maxIdx = -1;
|
||||
for (int x = sx; x <= ex; ++x)
|
||||
{
|
||||
float val = disMat.at<float>(y, x);
|
||||
if (maxVal < val)
|
||||
{
|
||||
maxVal = val;
|
||||
maxIdx = x;
|
||||
}
|
||||
}
|
||||
vec[y] = maxIdx;
|
||||
energyVec[y] = maxVal;
|
||||
sx = maxIdx - n;
|
||||
ex = maxIdx + n;
|
||||
sx = (sx >= 0 ? sx : 0);
|
||||
ex = (ex < disMat.cols ? ex : disMat.cols - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void recoverPathEnergy(vector<float>& vec)
|
||||
{
|
||||
assert(!vec.empty());
|
||||
|
||||
auto i = vec.rbegin();
|
||||
auto j = i;
|
||||
++j;
|
||||
while (j != vec.rend())
|
||||
{
|
||||
*i = *i - *j;
|
||||
++i;
|
||||
++j;
|
||||
}
|
||||
}
|
||||
|
||||
void dynamicProgramYWithSmooth(Mat& disMat,
|
||||
int n /*= 2*/, float sw /*= 1.0*/,
|
||||
const Mat& smoothMat /*= Mat()*/)
|
||||
{
|
||||
for (int y = 1; y < disMat.rows; ++y)
|
||||
{
|
||||
for (int x = 0; x < disMat.cols; ++x)
|
||||
{
|
||||
// find max neighbor
|
||||
int sy = y - 1;
|
||||
float maxVal = -1;
|
||||
int sj = x - n >= 0 ? x - n : 0;
|
||||
int ej = x + n <= disMat.cols - 1 ? x + n : disMat.cols - 1;
|
||||
float baseSVal = 0;
|
||||
if (!smoothMat.empty())
|
||||
{
|
||||
baseSVal = smoothMat.at<float>(y, x);
|
||||
}
|
||||
for (int j = sj; j <= ej; j++)
|
||||
{
|
||||
float disVal = disMat.at<float>(sy, j);
|
||||
float sVal = 0;
|
||||
if (!smoothMat.empty())
|
||||
{
|
||||
sVal = smoothMat.at<float>(sy, j);
|
||||
}
|
||||
float energyVal = disVal + (255 - abs(sVal - baseSVal))*sw;
|
||||
if (maxVal < energyVal)
|
||||
{
|
||||
maxVal = energyVal;
|
||||
}
|
||||
}
|
||||
|
||||
disMat.at<float>(y, x) += maxVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dynamicProgramYWithSmooth(Mat& disMat0, Mat& disMat1,
|
||||
const Mat& smoothMat0,
|
||||
const Mat& smoothMat1,
|
||||
int targetWidth,
|
||||
int n /* = 2 */,
|
||||
float sw /* = 1.0 */)
|
||||
{
|
||||
assert(targetWidth <= disMat0.cols + disMat1.cols);
|
||||
|
||||
for (int y = 1; y < disMat0.rows; ++y)
|
||||
{
|
||||
int sx = 0;
|
||||
int ex = disMat0.cols;
|
||||
if (targetWidth < disMat0.cols)
|
||||
{
|
||||
sx = disMat0.cols - targetWidth;
|
||||
}
|
||||
if (targetWidth > disMat1.cols)
|
||||
{
|
||||
ex = disMat0.cols - (targetWidth - disMat1.cols);
|
||||
}
|
||||
|
||||
for (int x = sx; x < ex; ++x)
|
||||
{
|
||||
// find max neighbor
|
||||
int sy = y - 1;
|
||||
float maxVal = -1;
|
||||
int sj0 = x - n >= 0 ? x - n : 0;
|
||||
int ej0 = x + n <= disMat0.cols - 1 ? x + n : disMat0.cols - 1;
|
||||
int sj1 = sj0 + targetWidth - disMat0.cols;
|
||||
int ej1 = ej0 + targetWidth - disMat0.cols;
|
||||
if (sj1 < 0)
|
||||
{
|
||||
sj0 += -sj1;
|
||||
}
|
||||
if (ej1 > disMat1.cols - 1)
|
||||
{
|
||||
ej0 -= ej1 - disMat1.cols + 1;
|
||||
}
|
||||
float baseSVal0 = 0;
|
||||
if (!smoothMat0.empty())
|
||||
{
|
||||
baseSVal0 = smoothMat0.at<float>(y, x);
|
||||
}
|
||||
float baseSVal1 = 0;
|
||||
if (!smoothMat1.empty())
|
||||
{
|
||||
baseSVal1 = smoothMat1.at<float>(y, x + targetWidth - smoothMat0.cols);
|
||||
}
|
||||
for (int j = sj0; j <= ej0; j++)
|
||||
{
|
||||
float disVal0 = disMat0.at<float>(sy, j);
|
||||
int j1 = j + targetWidth - disMat0.cols;
|
||||
float disVal1 = disMat1.at<float>(sy, j1);
|
||||
float sVal0 = 0;
|
||||
if (!smoothMat0.empty())
|
||||
{
|
||||
sVal0 = smoothMat0.at<float>(sy, j);
|
||||
}
|
||||
float sVal1 = 0;
|
||||
if (!smoothMat1.empty())
|
||||
{
|
||||
sVal1 = smoothMat1.at<float>(sy, j1);
|
||||
}
|
||||
float energyVal = disVal0 + disVal1 +
|
||||
(255 - abs(sVal0 - baseSVal0))*sw +
|
||||
(255 - abs(sVal1 - baseSVal1))*sw;
|
||||
if (maxVal < energyVal)
|
||||
{
|
||||
maxVal = energyVal;
|
||||
}
|
||||
}
|
||||
|
||||
disMat0.at<float>(y, x) += maxVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,146 @@
|
||||
#include "MultiScaleImageCompareModel.h"
|
||||
#include "ImageCompareModel.h"
|
||||
// no need to code for plotting in visual studio later than 2017,
|
||||
// install the ArrayPlotter extension to see the data distribution
|
||||
#if (_MSC_VER < 1910) // vs2017
|
||||
#include "../3rd/cvplot/cvplot.h"
|
||||
#endif
|
||||
|
||||
|
||||
void MultiScaleImageCompareModel::setBaseLevel(const ImageCompareModel* pModel)
|
||||
{
|
||||
ImageCompareModel* p = new ImageCompareModel;
|
||||
*p = *pModel;
|
||||
p->genOutterMask();
|
||||
clear();
|
||||
mMultiScaleModels.resize(1);
|
||||
mMultiScaleModels[0] = p;
|
||||
}
|
||||
|
||||
void MultiScaleImageCompareModel::genMultiScale()
|
||||
{
|
||||
resetMaxLevel();
|
||||
while (getLevel() >= 1)
|
||||
{
|
||||
if (mMultiScaleModels.size()>1)
|
||||
{
|
||||
ImageCompareModel* pScaledModel = mMultiScaleModels.back()->scale(mScaleStep);
|
||||
mMultiScaleModels.push_back(pScaledModel);
|
||||
downLevel();
|
||||
}
|
||||
else
|
||||
downLevel();
|
||||
}
|
||||
}
|
||||
|
||||
const ImageCompareModel* MultiScaleImageCompareModel::getCmpModel(int level)
|
||||
{
|
||||
if (level >= 0 && level < mLevelNum)
|
||||
{
|
||||
return mMultiScaleModels[level];
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void MultiScaleImageCompareModel::clear()
|
||||
{
|
||||
for_each(mMultiScaleModels.begin(), mMultiScaleModels.end(), [&](ImageCompareModel* p)
|
||||
{
|
||||
delete p;
|
||||
});
|
||||
}
|
||||
|
||||
void MultiScaleImageCompareModel::proc(void *pData)
|
||||
{
|
||||
ImageCompareData* pCmpData = (ImageCompareData*)pData;
|
||||
MultiScaleImage* pMSImg = pCmpData->getMSI();
|
||||
resetMaxLevel();
|
||||
float startAngle = pCmpData->getStartAngle();
|
||||
float endAngle = pCmpData->getEndAngle();
|
||||
float angleRange = (endAngle - startAngle) / 4.0;
|
||||
vector<Range> angleRangeVec(1, Range(0, 360));
|
||||
|
||||
ImageCompareModel::RotateData* pRotateData = pCmpData->getRotateData();
|
||||
int nlevel = getLevel();
|
||||
while (nlevel >= 0)
|
||||
{
|
||||
nlevel = getLevel();
|
||||
if (nlevel<0)
|
||||
break;
|
||||
const ImageCompareModel* pModel = NULL;
|
||||
if (nlevel >= mMultiScaleModels.size())
|
||||
pModel = mMultiScaleModels[0];
|
||||
else
|
||||
pModel = mMultiScaleModels[nlevel];
|
||||
assert(pModel);
|
||||
Mat img = pMSImg->getImg(nlevel);
|
||||
assert(!img.empty());
|
||||
|
||||
|
||||
#ifdef DEBUG_VIEW_INTERNAL_MAT
|
||||
Mat viewImg = img / 255.0;
|
||||
imshow("img", viewImg);
|
||||
#endif
|
||||
|
||||
if (angleRangeVec.size() == 1 && angleRangeVec.front().size() >= 360)
|
||||
{
|
||||
pModel->rotateMatchData(img, pRotateData, 1.0, startAngle, endAngle);
|
||||
ImageCompareModel::genCandidateAngleRanges(pRotateData->mDisValVec, 1, angleRangeVec);
|
||||
if (angleRangeVec.empty())
|
||||
{
|
||||
pRotateData->mDisValVec.clear();
|
||||
pRotateData->mRImgVec.clear();
|
||||
angleRangeVec.resize(1);
|
||||
angleRangeVec[0] = Range(0, 360);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Mat disMat;
|
||||
pModel->rotateMatchData(img, pRotateData, angleRangeVec, 1.0, disMat);
|
||||
ImageCompareModel::genCandidateAngleRanges(disMat, 1, angleRangeVec, 0.5);
|
||||
// pModel->rotateMatchData(img, pRotateData, 1.0, angleRangeVec);
|
||||
//
|
||||
// double bestAngle = pRotateData->bestAngle();
|
||||
// angleRangeVec.clear();
|
||||
// Range r;
|
||||
// r.start = bestAngle - angleRange;
|
||||
// r.end = bestAngle + angleRange;
|
||||
// angleRangeVec.push_back(r);
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG_VIEW_INTERNAL_MAT
|
||||
// Mat viewBestRImg = pRotateData->bestRImg() / 255.0;
|
||||
// imshow("bestRImg", viewBestRImg);
|
||||
#endif
|
||||
|
||||
// no need to code for plotting in visual studio later than 2017,
|
||||
// install the ArrayPlotter extension to see the data distribution
|
||||
#if (_MSC_VER < 1910) // vs2017
|
||||
#ifdef DEBUG_VIEW_PLOT
|
||||
{
|
||||
stringstream ss;
|
||||
ss << "multi_scale_comp_plot" << getLevel();
|
||||
CvPlot::clear(ss.str());
|
||||
CvPlot::plot<float>(ss.str(), &(pRotateData->mDisValVec[0]),
|
||||
pRotateData->mDisValVec.size());
|
||||
}
|
||||
{
|
||||
stringstream ss;
|
||||
ss << "multi_scale_comp_plot_0_360_" << getLevel();
|
||||
CvPlot::clear(ss.str());
|
||||
ImageCompareModel::RotateData testRotateData = *pRotateData;
|
||||
pModel->rotateMatchData(img, &testRotateData, 1.0, startAngle, endAngle);
|
||||
CvPlot::plot<float>(ss.str(), &(testRotateData.mDisValVec[0]),
|
||||
testRotateData.mDisValVec.size());
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
downLevel();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,74 @@
|
||||
/*! \file MultiScaleImageCompareModel.h
|
||||
\brief A brief file description.
|
||||
|
||||
A more elaborated file description.
|
||||
|
||||
Created: 2017/02/24, author: bang.jin.
|
||||
*/
|
||||
|
||||
#ifndef __MultiScaleImageCompareModel_h_
|
||||
#define __MultiScaleImageCompareModel_h_
|
||||
|
||||
#include "MultiScaleObj.h"
|
||||
#include <vector>
|
||||
#include "ImageCompareModel.h"
|
||||
|
||||
using std::vector;
|
||||
|
||||
class MultiScaleImageCompareModel : public MultiScaleObj
|
||||
{
|
||||
public:
|
||||
MultiScaleImageCompareModel(int levelNum = 2, float scaleStep = 0.5)
|
||||
: MultiScaleObj(levelNum, scaleStep)
|
||||
{
|
||||
|
||||
}
|
||||
~MultiScaleImageCompareModel()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
void setBaseLevel(const ImageCompareModel* pModel);
|
||||
void genMultiScale();
|
||||
const ImageCompareModel* getCmpModel(int level);
|
||||
void clear();
|
||||
void proc(void *pData);
|
||||
|
||||
protected:
|
||||
vector<ImageCompareModel*> mMultiScaleModels;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
class ImageCompareData
|
||||
{
|
||||
public:
|
||||
ImageCompareData(MultiScaleImage* pMSI)
|
||||
: mpMSI(pMSI)
|
||||
, mStartAngle(0)
|
||||
, mEndAngle(360)
|
||||
, mAngleRange(90)
|
||||
{}
|
||||
MultiScaleImage* getMSI() const { return mpMSI; }
|
||||
void setMSI(MultiScaleImage* val) { mpMSI = val; }
|
||||
|
||||
float getStartAngle() const { return mStartAngle; }
|
||||
void setStartAngle(float val) { mStartAngle = val; }
|
||||
float getEndAngle() const { return mEndAngle; }
|
||||
void setEndAngle(float val) { mEndAngle = val; }
|
||||
float getAngleRange() const { return mAngleRange; }
|
||||
void setAngleRange(float val) { mAngleRange = val; }
|
||||
|
||||
ImageCompareModel::RotateData* getRotateData() { return &mRotateData; }
|
||||
|
||||
protected:
|
||||
MultiScaleImage* mpMSI;
|
||||
ImageCompareModel::RotateData mRotateData;
|
||||
|
||||
float mStartAngle, mEndAngle;
|
||||
float mAngleRange;
|
||||
};
|
||||
|
||||
|
||||
#endif // __MultiScaleImageCompareModel_h_
|
||||
|
||||
@ -0,0 +1,64 @@
|
||||
#include "../include/MultiScaleObj.h"
|
||||
#include "../include/CVUtils.h"
|
||||
|
||||
MultiScaleObj::MultiScaleObj(int levelNum /*= 2*/, float scaleStep /*= 0.5*/)
|
||||
: mLevelNum(levelNum)
|
||||
, mScaleStep(scaleStep)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
MultiScaleObj::~MultiScaleObj()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
MultiScaleImage::MultiScaleImage()
|
||||
: mpProc(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
MultiScaleImage::~MultiScaleImage()
|
||||
{
|
||||
if (mpProc)
|
||||
{
|
||||
delete mpProc;
|
||||
}
|
||||
}
|
||||
|
||||
void MultiScaleImage::setBaseLevel(const Mat& img)
|
||||
{
|
||||
mMultiScaleImages.resize(1);
|
||||
mMultiScaleImages[0] = img;
|
||||
}
|
||||
|
||||
void MultiScaleImage::genMultiScale()
|
||||
{
|
||||
resetMaxLevel();
|
||||
while (getLevel() >= 1)
|
||||
{
|
||||
mMultiScaleImages.push_back(resize(mMultiScaleImages.back(), mScaleStep, INTER_CUBIC));
|
||||
downLevel();
|
||||
}
|
||||
}
|
||||
|
||||
void MultiScaleImage::proc(void *pData)
|
||||
{
|
||||
resetMaxLevel();
|
||||
while (getLevel() >= 1)
|
||||
{
|
||||
const Mat& img = mMultiScaleImages[getLevel() - 1];
|
||||
(*mpProc)(img, this, pData);
|
||||
downLevel();
|
||||
}
|
||||
}
|
||||
|
||||
cv::Mat MultiScaleImage::getImg(int level)
|
||||
{
|
||||
if (level < 0 || level >= mLevelNum)
|
||||
{
|
||||
return Mat();
|
||||
}
|
||||
return mMultiScaleImages[level];
|
||||
}
|
||||
@ -0,0 +1,87 @@
|
||||
/*! \file MultiScaleObj.h
|
||||
|
||||
Copyright (C) 2014 º¼ÖÝÀûçê¿Æ¼¼ÓÐÏÞ¹«Ë¾.
|
||||
|
||||
Created by bang.jin at 2017/02/20.
|
||||
*/
|
||||
|
||||
#ifndef __MultiScaleObj_h_
|
||||
#define __MultiScaleObj_h_
|
||||
|
||||
#include <vector>
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include <opencv2/opencv_modules.hpp>
|
||||
|
||||
using std::vector;
|
||||
using namespace cv;
|
||||
|
||||
class MultiScaleObj;
|
||||
|
||||
class MultiScaleImageProc
|
||||
{
|
||||
public:
|
||||
virtual void operator()(const Mat& img, MultiScaleObj* pMSObj, void* pData) = 0;
|
||||
};
|
||||
|
||||
class MultiScaleObj
|
||||
{
|
||||
public:
|
||||
MultiScaleObj(int level = 2, float scaleStep = 0.5);
|
||||
~MultiScaleObj();
|
||||
|
||||
int getLevelNum() const { return mLevelNum; }
|
||||
void setLevelNum(int val) { mLevelNum = val; }
|
||||
|
||||
int getLevel() const { return mLevel; }
|
||||
|
||||
float getScaleStep() const { return mScaleStep; }
|
||||
void setScaleStep(float iVal) { mScaleStep = iVal; }
|
||||
|
||||
int getMaxLevel() const { return getLevelNum() - 1; }
|
||||
int resetMaxLevel()
|
||||
{
|
||||
setLevel(getMaxLevel());
|
||||
return getLevel();
|
||||
}
|
||||
int downLevel()
|
||||
{
|
||||
mLevel--;
|
||||
return mLevel;
|
||||
}
|
||||
|
||||
virtual void proc(void *pData) = 0;
|
||||
|
||||
protected:
|
||||
void setLevel(int val) { mLevel = val; }
|
||||
|
||||
int mLevelNum;
|
||||
int mLevel;
|
||||
|
||||
float mScaleStep;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class MultiScaleImage : public MultiScaleObj
|
||||
{
|
||||
public:
|
||||
MultiScaleImage();
|
||||
~MultiScaleImage();
|
||||
|
||||
void setBaseLevel(const Mat& img);
|
||||
void genMultiScale();
|
||||
|
||||
virtual void proc(void *pData);
|
||||
|
||||
MultiScaleImageProc* getProc() const { return mpProc; }
|
||||
void setProc(MultiScaleImageProc* iVal) { mpProc = iVal; }
|
||||
|
||||
Mat getImg(int level);
|
||||
|
||||
protected:
|
||||
vector<Mat> mMultiScaleImages;
|
||||
MultiScaleImageProc* mpProc;
|
||||
private:
|
||||
};
|
||||
|
||||
#endif // __MultiScaleObj_h_
|
||||
@ -0,0 +1,457 @@
|
||||
/*! \file StdUtils.h
|
||||
\brief useful functions working with std functions.
|
||||
|
||||
|
||||
|
||||
Created: 2015/06/22, author: Jin Bingwen.
|
||||
*/
|
||||
|
||||
#ifndef __StdUtils_h_
|
||||
#define __StdUtils_h_
|
||||
|
||||
#if (defined(_MSC_VER) && _MSC_VER <= 1600)
|
||||
#define LITTLE_CPP11 1
|
||||
#else
|
||||
#include <thread>
|
||||
#endif
|
||||
|
||||
#if (defined _WINDOWS) || (defined WIN32)
|
||||
#define USE_WIN_API 1
|
||||
#endif
|
||||
|
||||
#include "CyclopsLock.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
|
||||
#include "Asserte.h"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::stringstream;
|
||||
|
||||
#if defined(LITTLE_CPP11)
|
||||
#define GET_SIGN(x) (x < 0 ? true : false)
|
||||
#else
|
||||
#define GET_SIGN(x) std::signbit(x)
|
||||
#endif
|
||||
|
||||
template<typename T, typename _Iter>
|
||||
T sum(_Iter s, _Iter e)
|
||||
{
|
||||
if (s == e)
|
||||
{
|
||||
return T();
|
||||
}
|
||||
T ret = *s;
|
||||
s++;
|
||||
while (s != e)
|
||||
{
|
||||
ret += *s;
|
||||
s++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T, typename _Iter>
|
||||
_Iter findTopNPercentEle(_Iter s, _Iter e, float nPersent)
|
||||
{
|
||||
auto maxVal = std::max_element(s, e);
|
||||
T threVal = (*maxVal)*(1.0f - nPersent);
|
||||
while (s != e)
|
||||
{
|
||||
if (*s < threVal)
|
||||
{
|
||||
return s;
|
||||
}
|
||||
++s;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
template<typename T, typename _Iter>
|
||||
_Iter findSumTopNPercentEle(_Iter s, _Iter e, float nPersent)
|
||||
{
|
||||
T sumVal = sum<T, _Iter>(s, e);
|
||||
T threVal = sumVal*nPersent;
|
||||
sumVal = 0;
|
||||
while (s != e)
|
||||
{
|
||||
sumVal += *s;
|
||||
if (sumVal > threVal)
|
||||
{
|
||||
s++;
|
||||
return s;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void clearAndResetVec(vector<T>* vec, int n)
|
||||
{
|
||||
if (vec) {
|
||||
vec->clear();
|
||||
vec->reserve(n);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void genIncVec(vector<T>& vec, T start, int count, T step)
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
vec.push_back(start);
|
||||
start += step;
|
||||
}
|
||||
}
|
||||
|
||||
class SortEle
|
||||
{
|
||||
public:
|
||||
SortEle() : mSortVal(0), pEle(NULL) {}
|
||||
SortEle(double val, const void* pData) : mSortVal(val), pEle(pData) {}
|
||||
double mSortVal;
|
||||
const void* pEle;
|
||||
bool operator< (const SortEle& i)
|
||||
{
|
||||
return mSortVal < i.mSortVal;
|
||||
}
|
||||
bool operator>(const SortEle& i)
|
||||
{
|
||||
return mSortVal > i.mSortVal;
|
||||
}
|
||||
SortEle operator+ (const SortEle& i)
|
||||
{
|
||||
return SortEle(mSortVal + i.mSortVal, pEle);
|
||||
}
|
||||
void operator+= (const SortEle& i)
|
||||
{
|
||||
mSortVal += i.mSortVal;
|
||||
}
|
||||
SortEle operator- (const SortEle& i)
|
||||
{
|
||||
return SortEle(mSortVal - i.mSortVal, pEle);
|
||||
}
|
||||
operator float()
|
||||
{
|
||||
return (float)mSortVal;
|
||||
}
|
||||
operator double()
|
||||
{
|
||||
return mSortVal;
|
||||
}
|
||||
SortEle operator* (float f)
|
||||
{
|
||||
return SortEle(mSortVal*f, pEle);
|
||||
}
|
||||
void operator= (float f)
|
||||
{
|
||||
mSortVal = f;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename _It, typename _Ty>
|
||||
_It findRange(_It s, _It e, const _Ty& val)
|
||||
{
|
||||
if (s == e)
|
||||
{
|
||||
return s;
|
||||
}
|
||||
_It mi = (e - s) / 2 + s;
|
||||
if (val < *mi)
|
||||
{
|
||||
return findRange(s, mi, val);
|
||||
}
|
||||
else if (val > *mi)
|
||||
{
|
||||
return findRange(mi + 1, e, val);
|
||||
}
|
||||
else
|
||||
{
|
||||
return mi;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename _Ty, typename _It>
|
||||
void add(_It s, _It e, const _Ty& val)
|
||||
{
|
||||
while (s != e)
|
||||
{
|
||||
*s += val;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename _Ty, typename _It>
|
||||
bool allInRange(_It s, _It e, _Ty minVal, _Ty maxVal)
|
||||
{
|
||||
while (s != e)
|
||||
{
|
||||
if (*s < minVal || *s > maxVal)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
++s;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename _Ty, typename _It>
|
||||
bool anyInRange(_It s, _It e, _Ty minVal, _Ty maxVal)
|
||||
{
|
||||
while (s != e)
|
||||
{
|
||||
if (*s >= minVal && *s <= maxVal)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
++s;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename _Ty, typename _It>
|
||||
bool anyIn(_It s, _It e, _Ty v)
|
||||
{
|
||||
while (s != e)
|
||||
{
|
||||
if (*s == v)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
++s;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename _T>
|
||||
bool loadAValueFromFile(string filePath, _T& ret)
|
||||
{
|
||||
std::fstream fs;
|
||||
fs.open(filePath, std::fstream::in);
|
||||
if (!fs.is_open())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
fs >> ret;
|
||||
fs.close();
|
||||
}
|
||||
|
||||
// search range is [si, ei), not include ei
|
||||
template<typename _PairIter>
|
||||
_PairIter max_first_element(_PairIter si, _PairIter ei)
|
||||
{
|
||||
if (si == ei)
|
||||
{
|
||||
return ei;
|
||||
}
|
||||
|
||||
// exclude ei
|
||||
_PairIter ret = --ei;
|
||||
ei++;
|
||||
|
||||
auto maxVal = si->first;
|
||||
si++;
|
||||
|
||||
while (si != ei)
|
||||
{
|
||||
if (maxVal < si->first)
|
||||
{
|
||||
maxVal = si->first;
|
||||
ret = si;
|
||||
}
|
||||
++si;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename _Ty0, typename _Ty1>
|
||||
string joinStr(_Ty0 s0, _Ty1 s1)
|
||||
{
|
||||
stringstream ss;
|
||||
ss << s0 << s1;
|
||||
return ss.str();
|
||||
}
|
||||
template<typename _Ty0, typename _Ty1, typename _Ty2>
|
||||
string joinStr(_Ty0 s0, _Ty1 s1, _Ty2 s2)
|
||||
{
|
||||
stringstream ss;
|
||||
ss << s0 << s1 << s2;
|
||||
return ss.str();
|
||||
}
|
||||
template<typename _Ty0, typename _Ty1, typename _Ty2, typename _Ty3>
|
||||
string joinStr(_Ty0 s0, _Ty1 s1, _Ty2 s2, _Ty3 s3)
|
||||
{
|
||||
stringstream ss;
|
||||
ss << s0 << s1 << s2 << s3;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
#define _DECLARE_PARAMETER_MEM(type, name)\
|
||||
protected:\
|
||||
type m##name;
|
||||
|
||||
#define _DECLARE_PARAMETER_GETFUN(type, name)\
|
||||
public:\
|
||||
type get##name() const { return m##name; }
|
||||
|
||||
#define _DECLARE_PARAMETER_SETFUN(type, name)\
|
||||
public:\
|
||||
void set##name(type val) { m##name = val; }
|
||||
|
||||
#define _DECLARE_PARAMETER_SETFUN2(type, name, val1, val2)\
|
||||
public:\
|
||||
void set##name(type val) {\
|
||||
assert(val >= val1 && val <= val2);\
|
||||
if (val >= val1 && val <= val2) m##name = val; }
|
||||
|
||||
#define _DECLARE_PARAMETER_SETENUM(type, name)\
|
||||
public:\
|
||||
void set##name(type val) { m##name = val; }\
|
||||
void set##name(int val) {\
|
||||
set##name(static_cast<type>(val)); }
|
||||
|
||||
#define _DECLARE_PARAMETER_SETENUM2(type, name, val1, val2)\
|
||||
public:\
|
||||
void set##name(type val) {\
|
||||
assert(val >= val1 && val <= val2);\
|
||||
if (val >= val1 && val <= val2) m##name = val; }\
|
||||
void set##name(int val) {\
|
||||
set##name(static_cast<type>(val)); }
|
||||
|
||||
#define _DECLARE_PARAMETER_SETPAIR(type, name)\
|
||||
public:\
|
||||
void set##name(type val1, type val2) {\
|
||||
if (val1 > val2) { m##name##Start = val2; m##name##End = val1; }\
|
||||
else { m##name##Start = val1; m##name##End = val2; }\
|
||||
}
|
||||
|
||||
#define _DECLARE_PARAMETER_SETPAIR2(type, name, val1, val2)\
|
||||
public:\
|
||||
void set##name(type value1, type value2) {\
|
||||
assert(value1 >= val1 && value1 <= val2 && value2 >= val1 && value2 <= val2);\
|
||||
if (value1 >= val1 && value1 <= val2 && value2 >= val1 && value2 <= val2) {\
|
||||
if (value1 > value2) { m##name##Start = value2; m##name##End = value1; }\
|
||||
else { m##name##Start = value1; m##name##End = value2; }\
|
||||
}\
|
||||
}
|
||||
|
||||
#define DECLARE_PARAMETER(type, name)\
|
||||
_DECLARE_PARAMETER_MEM(type, name)\
|
||||
_DECLARE_PARAMETER_GETFUN(type, name)\
|
||||
_DECLARE_PARAMETER_SETFUN(type, name)
|
||||
|
||||
#define DECLARE_PARAMETER2(type, name, val1, val2)\
|
||||
_DECLARE_PARAMETER_MEM(type, name)\
|
||||
_DECLARE_PARAMETER_GETFUN(type, name)\
|
||||
_DECLARE_PARAMETER_SETFUN2(type, name, val1 , val2)
|
||||
|
||||
#define DECLARE_PARAMETER_SET(type, name)\
|
||||
_DECLARE_PARAMETER_MEM(type, name)\
|
||||
_DECLARE_PARAMETER_SETFUN(type, name)
|
||||
|
||||
#define DECLARE_PARAMETER_SET2(type, name, val1, val2)\
|
||||
_DECLARE_PARAMETER_MEM(type, name)\
|
||||
_DECLARE_PARAMETER_SETFUN2(type, name, val1, val2)
|
||||
|
||||
#define DECLARE_PARAMETER_GET(type, name)\
|
||||
_DECLARE_PARAMETER_MEM(type, name)\
|
||||
_DECLARE_PARAMETER_GETFUN(type, name)
|
||||
|
||||
#define DECLARE_PARAMETER_ENUM(type, name)\
|
||||
_DECLARE_PARAMETER_MEM(type, name)\
|
||||
_DECLARE_PARAMETER_GETFUN(type, name)\
|
||||
_DECLARE_PARAMETER_SETENUM(type, name)
|
||||
|
||||
#define DECLARE_PARAMETER_ENUM2(type, name, val1, val2)\
|
||||
_DECLARE_PARAMETER_MEM(type, name)\
|
||||
_DECLARE_PARAMETER_GETFUN(type, name)\
|
||||
_DECLARE_PARAMETER_SETENUM2(type, name, val1, val2)
|
||||
|
||||
|
||||
#define DECLARE_PARAMETER_PAIR(type, name)\
|
||||
_DECLARE_PARAMETER_MEM(type, name##Start)\
|
||||
_DECLARE_PARAMETER_MEM(type, name##End)\
|
||||
_DECLARE_PARAMETER_GETFUN(type, name##Start)\
|
||||
_DECLARE_PARAMETER_GETFUN(type, name##End)\
|
||||
_DECLARE_PARAMETER_SETPAIR(type, name)
|
||||
|
||||
#define DECLARE_PARAMETER_PAIR2(type, name, val1, val2)\
|
||||
_DECLARE_PARAMETER_MEM(type, name##Start)\
|
||||
_DECLARE_PARAMETER_MEM(type, name##End)\
|
||||
_DECLARE_PARAMETER_GETFUN(type, name##Start)\
|
||||
_DECLARE_PARAMETER_GETFUN(type, name##End)\
|
||||
_DECLARE_PARAMETER_SETPAIR2(type, name, val1, val2)
|
||||
|
||||
|
||||
// Declare the provide class as a singleton.
|
||||
// Get instance via Class::getInstance().
|
||||
//
|
||||
// Note: according to C++11 standard, static object initialization will
|
||||
// be made only by one thread, other threads will wait till it complete.
|
||||
// start from VS2014, this macro is thread-safe.
|
||||
#define DECLARE_SINGLETON(type, ...)\
|
||||
public:\
|
||||
static type& getInstance() {\
|
||||
static type inst(__VA_ARGS__);\
|
||||
return inst;\
|
||||
}
|
||||
|
||||
// Declare the provide class as a singleton.
|
||||
// Get instance via Class::getInstance().
|
||||
//
|
||||
// Note: according to C++11 standard, static object initialization will
|
||||
// be made only by one thread, other threads will wait till it complete.
|
||||
// start from VS2014, this macro is thread-safe.
|
||||
#define DECLARE_SINGLETON_NOPARA(type)\
|
||||
public:\
|
||||
static type& getInstance() {\
|
||||
static type inst;\
|
||||
return inst;\
|
||||
}
|
||||
|
||||
// A simple version of object factory that use object name as key and hold object instances.
|
||||
// It's thread-safe.
|
||||
// Note: factory own the object instance, aka. own the object instance's memory, which means it will
|
||||
// deallocate the memory when it self is destroyed (when the who application is shutdown).
|
||||
// You don't need to delete the object instance yourself, and even worse, it will cause the double-delete crash.
|
||||
template<typename T, typename TPtr,
|
||||
typename std::enable_if<std::is_base_of<std::shared_ptr<T>, TPtr>::value>::type* = nullptr>
|
||||
class ObjectFactory
|
||||
{
|
||||
DECLARE_SINGLETON_NOPARA(ObjectFactory)
|
||||
|
||||
public:
|
||||
~ObjectFactory() {}
|
||||
TPtr getObject(const char* name)
|
||||
{
|
||||
CyclopsLockGuard guard(&mLock);
|
||||
auto it = mLookupTable.find(name);
|
||||
if (it == mLookupTable.end()) {
|
||||
// create new
|
||||
TPtr ptr = std::make_shared<T>();
|
||||
it = mLookupTable.insert(std::make_pair(name, ptr)).first;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
private:
|
||||
ObjectFactory() {}
|
||||
std::map<string, TPtr> mLookupTable;
|
||||
CyclopsLock mLock;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline T minMax(T val, T minVal, T maxVal) {
|
||||
return std::min<T>(maxVal, std::max<T>(minVal, val));
|
||||
}
|
||||
|
||||
#endif // __StdUtils_h_
|
||||
|
||||
@ -0,0 +1,297 @@
|
||||
#include "TransSolver.h"
|
||||
#include "CVUtils.h"
|
||||
|
||||
#define M_LOW_TOLERANCE 0.000001
|
||||
|
||||
Matx33d affineTrans(const vector<Point2d>& src, const vector<Point2d>& dst)
|
||||
{
|
||||
if (dst.empty() || src.empty()) {
|
||||
return Mat();
|
||||
}
|
||||
|
||||
Point2d pc, qc;
|
||||
int smallerSize = src.size() < dst.size() ? src.size() : dst.size();
|
||||
|
||||
for (int i = 0; i < smallerSize; i++) {
|
||||
pc += src[i];
|
||||
qc += dst[i];
|
||||
}
|
||||
pc.x /= smallerSize;
|
||||
pc.y /= smallerSize;
|
||||
qc.x /= smallerSize;
|
||||
qc.y /= smallerSize;
|
||||
|
||||
Matx21d pit;
|
||||
Matx12d pi;
|
||||
Matx12d qi;
|
||||
Matx22d spitpi = Matx22d::zeros();
|
||||
Matx22d pitpi;
|
||||
Matx22d pitqi;
|
||||
Matx22d spitqi = Matx22d::zeros();
|
||||
|
||||
for (int i = 0; i < src.size() && i < dst.size(); i++) {
|
||||
Point2d qpi = src[i] - pc;
|
||||
Point2d qqi = dst[i] - qc;
|
||||
|
||||
pit(0) = qpi.x;
|
||||
pit(1) = qpi.y;
|
||||
pi(0) = qpi.x;
|
||||
pi(1) = qpi.y;
|
||||
qi(0) = qqi.x;
|
||||
qi(1) = qqi.y;
|
||||
pitpi = pit*pi;
|
||||
spitpi = pitpi + spitpi;
|
||||
pitqi = pit*qi;
|
||||
spitqi = pitqi + spitqi;
|
||||
}
|
||||
Matx22d ispitpi;
|
||||
ispitpi = spitpi.inv();
|
||||
|
||||
Matx22d M = ispitpi*spitqi;
|
||||
|
||||
double m11 = M(0, 0);
|
||||
double m21 = M(0, 1);
|
||||
double m12 = M(1, 0);
|
||||
double m22 = M(1, 1);
|
||||
|
||||
Matx33d qm(m11, m12, 0, m21, m22, 0, 0, 0, 1);
|
||||
Matx33d pcm(1.0, 0, -pc.x, 0, 1.0, -pc.y, 0, 0, 1);
|
||||
Matx33d qcm(1.0, 0, qc.x, 0, 1.0, qc.y, 0, 0, 1);
|
||||
|
||||
Matx33d ret = qcm*qm*pcm;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Matx33d rigidTrans(const vector<Point2d>& src, const vector<Point2d>& dst)
|
||||
{
|
||||
if (dst.empty() || src.empty()) {
|
||||
return Mat();
|
||||
}
|
||||
|
||||
vector<double> weights(src.size(), 1.0 / src.size());
|
||||
Point2d pc, qc;
|
||||
double wsum = 0;
|
||||
|
||||
for (int i = 0; i < src.size(); i++) {
|
||||
double w = 1.0 / src.size();
|
||||
weights[i] = w;
|
||||
pc += src[i] * w;
|
||||
qc += dst[i] * w;
|
||||
wsum += w;
|
||||
}
|
||||
pc.x /= wsum;
|
||||
pc.y /= wsum;
|
||||
qc.x /= wsum;
|
||||
qc.y /= wsum;
|
||||
|
||||
double u = 0;
|
||||
double u1, u2;
|
||||
u1 = 0;
|
||||
u2 = 0;
|
||||
for (int i = 0; i < src.size() && i < dst.size(); i++) {
|
||||
Point2d qpi = src[i] - pc;
|
||||
Point2d qqi = dst[i] - qc;
|
||||
Point2d pi(qpi.x, qpi.y);
|
||||
Point2d qi(qqi.x, qqi.y);
|
||||
u1 += pi.dot(qi)*weights[i];
|
||||
Point2d pi_(pi.y, -pi.x);
|
||||
u2 += qi.dot(pi_)*weights[i];
|
||||
}
|
||||
u = sqrt(u1*u1 + u2*u2);
|
||||
if (u < M_LOW_TOLERANCE) {
|
||||
u = M_LOW_TOLERANCE;
|
||||
}
|
||||
|
||||
Matx22d R = Matx22d::zeros();
|
||||
Matx22d r = Matx22d::zeros();
|
||||
|
||||
for (int i = 0; i < src.size() && i < dst.size(); i++) {
|
||||
Point2d qpi = src[i] - pc;
|
||||
Point2d qqi = dst[i] - qc;
|
||||
Point2d pi(qpi.x, qpi.y);
|
||||
Point2d qi(qqi.x, qqi.y);
|
||||
Point2d pi_(pi.y, -pi.x);
|
||||
Point2d qi_(qi.y, -qi.x);
|
||||
|
||||
r(0, 0) = pi.dot(qi);
|
||||
r(0, 1) = pi.dot(qi_);
|
||||
r(1, 0) = pi_.dot(qi);
|
||||
r(1, 1) = pi_.dot(qi_);
|
||||
|
||||
R = R + r * (weights[i] / u);
|
||||
}
|
||||
|
||||
double m11 = R(0, 0);
|
||||
double m21 = R(0, 1);
|
||||
double m12 = R(1, 0);
|
||||
double m22 = R(1, 1);
|
||||
Matx33d qm(m11, m12, 0, m21, m22, 0, 0, 0, 1);
|
||||
Matx33d pcm(1.0, 0, -pc.x, 0, 1.0, -pc.y, 0, 0, 1);
|
||||
Matx33d qcm(1.0, 0, qc.x, 0, 1.0, qc.y, 0, 0, 1);
|
||||
Matx33d ret = qcm*qm*pcm;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool cmpPointVec(const vector<Point2d>& vec0, const vector<Point2d>& vec1, const Matx33d& mat, double tor)
|
||||
{
|
||||
int smallerSize = vec0.size() < vec1.size() ? vec0.size() : vec1.size();
|
||||
for (int i = 0; i < smallerSize; ++i)
|
||||
{
|
||||
Point2d p0, p1;
|
||||
p0 = vec0[i];
|
||||
p1 = vec1[i];
|
||||
Point3d tp0 = mat*p0;
|
||||
tp0.x /= tp0.z;
|
||||
tp0.y /= tp0.z;
|
||||
if (abs(p1.x - tp0.x) > tor || abs(p1.y - tp0.y) > tor)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void testTransSolver()
|
||||
{
|
||||
{
|
||||
//rotation only
|
||||
|
||||
vector<Point2d> vec0, vec1;
|
||||
vec0.push_back(Point2d());
|
||||
vec0.push_back(Point2d(1, 0));
|
||||
vec0.push_back(Point2d(1, 1));
|
||||
vec0.push_back(Point2d(0, 1));
|
||||
|
||||
vec1.push_back(Point2d());
|
||||
vec1.push_back(Point2d(0, 1));
|
||||
vec1.push_back(Point2d(-1, 1));
|
||||
vec1.push_back(Point2d(-1, 0));
|
||||
|
||||
Matx33d ret = affineTrans(vec0, vec1);
|
||||
assert(cmpPointVec(vec0, vec1, ret, M_LOW_TOLERANCE));
|
||||
|
||||
ret = rigidTrans(vec0, vec1);
|
||||
assert(cmpPointVec(vec0, vec1, ret, M_LOW_TOLERANCE));
|
||||
}
|
||||
{
|
||||
// rotation and scale
|
||||
|
||||
vector<Point2d> vec0, vec1;
|
||||
vec0.push_back(Point2d());
|
||||
vec0.push_back(Point2d(1, 0));
|
||||
vec0.push_back(Point2d(1, 1));
|
||||
vec0.push_back(Point2d(0, 1));
|
||||
|
||||
vec1.push_back(Point2d());
|
||||
vec1.push_back(Point2d(1, 1));
|
||||
vec1.push_back(Point2d(0, 2));
|
||||
vec1.push_back(Point2d(-1, 1));
|
||||
|
||||
Matx33d ret = affineTrans(vec0, vec1);
|
||||
assert(cmpPointVec(vec0, vec1, ret, M_LOW_TOLERANCE));
|
||||
}
|
||||
{
|
||||
// scale only
|
||||
|
||||
vector<Point2d> vec0, vec1;
|
||||
vec0.push_back(Point2d());
|
||||
vec0.push_back(Point2d(1, 0));
|
||||
vec0.push_back(Point2d(1, 1));
|
||||
vec0.push_back(Point2d(0, 1));
|
||||
|
||||
vec1.push_back(Point2d());
|
||||
vec1.push_back(Point2d(2, 0));
|
||||
vec1.push_back(Point2d(2, 2));
|
||||
vec1.push_back(Point2d(0, 2));
|
||||
|
||||
Matx33d ret = affineTrans(vec0, vec1);
|
||||
assert(cmpPointVec(vec0, vec1, ret, M_LOW_TOLERANCE));
|
||||
}
|
||||
{
|
||||
// translation only
|
||||
|
||||
vector<Point2d> vec0, vec1;
|
||||
vec0.push_back(Point2d());
|
||||
vec0.push_back(Point2d(1, 0));
|
||||
vec0.push_back(Point2d(1, 1));
|
||||
vec0.push_back(Point2d(0, 1));
|
||||
|
||||
vec1.push_back(Point2d(1, 1));
|
||||
vec1.push_back(Point2d(2, 1));
|
||||
vec1.push_back(Point2d(2, 2));
|
||||
vec1.push_back(Point2d(1, 2));
|
||||
|
||||
Matx33d ret = affineTrans(vec0, vec1);
|
||||
assert(cmpPointVec(vec0, vec1, ret, M_LOW_TOLERANCE));
|
||||
|
||||
ret = rigidTrans(vec0, vec1);
|
||||
assert(cmpPointVec(vec0, vec1, ret, M_LOW_TOLERANCE));
|
||||
}
|
||||
{
|
||||
for (int i = 0; i < 10000; ++i)
|
||||
{
|
||||
// random rotation and translation
|
||||
Mat mat23 = getRotationMatrix2D(Point2f(), rand() % 360, 1.0);
|
||||
mat23.at<double>(0, 2) = (rand() % 1000) / 1000.0;
|
||||
mat23.at<double>(1, 2) = (rand() % 1000) / 1000.0;
|
||||
Matx33d matx = Matx33d::eye();
|
||||
Mat mat(3, 3, CV_64FC1, matx.val);
|
||||
mat23.copyTo(mat.rowRange(0, 2));
|
||||
|
||||
vector<Point2d> vec0, vec1;
|
||||
vec0.push_back(Point2d());
|
||||
vec0.push_back(Point2d(1, 0));
|
||||
vec0.push_back(Point2d(1, 1));
|
||||
vec0.push_back(Point2d(0, 1));
|
||||
|
||||
vec1 = vec0;
|
||||
transPoints(vec1, matx);
|
||||
|
||||
Matx33d ret = affineTrans(vec0, vec1);
|
||||
assert(cmpPointVec(vec0, vec1, ret, M_LOW_TOLERANCE));
|
||||
ret = rigidTrans(vec0, vec1);
|
||||
assert(cmpPointVec(vec0, vec1, ret, M_LOW_TOLERANCE));
|
||||
}
|
||||
}
|
||||
{
|
||||
// skew only
|
||||
|
||||
vector<Point2d> vec0, vec1;
|
||||
vec0.push_back(Point2d());
|
||||
vec0.push_back(Point2d(1, 0));
|
||||
vec0.push_back(Point2d(1, 1));
|
||||
vec0.push_back(Point2d(0, 1));
|
||||
|
||||
vec1.push_back(Point2d());
|
||||
vec1.push_back(Point2d(1, 0));
|
||||
vec1.push_back(Point2d(2, 1));
|
||||
vec1.push_back(Point2d(1, 1));
|
||||
|
||||
Matx33d ret = affineTrans(vec0, vec1);
|
||||
assert(cmpPointVec(vec0, vec1, ret, M_LOW_TOLERANCE));
|
||||
}
|
||||
{
|
||||
// random affine
|
||||
|
||||
for (int i = 0; i < 10000; ++i)
|
||||
{
|
||||
vector<Point2d> vec0, vec1;
|
||||
vec0.push_back(Point2d());
|
||||
vec0.push_back(Point2d(1, 0));
|
||||
vec0.push_back(Point2d(1, 1));
|
||||
vec0.push_back(Point2d(0, 1));
|
||||
|
||||
Matx33d trans = Matx33d::eye();
|
||||
Mat mat(3, 3, CV_64FC1, trans.val);
|
||||
randu(mat.rowRange(0, 2), 0, 1.0);
|
||||
|
||||
vec1 = vec0;
|
||||
transPoints(vec1, trans);
|
||||
|
||||
Matx33d ret = affineTrans(vec0, vec1);
|
||||
assert(cmpPointVec(vec0, vec1, ret, M_LOW_TOLERANCE));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
/*! \file TransSolver.h
|
||||
\brief A brief file description.
|
||||
|
||||
A more elaborated file description.
|
||||
|
||||
Created: 2015/11/15, author: bang.jin.
|
||||
*/
|
||||
|
||||
#ifndef __TransSolver_h_
|
||||
#define __TransSolver_h_
|
||||
|
||||
#include <vector>
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
using namespace cv;
|
||||
using std::vector;
|
||||
|
||||
Matx33d affineTrans(const vector<Point2d>& src, const vector<Point2d>& dst);
|
||||
|
||||
Matx33d rigidTrans(const vector<Point2d>& src, const vector<Point2d>& dst,
|
||||
Mat* pCenRotScaleMat = NULL);
|
||||
|
||||
void testTransSolver();
|
||||
|
||||
#endif // __TransSolver_h_
|
||||
|
||||
@ -0,0 +1,182 @@
|
||||
#include "cvdrawutils.h"
|
||||
#include "CVUtils.h"
|
||||
#include "DetectRoi.h"
|
||||
|
||||
cv::Mat drawLines(const Mat& img, const vector<PointfPair>& segPointVec)
|
||||
{
|
||||
#ifdef LP_DISABLE_DRAW
|
||||
return Mat();
|
||||
#else
|
||||
|
||||
Mat canvas = normCanvas(img);
|
||||
for (size_t i = 0; i < segPointVec.size(); ++i)
|
||||
{
|
||||
const PointfPair& pointPair = segPointVec[i];
|
||||
cv::line(canvas, pointPair.first, pointPair.second, Scalar(255, 255, 255, 0.5));
|
||||
}
|
||||
return canvas;
|
||||
#endif
|
||||
}
|
||||
|
||||
cv::Mat drawLines(const Mat& img, const vector<PointPair>& segPointVec)
|
||||
{
|
||||
#ifdef LP_DISABLE_DRAW
|
||||
return Mat();
|
||||
#else
|
||||
|
||||
Mat canvas = normCanvas(img);
|
||||
for (size_t i = 0; i < segPointVec.size(); ++i)
|
||||
{
|
||||
const PointPair& pointPair = segPointVec[i];
|
||||
cv::line(canvas, pointPair.first, pointPair.second, Scalar(255, 255, 255, 0.5));
|
||||
}
|
||||
return canvas;
|
||||
#endif
|
||||
}
|
||||
|
||||
void drawLine(Mat& canvas, const Vec4f& l, const Scalar& color)
|
||||
{
|
||||
line(canvas, Point(l.val[0], l.val[1]), Point(l.val[2], l.val[3]), color);
|
||||
}
|
||||
|
||||
void drawPoint(Mat& canvas, int x, int y, const Scalar& color, int size)
|
||||
{
|
||||
int halfSize = size / 2;
|
||||
Rect rect(x - halfSize, y - halfSize, size, size);
|
||||
#if (CV_MAJOR_VERSION >= 3)
|
||||
rectangle(canvas, rect, color, FILLED);
|
||||
#else
|
||||
rectangle(canvas, rect, color, CV_FILLED);
|
||||
#endif
|
||||
}
|
||||
|
||||
Scalar getRandomColor()
|
||||
{
|
||||
RNG& r = cv::theRNG();
|
||||
return Scalar(r.next() % 256, r.next() % 256, r.next() % 256, 255);
|
||||
}
|
||||
|
||||
Mat getColorCanvas(const Mat& img, float resizeFactor)
|
||||
{
|
||||
Mat canvas;
|
||||
if (resizeFactor == 1.) canvas = img.clone();
|
||||
else resize(img, canvas, Size(), resizeFactor, resizeFactor);
|
||||
if (canvas.channels() == 1) cvtColor(canvas, canvas, CV_GRAY2BGR);
|
||||
return canvas;
|
||||
}
|
||||
|
||||
cv::Mat drawPoints(const Mat& img, const vector<Point>& pointVec, int grayVal /*= 255*/, int xRadius /*= 0*/, int yRadius /*= 0*/)
|
||||
{
|
||||
#ifdef LP_DISABLE_DRAW
|
||||
return Mat();
|
||||
#else
|
||||
Mat canvas = normCanvas(img);
|
||||
for (size_t i = 0; i < pointVec.size(); ++i)
|
||||
{
|
||||
Point pt(pointVec[i]);
|
||||
if (xRadius == 0 && yRadius == 0)
|
||||
{
|
||||
canvas.at<uchar>(pt.y, pt.x) = grayVal;
|
||||
}
|
||||
else
|
||||
{
|
||||
Rect rect(pt.x - xRadius, pt.y - yRadius, xRadius * 2 + 1, yRadius * 2 + 1);
|
||||
rectangle(canvas, rect, Scalar(grayVal, grayVal, grayVal));
|
||||
}
|
||||
|
||||
}
|
||||
return canvas;
|
||||
#endif
|
||||
}
|
||||
|
||||
cv::Mat drawPointsWithKeyPoints(const Mat& img, const vector<Point>& pointVec)
|
||||
{
|
||||
#ifdef LP_DISABLE_DRAW
|
||||
return Mat();
|
||||
#else
|
||||
vector<KeyPoint> keypointVec;
|
||||
for (size_t i = 0; i < pointVec.size(); ++i)
|
||||
{
|
||||
Point pt = pointVec[i];
|
||||
keypointVec.push_back(KeyPoint(Point2f((float)pt.x, (float)pt.y), 1));
|
||||
}
|
||||
Mat canvas = normCanvas(img);
|
||||
drawKeypoints(canvas, keypointVec, canvas);
|
||||
|
||||
return canvas;
|
||||
#endif
|
||||
}
|
||||
|
||||
void drawRotateRect(Mat& canvas, const RotatedRect& rr, const Scalar& color, int angleLen /*= 30*/)
|
||||
{
|
||||
// center
|
||||
drawPoint(canvas, rr.center.x, rr.center.y, color);
|
||||
|
||||
// draw pose rect
|
||||
Point2f pts[4];
|
||||
rr.points(pts);
|
||||
for (int i = 0; i < 3; ++i)
|
||||
line(canvas, pts[i], pts[i + 1], color);
|
||||
line(canvas, pts[3], pts[0], color);
|
||||
|
||||
// draw angle
|
||||
int xshift = cos(rr.angle / 180 * CV_PI) * angleLen;
|
||||
int yshift = sin(rr.angle / 180 * CV_PI) * angleLen;
|
||||
Point2f p(rr.center.x + xshift, rr.center.y + yshift);
|
||||
line(canvas, Point(rr.center.x, rr.center.y), p, color);
|
||||
}
|
||||
|
||||
#if (CV_MAJOR_VERSION >= 3)
|
||||
Mat highlightRoi(const Mat& roiImg, const Rect& r, const vector<Point2f>& roiVertexes)
|
||||
{
|
||||
assert(r.width == roiImg.cols && r.height == roiImg.rows);
|
||||
|
||||
Mat mask = DetectRoi::genMask(r, roiVertexes);
|
||||
Mat canvas(roiImg.rows, roiImg.cols, CV_8UC4);
|
||||
|
||||
// bgr
|
||||
static int from_to1_gay[] = { 0,0,0,1,0,2 };
|
||||
static int from_to1_color[] = { 0,0,1,1,2,2 };
|
||||
int* from_to1 = nullptr;
|
||||
int channelCount = roiImg.channels();
|
||||
if (channelCount == 1)
|
||||
from_to1 = from_to1_gay;
|
||||
else if (channelCount == 3 || channelCount == 4)
|
||||
from_to1 = from_to1_color;
|
||||
else {
|
||||
assert(false && "highlightRoi: unexpected channel.");
|
||||
return gDummyMat;
|
||||
}
|
||||
|
||||
mixChannels(roiImg, canvas, from_to1, 3);
|
||||
|
||||
// a
|
||||
static int from_to2[] = { 0,3 };
|
||||
mixChannels(mask, canvas, from_to2, 1);
|
||||
|
||||
return canvas;
|
||||
}
|
||||
#endif
|
||||
|
||||
void drawPointDir(Mat& canvas, const Point& p, float angle, const Scalar& color, const Scalar& centerColor, int len, int thick)
|
||||
{
|
||||
float halfLen = len / 2.f;
|
||||
float yStep = sin((90 + angle) / 180 * CV_PI) * halfLen;
|
||||
float xStep = cos((90 + angle) / 180 * CV_PI) * halfLen;
|
||||
line(canvas, Point(p.x - xStep, p.y - yStep), Point(p.x + xStep, p.y + yStep), color, thick, CV_AA);
|
||||
#if (CV_MAJOR_VERSION >= 3)
|
||||
rectangle(canvas, p, p, centerColor, FILLED);
|
||||
#else
|
||||
rectangle(canvas, p, p, centerColor, CV_FILLED);
|
||||
#endif
|
||||
}
|
||||
|
||||
void drawPatternPose(Mat& canvas, const Size& templateSize, const Vec4f& pose, const Scalar& color)
|
||||
{
|
||||
int cols = templateSize.width;
|
||||
int rows = templateSize.height;
|
||||
RotatedRect rr(Point2f(pose[0], pose[1]), Size2f(pose[3] * cols, pose[3] * cols), pose[2]);
|
||||
|
||||
drawRotateRect(canvas, rr, color);
|
||||
}
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
#ifndef cvdrawutils_h__
|
||||
#define cvdrawutils_h__
|
||||
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include <opencv2/opencv_modules.hpp>
|
||||
#include <vector>
|
||||
#include "pointpair.h"
|
||||
|
||||
using std::vector;
|
||||
using namespace cv;
|
||||
|
||||
Scalar getRandomColor();
|
||||
|
||||
Mat getColorCanvas(const Mat& img, float resizeFactor = 1.);
|
||||
|
||||
Mat drawPoints(const Mat& img, const vector<Point>& pointVec, int grayVal = 255, int xRadius = 0, int yRadius = 0);
|
||||
|
||||
Mat drawPointsWithKeyPoints(const Mat& img, const vector<Point>& pointVec);
|
||||
|
||||
Mat drawLines(const Mat& img, const vector<PointfPair>& segPointVec);
|
||||
|
||||
Mat drawLines(const Mat& img, const vector<PointPair>& segPointVec);
|
||||
|
||||
void drawLine(Mat& canvas, const Vec4f& l, const Scalar& color);
|
||||
|
||||
void drawPoint(Mat& canvas, int x, int y, const Scalar& color, int size = 1);
|
||||
|
||||
void drawRotateRect(Mat& canvas, const RotatedRect& rr, const Scalar& color, int angleLen = 30);
|
||||
|
||||
Mat highlightRoi(const Mat& roiImg, const Rect& r, const vector<Point2f>& roiVertexes);
|
||||
|
||||
void drawPointDir(Mat& canvas, const Point& p, float angle, const Scalar& color,
|
||||
const Scalar& centerColor, int len = 5, int thick = 1);
|
||||
|
||||
void drawPatternPose(Mat& canvas, const Size& templateSize, const Vec4f& pose, const Scalar& color);
|
||||
|
||||
|
||||
#endif // cvdrawutils_h__
|
||||
@ -0,0 +1,217 @@
|
||||
#include "cvmatutils.h"
|
||||
#include <list>
|
||||
#include <iostream>
|
||||
|
||||
using std::list;
|
||||
using std::iostream;
|
||||
|
||||
cv::Mat getTranslateMatrix2D(float dx, float dy)
|
||||
{
|
||||
Mat ret(3, 2, CV_32FC1);
|
||||
ret.setTo(0);
|
||||
float* p = (float*)ret.data;
|
||||
p[0] = 1.0;
|
||||
p[2] = dx;
|
||||
p[4] = 1.0;
|
||||
p[5] = dy;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void cutMargin(Mat& img, int w)
|
||||
{
|
||||
Rect r(w, w, img.cols - 2 * w, img.rows - 2 * w);
|
||||
img = Mat(img, r);
|
||||
}
|
||||
|
||||
cv::Mat duplicateChannels(const Mat& mat, int n)
|
||||
{
|
||||
assert(mat.channels() == 1);
|
||||
|
||||
vector<Mat> matVec(n, mat);
|
||||
|
||||
Mat ret;
|
||||
merge(matVec, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
cv::Scalar sum(const Mat& mat, const Mat& mask)
|
||||
{
|
||||
// double minVal, maxVal;
|
||||
// minMaxIdx(mask, &minVal, &maxVal);
|
||||
// mask /= maxVal;
|
||||
Mat mask3ch = duplicateChannels(mask, 3);
|
||||
Mat maskedMat = mask3ch & mat;
|
||||
return sum(maskedMat);
|
||||
}
|
||||
|
||||
string toStr(const Mat& m)
|
||||
{
|
||||
stringstream ss;
|
||||
switch (m.type())
|
||||
{
|
||||
case CV_8UC1:
|
||||
for (int i = 0; i < m.rows; ++i)
|
||||
{
|
||||
uchar* pRowData = m.row(i).data;
|
||||
for (int j = 0; j < m.cols; ++j)
|
||||
{
|
||||
ss << (int)pRowData[j] << " ";
|
||||
}
|
||||
ss << "\n";
|
||||
}
|
||||
break;
|
||||
case CV_32FC1:
|
||||
for (int i = 0; i < m.rows; ++i)
|
||||
{
|
||||
float* pRowData = (float*)m.row(i).data;
|
||||
for (int j = 0; j < m.cols; ++j)
|
||||
{
|
||||
ss << (float)pRowData[j] << " ";
|
||||
}
|
||||
ss << "\n";
|
||||
}
|
||||
break;
|
||||
case CV_8UC4:
|
||||
for (int i = 0; i < m.rows; ++i)
|
||||
{
|
||||
uchar* pRowData = m.row(i).data;
|
||||
for (int j = 0; j < m.cols * 4; ++j)
|
||||
{
|
||||
ss << (int)pRowData[j] << " ";
|
||||
}
|
||||
ss << "\n";
|
||||
}
|
||||
break;
|
||||
case CV_8UC3:
|
||||
for (int i = 0; i < m.rows; ++i)
|
||||
{
|
||||
uchar* pRowData = m.row(i).data;
|
||||
for (int j = 0; j < m.cols * 3; ++j)
|
||||
{
|
||||
ss << (int)pRowData[j] << " ";
|
||||
}
|
||||
ss << "\n";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
cv::Mat fromStr(const string& str, int rows, int cols, int type)
|
||||
{
|
||||
Mat ret;
|
||||
stringstream ss(str);
|
||||
int count = 0;
|
||||
switch (type)
|
||||
{
|
||||
case CV_8UC1:
|
||||
ret.create(rows, cols, CV_8UC1);
|
||||
for (int i = 0; i < rows; ++i)
|
||||
{
|
||||
uchar* pRowData = ret.row(i).data;
|
||||
for (int j = 0; j < cols; ++j)
|
||||
{
|
||||
if (ss.eof())
|
||||
{
|
||||
return Mat();
|
||||
}
|
||||
int v;
|
||||
ss >> v;
|
||||
(*pRowData++) = v;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CV_32FC1:
|
||||
ret.create(rows, cols, CV_32FC1);
|
||||
for (int i = 0; i < rows; ++i)
|
||||
{
|
||||
float* pRowData = (float*)ret.row(i).data;
|
||||
for (int j = 0; j < cols; ++j)
|
||||
{
|
||||
if (ss.eof())
|
||||
{
|
||||
return Mat();
|
||||
}
|
||||
float v;
|
||||
ss >> v;
|
||||
(*pRowData++) = v;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CV_32FC3:
|
||||
ret.create(rows, cols / 3, CV_32FC3);
|
||||
for (int i = 0; i < rows; ++i)
|
||||
{
|
||||
float* pRowData = (float*)ret.row(i).data;
|
||||
for (int j = 0; j < cols; ++j)
|
||||
{
|
||||
if (ss.eof())
|
||||
{
|
||||
return Mat();
|
||||
}
|
||||
float v;
|
||||
ss >> v;
|
||||
(*pRowData++) = v;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CV_32FC4:
|
||||
ret.create(rows, cols / 4, CV_32FC4);
|
||||
for (int i = 0; i < rows; ++i)
|
||||
{
|
||||
float* pRowData = (float*)ret.row(i).data;
|
||||
for (int j = 0; j < cols; ++j)
|
||||
{
|
||||
if (ss.eof())
|
||||
{
|
||||
return Mat();
|
||||
}
|
||||
float v;
|
||||
ss >> v;
|
||||
(*pRowData++) = v;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CV_8UC4:
|
||||
ret.create(rows, cols / 4, CV_8UC4);
|
||||
for (int i = 0; i < rows; ++i)
|
||||
{
|
||||
uchar* pRowData = ret.row(i).data;
|
||||
for (int j = 0; j < cols; ++j)
|
||||
{
|
||||
if (ss.eof())
|
||||
{
|
||||
return Mat();
|
||||
}
|
||||
int v;
|
||||
ss >> v;
|
||||
(*pRowData++) = v;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CV_8UC3:
|
||||
ret.create(rows, cols / 3, CV_8UC3);
|
||||
for (int i = 0; i < rows; ++i)
|
||||
{
|
||||
uchar* pRowData = ret.row(i).data;
|
||||
for (int j = 0; j < cols; ++j)
|
||||
{
|
||||
if (ss.eof())
|
||||
{
|
||||
return Mat();
|
||||
}
|
||||
int v;
|
||||
ss >> v;
|
||||
(*pRowData++) = v;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return Mat();
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
#ifndef _cvmatutils_h_
|
||||
#define _cvmatutils_h_
|
||||
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include <opencv2/opencv_modules.hpp>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iosfwd>
|
||||
|
||||
using namespace cv;
|
||||
using std::vector;
|
||||
using std::string;
|
||||
using std::stringstream;
|
||||
|
||||
Mat getTranslateMatrix2D(float dx, float dy);
|
||||
|
||||
void cutMargin(Mat& img, int w);
|
||||
|
||||
Mat duplicateChannels(const Mat& mat, int n);
|
||||
|
||||
Scalar sum(const Mat& mat, const Mat& mask);
|
||||
|
||||
string toStr(const Mat& m);
|
||||
Mat fromStr(const string& str, int rows, int cols, int type);
|
||||
|
||||
#endif // _cvmatutils_h_
|
||||
@ -0,0 +1,78 @@
|
||||
#ifndef pointpair_h__
|
||||
#define pointpair_h__
|
||||
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include <opencv2/opencv_modules.hpp>
|
||||
#include <vector>
|
||||
|
||||
using std::vector;
|
||||
using std::pair;
|
||||
using namespace cv;
|
||||
|
||||
template<typename _Point>
|
||||
class _PointPair : public pair<_Point, _Point>
|
||||
{
|
||||
public:
|
||||
_PointPair()
|
||||
: pair<_Point, _Point>(), mAver(0) {}
|
||||
|
||||
_PointPair(const _Point& p0, const _Point& p1)
|
||||
: pair<_Point, _Point>(p0, p1), mAver(0) {}
|
||||
|
||||
_PointPair(const _PointPair<_Point>& pointPair)
|
||||
: pair<_Point, _Point>(pointPair.first, pointPair.second)
|
||||
, mAver(pointPair.aver())
|
||||
, mStr(pointPair.getStr())
|
||||
{}
|
||||
|
||||
void setAver(float val) { mAver = val; }
|
||||
float aver() const { return mAver; }
|
||||
|
||||
std::string getStr() const { return mStr; }
|
||||
void setStr(std::string iVal) { mStr = iVal; }
|
||||
|
||||
protected:
|
||||
float mAver;
|
||||
std::string mStr;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
typedef _PointPair<Point> PointPair;
|
||||
typedef _PointPair<Point2f> PointfPair;
|
||||
|
||||
void convertPointPair2PointfPair(const vector<PointPair>& vec0,
|
||||
vector<PointfPair>& vec1);
|
||||
|
||||
template<typename _Point>
|
||||
double pointDis(const _Point& i, const _Point& j)
|
||||
{
|
||||
return norm(i - j);
|
||||
}
|
||||
|
||||
template<typename _PointPair>
|
||||
double pointPairXDis(const _PointPair& i, const _PointPair& j)
|
||||
{
|
||||
return (abs(i.first.x - j.first.x) +
|
||||
abs(i.second.x - j.second.x)) / 2.0;
|
||||
}
|
||||
|
||||
double pointPairDis(const PointPair& i, const PointPair& j);
|
||||
|
||||
template<typename _PointPair>
|
||||
double pointPairLen(const _PointPair& p)
|
||||
{
|
||||
return pointDis(p.first, p.second);
|
||||
}
|
||||
|
||||
template<typename _PointPair>
|
||||
void addYToPointPairs(vector<_PointPair>& vec, int y)
|
||||
{
|
||||
for (auto i = vec.begin(); i != vec.end(); ++i)
|
||||
{
|
||||
i->first.y += y;
|
||||
i->second.y += y;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // pointpair_h__
|
||||
Loading…
Reference in New Issue