diff --git a/molunCar/CVUtils.cpp b/molunCar/CVUtils.cpp deleted file mode 100644 index ce6990e..0000000 --- a/molunCar/CVUtils.cpp +++ /dev/null @@ -1,3066 +0,0 @@ -#include "CVUtils.h" -#include "DynamicProgramSearch.h" -#include "StdUtils.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 -// #include "Luffy.h" -// #include "cvmatutils.h" -// #include "cvmlutils.h" -// #include "cvdrawutils.h" -#include "TransSolver.h" - -namespace CyclopsUtils { - -Mat gDummyMat; -Scalar gDummyScalar; - -bool localMeanVarNorm(const Mat& srcMat, Mat& dstMat, int winRadius, double tarMean/* = 120*/, double tarStd /*= 30*/) -{ - int width = srcMat.cols; - int height = srcMat.rows; - - if (winRadius * 2 + 1 >= width || winRadius * 2 + 1 >= height) - { - return false; - } - - dstMat = srcMat.clone(); - - Mat sumMat, sqSumMat; - cv::integral(srcMat, sumMat, sqSumMat, CV_64F); - int area = (2 * winRadius + 1)*(2 * winRadius + 1); - for (int i = winRadius; i < height - winRadius; i++) - { - const uchar *pData = srcMat.ptr(i); - uchar *tarData = dstMat.ptr(i); - double *pSumY1 = (double *)sumMat.ptr(i - winRadius); - double *pSumY2 = (double *)sumMat.ptr(i + winRadius + 1); - double *pSqSumY1 = (double *)sqSumMat.ptr(i - winRadius); - double *pSqSumY2 = (double *)sqSumMat.ptr(i + winRadius + 1); - for (int j = winRadius; j < width - winRadius; j++) - { - double sumX1Y1 = pSumY1[j - winRadius]; - double sumX2Y2 = pSumY2[j + winRadius + 1]; - double sumX1Y2 = pSumY2[j - winRadius]; - double sumX2Y1 = pSumY1[j + winRadius + 1]; - double sqSumX1Y1 = pSqSumY1[j - winRadius]; - double sqSumX2Y2 = pSqSumY2[j + winRadius + 1]; - double sqSumX1Y2 = pSqSumY2[j - winRadius]; - double sqSumX2Y1 = pSqSumY1[j + winRadius + 1]; - double val = sumX2Y2 + sumX1Y1 - sumX1Y2 - sumX2Y1; - double meanVal = val / area; - double sqSum = sqSumX2Y2 + sqSumX1Y1 - sqSumX1Y2 - sqSumX2Y1; - double stdVar = sqrt((sqSum - 2 * val*meanVal + area * meanVal * meanVal) / area); - double s = tarStd / stdVar; - double t = tarMean - meanVal * s; - - int value = pData[j] * s + t; - - if (value > 255) - { - tarData[j] = 255; - } - else - { - tarData[j] = value; - } - } - } - - return true; -} -void meanvarnorm(Mat& src, Mat &dst, double avg, double var, Mat mask /*= Mat()*/) -{ - Scalar m, v; - cv::meanStdDev(src, m, v, mask); - // (I - m)*var/v + avg = I*var/v - m*var/v + avg - double s = var / v.val[0]; - double t = avg - m.val[0] * var / v.val[0]; - dst = src * s + t; -} - -Mat gridThre(const Mat& img, int gridWidth, int gridHeight, float threStdDevScale, - LogicOper oper /*= LP_LOGIC_SMALLER*/, - float majority /*= 0.8*/) -{ - Mat ret = Mat::zeros(img.size(), CV_8UC1); - int gridXNum = img.cols / gridWidth + 1; - int gridYNum = img.rows / gridHeight + 1; - for (int gy = 0; gy < gridYNum - 1; ++gy) - { - int y = gy*gridHeight; - for (int gx = 0; gx < gridXNum - 1; ++gx) - { - int x = gx*gridWidth; - Rect roi(x, y, gridWidth, gridHeight); - Mat roiImg(img, roi); - double mean, stddev; - meanStdDev(roiImg, Mat(), &mean, &stddev, majority); - Mat threImg; - switch (oper) - { - case LP_LOGIC_SMALLER: - threImg = roiImg < (mean + stddev*threStdDevScale); - break; - case LP_LOGIC_LARGER: - threImg = roiImg > (mean + stddev*threStdDevScale); - break; - } - - threImg.copyTo(Mat(ret, roi)); - } - } - for (int gy = 0; gy < gridYNum; ++gy) - { - int y = gy*gridHeight; - Rect roi(img.cols - gridWidth, y, gridWidth, gridHeight); - roi &= Rect(0, 0, img.cols, img.rows); - if (roi.width == 0 || roi.height == 0) - { - continue; - } - Mat roiImg(img, roi); - double mean, stddev; - meanStdDev(roiImg, Mat(), &mean, &stddev, majority); - Mat threImg; - switch (oper) - { - case LP_LOGIC_SMALLER: - threImg = roiImg < (mean + stddev*threStdDevScale); - break; - case LP_LOGIC_LARGER: - threImg = roiImg > (mean + stddev*threStdDevScale); - break; - } - threImg.copyTo(Mat(ret, roi)); - } - return ret; -} -Mat gridWhiteThre(const Mat& img, int gridWidth, int gridHeight, float threStdDevScale, float majority /*= 0.8*/) -{ - return gridThre(img, gridWidth, gridHeight, threStdDevScale, LP_LOGIC_LARGER, majority); -} -Mat gridBlackThre(const Mat& img, int gridWidth, int gridHeight, float threStdDevScale, float majority /*= 0.8*/) -{ - return gridThre(img, gridWidth, gridHeight, threStdDevScale, LP_LOGIC_SMALLER, majority); - - Mat ret = Mat::zeros(img.size(), CV_8UC1); - int gridXNum = img.cols / gridWidth + 1; - int gridYNum = img.rows / gridHeight + 1; - for (int gy = 0; gy < gridYNum - 1; ++gy) - { - int y = gy*gridHeight; - for (int gx = 0; gx < gridXNum - 1; ++gx) - { - int x = gx*gridWidth; - Rect roi(x, y, gridWidth, gridHeight); - Mat roiImg(img, roi); - double mean, stddev; - meanStdDev(roiImg, Mat(), &mean, &stddev, majority); - Mat threImg = roiImg < (mean + stddev*threStdDevScale); - threImg.copyTo(Mat(ret, roi)); - } - } - for(int gy = 0; gy < gridYNum; ++gy) - { - int y = gy*gridHeight; - Rect roi((gridXNum - 1)*gridWidth, y, gridWidth, gridHeight); - roi &= Rect(0, 0, img.cols, img.rows); - if (roi.width == 0 || roi.height == 0) - { - continue; - } - Mat roiImg(img, roi); - double mean, stddev; - meanStdDev(roiImg, Mat(), &mean, &stddev, (float)0.8); - Mat threImg = roiImg < (mean + stddev*threStdDevScale); - threImg.copyTo(Mat(ret, roi)); - } - return ret; -} - -void converToType(cv::Mat& mat, int mattype) -{ - cv::Mat _mat; - mat.convertTo(_mat, mattype); - mat = _mat; -} - -void genScharrImage(Mat& img) -{ - Mat sobelx, sobely; - Sobel(img, sobelx, CV_32FC1, 1, 0, CV_SCHARR); - Sobel(img, sobely, CV_32FC1, 0, 1, CV_SCHARR); - img = sobelx.mul(sobelx) + sobely.mul(sobely); - Mat tempImg; - img.convertTo(tempImg, CV_32FC1); - Mat tempImg0; - sqrt(tempImg, tempImg0); - img = tempImg0; -} - -void genSobelImage(Mat& img, Mat* pSobelx /*= NULL*/, Mat* pSobely /*= NULL*/) -{ - Mat sobelx, sobely; - Sobel(img, sobelx, CV_32FC1, 1, 0, BORDER_REPLICATE); - Sobel(img, sobely, CV_32FC1, 0, 1, BORDER_REPLICATE); - img = sobelx.mul(sobelx) + sobely.mul(sobely); - Mat tempImg; - img.convertTo(tempImg, CV_32FC1); - Mat tempImg0; - sqrt(tempImg, tempImg0); - img = tempImg0; - - if (pSobelx) - { - *pSobelx = sobelx; - } - if (pSobely) - { - *pSobely = sobely; - } -} - -cv::Mat genXDeriLineKernel(int w, int type, double absVal) -{ - assert(w % 2 == 1); - - Mat leftKernel = Mat::ones(1, w / 2, type)*absVal; - Mat rightKernel = Mat::ones(1, w / 2, type)*absVal*(-1); - Mat kernel = Mat::zeros(1, w, type); - leftKernel.copyTo(kernel.colRange(0, w / 2)); - rightKernel.copyTo(kernel.colRange(w / 2 + 1, w)); - return kernel; -} - -cv::Mat genXDeriMat(const Mat& img, int w, double absVal) -{ - assert(w % 2 == 1); - int kernelRadius = w / 2; - - Mat xKernel = genXDeriLineKernel(kernelRadius * 2 + 1, CV_32FC1, 1); - Mat xDeriMat; - sepFilter2D(img, xDeriMat, CV_32FC1, xKernel, Mat::ones(1, 1, CV_32FC1)); - - return xDeriMat; -} - -cv::Mat normEachRow(const Mat& img) -{ - Mat ret(img.rows, img.cols, img.type()); - for (int y = 0; y < img.rows; y++) - { - Mat rowMat = img.row(y); - double minVal, maxVal; - cv::minMaxIdx(rowMat, &minVal, &maxVal); - rowMat = rowMat / maxVal; - rowMat.copyTo(ret.row(y)); - } - return ret; -} - -cv::Mat genGradientDir4EachRow(const Mat& img) -{ - assert(img.cols >= 2); - - Mat xDeriMat = genXDeriMat(img, 3, 1); - Mat threMat; - threshold(xDeriMat, threMat, 0, 1, cv::THRESH_BINARY); - - return threMat; -} - -void findMatElementsEquals(const Mat& img, vector& pointVec, float val, int xPadding) -{ - assert(img.type() == CV_32FC1); - - for (int y = 0; y < img.rows; ++y) - { - float* pRowData = (float*)img.row(y).data; - float* pRowDataStart = pRowData; - float* pRowDataEnd = pRowData + img.cols - xPadding; - pRowData += xPadding; - while (pRowData != pRowDataEnd) - { - if (abs(*pRowData - val) < 0.0001) - { - pointVec.push_back(Point(pRowData - pRowDataStart, y)); - } - pRowData++; - } - } -} - -double localMatSum(const Mat& mat, const Rect& roi) -{ - Mat localMat(mat, roi); - return sum(localMat).val[0]; -} - -cv::Mat normCanvas(const Mat& img) -{ - Mat canvas; - double maxVal, minVal; - minMaxIdx(img, &minVal, &maxVal); - if (maxVal <= 1.0) - { - img.convertTo(canvas, CV_8UC1, 255); - } - else - { - img.convertTo(canvas, CV_8UC1); - } - return canvas; -} - -void findEdgePointsEachRow(const Mat& img, vector& edgePointVec, int xPadding) -{ - // img is a binary image. - // an edge point in a row satisfies: - // 1) left neighbor pixels are all black (0) or white (1); - // 2) right neighbor pixels are all white or black. - - // find candidate turning points - Mat sumKernelMat = Mat::ones(1, 2, img.type()); - Mat sumMat; - sepFilter2D(img, sumMat, img.type(), sumKernelMat, Mat::ones(1, 1, img.type())); - vector turningPointVec; - - // for pixels ... 0, 0, 1, 1 ..., turning point is - // * - findMatElementsEquals(sumMat, turningPointVec, 1.0, xPadding); - - // filter turning points - vector filteredTurningPointVec; - int localRadius = 30; - int localSumTor = 5; - for (size_t i = 0; i < turningPointVec.size(); ++i) - { - Point pt(turningPointVec[i]); - Rect leftRoi(pt.x - localRadius, pt.y, localRadius, 1); - double leftSum = localMatSum(img, leftRoi); - Rect rightRoi(pt.x, pt.y, localRadius, 1); - double rightSum = localMatSum(img, rightRoi); - if (leftSum > rightSum && abs(leftSum - localRadius) < localSumTor && rightSum < 0.0001) - { - filteredTurningPointVec.push_back(pt); - } - else if (leftSum < rightSum && leftSum < 0.0001 && abs(rightSum - localRadius) < localSumTor) - { - filteredTurningPointVec.push_back(pt); - } - } - - - //Mat canvas = drawPoints(img, filteredTurningPointVec, 125, 10); - - - edgePointVec = filteredTurningPointVec; -} - -Mat sumEachRow2(const Mat& img) -{ -#define _sumEachRow2(t)\ -if (img.channels() == 1) return sumEachRow(img);\ -else if (img.channels() == 2) return sumEachRowN(img);\ -else if (img.channels() == 3) return sumEachRowN(img);\ -else if (img.channels() == 4) return sumEachRowN(img);\ -else { _ASSERTE(false && "not implemented"); return gDummyMat; } - - switch (img.depth()) - { - case CV_8U: - _sumEachRow2(unsigned char); - case CV_16S: - _sumEachRow2(short); - case CV_32S: - _sumEachRow2(int); - case CV_32F: - _sumEachRow2(float); - case CV_64F: - _sumEachRow2(double); - default: - _ASSERTE(false && "not implemented"); - } - return gDummyMat; -} - -Mat sumEachCol2(const Mat& img) -{ -#define _sumEachCol2(t)\ -if (img.channels() == 1) return sumEachCol(img);\ -else if (img.channels() == 2) return sumEachColN(img);\ -else if (img.channels() == 3) return sumEachColN(img);\ -else if (img.channels() == 4) return sumEachColN(img);\ -else { _ASSERTE(false && "not implemented"); return gDummyMat; } - - switch (img.depth()) - { - case CV_8U: - _sumEachCol2(unsigned char); - case CV_16S: - _sumEachCol2(short); - case CV_32S: - _sumEachCol2(int); - case CV_32F: - _sumEachCol2(float); - case CV_64F: - _sumEachCol2(double); - default: - _ASSERTE(false && "not implemented"); - } - return gDummyMat; -} - -cv::Mat thresholdEachRowLocally(const Mat& img, int localRange /*= 501*/, int C /*= 10*/) -{ - Mat ret = img.clone(); - for (int y = 0; y < img.rows; ++y) - { - Mat rowMat = img.row(y); - uchar* pData = (uchar*)rowMat.data; - cv::adaptiveThreshold(rowMat, ret.row(y), 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, localRange, C); - } - return ret; -} - -cv::Mat thresholdEachRow(const Mat& img, float threScale /*= 0.5*/) -{ - Mat ret = img.clone(); - for (int y = 0; y < img.rows; ++y) - { - Mat rowMat = img.row(y); - double rowSum = sum(rowMat).val[0]; - double rowAvg = rowSum / img.cols * threScale; - Mat rowThre = ret.row(y); - threshold(rowMat, rowThre, rowAvg, 255, THRESH_BINARY); - } - return ret; -} - -cv::Mat thresholdEachRow(const Mat& img, const Mat& rowThre, float threScale) -{ - Mat ret = Mat::zeros(img.rows, img.cols, img.type()); - for (int y = 0; y < img.rows; ++y) - { - Mat retRow = ret.row(y); - uchar* pRetData = retRow.data; - Mat imgRow = img.row(y); - uchar* pData = imgRow.data; - double* pThreData = (double*)rowThre.data; - for (int x = 0; x < img.cols; ++x) - { - if (*pData < (*pThreData)*threScale) - { - *pRetData = 0; - } - else - { - *pRetData = 255; - } - pData++; - pThreData++; - pRetData++; - } - } - return ret; -} - -void convertPointPair2PointfPair(const vector& vec0, vector& vec1) -{ - vec1.clear(); - for (auto i = vec0.begin(); i != vec0.end(); ++i) - { - PointfPair pointfPair(i->first, i->second); - pointfPair.setAver(i->aver()); - pointfPair.setStr(i->getStr()); - vec1.push_back(pointfPair); - } -} - -double pointPairDis(const PointPair& i, const PointPair& j) -{ - double dis0 = pointDis(i.first, j.first); - double dis1 = pointDis(i.second, j.second); - return (dis0 + dis1) / 2.0; -} - -void segEachRow(const Mat& img, vector& pointPairVec, int xPadding) -{ - for (int y = 0; y < img.rows; ++y) - { - Mat rowMat = img.row(y); - uchar* pRowData = rowMat.data; - uchar* pRowStart = pRowData; - uchar* pRowEnd = rowMat.data + img.cols - xPadding; - pRowData += xPadding; - int leftX = -1; - while (pRowData != pRowEnd) - { - uchar val = *pRowData; - if (val == 0 && leftX == -1) - { - leftX = pRowData - pRowStart; - } - else if (val != 0 && leftX >= 0) - { - Point leftPt(leftX, y); - Point rightPt(pRowData - pRowStart - 1, y); - PointPair pointPair(leftPt, rightPt); - pointPairVec.push_back(pointPair); - leftX = -1; - } - pRowData++; - } - } -} - -void fillPointPairVal(const Mat& img, std::string filePath, vector& pointPairVec) -{ - for (auto i = pointPairVec.begin(); i != pointPairVec.end(); ++i) - { - Mat mat(img, Rect(i->first.x, i->first.y, i->second.x - i->first.x, 1)); - i->setAver(sum(mat).val[0] / (double)mat.cols); - std::stringstream ss; - ss << filePath << " x: " << i->first.x << " y: " << i->first.y; - i->setStr(ss.str()); - } -} - -cv::Mat getFirstChannel(const Mat& img) -{ - vector channels; - split(img, channels); - return channels.front(); -} -Mat getChannel(const Mat& img, int i) -{ - if (i < 0 || i >= img.channels()) - { - return Mat(); - } - vector channels; - split(img, channels); - - return channels[i]; -} - -void mulEachRow(Mat& img, const Mat& scaleRow) -{ - for (int i = 0; i < img.rows; ++i) - { - Mat row = img.row(i); - uchar* pRowData = (uchar*)row.data; - double* pScaleData = (double*)scaleRow.data; - for (int j = 0; j < row.cols; ++j) - { - *pRowData *= *pScaleData; - ++pRowData; - ++pScaleData; - } - } -} - -void genRandomPoints(const Mat& img, vector& points, RNG rng, int sampleCnt /* = 1000 */) -{ - sampleCnt = cv::min(sampleCnt, img.rows * img.cols ); - for (int i = 0; i < sampleCnt; ++i) - { - Vec3b* pData = (Vec3b*)img.row(rng.uniform(0, img.rows)).data; - Vec3b& d = pData[rng.uniform(0, img.cols)]; - - Point p; - p.x = d[0]; - p.y = d[1]; - points.push_back(p); - } -} - -void plot8uVec(const Mat& vec, float scale /*= 1.0*/) -{ - - Mat canvas = Mat::zeros(100 * scale, 100 * scale, CV_8UC1); - Rect rect(0, 0, canvas.cols * scale, canvas.rows * scale); - - int size = cv::max(vec.rows, vec.cols); - uchar* pVecData = vec.data; - for (int i = 0; i < size; ++i) - { - Point pt(i * scale, canvas.rows - 1 - pVecData[i] * scale); - if (rect.contains(pt)) - { - canvas.at(pt.y, pt.x) = 255; - } - } - imshow("plot8uVec", canvas); -} - -void plot32fVec(const Mat& vec, float scale /*= 1.0*/) -{ - Mat canvas = Mat::zeros(100 * scale, 100 * scale, CV_8UC1); - Rect rect(0, 0, canvas.cols * scale, canvas.rows * scale); - int size = cv::max(vec.rows, vec.cols); - float* pVecData = (float*)vec.data; - for (int i = 0; i < size; ++i) - { - Point pt(i * scale, canvas.rows - 1 - pVecData[i] * scale); - if (rect.contains(pt)) - { - canvas.at(pt.y, pt.x) = 255; - } - } - imshow("plot32fVec", canvas); -} - -cv::Mat calcHist(const Mat& img, const Mat& mask, int histSize /*= 256*/, int minVal, int maxVal) -{ - Mat histMat; - float fRange[] = { minVal, maxVal }; - const float* fHistRange = { fRange }; - - cv::calcHist(&img, 1, NULL, mask, histMat, 1, &histSize, &fHistRange); - return histMat; -} - -Mat resize(const Mat& img, float s, int interMethod /*= cv::INTER_LINEAR*/) -{ - Mat ret; - Size newSize(img.cols*s, img.rows*s); - if (newSize.width == 0 || newSize.height == 0) - { - return img; - } - resize(img, ret, Size(), s, s, interMethod); - return ret; -} - -void writeFile(const Mat& mat, std::string filePath, std::string matName /*= "mat"*/) -{ - FileStorage fs; - fs.open(filePath, FileStorage::WRITE); - fs << matName << mat; - fs.release(); -} - -cv::Mat readFile(std::string filePath, std::string matName) -{ - FileStorage fs; - fs.open(filePath, FileStorage::READ); - Mat ret; - fs[matName] >> ret; - return ret; -} - -void gaussianBlurEachRow(const Mat& src, Mat& dst, int ksize /*= 3*/) -{ - dst = Mat::zeros(src.rows, src.cols, src.type()); - for (int y = 0; y < src.rows; y++) - { - Mat dstRow = dst.row(y); - Mat srcRow = src.row(y); - cv::GaussianBlur(srcRow, dstRow, cv::Size(ksize, 1), 1.0); - } -} - -void medianBlurEachRow(const Mat& src, Mat& dst, int ksize /*= 3*/) -{ - dst = Mat::zeros(src.rows, src.cols, src.type()); - for (int y = 0; y < src.rows; y++) - { - Mat dstRow = dst.row(y); - Mat srcRow = src.row(y); - cv::medianBlur(srcRow, dstRow, 1); - } -} - -double maxLaplacianX(const Mat& rowMat, float scale /*= 1.0*/) -{ - Mat sRowMat; - Mat lapMat; - - if (scale != 1.0) - { - resize(rowMat, sRowMat, Size(), scale, 1.0, INTER_CUBIC); - Laplacian(sRowMat, lapMat, CV_32FC1, 3); - } - else - { - Laplacian(rowMat, lapMat, CV_32FC1); - } - double minVal, maxVal; - int minIdx, maxIdx; - minMaxIdx(lapMat, &minVal, &maxVal, &minIdx, &maxIdx); - return maxIdx / scale; -} - -double minLaplacianX(const Mat& rowMat, float scale /*= 1.0*/) -{ - Mat sRowMat; - Mat lapMat; - - if (scale != 1.0) - { - resize(rowMat, sRowMat, Size(), scale, 1.0, INTER_CUBIC); - Laplacian(sRowMat, lapMat, CV_32FC1, 3); - } - else - { - Laplacian(rowMat, lapMat, CV_32FC1); - } - double minVal, maxVal; - int minIdx, maxIdx; - minMaxIdx(lapMat, &minVal, &maxVal, &minIdx, &maxIdx); - return minIdx / scale; -} - -void Laplacian1D(const Mat& src, Mat& dst, int ddepth, int ksize /*= 1*/) -{ - assert(src.rows == 1); - Mat kernel; - float K1[3] = { 1, -2, 1 }; - float K3[5] = { 1, 2, -6, 2, 1 }; - float K5[7] = { 1, 1, 1, -6, 1, 1, 1 }; - float K7[9] = { 1, 1, 1, 1, -8, 1, 1, 1, 1 }; - float K9[11] = { 1, 1, 1, 1, 1, -10, 1, 1, 1, 1, 1 }; - switch (ksize) - { - case 1: - kernel = Mat(1, 3, CV_32F, K1); - break; - case 3: - kernel = Mat(1, 5, CV_32F, K3); - break; - case 5: - kernel = Mat(1, 7, CV_32F, K5); - break; - case 7: - kernel = Mat(1, 9, CV_32F, K7); - break; - case 9: - kernel = Mat(1, 11, CV_32F, K9); - break; - default: - assert(0); - break; - } - filter2D(src, dst, ddepth, kernel); -} - - -void _filterKeyPointsByNeighborDistance(vector& vec, float ndis) -{ - vector ret; - for (size_t i = 0; i < vec.size(); ++i) - { - KeyPoint kp0 = vec[i]; - bool isDiscard = false; - for (size_t j = i + 1; j < vec.size(); ++j) - { - KeyPoint kp1 = vec[j]; - float dis = pointDis(kp0.pt, kp1.pt); - if (dis < ndis) - { - if (kp0.response < kp1.response) - { - isDiscard = true; - break; - } - } - } - if (!isDiscard) - { - ret.push_back(kp0); - } - } - vec = ret; -} - -void filterKeyPointsByNeighborDistance(vector& vec, float ndis) -{ - _filterKeyPointsByNeighborDistance(vec, ndis); - vec = vector(vec.rbegin(), vec.rend()); - _filterKeyPointsByNeighborDistance(vec, ndis); -} - -float IC_Angle_u8(const Mat& image, const int half_k, Point2f pt, - const vector & u_max) -{ - int m_01 = 0, m_10 = 0; - - const uchar* center = &image.at(cvRound(pt.y), cvRound(pt.x)); - - // Treat the center line differently, v=0 - for (int u = -half_k; u <= half_k; ++u) - m_10 += u * center[u]; - - // Go line by line in the circular patch - int step = (int)image.step1(); - for (int v = 1; v <= half_k; ++v) - { - // Proceed over the two lines - int v_sum = 0; - int d = u_max[v]; - for (int u = -d; u <= d; ++u) - { - int val_plus = center[u + v*step], val_minus = center[u - v*step]; - v_sum += (val_plus - val_minus); - m_10 += u * (val_plus + val_minus); - } - m_01 += v * v_sum; - } - - return fastAtan2((float)m_01, (float)m_10); -} - -float IC_Angle_f32(const Mat& image, const int half_k, Point2f pt, - const vector & u_max) -{ - float m_01 = 0, m_10 = 0; - - const float* center = &image.at(cvRound(pt.y), cvRound(pt.x)); - - // Treat the center line differently, v=0 - for (int u = -half_k; u <= half_k; ++u) - m_10 += u * center[u]; - - // Go line by line in the circular patch - int step = (int)image.step1(); - for (int v = 1; v <= half_k; ++v) - { - // Proceed over the two lines - float v_sum = 0; - int d = u_max[v]; - for (int u = -d; u <= d; ++u) - { - float val_plus = center[u + v*step], val_minus = center[u - v*step]; - v_sum += (val_plus - val_minus); - m_10 += u * (val_plus + val_minus); - } - m_01 += v * v_sum; - } - - return fastAtan2((float)m_01, (float)m_10); -} - -float IC_Angle(const Mat& image, const int half_k, Point2f pt, - const vector & u_max) -{ - if (image.type() == CV_8UC1) - { - return IC_Angle_u8(image, half_k, pt, u_max); - } - else if (image.type() == CV_32FC1) - { - return IC_Angle_f32(image, half_k, pt, u_max); - } - else - { - std::cout << "image type " << image.type() << " is not supported" << std::endl; - return FLT_MAX; - } -} - -void computeOrientation(const Mat& image, vector& keypoints, - int halfPatchSize, const vector& umax) -{ - // Process each keypoint - for (vector::iterator keypoint = keypoints.begin(), - keypointEnd = keypoints.end(); keypoint != keypointEnd; ++keypoint) - { - keypoint->angle = IC_Angle(image, halfPatchSize, keypoint->pt, umax); - } -} - -void genUMax(vector& umax, int halfPatchSize) -{ - umax.resize(halfPatchSize + 2); - - int v, v0, vmax = cvFloor(halfPatchSize * sqrt(2.f) / 2 + 1); - int vmin = cvCeil(halfPatchSize * sqrt(2.f) / 2); - for (v = 0; v <= vmax; ++v) - umax[v] = cvRound(sqrt((double)halfPatchSize * halfPatchSize - v * v)); - - // Make sure we are symmetric - for (v = halfPatchSize, v0 = 0; v >= vmin; --v) - { - while (umax[v0] == umax[v0 + 1]) - ++v0; - umax[v] = v0; - ++v0; - } -} - -void filterKeyPointsByRotationInvariants(vector& vec, const Mat& img, - FeatureDetector* pFeatDetector, float tor) -{ - Point2f cen(img.cols / 2.0, img.rows / 2.0); - -// no longer supported in opencv3.4.1 -#if (CV_MAJOR_VERSION < 3) - int patchSize = pFeatDetector->getInt("patchSize"); -#else - int patchSize = pFeatDetector->descriptorSize(); -#endif - int halfPatchSize = patchSize / 2; - vector umax; - genUMax(umax, halfPatchSize); - - for (int i = 0; i < 360; ++i) - { - Mat trans = getRotationMatrix2D(cen, i, 1.0); - Mat transedImg; - warpAffine(img, transedImg, trans, Size(img.cols, img.rows)); - computeOrientation(img, vec, halfPatchSize, umax); - } -} - -double localIC_Angle(const Mat& img, Point2f center, int patchSize) -{ - int halfPatchSize = patchSize / 2; - vector umax; - genUMax(umax, halfPatchSize); - - return IC_Angle(img, halfPatchSize, center, umax); -} - -double localAngle_WeightedCen(const Mat& img, Point2f center) -{ -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vImg = img/255.0; -#endif - Point2f weightedCen(0, 0); - float sum = 0; - for (int y = 0; y < img.rows; ++y) - { - float* pRowData = (float*)img.row(y).data; - for (int x = 0; x < img.cols; ++x) - { - float val = pRowData[x]; - if (val == 0) - { - continue; - } - weightedCen.x += x*val; - weightedCen.y += y*val; - sum += val; - } - } - weightedCen.x /= sum; - weightedCen.y /= sum; - - weightedCen = weightedCen - center; - - return fastAtan2(weightedCen.y, weightedCen.x); -} - -double localAngle_(const Mat& img, Point2f center, Mat mask) -{ -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vImg = img / 255.0; -#endif - Scalar meanScalar, stddevScalar; - meanStdDev(img, meanScalar, stddevScalar, mask); - Mat meanNormImg = img - meanScalar.val[0]; - float thre = stddevScalar.val[0] * 4; - meanNormImg.setTo(0, meanNormImg < thre); - meanNormImg.setTo(1, meanNormImg > thre); - return localAngle_WeightedCen(meanNormImg, center); -} - -void upperMajorityMask(const Mat& img, Mat& mask, float majority) -{ - Mat hist; - majorityHistUpper(img, Mat(), hist, majority); - float* pHistData = (float*)hist.data; - int histSize = hist.rows > hist.cols ? hist.rows : hist.cols; - float* pEndHistData = pHistData + histSize; - int idx = 0; - while (pHistData != pEndHistData) - { - if (*pHistData) - { - break; - } - idx++; - pHistData++; - } - mask = (img >= idx); -} - -void lowerMajorityHist(const Mat& img, const Mat& mask, Mat& hist, float majority) -{ - hist = calcHist(img, mask); - - // suppose there is only one peak - float* pHistData = (float*)hist.data; - float curRatio = 1.0; - int totalNum = sum(hist).val[0]; - - float* pFront = pHistData; - float* pTail = pHistData + 254; - while (pFront != pTail) - { - if (*pTail == 0) - { - pTail--; - continue; - } - - { - curRatio -= *pTail / totalNum; - *pTail = 0; - pTail--; - } - if (curRatio <= majority) - { - break; - } - } - -} - -void majorityHistLower(const Mat& img, const Mat& mask, Mat& hist, float majority) -{ - hist = calcHist(img, mask); - - // suppose there is only one peak - float* pHistData = (float*)hist.data; - float curRatio = 1.0; - int totalNum = sum(hist).val[0]; - - float* pFront = pHistData; - float* pTail = pHistData + 254; - while (pFront != pTail) - { - if (*pTail == 0) - { - pTail--; - continue; - } - - { - curRatio -= *pTail / totalNum; - *pTail = 0; - pTail--; - } - if (curRatio <= majority) - { - break; - } - } - -} - -void majorityHistUpper(const Mat& img, const Mat& mask, Mat& hist, float majority) -{ - hist = calcHist(img, mask); - - // suppose there is only one peak - float* pHistData = (float*)hist.data; - float curRatio = 1.0; - int totalNum = sum(hist).val[0]; - - float* pFront = pHistData; - float* pTail = pHistData + 254; - while (pFront != pTail) - { - if (*pFront == 0) - { - pFront++; - continue; - } - - { - curRatio -= *pFront / totalNum; - *pFront = 0; - pFront++; - } - if (curRatio <= majority) - { - break; - } - } - -} -void majorityHist(const Mat& img, const Mat& mask, Mat& hist, float majority) -{ - hist = calcHist(img, mask); - - // suppose there is only one peak - float* pHistData = (float*)hist.data; - float curRatio = 1.0; - int totalNum = sum(hist).val[0]; - - float* pFront = pHistData; - float* pTail = pHistData + 254; - while (pFront != pTail) - { - if (*pFront == 0) - { - pFront++; - continue; - } - if (*pTail == 0) - { - pTail--; - continue; - } - if (*pFront < *pTail) - { - curRatio -= *pFront / totalNum; - *pFront = 0; - pFront++; - } - else - { - curRatio -= *pTail / totalNum; - *pTail = 0; - pTail--; - } - if (curRatio <= majority) - { - break; - } - } - - -} - -Mat lowerMajorityMask(const Mat& img, const Mat& mask, float majority) -{ - Mat hist; - lowerMajorityHist(img, mask, hist, majority); - float* pHistData = (float*)hist.data; - - Mat ret = mask.clone(); - - for (int i = 0; i < img.rows; ++i) - { - uchar* pRowData = (uchar*)img.row(i).data; - uchar* pMaskRowData = (uchar*)ret.row(i).data; - for (int j = 0; j < img.cols; ++j) - { - uchar val = pRowData[j]; - if (!pHistData[val]) - { - pMaskRowData[j] = 0; - } - } - } - - return ret; -} - -void meanStdDev(const Mat& img, const Mat& mask, - double* pMean, double* pStdDev, float majority, int type) -{ - Mat hist; - switch (type) - { - default: - case 0: - majorityHist(img, mask, hist, majority); - break; - case 1: - majorityHistLower(img, mask, hist, majority); - break; - case 2: - majorityHistUpper(img, mask, hist, majority); - break; - } - - // suppose there is only one peak - Mat rowHist;// = toRowVec(hist); - float* pHistData = (float*)rowHist.data; - - histMeanStddev(rowHist, pMean, pStdDev); -} - -float interpolate(float* pY, int n, float stepX, float x) -{ - int lIdx = (int)(x/stepX); - int rIdx = lIdx + 1; - if (rIdx > n - 1) - { - return pY[n - 1]; - } - assert(lIdx >= 0 && lIdx < n && rIdx >= 0 && rIdx < n); - float s = (x - lIdx*stepX)/stepX; - float ly = pY[lIdx]; - float ry = pY[rIdx]; - return ly + (ry - ly)*s; -} - -cv::Mat cocentricNorm(const Mat& img, Point2f center, const Mat& weightMat, float dstMeanVal) -{ - assert(weightMat.empty() || weightMat.type() == CV_32FC1); - - int w = img.cols; - int h = img.rows; - vector corners; - corners.push_back(Point2f(0, 0)); - corners.push_back(Point2f(0, h)); - corners.push_back(Point2f(w, h)); - corners.push_back(Point2f(w, 0)); - vector cornerDisVec; - for_each(corners.begin(), corners.end(), [&](const Point2f& pt) - { - double dis = pointDis(center, pt); - cornerDisVec.push_back(dis); - }); - - auto farthestCornerDis = max_element(cornerDisVec.begin(), cornerDisVec.end()); - float maxRadius = *farthestCornerDis; - - int radiusNum = floorf(maxRadius); - //radiusNum = 20; - float radiusStep = (maxRadius / radiusNum); - Mat cocentricSumMat = Mat::zeros(1, radiusNum, CV_32FC1); - float* pSumData = (float*)cocentricSumMat.data; - Mat cocentricWeightSumMat = Mat::zeros(1, radiusNum, CV_32FC1); - float* pWeightSumData = (float*)cocentricWeightSumMat.data; - Mat radiusMat(img.rows, img.cols, CV_32FC1); - - for (int y = 0; y < h; y++) - { - const Mat& imgRow = img.row(y); - float* pImgRowData = (float*)imgRow.data; - float* pRadiusRowData = (float*)radiusMat.row(y).data; - - float* pWeightRowData = NULL; - if (!weightMat.empty()) - { - pWeightRowData = (float*)weightMat.row(y).data; - } - - for (int x = 0; x < w; x++) - { - //std::cout << x << " " << y << std::endl; - float weight; - if (pWeightRowData) - { - weight = pWeightRowData[x]; - } - else - { - weight = 1.0; - } - float val = pImgRowData[x] * weight; - float radius = pointDis(Point2f(x, y), center); - pRadiusRowData[x] = radius; - int radiusIdx0 = (int)(radius / radiusStep); - assert(radiusIdx0 >= 0); - int radiusIdx1 = radiusIdx0 + 1; - if (radiusIdx0 >= radiusNum - 1) - { - pSumData[radiusNum - 1] += val; - pWeightSumData[radiusNum - 1] += weight; - } - else - { - float s = (radius - radiusStep*radiusIdx0) / radiusStep; - pSumData[radiusIdx0] += val*s; - pSumData[radiusIdx1] += val*(1 - s); - pWeightSumData[radiusIdx0] += s*weight; - pWeightSumData[radiusIdx1] += (1 - s)*weight; - } - } - } - - for (int i = 0; i < radiusNum; ++i) - { - //float radius = (i*radiusStep + radiusStep) / 2; - if (pWeightSumData[i] == 0) - { - - } - else - { - pSumData[i] /= pWeightSumData[i]; - } - } - - Mat retMat = Mat::zeros(img.rows, img.cols, img.type()); - Mat normMask = Mat::zeros(img.rows, img.cols, img.type()); - for (int y = 0; y < h; y++) - { - float* pImgRowData = (float*)img.row(y).data; - float* pRetRowData = (float*)retMat.row(y).data; - float* pRadiusData = (float*)radiusMat.row(y).data; - float *pNormData = (float *)normMask.row(y).data; - for (int x = 0; x < w; x++) - { - float val = pImgRowData[x]; - float radius = pRadiusData[x]; - float mean = interpolate(pSumData, radiusNum, radiusStep, radius); - if (mean == 0) - { - continue; - } - float newVal = (float)val * dstMeanVal / mean; - - // if (newVal - dstMeanVal > -30) - //{ - pRetRowData[x] = newVal; - //pNormData[x] = 255; - // } - //else - //{ - // continue; - //} - - } - } - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat viewRetMat = retMat/255.0; -#endif - /*Mat retNromMask = normMask.mul(retMat); - Mat normTest = retNromMask / 255.0;*/ - - return retMat; - //return normTest; -} - -cv::Mat meanNorm(const Mat& img, const Mat& mask, float dstMeanVal, float majority /*= 1.0*/, PixelSelectionMethod method /*= LP_PIXEL_SELECT_ALL*/) -{ - double meanVal = 0; - if (method == LP_PIXEL_SELECT_ALL) - { - meanVal = mean(img, mask).val[0]; - } - else if (method == LP_PIXEL_SELECT_MAJORITY_FAST || - method == LP_PIXEL_SELECT_MAJORITY) - { - meanStdDev(img, mask, &meanVal, NULL, majority); - } - return img + (int)(dstMeanVal - meanVal); -} - -// cv::Mat getRoiImg(const Mat& img, vector ptVec, int radius) -// { -// Rect defectRoi(genRectCenRadius(ptVec, radius)); -// -// defectRoi &= Rect(0, 0, img.cols, img.rows); -// return Mat(img, defectRoi); -// } -// -// cv::Mat getRoiImg(const Mat& img, Point2i cen, int radius) -// { -// Rect defectRoi(genRectCenRadius(cen, radius)); -// -// defectRoi &= Rect(0, 0, img.cols, img.rows); -// return Mat(img, defectRoi); -// } - -cv::Mat filterY(const Mat& img, float* kernel, int size, int ddepth /*= CV_32FC1*/) -{ - Mat kernelMat(size, 1, CV_32FC1, kernel); - - Mat ret; - cv::filter2D(img, ret, ddepth, kernelMat); - - return ret; -} - -float circleDegree(const vector& contour) -{ - Rect br = boundingRect(contour); - float r = sqrt((float)(br.width*br.width / 4 + br.height*br.height / 4)); - float circleArea = CV_PI*r*r; - float area = contourArea(contour); - if (circleArea < 0.00001) - { - return 0; - } - return area / circleArea; -} - -float lpContourArea(const vector& contour) -{ - double area = 0; - if (contour.size() == 1) - { - area = 1; - } - else if (contour.size() != 0) - { - area = contourArea(contour); - area += arcLength(contour, true); - } - return area; -} - -cv::Mat minMaxNorm(const Mat& img, double tarMin, double tarMax, const Mat& mask /*= Mat()*/) -{ - double minVal, maxVal; - minMaxIdx(img, &minVal, &maxVal, 0, 0, mask); - double s = ((tarMax - tarMin) / (maxVal - minVal)); - return img * s + (tarMin - minVal * s); -} - -double longShortRatio(const Size& s) -{ - if (s.width > s.height) - { - if (s.height < 0.000001) - { - return 0; - } - return (double)s.width / (double)s.height; - } - else - { - if (s.width < 0.000001) - { - return 0; - } - return (double)s.height / (double)s.width; - } -} - -void closeShapesToConvex(const Mat& mask, Mat& closedMask) -{ - closedMask.create(mask.rows, mask.cols, mask.type()); - closedMask.setTo(0); - - Mat canvas; - mask.copyTo(canvas); - vector< vector > contours; - findContours(canvas, contours, RETR_LIST, cv::CHAIN_APPROX_NONE); - vector< vector > convextContours; - for (size_t i = 0; i < contours.size(); ++i) - { - const vector& contour = contours[i]; - vector convexContour; - convexHull(contour, convexContour); - convextContours.push_back(convexContour); - } - fillPoly(closedMask, convextContours, Scalar(255, 255, 255)); -} - -cv::Mat genCircleMask(int rows, int cols, int type, - Point cen, double r, const Scalar& color, int thickness, int lineType /*= 8*/, int shift /*= 0*/) -{ - Mat mask = Mat::zeros(rows, cols, type); - circle(mask, cen, r, color, thickness, lineType, shift); - return mask; -} - -void openOper(Mat& img, int w) -{ - Mat kernel(w, w, CV_8UC1); - kernel.setTo(1); - openOper(img, kernel); -} - -void openOper(Mat& img, const Mat& kernel) -{ - erode(img, img, kernel); - dilate(img, img, kernel); -} - -void closeOper(Mat& img, int w) -{ - Mat kernel(w, w, CV_8UC1); - kernel.setTo(1); - closeOper(img, kernel); -} - -void closeOper(Mat& img, const Mat& kernel) -{ - dilate(img, img, kernel); - erode(img, img, kernel); -} - -CV_WRAP GroupMatcher::GroupMatcher( - int normType /*= NORM_L2*/, bool crossCheck /*= false*/) - : BFMatcher(normType, crossCheck) -{ - -} - -Ptr GroupMatcher::clone(bool emptyTrainData /*= false*/) const -{ - return new GroupMatcher(); -} - -// no longer supported in opencv3.4.1 -#if (CV_MAJOR_VERSION < 3) -AlgorithmInfo* GroupMatcher::info() const -{ - return NULL; -} -#endif - -void GroupMatcher::knnMatchImpl(const Mat& queryDescriptors, - vector >& matches, - int k, - const vector& masks /*= vector()*/, - bool compactResult /*= false*/) -{ - BFMatcher::knnMatchImpl(queryDescriptors, matches, k, masks, - compactResult); - - -} - -void GroupMatcher::radiusMatchImpl(const Mat& queryDescriptors, - vector >& matches, - float maxDistance, - const vector& masks /*= vector()*/, - bool compactResult /*= false*/) -{ - BFMatcher::radiusMatchImpl(queryDescriptors, - matches, maxDistance, masks, compactResult); -} - - -Mat getContourBoundedRoiImg(const Mat& src, const vector& contour, Rect* pRoiRect /* = NULL*/) -{ - Rect cr = boundingRect(contour); - Mat cmask(cr.height, cr.width, CV_8UC1); - cmask.setTo(0); - cv::fillPoly(cmask, vector< vector >(1, contour), Scalar(255, 255, 255), 8, 0, cr.tl()*(-1.0)); - Mat localMask; - Mat(src, cr).copyTo(localMask); - if (pRoiRect) - { - *pRoiRect = cr; - } - return localMask & cmask; -} - -void filterContours(const vector< vector >& contours, const Mat& srcImg, - vector< vector >& filteredContours, - int minArea, double minLength, double minLongShortRatio, - double maxCircleDegree, vector* pAreaMaxContour) -{ - int areaMaxIdx = -1; - double maxarea = -1; - for (int j = 0; j < contours.size(); ++j) - { - const vector& contour = contours[j]; - if (contour.size() < 5) - { - continue; - } - - int area = -1; - if (!srcImg.empty()) - { - Mat localMask = getContourBoundedRoiImg(srcImg, contour); - area = countNonZero(localMask); - } - else - { - area = contourArea(contour); - } - - RotatedRect rr = minAreaRect(contour); - - double l = max(rr.size.width, rr.size.height); - if (area < minArea && l < minLength) - { - continue; - } - - double cd = circleDegree(contour); - if (cd > maxCircleDegree) - { - continue; - } - - double lsr = longShortRatio(rr.size); - if (lsr < minLongShortRatio) - { - continue; - } - - if (area > maxarea) - { - maxarea = area; - areaMaxIdx = j; - } - - filteredContours.push_back(contour); - } - - if (areaMaxIdx >= 0 && pAreaMaxContour) - { - *pAreaMaxContour = contours[areaMaxIdx]; - } -} - -void filterContours(Mat hsvColorThresImg, - int minArea, double minLength, double minLongShortRatio, - double maxCircleDegree, vector* pAreaMaxContour /*= NULL*/) -{ - vector< vector > contours; - Mat canvas = hsvColorThresImg.clone(); - findContours(canvas, contours, RETR_LIST, CHAIN_APPROX_NONE); - canvas.setTo(0); - - vector< vector > filteredContours; - filterContours(contours, hsvColorThresImg, filteredContours, - minArea, minLength, minLongShortRatio, maxCircleDegree, pAreaMaxContour); - - // redraw - cv::fillPoly(canvas, filteredContours, Scalar(255, 255, 255)); - hsvColorThresImg &= canvas; -} - - -int filterSmallAndFindMaxContours(vector< vector >& contours, double minArea) -{ - vector< vector > filteredContours; - int maxindex = -1; - double maxarea = -1; - for (int j = 0; j < contours.size(); ++j) - { - const vector& contour = contours[j]; - double area = contourArea(contour); - if (area > minArea) - { - filteredContours.push_back(contour); - } - - if (area > maxarea) - { - maxarea = area; - maxindex = j; - } - } - contours = filteredContours; - return maxindex; -} - - -void filterContours(Mat& img, double minArea) -{ - Mat canvas; - img.copyTo(canvas); - - vector< vector > contours; - findContours(canvas, contours, RETR_LIST, cv::CHAIN_APPROX_NONE); - filterSmallAndFindMaxContours(contours, minArea); - canvas.setTo(0); - cv::fillPoly(canvas, contours, Scalar(255, 255, 255)); - - img = canvas; -} - - -Mat genInRangeMask(const Mat& src, std::map>& colorRanges) -{ - Mat mask = Mat::zeros(src.rows, src.cols, CV_8UC1); - - for (auto iter = colorRanges.begin(); iter != colorRanges.end(); ++iter) - { - int key = iter->first; - Scalar low = iter->second.first; - Scalar high = iter->second.second; - Mat imgThresholded; - inRange(src, low, high, imgThresholded); - mask |= imgThresholded; - } - - return mask; -} - -void localCloseOper(Mat& img, vector< vector >& contours, float longerScale) -{ - Mat tmp = img.clone(); - for (int i = 0; i < contours.size(); ++i) - { - const vector& contour = contours[i]; - RotatedRect rr = minAreaRect(contour); - int longer = cv::max(rr.size.width, rr.size.height)*longerScale; - - Rect br = boundingRect(contour); - br.x -= longer*1.5; - br.y -= longer*1.5; - br.width += longer * 3; - br.height += longer * 3; - - br.x = cv::max(0, br.x); - br.y = cv::max(0, br.y); - br.width = cv::min(img.cols - br.x - 1, br.width); - br.height = cv::min(img.rows - br.y - 1, br.height); - - Mat roiMat = Mat(img, br).clone(); - closeOper(roiMat, Mat::ones(longer, 1, CV_8UC1)); - br.x -= 1; - br.y -= 1; - br.x = cv::max(0, br.x); - br.y = cv::max(0, br.y); - - roiMat.copyTo(Mat(tmp, br)); - } - img |= tmp; -} - -Mat genWithCopiedCols(const Mat& m, int multiples = 3) -{ - Mat ret(m.rows, m.cols * multiples, m.type()); - for (int i = 0; i < multiples; ++i) - { - m.copyTo(ret.colRange(i*m.cols, i*m.cols + m.cols)); - } - return ret; -} - - - -double matDisWithReversedRows(const Mat& m0, const Mat& m1) -{ - assert(m0.rows == m1.rows); - assert(m0.cols == m1.cols); - - int rows = m0.rows; - int cols = m0.cols; - - Mat rowDisVec(rows, 1, CV_64FC1); - double* pRowDisVec = (double*)rowDisVec.data; - for (int i = 0; i < rows; ++i) - { - Mat row0 = 255 - m0.row(i); - Mat row1 = 255 - m1.row(rows - i - 1); - //Mat weightedRow0 = 255 - row0; - //*pRowDisVec = ((row0 - row1).dot(weightedRow0)); - Mat row0f; - row0.convertTo(row0f, CV_32FC1); - Mat row1f; - row1.convertTo(row1f, CV_32FC1); - *pRowDisVec = compareHist(row0f, row1f, CV_COMP_CORREL); - pRowDisVec++; - } - - Mat kernel = cv::getGaussianKernel(rows * 2, 1).rowRange(rows, rows * 2); - - return rowDisVec.dot(kernel); -} - -double matDis(const Mat& m0, const Mat& m1) -{ - assert(m0.rows == m1.rows); - assert(m0.cols == m1.cols); - - int rows = m0.rows; - int cols = m0.cols; - - Mat rowDisVec(rows, 1, CV_64FC1); - double* pRowDisVec = (double*)rowDisVec.data; - for (int i = 0; i < rows; ++i) - { - Mat row0 = 255 - m0.row(i); - Mat row1 = 255 - m1.row(i); - - Mat row0f; - row0.convertTo(row0f, CV_32FC1); - Mat row1f; - row1.convertTo(row1f, CV_32FC1); - *pRowDisVec = compareHist(row0f, row1f, CV_COMP_CORREL); - pRowDisVec++; - } - - Mat kernel = cv::getGaussianKernel(rows * 2, 1).rowRange(rows, rows * 2); - - return rowDisVec.dot(kernel); -} - -int searchBestMatchDx(int searchRadius, int startCol, int endCol, const Mat& curRow, const Mat& preRowMid) -{ - vector valVec; - for (int dx = -searchRadius; dx <= searchRadius; dx++) - { - int curStartCol = startCol + dx; - int curEndCol = endCol + dx; - Mat curRowMid = curRow.colRange(curStartCol, curEndCol); - double val = -matDisWithReversedRows(curRowMid, preRowMid); - valVec.push_back(val); - } - auto minIter = std::min_element(valVec.begin(), valVec.end()); - int bestDx = minIter - valVec.begin() - searchRadius; - - return bestDx; -} - -Mat searchBestMatchSubRowMat(const Mat& img, int startRow, int rowWidth, int searchRadius, const Mat& preRowMid) -{ - Mat curRow = genWithCopiedCols(img.rowRange(startRow, rowWidth + startRow), 3); - int startCol = img.cols; - int endCol = img.cols * 2; - - int bestDx = searchBestMatchDx(searchRadius, startCol, endCol, curRow, preRowMid); - - return curRow.colRange(startCol + bestDx, endCol + bestDx); -} - -void xEnergeyMat(const Mat& img, Mat& energyMat, - int kernelWidth = 12, int backgroundThre = 40, int method = 2) -{ - switch (method) - { - case 0: - { - // sobel edge - Mat sobelMat; - cv::Sobel(img, sobelMat, CV_32FC1, 1, 0); - sobelMat = cv::abs(sobelMat); - energyMat = sobelMat; - } - break; - case 1: - { - // edge with first derivative - Mat kernel = cv::getGaussianKernel(kernelWidth, 4).t(); - Mat halfKernel(kernel.colRange(0, kernel.cols / 2)); - halfKernel *= -1.0; - filter2D(img, energyMat, CV_32FC1, kernel); - energyMat = abs(energyMat); - } - break; - case 2: - { - // edge with second derivative - Mat kernel = cv::getGaussianKernel(kernelWidth, 4).t(); - Mat halfKernel(kernel.colRange(0, kernel.cols / 2)); - halfKernel *= -1.0; - filter2D(img, energyMat, CV_32FC1, kernel); - energyMat = abs(energyMat); - - Mat secondEnergyMat; - filter2D(energyMat, secondEnergyMat, CV_32FC1, kernel); - secondEnergyMat = abs(secondEnergyMat); - - energyMat = secondEnergyMat; - } - break; - case 3: - { - // darker edge with first derivative - Mat kernel = cv::getGaussianKernel(kernelWidth, 4).t(); - Mat gaussMat; - filter2D(img, gaussMat, CV_32FC1, kernel); - gaussMat = 255.0 - gaussMat; - Mat halfKernel(kernel.colRange(0, kernel.cols / 2)); - halfKernel *= -1.0; - filter2D(img, energyMat, CV_32FC1, kernel); - energyMat = abs(energyMat) + gaussMat*0.2; - } - case 4: - { - // darker edge with thresholding - Mat threMat = img < backgroundThre; - converToType(threMat, CV_32FC1); - - Mat kernel = cv::getGaussianKernel(kernelWidth, 4).t(); - - Mat halfKernel(kernel.colRange(0, kernel.cols / 2)); - halfKernel *= -1.0; - filter2D(img, energyMat, CV_32FC1, kernel); - energyMat = abs(energyMat) + threMat; - } - break; - } -} - -void findBoundaryY(const Mat& img, vector& vec, vector& energyVec, - int gradientKernelWidth = 12, - int smoothKernelWidth = 32, - float smoothWeight = 3.0, - int backgroundThre = 40, - int energyType = 4) -{ - // generate energy mat (sobel) - Mat energyMat; - xEnergeyMat(img, energyMat, gradientKernelWidth, backgroundThre, energyType); - - int n = 4; - Mat energyMatBack = energyMat.clone(); - - Mat smoothImg, showMat; - { - Mat kernel = cv::getGaussianKernel(smoothKernelWidth, 4.0).t(); - filter2D(img, smoothImg, CV_32FC1, kernel); - } - - float w = pow(10, smoothWeight); - dynamicProgramYWithSmooth(energyMat, n, w/255.0, smoothImg); - findMaxYPath(energyMat, vec, energyVec, n); - - recoverPathEnergy(energyVec); -} - -void findBoundaryY(const Mat& img0, const Mat& img1, int targetWidth, - vector& vec, vector& energyVec) -{ - // generate energy mat - Mat energyMat0, energyMat1; - xEnergeyMat(img0, energyMat0); - xEnergeyMat(img1, energyMat1); - - // generate smooth mat (gauss) - Mat smoothImg0, smoothImg1, showMat; - { - Mat kernel = cv::getGaussianKernel(31, 4.0).t(); - filter2D(img0, smoothImg0, CV_32FC1, kernel); - filter2D(img1, smoothImg1, CV_32FC1, kernel); - } - - int n = 4; - float sw = 100.0 / 255.0; - dynamicProgramYWithSmooth(energyMat0, energyMat1, - smoothImg0, smoothImg1, targetWidth, n, sw); - - findMaxYPath(energyMat0, vec, energyVec, n); - - recoverPathEnergy(energyVec); -} - -// assuming with two boundaries (left and right) -void autoAlignEachRowGloballyWithIndependentBoundaries(Mat& img) -{ - // divide into two part: left and right - Mat leftImg(img.colRange(0, img.cols / 2)); - Mat rightImg(img.colRange(img.cols / 2, img.cols)); - - // search a boundary for each part - vector leftVec, rightVec; - vector leftEnergyVec, rightEnergyVec; - findBoundaryY(leftImg, leftVec, leftEnergyVec); - findBoundaryY(rightImg, rightVec, rightEnergyVec); - - // draw path - Mat canvas = img.clone(); - drawPointsY(leftVec, canvas, 0, 0, 255); - drawPointsY(rightVec, canvas, canvas.cols / 2, 0, 255); - - // align centers of each row - int rightBaseX = img.cols / 2; - int centerX = (leftVec[0] + rightVec[0] + rightBaseX) / 2; - Mat ret = img.clone(); - ret.setTo(0); - - // move each row to align - for (int i = 0; i < img.rows; ++i) - { - int curCenterX = (leftVec[i] + rightVec[i] + rightBaseX) / 2; - int dx = centerX - curCenterX; - Mat curRow = genWithCopiedCols(img.row(i), 3); - curRow.colRange(img.cols - dx, img.cols * 2 - dx).copyTo(ret.row(i)); - } - - ret.copyTo(img); -} - -void autoAlignEachRowWithWeightedXCen(Mat& img, int tarCenX, vector& dxVec) -{ - dxVec.resize(img.rows, 0); - - for (int i = 0; i < img.rows; ++i) - { - Mat r = img.row(i); - uchar* p = r.data; - uchar* ep = p + r.cols; - int j = 0; - float wx = 0; - float ws = 0; - while (p != ep) - { - float w = (*p) * (*p); - ws += w; - wx += j*w; - j++; - p++; - } - wx /= ws; - int dx = floorf(tarCenX - wx); - dxVec[i] = dx; - } - - alignEachRow(img, dxVec); -} - -void alignEachRow(Mat& img, const vector& dxVec) -{ - Mat ret = img.clone(); - ret.setTo(0); - - for (int i = 0; i < img.rows; ++i) - { - Mat curRow = genWithCopiedCols(img.row(i), 3); - int dx = dxVec[i]; - curRow.colRange(img.cols - dx, img.cols * 2 - dx).copyTo(ret.row(i)); - } - - ret.copyTo(img); -} - -void autoAlignEachRowGloballyWithWidthConstraint(Mat& img, int tarCenX, vector& dxVec) -{ - // divide into two part: left and right - Mat leftImg(img.colRange(0, img.cols / 2)); - Mat rightImg(img.colRange(img.cols / 2, img.cols)); - - // search a boundary for each part - vector leftVec, rightVec; - vector leftEnergyVec, rightEnergyVec; - findBoundaryY(leftImg, leftVec, leftEnergyVec); - findBoundaryY(rightImg, rightVec, rightEnergyVec); - - // draw path - Mat canvas = img.clone(); - drawPointsY(leftVec, canvas, 0, 0, 255); - drawPointsY(rightVec, canvas, canvas.cols / 2, 0, 255); - - float avrLeft = sum(leftVec.begin(), leftVec.end()) / leftVec.size(); - float avrRight = sum(rightVec.begin(), rightVec.end()) / rightVec.size(); - int tarWidth = avrRight + leftImg.cols - avrLeft; - - leftVec.clear(); - leftEnergyVec.clear(); - findBoundaryY(leftImg, rightImg, tarWidth, leftVec, leftEnergyVec); - - rightVec = leftVec; - add(rightVec.begin(), rightVec.end(), tarWidth); - - drawPointsY(leftVec, canvas, 0, 0, 180); - drawPointsY(rightVec, canvas, 0, 0, 180); - - // align centers of each row - int centerX = leftVec[0] + tarWidth / 2; - if (tarCenX >= 0) - { - centerX = tarCenX; - } - Mat ret = img.clone(); - ret.setTo(0); - - // move each row to align - dxVec.resize(img.rows, 0); - for (int i = 0; i < img.rows; ++i) - { - int curCenterX = leftVec[i] + tarWidth / 2; - int dx = centerX - curCenterX; - dxVec[i] = dx; - Mat curRow = genWithCopiedCols(img.row(i), 3); - curRow.colRange(img.cols - dx, img.cols * 2 - dx).copyTo(ret.row(i)); - } - - ret.copyTo(img); -} - -void autoAlignEachRowLocally(Mat& img, int searchRadius /*= 5*/, int rowWidth /*= 1*/, const Mat& preImg /*= Mat()*/) -{ - Mat ret = img.clone(); - ret.setTo(0); - - Mat preRow; - if (!preImg.empty()) - { - preRow = genWithCopiedCols(preImg.rowRange(0, rowWidth), 3); - } - else - { - preRow = genWithCopiedCols(img.rowRange(0, rowWidth), 3); - } - - Mat preRowMid = preRow.colRange(img.cols, img.cols * 2); - if (!preImg.empty()) - { - preRowMid = searchBestMatchSubRowMat(img, 0, rowWidth, searchRadius, preRowMid); - } - preRowMid.copyTo(ret.rowRange(0, rowWidth)); - - for (int i = rowWidth; i <= img.rows - rowWidth; i += rowWidth) - { - preRowMid = searchBestMatchSubRowMat(img, i, rowWidth, searchRadius, preRowMid); - - preRowMid.copyTo(ret.rowRange(i, i + rowWidth)); - } - - ret.copyTo(img); -} - -void autoAlignEachRowWithAutoThreshold(Mat& img, int tarCenX, vector& dxVec) -{ - dxVec.resize(img.rows, 0); - - for (int i = 0; i < img.rows; ++i) - { - Mat row(img.row(i)); - Mat trow; - threshold(row, trow, 0, 255, THRESH_OTSU); - uchar* p = trow.data; - uchar* ep = p + trow.cols; - int l, r; - while (p != ep) - { - if (*p) - { - l = p - trow.data; - break; - } - p++; - } - p = ep - 1; - do - { - if (*p) - { - r = p - trow.data; - break; - } - p--; - } while (p != trow.data); - int curCenX = floorf((l + r) / 2.0); - dxVec[i] = tarCenX - curCenX; - } - - alignEachRow(img, dxVec); -} - -void alignEachRowRightBound(Mat& img, int tarCen, vector& dxVec, - int gradientKernelWidth /*= 12*/, - int smoothBoundaryKernelWidth /*= 32*/, - float smoothBoundaryWeight /*= 3.0*/, - int backgroundThre /*= 40*/) -{ - // right part - Mat rightImg(img.colRange(img.cols / 2, img.cols)); - - // search a boundary - vector rightVec; - vector rightEnergyVec; - findBoundaryY(rightImg, rightVec, rightEnergyVec, gradientKernelWidth, - smoothBoundaryKernelWidth, smoothBoundaryWeight, backgroundThre); - - // draw path - Mat canvas = img.clone(); - drawPointsY(rightVec, canvas, canvas.cols / 2, 0, 255); - - // align centers of each row - int rightBaseX = img.cols / 2; - int centerX = tarCen; - Mat ret = img.clone(); - ret.setTo(0); - - // move each row to align - for (int i = 0; i < img.rows; ++i) - { - int dx = img.cols - rightVec[i] - rightBaseX - 1; - dxVec.push_back(dx); - Mat curRow = genWithCopiedCols(img.row(i), 3); - curRow.colRange(img.cols - dx, img.cols * 2 - dx).copyTo(ret.row(i)); - } - - ret.copyTo(img); -} - -cv::Mat genDirColorImg(const Mat& img, Mat* pValueMat /*= NULL*/) -{ - Mat hsvImg(img.rows, img.cols, CV_8UC3); - vector channels(3); - channels[0] = img; - channels[1] = Mat::zeros(img.rows, img.cols, CV_8UC1); - channels[2] = channels[1]; - channels[1].setTo(255); - if (pValueMat) - { - channels[2] = *pValueMat; - } - else - { - channels[2].setTo(255); - } - merge(channels, hsvImg); - Mat rgbImg; - cvtColor(hsvImg, rgbImg, COLOR_HSV2BGR); - return rgbImg; -} - -void genSobelDir(Mat& img) -{ - Mat srcImg = img.clone(); - Mat sobelX, sobelY; - genSobelImage(srcImg, &sobelX, &sobelY); - img = genSobelDir(sobelX, sobelY); -} - -cv::Mat genSobelDir(const Mat& sobelX, const Mat& sobelY) -{ - Mat img(sobelX.rows, sobelX.cols, CV_8UC1); - for (int i = 0; i < img.rows; ++i) - { - Mat row = img.row(i); - float* pDataX = (float*)sobelX.row(i).data; - float* pDataY = (float*)sobelY.row(i).data; - uchar* pData = row.data; - for (int j = 0; j < img.cols; ++j) - { - float dx = pDataX[j]; - float dy = pDataY[j]; - float angle = 0; - if (dx == 0 && dy == 0) - { - angle = 0; - } - else - { - angle = atan2f(dy, dx); - if (angle < 0) - { - angle += 2.0 * M_PI; - } - } - pData[j] = floorf((angle / M_PI) * 90); - } - } - return img; -} - -void genContrastImg(const Mat& img, Mat& contrastImg, const Mat& kernelMat) -{ - Mat maxMat, minMat; - dilate(img, maxMat, kernelMat); - erode(img, minMat, kernelMat); - - contrastImg = maxMat - minMat; -} - -void genContrastImg(const Mat& img, Mat& contrastImg, int ksize) -{ - Mat kernelMat(ksize, ksize, CV_8UC1); - genContrastImg(img, contrastImg, kernelMat); -} - -void genYContrastImg(const Mat& img, Mat& constrastImg, int ksize) -{ - Mat kernelMat(ksize, 1, CV_8UC1); - genContrastImg(img, constrastImg, kernelMat); -} - -void genHalfContrastImg(const Mat& img, Mat& contrastImg, const Mat& kernelMat) -{ - assert(img.type() == CV_8UC1); - - uchar* pData = img.data; - int wstep = img.step; - int kernelXStep = kernelMat.cols; - int kernelYStep = kernelMat.rows; - - contrastImg.create(img.rows / kernelXStep, img.cols / kernelYStep, CV_8UC1); - uchar* pContrastData = contrastImg.data; - int wContrastStep = contrastImg.step; - - for (int y = 0; y < img.rows; y += kernelYStep) - { - uchar* pRowData = pData; - uchar* pContrastRowData = pContrastData; - for (int x = 0; x < img.cols; x += kernelXStep) - { - Mat roiMat(kernelMat.rows, kernelMat.cols, CV_8UC1, pRowData); - roiMat.step = wstep; - - - - pRowData += kernelXStep; - pContrastRowData += 1; - } - pData += wstep*kernelYStep; - pContrastData += wContrastStep; - } -} - -void genHalfContrastImg(const Mat& img, Mat& contrastImg, int ksize) -{ - -} - -void cvtColor(Mat& img, int t) -{ - Mat tImg; - cvtColor(img, tImg, t); - img = tImg; -} - -cv::Mat rotateImage(const Mat& img, Point2f cen, float degree) -{ - Mat t = getRotationMatrix2D(cen, degree, 1.0); - Mat rImg; - warpAffine(img, rImg, t, img.size(), INTER_CUBIC, BORDER_CONSTANT); - return rImg; -} - -cv::Mat normAngle(const Mat& img, Mat mask) -{ - Point2f cen(img.cols / 2.0, img.rows / 2.0); - double angle = localAngle_(img, cen, mask); - return rotateImage(img, cen, -angle); -} - -float normAngle(float angle) -{ - angle = angle - (int)(angle / 360.0) * 360; - if (angle < 0) - { - angle += 360.0; - } - return angle; -} - -void printMatInfo(const Mat& m, int baseIndentNum /*= 0*/, int indent /*= 4*/) -{ - printIndent(baseIndentNum, indent); - std::cout << "rows: " << m.rows << ", " << - "cols: " << m.cols << ", " << - "channels: " << m.channels() << ", " << - "elementSize: " << m.elemSize() << "; "; -} - -string templateMatchMethod2Str(int method) -{ - switch (method) - { - case cv::TM_SQDIFF: - return "TM_SQDIFF"; - case cv::TM_SQDIFF_NORMED: - return "TM_SQDIFF_NORMED"; - case cv::TM_CCORR: - return "TM_CCORR"; - case cv::TM_CCORR_NORMED: - return "TM_CCORR_NORMED"; - case cv::TM_CCOEFF: - return "TM_CCOEFF"; - case cv::TM_CCOEFF_NORMED: - return "TM_CCOEFF_NORMED"; - default: - return ""; - } -} - -void printIndent(int indentNum, int indent /*= 4*/) -{ - for (int i = 0; i < indentNum; i++) - { - for (int j = 0; j < indent; j++) - { - std::cout << " "; - } - } -} - -Mat genSimpleXGradient(const Mat& m) -{ - Mat kernel(1, 2, CV_32FC1); - float* p = (float*)kernel.data; - p[0] = -1; - p[1] = 1; - Mat dm; - filter2D(m, dm, CV_32FC1, kernel, - Point(-1, -1), 0, BORDER_REFLECT); - return dm; -} - -void uniformLocalMinExtremas(const Mat& vec, Mat& localExtremaValVec, - vector& idxVec, int n, int refineRange) -{ - idxVec.resize(n); - - float step = (float)(vec.cols - 1) / (float)n; - float* pVec = (float*)vec.data; - localExtremaValVec.create(1, n + 1, CV_32FC1); - float* pExtremaValVec = (float*)localExtremaValVec.data; - - float* pVecData = (float*)vec.data; - for (int i = 0; i < n; ++i) - { - int idx = floorf(step*i); - int sIdx = idx - refineRange; - int eIdx = idx + refineRange; - sIdx = max(0, sIdx); - eIdx = min(vec.cols - 1, eIdx) + 1; - float* pExtrema = std::min_element(pVec + sIdx, pVec + eIdx); - idxVec[i] = pExtrema - pVec; - pExtremaValVec[i] = *pExtrema; - } - - pExtremaValVec[n] = pExtremaValVec[0]; -} - -void equalizeHist(const Mat& src, Mat& dst, const Mat& mask /*= Mat()*/) -{ - if (mask.empty()) - { - cv::equalizeHist(src, dst); - return; - } - Mat hist = calcHist(src, mask); - hist *= 255.0 / countNonZero(mask); - - float* pHistData = (float*)hist.data; - Mat mapHist = Mat::zeros(hist.rows, hist.cols, CV_32FC1); - float* pMapHistData = (float*)mapHist.data; - pMapHistData[0] = pHistData[0]; - for (int i = 1; i < 256; ++i) - { - pMapHistData[i] = pMapHistData[i - 1] + pHistData[i]; - } - - dst.create(src.size(), src.type()); - for (int y = 0; y < dst.rows; ++y) - { - uchar* pDstData = dst.row(y).data; - uchar* pSrcData = src.row(y).data; - for (int x = 0; x < dst.cols; ++x) - { - pDstData[x] = pMapHistData[pSrcData[x]]; - } - } -} - -void removeHighlights(const Mat& src, Mat& dst, float thre) -{ - dst = Mat::zeros(src.size(), src.type()); - Mat hightlightMask = src < thre; - src.copyTo(dst, hightlightMask); -} - -void genSectorSumVec(const Mat& img, const Mat& weightMat, Mat& hist, - Mat& weightHist, const Point2f& cen, float angleStep, - Mat* pAngMat /*= NULL*/, Mat* pMagMat /*= NULL*/) -{ - int count = floorf(360.0 / angleStep); - hist = Mat::zeros(1, count, CV_32FC1); - weightHist = Mat::zeros(1, count, CV_32FC1); - float* pData = (float*)img.data; - float* pWeightData = (float*)weightMat.data; - float* pHistData = (float*)hist.data; - float* pWeightHistData = (float*)weightHist.data; - float *x = new float[img.cols]; - for (int i = 0; i < img.cols; ++i) x[i] = i - cen.x; - Mat xRow(1, img.cols, CV_32FC1, x); - Mat magMat(img.rows, img.cols, CV_32FC1); - Mat angMat(img.rows, img.cols, CV_32FC1); - for (int i = 0; i < img.rows; ++i) - { - Mat yRow = Mat::ones(xRow.size(), xRow.type())*(i - cen.y); - - Mat magRow, angRow; - cartToPolar(xRow, yRow, magRow, angRow, true); - magRow.copyTo(magMat.row(i)); - angRow.copyTo(angMat.row(i)); - - float* pAngleData = (float*)angRow.data; - float* pRadiusData = (float*)magRow.data; - for (int j = 0; j < img.cols; ++j) - { - if (i == 100 && j == 90) - { - int a = 0; - } - float val = pData[j]; - float weight = pWeightData[j]; - float radius = pRadiusData[j]; - if (radius == 0) - { - continue; - } - float angle = pAngleData[j]; - - val *= weight; - - float angleRange = 28.6479 / radius; - float langle = angle - angleRange; - float rangle = angle + angleRange; - - int lIntAngle = (int)(langle); - int rIntAngle = (int)rangle; - int li = normAngle(lIntAngle); - int ri = normAngle(rIntAngle); - float totalRange = angleRange*2.0; - //pHistData[li] += val*(langle - ceil(langle)) / totalRange; - pHistData[li] += val*(1 - langle + lIntAngle) / totalRange; - //pWeightHistData[li] += weight*(langle - ceil(langle)) / totalRange; - pWeightHistData[li] += weight*(1 - langle + lIntAngle) / totalRange; - pHistData[ri] += val*(rangle - rIntAngle) / totalRange; - pWeightHistData[ri] += weight*(rangle - rIntAngle) / totalRange; - lIntAngle++; -#if defined(LITTLE_CPP11) - if (_isnan(pHistData[li]) || _isnan(pHistData[ri])) -#else - if (isnan(pHistData[li]) || isnan(pHistData[ri])) -#endif - { - waitKey(); - } - while (lIntAngle < rIntAngle) - { - li = normAngle(lIntAngle); - pHistData[li] += val / totalRange; - pWeightHistData[li] += weight / totalRange; - lIntAngle++; - } - } - pData += img.step1(); - pWeightData += weightMat.step1(); - } - - if (pAngMat) - { - *pAngMat = angMat; - } - if (pMagMat) - { - *pMagMat = magMat; - } - - free(x); -} - -Mat matDivideNonzero(const Mat& m0, const Mat& m1) -{ - // m0/m1 - Mat m1copy = m1.clone(); - m0.copyTo(m1copy, m1copy < 0.0000001); - return m0 / m1copy; -} - - -Mat matDivideNonzero(float m0, const Mat& m1) -{ - // m0/m1 - Mat m1copy = m1.clone(); - m1copy.setTo(m0, m1 < 0.0000001); - return m0 / m1copy; -} - - -void normSectors(Mat& _img, Mat weightMat, const Point2f& cen, - float angleStep, float tarVal) -{ - if (weightMat.empty()) - { - weightMat = Mat::ones(_img.size(), CV_32FC1); - } - Mat img = _img; - if (img.channels() != 1) - { - img = getFirstChannel(img); - } - if (img.type() != CV_32FC1) - { - converToType(img, CV_32FC1); - } - int count = floorf(360.0 / angleStep); - Mat hist = Mat::zeros(1, count, CV_32FC1); - Mat weightHist = Mat::zeros(1, count, CV_32FC1); - Mat magMat(img.rows, img.cols, CV_32FC1); - Mat angMat(img.rows, img.cols, CV_32FC1); - - genSectorSumVec(img, weightMat, hist, weightHist, cen, angleStep, - &angMat, &magMat); - - hist = matDivideNonzero(hist, weightHist); - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vAngleMat = angMat / 360; - Mat vMagMat = magMat / sqrt(img.cols*img.cols / 4.0 + img.rows*img.rows / 4.0); - Mat vHist = hist; - vHist = minMaxNorm(vHist, 0, 1.0); - Mat vWeightHist = weightHist; - vWeightHist = minMaxNorm(vWeightHist, 0, 1.0); -#endif - - Mat scaleHist = matDivideNonzero(tarVal, hist); - - applySectorScales(img, scaleHist, angMat); - - _img = img; -} - -void normSectors_tarImg(Mat& img, Mat weightMat, const Point2f& cen, float angleStep, - const Mat& tarImg) -{ - Mat hist, weightHist, angMat, magMat; - genSectorSumVec(img, weightMat, hist, weightHist, cen, angleStep, - &angMat, &magMat); - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vHist0 = minMaxNorm(hist, 0, 1.0); - Mat vWeightHist = minMaxNorm(weightHist, 0, 1.0); -#endif - - hist = matDivideNonzero(hist, weightHist); - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vHist1 = hist / 255.0; -#endif - - Mat tarHist; - genSectorSumVec(tarImg, weightMat, tarHist, weightHist, cen, angleStep); - tarHist = matDivideNonzero(tarHist, weightHist); - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vTarHist = tarHist/255.0; -#endif - - normSectorsMeans_tarHist(img, hist, cen, angleStep, tarHist, angMat); -} - -void normSectorsMeans_tarHist(Mat& img, const Mat& hist, - const Point2f& cen, float angleStep, const Mat& tarHist, const Mat& angMat) -{ - Mat scaleHist = matDivideNonzero(tarHist, hist); - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vScaleHist = minMaxNorm(scaleHist, 0, 1.0); -#endif - applySectorScales(img, scaleHist, angMat); -} - -void applySectorScales(Mat& img, const Mat& scaleHist, const Mat& angMat) -{ - float* pData = (float*)img.data; - float* pHistData = (float*)scaleHist.data; - for (int i = 0; i < img.rows; ++i) - { - Mat angRow = angMat.row(i); - - float* pAngleData = (float*)angRow.data; - for (int j = 0; j < img.cols; ++j) - { - float angle = pAngleData[j]; - int base = (int)angle; - float s = pHistData[base]; - pData[j] *= s; - } - pData += img.step1(); - } -} - -cv::Point2f imgCen(const Mat& img) -{ - return Point2f(img.cols / 2.0, img.rows / 2.0); -} - -cv::Mat getForeImage(const Mat & src, const Mat &backgroundImg) -{ - Mat resizedBackgroundImg = backgroundImg; - if (backgroundImg.size() != src.size()) { - resize(backgroundImg, resizedBackgroundImg, src.size()); - } - return (src - resizedBackgroundImg); -} -#define ALG_RESIZE_IMAGE_WIDTH 416.0 -// -// cv::Mat findCircleObject(const Mat &src, const Mat& backgroundImg, -// int nThres /*= 20*/, luffy_base::luffyCircle *pCircle /*= NULL*/) -// { -// if (src.empty() || backgroundImg.empty() || src.rows < 500) { -// return Mat(); -// } -// -// assert(backgroundImg.type() == CV_8UC1); -// Mat imgTmp, imgBinary; -// const cv::Size cSize = cv::Size(ALG_RESIZE_IMAGE_WIDTH, floorf(ALG_RESIZE_IMAGE_WIDTH / (float)src.cols*(float)src.rows)); -// cv::resize(src, imgTmp, cSize); -// Mat foregroundImg = getForeImage(imgTmp, backgroundImg); -// -// using namespace luffy_base; -// luffy_threshold::Threshold(foregroundImg, imgBinary, nThres); -// -// Mat dilatedImgBin; -// dilate(imgBinary, dilatedImgBin, Mat::ones(7, 7, CV_32FC1)); -// erode(dilatedImgBin, imgBinary, Mat::ones(7, 7, CV_32FC1)); -// -// openOper(imgBinary, Mat::ones(1, 13, CV_32FC1)); -// -// vector> conts; -// cv::findContours(imgBinary, conts, RETR_EXTERNAL, CHAIN_APPROX_NONE); -// imgBinary.setTo(0); -// for (int i = 0; i < conts.size(); i++) { -// const vector &pt = conts.at(i); -// if (pt.size() < 20) { -// continue; -// } -// Rect rt = boundingRect(pt); -// if (rt.width < 5 || rt.height < 5) { -// continue; -// } -// drawContours(imgBinary, conts, i, Scalar::all(255), -1); -// } -// Mat hit; vector pts; -// luffy_hit::firstHit4Circle(imgBinary, hit, pts, Point(cSize.width / 2, cSize.height / 2), 0, cSize.width / 2, 360, luffy_hit::emHitOut2In); -// -// //luffy_imageProc::RansacParam rs(0.02, 2.5, 70, 100, 220); -// luffy_imageProc::RansacParam rs(0.001, 1.5, 2240, 100, 420); -// vector pts2 = luffy_imageProc::fitModelbyRansac(pts, luffy_imageProc::emModelCircle, &rs); -// -// #ifdef _DEBUG -// Mat imgColor; -// cv::cvtColor(imgTmp, imgColor, CV_GRAY2BGR); -// for (int i = 0; i < pts.size(); i++) { -// imgColor.at(pts.at(i))[0] = 255;//B -// imgColor.at< cv::Vec3b >(pts.at(i))[1] = 0;//G -// imgColor.at< cv::Vec3b >(pts.at(i))[2] = 0;//R -// } -// for (int i = 0; i < pts2.size(); i++) { -// imgColor.at(pts2.at(i))[0] = 0;//B -// imgColor.at< cv::Vec3b >(pts2.at(i))[1] = 0;//G -// imgColor.at< cv::Vec3b >(pts2.at(i))[2] = 255;//R -// } -// #endif -// -// float fRadius; -// Point2f ptCenter; -// bool bFind = luffy_imageProc::lsCircleFit(pts2, fRadius, ptCenter); -// -// if (!bFind) { -// return Mat(); -// } -// Mat dst; -// const int nOffset = 1; -// fRadius += nOffset; -// Rect rt(ptCenter.x - fRadius + nOffset, ptCenter.y - fRadius + nOffset, 2 * fRadius, 2 * fRadius); -// rt &= Rect(0, 0, imgTmp.cols, imgTmp.rows); -// Mat test; -// imgTmp(rt).copyTo(test); -// static int nCount = cv::getTickCount(); -// //QString str = "d://image//" + QString::number(cv::getTickCount()); -// //QString strTest = str + "_1.jpg"; -// //cv::imwrite(strTest.toLatin1().data(), test); -// // -// if (pCircle) { -// float fScale = src.cols / ALG_RESIZE_IMAGE_WIDTH; -// Mat matBig = src - backgroundImg; -// pCircle->fRadius = fRadius * fScale; -// pCircle->ptCenter = Point(ptCenter.x * fScale, ptCenter.y * fScale); -// Mat matBinary; -// luffy_threshold::Threshold(matBig, matBinary, nThres); -// Mat hit; vector pts; -// luffy_hit::firstHit4Circle(matBinary, hit, pts, pCircle->ptCenter, 0, pCircle->fRadius + 10, 360, luffy_hit::emHitOut2In); -// luffy_imageProc::RansacParam rs(0.01, 2.5, 100, 100, 220); -// vector pts2 = luffy_imageProc::fitModelbyRansac(pts, luffy_imageProc::emModelCircle, &rs); -// float fRadius2; -// Point2f ptCenter2; -// bool bFind = luffy_imageProc::lsCircleFit(pts2, fRadius2, ptCenter2); -// if (bFind) { -// pCircle->fRadius = fRadius2; -// pCircle->ptCenter = ptCenter2; -// Rect rt(ptCenter2.x - fRadius2 + nOffset, ptCenter2.y - fRadius2 + nOffset, 2 * fRadius2, 2 * fRadius2); -// src(rt).copyTo(dst); -// int nWidth = ((int)((double)dst.cols / fScale / 4)) * 4; -// cv::resize(dst, dst, cv::Size(nWidth, nWidth)); -// //QString strTest = str + "_2.jpg"; -// //cv::imwrite(strTest.toLatin1().data(), dst); -// } -// } -// if (dst.empty()) { -// imgTmp(rt).copyTo(dst); -// } -// -// return dst; -// } - -bool ensureGrayImg(const Mat& img, Mat& gray) -{ - if (img.channels() == 3) - { - cvtColor(img, gray, COLOR_BGR2GRAY); - return true; - } - else if (img.channels() == 4) - { - cvtColor(img, gray, COLOR_BGRA2GRAY); - return true; - } - else if (img.channels() == 1) - { - gray = img; - return false; - } - else - { - assert(false && "unsupported image conversion."); - return false; - } -} - -double hsvDis(const Vec3b& v0, const Vec3b& v1) -{ - float h0 = v0[0] * 2.0 * 0.01745; - float s0 = v0[1] * (v0[2] / 255.0) * 2.0; - float h1 = v1[0] * 2.0 * 0.01745; - float s1 = v1[1] * (v1[2] / 255.0) * 2.0; - - double dVal = norm(Vec3f(cos(h0)*s0, sin(h0)*s0, v0[2]), - Vec3f(cos(h1)*s1, sin(h1)*s1, v1[2])); - - return dVal; -} - -cv::Mat genHSVColorDisMat(const Mat& m0, const Mat& m1) -{ - Scalar mean, stddev; - meanStdDev(m1, mean, stddev); - Vec3b baseColor(mean.val[0], mean.val[1], mean.val[2]); - return genHSVColorDisMat(m0, baseColor); -} - -cv::Mat genHSVColorDisMat(const Mat& m, Vec3b baseColor) -{ - Mat ret = Mat::zeros(m.size(), CV_32FC1); - uchar* pRet = ret.data; - uchar* pData0 = m.data; - for (int i = 0; i < m.rows; ++i) - { - float* pRet32f = (float*)pRet; - Vec3b* pData32f0 = (Vec3b*)pData0; - for (int j = 0; j < m.cols; ++j) - { - Vec3b& v0 = pData32f0[j]; - pRet32f[j] = (float)hsvDis(v0, baseColor); - } - - pRet += ret.step; - pData0 += m.step; - } - return ret; -} - -cv::Mat genHSVColorDisMat(const Mat& m) -{ - Scalar mean, stddev; - meanStdDev(m, mean, stddev); - return genHSVColorDisMat(m, Vec3b(mean.val[0], mean.val[1], mean.val[2])); -} - -cv::Mat genBlueGreenRatioMat(const Mat& m, float alpha /*= 50.0*/, float beta /*= -17.0*/) -{ - vector channels; - split(m, channels); - Mat blue32f, green32f; - channels[0].convertTo(blue32f, CV_32FC1); - channels[1].convertTo(green32f, CV_32FC1, 1.0, -beta); - Mat ratioMat = green32f / blue32f; - Mat ratioMat8u; - ratioMat.convertTo(ratioMat8u, CV_8UC1, alpha); - return ratioMat8u; -} - -Mat genColorFuncDisMat(const Mat& m, float a, float b, float c) -{ - vector channels; - split(m, channels); - Mat blue32f, green32f; - channels[0].convertTo(blue32f, CV_32FC1); - channels[1].convertTo(green32f, CV_32FC1); - Mat sqrBlue = blue32f.mul(blue32f, a); - Mat bBlue = blue32f*b; - //Mat dis = ((sqrBlue + bBlue) - green32f); - Mat dis = (green32f - sqrBlue + c) / blue32f; - Mat ret; - dis.convertTo(ret, CV_8UC1, 255); - return ret; -} - -void setChannel(Mat& img, int i, Mat chnMat) -{ - vector channels; - split(img, channels); - channels[i] = chnMat; - merge(channels, img); -} - - -void transPoints(const vector& vec, vector& oVec, const Matx23f& mat) -{ - oVec.resize(vec.size()); - for (size_t i = 0; i < vec.size(); ++i) - { - Point2f p = vec[i]; - Point2f tp = mat * Vec3f(p.x, p.y, 1.0); - oVec[i] = Point2f(tp.x, tp.y); - } -} - -void transPoints(vector& vec, const Matx33d& mat) -{ - for (size_t i = 0; i < vec.size(); ++i) - { - Point2d p = vec[i]; - Point3d tp = mat * p; - vec[i] = Point2d(tp.x / tp.z, tp.y / tp.z); - } -} - -void transPoints(vector& vec, const Mat& mat) -{ - Matx33d matx = Matx33d::eye(); - Mat matx_(3, 3, CV_64FC1, matx.val); - - if (mat.rows == 2 && mat.cols == 3) - { - mat.copyTo(matx_.rowRange(0, 2)); - } - else if (mat.rows == 3 && mat.cols == 3) - { - mat.copyTo(matx_); - } - else - { - std::cout << "not supported transformation mat with its size as " \ - << mat.rows << "x" << mat.cols << std::endl; - return; - } - transPoints(vec, matx); -} - -Matx23f getRotationMatrix23f(Point2f center, float angle, float scale, float xOffset, float yOffset) -{ - Matx23f rotMat; - float* pRotVal = rotMat.val; - float a_pi = -angle * CV_PI / 180; - float alpha = cos(a_pi)*scale; - float beta = sin(a_pi)*scale; - pRotVal[0] = alpha; - pRotVal[1] = beta; - pRotVal[2] = -alpha * center.x - beta * center.y + xOffset; - pRotVal[3] = -beta; - pRotVal[4] = alpha; - pRotVal[5] = beta * center.x - alpha * center.y + yOffset; - - return rotMat; -} - -void getRigidTransform_(const Point2f& u1, const Point2f& u2, const Point2f& v1, const Point2f& v2, - double& x0, double& y0, double& angle, double& scale) -{ - vector srcPtVec(2), dstPtVec(2); - srcPtVec[0] = Point2d(u1.x, u1.y); - srcPtVec[1] = Point2d(u2.x, u2.y); - dstPtVec[0] = Point2d(v1.x, v1.y); - dstPtVec[1] = Point2d(v2.x, v2.y); - - Mat srMat; - Matx33d t = rigidTrans(srcPtVec, dstPtVec, &srMat); - - double t0 = t.val[0]; - double t1 = t.val[1]; - double l = sqrt(t0 * t0 + t1 * t1); - if (abs(l) > FLT_EPSILON) - { - t0 /= l; - t1 /= l; - scale = 1.0 / l; - angle = acos(t0) / CV_PI * 180; - angle = normAngle(angle); - } - else - { - angle = 0; - scale = 1.0; - } - - Point2d vCen = v1 + v2; - - x0 = vCen.x / 2.; - y0 = vCen.y / 2.; -} - -void getRigidTransform(const Point2f& u1, const Point2f& u2, const Point2f& v1, const Point2f& v2, - double& x0, double& y0, double& angle, double& scale) -{ - float theta_u = atan2f(u2.y - u1.y, u2.x - u1.x); - float theta_v = atan2f(v2.y - v1.y, v2.x - v1.x); - angle = (theta_v - theta_u) * 180 / CV_PI; - angle = normAngle(angle); - - float sin_a = sin(angle / 180 * CV_PI); - float cos_a = cos(angle / 180 * CV_PI); - - double f = (u2.x - u1.x) * cos_a - (u2.y - u1.y) * sin_a; - if (abs(f) > FLT_EPSILON) - { - scale = (v2.x - v1.x) / f; - } - else - { - scale = sqrt(pow(u2.x - u1.x, 2) + pow(u2.y - u1.y, 2)) / sqrt(pow(v2.x - v1.x, 2) + pow(v2.y - v1.y, 2)); - } - - x0 = v1.x - u1.x * scale * cos_a + u1.y * scale * sin_a; - y0 = v1.y - u1.x * scale * sin_a - u1.y * scale * cos_a; -} - -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) -{ - getRigidTransform(u1 - cen1, u2 - cen1, v1 - cen2, v2 - cen2, x0, y0, angle, 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) -{ - getRigidTransform(u1 - cen1, ua, v1 - cen2, va, x0, y0, angle, scale); -} - -void getRigidTransform(const Point2f& u1, float ua, - const Point2f& v1, float va, - double& x0, double& y0, double& angle, double& scale) -{ - getRigidTransform(u1, u1 + Point2f(cos(ua / 180 * CV_PI), sin(ua / 180 * CV_PI)), - v1, v1 + Point2f(cos(va / 180 * CV_PI), sin(va / 180 * CV_PI)), - x0, y0, angle, 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) -{ - getRigidTransform(u1 - cen1, ua, v1 - cen2, va, s, x0, y0, angle, scale); -} - -void getRigidTransform(const Point2f& u1, float ua, - const Point2f& v1, float va, - float s, - double& x0, double& y0, double& angle, double& scale) -{ - getRigidTransform(u1, u1 + Point2f(cos(ua / 180 * CV_PI), sin(ua / 180 * CV_PI)), - v1, v1 + Point2f(cos(va / 180 * CV_PI), sin(va / 180 * CV_PI)) * s, - x0, y0, angle, scale); -} - -Mat applyPerspectiveTransform(const Mat& img, std::vector& transVertexes, int flags) -{ - if (img.empty()) return gDummyMat; - - int w = img.cols, h = img.rows; -#if defined(LITTLE_CPP11) - std::vector pnts1(4); - pnts1[0] = Point2f(0, 0); - pnts1[1] = Point2f(w - 1, 0); - pnts1[2] = Point2f(w - 1, h - 1); - pnts1[3] = Point2f(0, h - 1); -#else - std::vector pnts1 = { - Point2f(0, 0), Point2f(w - 1, 0), Point2f(w - 1, h - 1), Point2f(0, h - 1) - }; -#endif - Mat H = findHomography(pnts1, transVertexes); - Mat img_warp; - warpPerspective(img, img_warp, H, img.size(), flags); - return img_warp; -} - - -}; diff --git a/molunCar/CVUtils.h b/molunCar/CVUtils.h deleted file mode 100644 index 4960ff0..0000000 --- a/molunCar/CVUtils.h +++ /dev/null @@ -1,704 +0,0 @@ -/*! \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 -#include - -#include -#include -#include -#include -#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_ Sized; -typedef Size_ 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 -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& 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& dxVec); -void autoAlignEachRowWithAutoThreshold(Mat& img, int tarCenX, vector& dxVec); -void alignEachRow(Mat& img, const vector& dxVec); -void autoAlignEachRowGloballyWithWidthConstraint(Mat& img, int tarCenX, vector& 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 >& 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& contour); - - -float circleDegree(const vector& 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 -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& pointVec, float val, int xPadding); - -double localMatSum(const Mat& mat, const Rect& roi); - -void findEdgePointsEachRow(const Mat& img, vector& edgePointVec, int xPadding); - -template -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 -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 >(i); - for (int j = 0; j < cn; ++j) - d[j] = s[j] / iMat.cols; - } - return oVec; -} - -Mat sumEachRow2(const Mat& img); - -template -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 -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 >(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& pointPairVec, int xPadding); - -void fillPointPairVal(const Mat& img, std::string filePath, vector& 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& 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 -Mat calcHist(const vector& 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& vec, float dis); - -void filterKeyPointsByRotationInvariants(vector& 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 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 >& matches, int k, - const vector& masks = vector(), bool compactResult = false); - virtual void radiusMatchImpl(const Mat& queryDescriptors, vector >& matches, float maxDistance, - const vector& masks = vector(), 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 ptVec, int radius); - - -Mat filterY(const Mat& img, float* kernel, int size, int ddepth = CV_32FC1); - -Mat getContourBoundedRoiImg(const Mat& src, const vector& contour, Rect* pRoiRect = NULL); - -void filterContours(Mat hsvColorThresImg, - int minArea, double minLength, double minLongShortRatio, - double maxCircleDegree, vector* pAreaMaxContour = NULL); -void filterContours(Mat& img, double minArea); -void filterContours(const vector< vector >& contours, const Mat& srcImg, - vector< vector >& filteredContours, int minArea, double minLength, - double minLongShortRatio, double maxCircleDegree, vector* pAreaMaxContour = NULL); -int filterSmallAndFindMaxContours(vector< vector >& contours, double minArea); -Mat genInRangeMask(const Mat& src, std::map>& 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& 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 -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 -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(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 -vector cvtMat2Vec(const Mat& img) -{ - _ASSERTE(!img.empty()); - int count = img.cols * img.rows; - - std::vector 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(i), rowStep); - vals_p += img.cols; - } - } - - return vals; -} - -template -std::list cvtMat2List(const Mat& img) -{ - _ASSERTE(!img.empty()); - int rows = img.rows; - int cols = img.cols; - int count = cols * rows; - - std::list vals; - for (int i = 0; i < rows; ++i) { - const S* img_p = img.ptr(i); - for (int j = 0; j < cols; ++j) { - vals.push_back((S)(img_p[j])); - } - } - - return vals; -} - -template -T getNthElement(const Mat& img, int n) -{ - _ASSERTE(!img.empty()); - int count = img.cols * img.rows; - _ASSERTE(n < count); - - std::vector vals = cvtMat2Vec(img); - - std::nth_element(vals.begin(), vals.begin() + n, vals.end()); - - return vals[n]; -} - -int getLocalMaximun(const Mat& vec, double thres, std::vector* pMaxIdxVec); -int getLocalMinimun(const Mat& vec, double thres, std::vector* pMaxIdxVec); - -enum EnumAbnormalType { - AbTypePositive = 0, - AbTypeNegative, - AbTypeBoth -}; -int detectAbnormal(const Mat& vec, int kernelSize, EnumAbnormalType abnormalType, double abnormalThreshold, - Mat* pScores = nullptr, std::vector* pAbIdxVec = nullptr); - - -/************************************************************************/ -/* Angle */ -/************************************************************************/ - -inline float normAngle(float x, float y) -{ - float angle = atan2f(y, x); - return angle / CV_PI * 180.0; -} - -// convert angle to (0, 360) -// inline float normAngle(float angle) -// { -// int c = angle / 360; -// float ret = angle - c * 360; -// return ret < 0 ? ret + 360 : ret; -// } -inline int normAngle(int angle) -{ - int c = angle / 360; - int ret = angle - c * 360; - return ret < 0 ? ret + 360 : ret; -} -inline double normAngle(double angle) -{ - int c = angle / 360; - double ret = angle - c * 360; - return ret < 0 ? ret + 360 : ret; -} -inline float normAngle180(float angle) -{ - int c = angle / 360; - float ret = angle - c * 360; - return ret > 180 ? ret - 360 : (ret < -180 ? ret + 360 : ret); -} - -inline float diffAngle(float angle1, float angle2) -{ - float diff = abs(angle1 - angle2); - return diff > 180 ? 360 - diff : diff; -} - -inline float diffAngle2(float angle1, float angle2) -{ - Vec2f vp(cos(angle1 / 180 * CV_PI), sin(angle1 / 180 * CV_PI)); - Vec2f vpp(cos(angle2 / 180 * CV_PI), sin(angle2 / 180 * CV_PI)); - - return vp.dot(vpp); -} - -inline float diffAngleRaw(float angle1, float angle2) -{ - return diffAngle(normAngle(angle1), normAngle(angle2)); -} - -inline float bisectAngle(float angle1, float angle2) -{ - float diff = abs(angle1 - angle2); - return diff < 180 ? (angle1 + angle2) / 2 : (angle1 + angle2 + 360) / 2; -} - -/************************************************************************/ -/* Transform */ -/************************************************************************/ - -void transPoints(vector& vec, const Mat& mat); -void transPoints(vector& vec, const Matx33d& mat); -void transPoints(const vector& vec, vector& 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& transVertexes, // in order top-left, top-right, bottom-right, bottom-left - int flags = INTER_LINEAR); -}; -using namespace CyclopsUtils; - -#endif // __CVUtils_h_ - diff --git a/molunCar/DynamicProgramSearch.cpp b/molunCar/DynamicProgramSearch.cpp deleted file mode 100644 index 8321526..0000000 --- a/molunCar/DynamicProgramSearch.cpp +++ /dev/null @@ -1,243 +0,0 @@ -#include "DynamicProgramSearch.h" -#include - -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(sy, j); - if (maxVal < val) - { - maxVal = val; - } - } - - disMat.at(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(i, sx); - if (maxVal < val) - { - maxVal = val; - } - } - - disMat.at(y, x) += maxVal; - } - } -} - -void findMaxXPath(const Mat& disMat, vector& vec, vector& 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(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& vec, vector& 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(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& 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(y, x); - } - for (int j = sj; j <= ej; j++) - { - float disVal = disMat.at(sy, j); - float sVal = 0; - if (!smoothMat.empty()) - { - sVal = smoothMat.at(sy, j); - } - float energyVal = disVal + (255 - abs(sVal - baseSVal))*sw; - if (maxVal < energyVal) - { - maxVal = energyVal; - } - } - - disMat.at(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(y, x); - } - float baseSVal1 = 0; - if (!smoothMat1.empty()) - { - baseSVal1 = smoothMat1.at(y, x + targetWidth - smoothMat0.cols); - } - for (int j = sj0; j <= ej0; j++) - { - float disVal0 = disMat0.at(sy, j); - int j1 = j + targetWidth - disMat0.cols; - float disVal1 = disMat1.at(sy, j1); - float sVal0 = 0; - if (!smoothMat0.empty()) - { - sVal0 = smoothMat0.at(sy, j); - } - float sVal1 = 0; - if (!smoothMat1.empty()) - { - sVal1 = smoothMat1.at(sy, j1); - } - float energyVal = disVal0 + disVal1 + - (255 - abs(sVal0 - baseSVal0))*sw + - (255 - abs(sVal1 - baseSVal1))*sw; - if (maxVal < energyVal) - { - maxVal = energyVal; - } - } - - disMat0.at(y, x) += maxVal; - } - } -} - diff --git a/molunCar/DynamicProgramSearch.h b/molunCar/DynamicProgramSearch.h deleted file mode 100644 index 3d1c0e4..0000000 --- a/molunCar/DynamicProgramSearch.h +++ /dev/null @@ -1,118 +0,0 @@ -#ifndef _DynamicProgramSearch_h_ -#define _DynamicProgramSearch_h_ - -#include -#include "CVUtils.h" - -using namespace cv; - -using std::vector; - -void dynamicProgramYWithSmooth(Mat& disMat, int n = 2, float sw = 1.0, const Mat& smoothMat = Mat()); -void dynamicProgramYWithSmooth(Mat& disMat0, Mat& disMat1, - const Mat& smoothMat0, const Mat& smoothMat1, int targetWidth, int n, float sw); - -void dynamicProgramY(Mat& disMat, int n = 2); -void dynamicProgramX(Mat& disMat, int n = 2); - -void findMaxXPath(const Mat& disMat, vector& vec, vector& energyVec, - int n = 2); -void findMaxYPath(const Mat& disMat, vector& vec, vector& energyVec, - int n = 2); - -void recoverPathEnergy(vector& vec); - -inline float ptLineDisY(const Vec4f& line, const Point& pt) -{ - float p0x = line.val[2]; - float p0y = line.val[3]; - float p1x = line.val[0] + p0x; - float p1y = line.val[1] + p0y; - - float px = pt.x; - float py = pt.y; - - float y = p0y + (p1y - p0y) / (p1x - p0x) * (px - p0x); - - float dy = y - py; - if (dy > 0) - { - return dy; - } - else - { - return -dy; - } -} - -inline float ptLineDis(const Vec4f& line, const Point& pt) -{ - float a = line.val[1]; - float b = -line.val[0]; - float c = -a*line.val[2] - b*line.val[3]; - return (a * (float)pt.x + b * (float)pt.y + c) * InvSqrt(a*a + b*b); -} - -inline float ptLineDis(const Vec4f& line, const Point2f& pt) -{ - float a = line.val[1]; - float b = -line.val[0]; - float c = -a*line.val[2] - b*line.val[3]; - return (a * pt.x + b * pt.y + c) * InvSqrt(a*a + b*b); -} - -inline float ptLineDis(const Vec4f& line, const vector& ptVec) -{ - float ret = 0; - for (int i = 0; i < ptVec.size(); ++i) - { - const Point& pt(ptVec[i]); - float d = ptLineDis(line, pt); - ret += abs(d); - } - return ret; -} - -template -void drawPointsX(vector& xVec, Mat& img, int sx, int sy, int color = 255, int w = 1) -{ - for (int x = 0; x < xVec.size(); ++x) - { - int y = xVec[x] + sy; - img.at<_T>(y, x + sx) = color; - for (int i = 1; i <= w / 2; ++i) - { - if (y - i >= 0) - { - img.at<_T>(y - i, x + sx) = color; - } - if (y + i < img.rows) - { - img.at<_T>(y + i, x + sx) = color; - } - } - } -} - -template -void drawPointsY(vector& yVec, Mat& img, int sx, int sy, int color = 255, int w = 1) -{ - for (int y = 0; y < yVec.size(); ++y) - { - int x = yVec[y] + sx; - img.at<_T>(y + sy, x) = color; - for (int i = 1; i <= w / 2; ++i) - { - if (x - i >= 0) - { - img.at<_T>(y + sy, x - i) = color; - } - if (x + i < img.cols) - { - img.at<_T>(y + sy, x + i) = color; - } - } - } -} - -#endif // _DynamicProgramSearch_h_ diff --git a/molunCar/ImageCompareModel.cpp b/molunCar/ImageCompareModel.cpp deleted file mode 100644 index c6e6f4b..0000000 --- a/molunCar/ImageCompareModel.cpp +++ /dev/null @@ -1,2440 +0,0 @@ -/*! \file ImageCompareModel.cpp - - Copyright (C) 2014 Hangzhou Leaper. - - Created by bang.jin at 2017/02/04. - -*/ - -#include "ImageCompareModel.h" -#include "CVUtils.h" -#include "MultiScaleImageCompareModel.h" -#include -#include -//#define DEBUG_VIEW_INTERNAL_MAT -#define IMGCMP_STR_NAME "name" -#define IMGCMP_STR_IMAGE_COMPARE_MODEL "imageCompareModel" -#define IMGCMP_STR_ALIGN_BASE_IMAGE "alignBaseImage" -#define IMGCMP_STR_COMPARE_BASE_IMAGE "compareBaseImage" -#define IMGCMP_STR_WEIGHT_MAT "weightMat" -#define IMGCMP_STR_MATCH_VAL_SCALE "matchValScale" -#define IMGCMP_STR_TARGET_MEAN_VAL "targetMeanVal" -#define IMGCMP_STR_TARGET_STDDEV_VAL "targetStddevVal" -#define IMGCMP_STR_REPEAT_NUM "repeatNum" -#define IMGCMP_STR_TRUE_SAMPLE_DIS_MEAN "trueSampleDisMean" -#define IMGCMP_STR_TRUE_SAMPLE_DIS_STDDEV "trueSampleDisStddev" -#define IMGCMP_STR_TRUE_SAMPLE_DIS_MIN "trueSampleDisMin" -#define IMGCMP_STR_TRUE_SAMPLE_DIS_MAX "trueSampleDisMax" -#define IMGCMP_STR_DIS_THRE "disThre" -#define IMGCMP_STR_FALSE_SAMPLE_MIN_DIS "falseSampleMinDis" -#define IMGCMP_STR_TRAIN_DIS "trainDis" -#define IMGCMP_STR_SMALLEST_MATCH_DIS "falseMinDis" -#define IMGCMP_STR_AVER_DIAMETER "averageDiameter" -#define IMGCMP_STR_INSIDE_WEIGHT "insideWeightimage" -#define IMGCMP_STR_INSIDE_AVE_IMAGE "insideBaseimage" -#define IMGCMP_STR_INSIDE_COMP_AVE_IMAGE "insideCompareBaseImage" -#define IMGCMP_STR_INSIDE_RADIUS "insideRadius" -#define IMGCMP_STR_INSIDE_TEMPL "innerTempl" - -#define IMGCMP_CACHE_MAX_SIZE 100 - -#define MIN_CIRCLE_RADII 5 -#define MAX_CIRCLE_RADII 110 -int ImageCompareModel::m_parallelFlag = 0; -cv::Point2f ImageCompareModel::refineCircleCen(const Mat& img, Point2f cen) -{ - int r = 2; - vector vec; - double minDiff = DBL_MAX; - Point2f bestCenter; - vector bestDftVec; - for (float y = cen.y - r; y <= cen.y + r; y += 0.5) - { - for (float x = cen.x - r; x <= cen.x + r; x += 0.5) - { - std::cout << "newCenter: " << x << "-" << y << ", "; - - Point2f newCenter(x, y); - - vector vec; - selfRotationSimilarityFeature(img, vec, newCenter); - - vector dftVec; - dft(vec, dftVec); - -// 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 - CvPlot::plot("refineCenter", &(vec[0]), vec.size()); -#endif - - float diffVal = sum(vec.begin(), vec.end()); - - vec.push_back(diffVal); - - if (minDiff > diffVal) - { - minDiff = diffVal; - bestCenter = newCenter; - bestDftVec = dftVec; - } - - std::cout << "diff: " << diffVal << ", " - " minDiff: " << minDiff << ", " - " bestCenter: " << bestCenter.x << "-" << bestCenter.y << - std::endl; - } - } - - return bestCenter; -} - -cv::Mat ImageCompareModel::genWeightImage(const Mat& img, Point2f center, - float innerR /*= -1*/, float outterR /*= -1*/) -{ - if (innerR == -1) - { - // default is 30 - innerR = img.rows*0.175; - } - if (outterR == -1) - { - // default is max radius - 10 - outterR = img.rows*0.475; - } - - Mat weightImg; - weightImg.create(img.size(), CV_32FC1); - weightImg.setTo(0); - - uchar* pData = weightImg.data; - for (int y = 0; y < weightImg.rows; y++) - { - float* pFData = (float*)weightImg.row(y).data; - for (int x = 0; x < weightImg.cols; x++) - { - float& val = pFData[x]; - float dx = center.x - x; - float dy = center.y - y; - float r = sqrt(dx*dx + dy*dy); - if (r > outterR || r < innerR) - { - val = 0; - } - else - { - val = min(outterR - r, r - innerR); - } - } - } - - return weightImg; -} - -void ImageCompareModel::selfRotationSimilarityFeature( - const Mat& img, vector& vec, Point2f center /*= Point2f(-1, -1)*/) -{ - float angleStep = 1.0; - if (center.x < 0 || center.y < 0) - { - center = Point2f(img.cols / 2.0, img.rows / 2.0); - } - - double bestVal = DBL_MAX; - Mat bestRImg; - Mat fImg; - img.convertTo(fImg, CV_32FC1); - - Mat weightImg = genWeightImage(img, center); - fImg = fImg.mul(weightImg); - - double sumVal = sum(weightImg).val[0]; - - Mat baseImg; - { - Mat t = getRotationMatrix2D(center, 1.0, 1.0); - Mat rImg; - warpAffine(fImg, rImg, t, fImg.size(), CV_INTER_CUBIC); - t = getRotationMatrix2D(center, -1.0, 1.0); - warpAffine(rImg, baseImg, t, rImg.size(), CV_INTER_CUBIC); - } - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat viewBaseImg = baseImg / 255.0/25.0; - Mat viewfImg = fImg / 255.0/25.0; -#endif - - for (float a = 0; a <= 360.0; a += angleStep) - { - Mat t = getRotationMatrix2D(center, a, 1.0); - Mat rImg; - warpAffine(fImg, rImg, t, fImg.size(), CV_INTER_CUBIC); - - Mat diffImg = baseImg - rImg; - //diffImg = diffImg.mul(weightImg); - double diffVal = norm(diffImg)/sumVal; - vec.push_back(diffVal); - } -} - -cv::Mat ImageCompareModel::genMask(const Mat& img, Point2f center, - float innerR /*= -1*/, float outterR /*= -1*/, int type /*= CV_32FC1*/) -{ - Mat mask(img.size(), CV_8UC1); - mask.setTo(0); - if (innerR == -1) - { - // default is 30 - innerR = img.rows*0.178; - //innerR = img.rows; - } - if (outterR == -1) - { - // default is max radius - 10 - outterR = img.rows*0.425; - //outterR = img.rows; - } - circle(mask, center, outterR, Scalar(255), -1); - circle(mask, center, innerR, Scalar(0), -1); - if (type != CV_8UC1) - { - converToType(mask, type); - mask /= 255; - } - return mask; -} - -void ImageCompareModel::genMask() -{ - m32fMaskImg = genMask(mAlignBaseImg, Point2f(mAlignBaseImg.cols / 2.0, mAlignBaseImg.rows / 2.0)); - m8uMaskImg = genMask(mAlignBaseImg, Point2f(mAlignBaseImg.cols / 2.0, mAlignBaseImg.rows / 2.0), - -1.0, -1.0, CV_8UC1); - m32fInsideMaskImg = genInsideMask(mInSideBaseImg, Point2f(mInSideBaseImg.cols / 2.0, mInSideBaseImg.rows / 2.0)); - m8uInsideMaskImg = genInsideMask(mInSideBaseImg, Point2f(mInSideBaseImg.cols / 2.0, mInSideBaseImg.rows / 2.0), - -1.0, -1.0, CV_8UC1); -} - -void ImageCompareModel::printInfo() -{ - std::cout << IMGCMP_STR_IMAGE_COMPARE_MODEL << ": "; - std::cout << std::endl; - - printProperty(1, IMGCMP_STR_NAME, mName); - - printIndent(1); - std::cout << IMGCMP_STR_ALIGN_BASE_IMAGE << ": "; - std::cout << std::endl; - printMatInfo(mAlignBaseImg, 2); - std::cout << std::endl; - - printIndent(1); - std::cout << IMGCMP_STR_WEIGHT_MAT << ": "; - std::cout << std::endl; - printMatInfo(mWeightMat, 2); - std::cout << std::endl; - - printProperty(1, IMGCMP_STR_MATCH_VAL_SCALE, mMatchValScale); - printProperty(1, IMGCMP_STR_TARGET_MEAN_VAL, mTargetMeanVal); - printProperty(1, IMGCMP_STR_TARGET_STDDEV_VAL, mTargetStddevVal); - printProperty(1, IMGCMP_STR_REPEAT_NUM, mRepeatNum); - printProperty(1, IMGCMP_STR_DIS_THRE, mDisThre); - printProperty(1, IMGCMP_STR_TRUE_SAMPLE_DIS_STDDEV, mTrueSampleDisStddev); - printProperty(1, IMGCMP_STR_TRUE_SAMPLE_DIS_MEAN, mTrueSampleDisMean); - printProperty(1, IMGCMP_STR_TRUE_SAMPLE_DIS_MAX, mTrueSampleDisMax); - printProperty(1, IMGCMP_STR_TRUE_SAMPLE_DIS_MIN, mTrueSampleDisMin); - - printProperty(1, "filePath", mFilePath); - printProperty(1, "isEnableCache", mIsEnableCache); -} - -void ImageCompareModel::saveImages(string dirPath) -{ - imwrite(dirPath + "/base.png", mAlignBaseImg); - imwrite(dirPath + "/weight.png", mWeightMat); -} - -bool ImageCompareModel::save2file(string filePath) -{ - FileStorage fs(filePath, FileStorage::WRITE); - if (!fs.isOpened()) - { - return false; - } - - fs << IMGCMP_STR_NAME << mName << - IMGCMP_STR_ALIGN_BASE_IMAGE << mAlignBaseImg << - IMGCMP_STR_COMPARE_BASE_IMAGE << mCompareBaseImg << - IMGCMP_STR_WEIGHT_MAT << mWeightMat << - IMGCMP_STR_INSIDE_AVE_IMAGE << mInSideBaseImg << - IMGCMP_STR_INSIDE_COMP_AVE_IMAGE << mInsideCompareBaseImg << - IMGCMP_STR_INSIDE_WEIGHT << mInsideWeightMat << - IMGCMP_STR_INSIDE_TEMPL << innerTempl << - IMGCMP_STR_MATCH_VAL_SCALE << mMatchValScale << - IMGCMP_STR_TARGET_MEAN_VAL << mTargetMeanVal << - IMGCMP_STR_TARGET_STDDEV_VAL << mTargetStddevVal << - IMGCMP_STR_REPEAT_NUM << mRepeatNum << - IMGCMP_STR_TRUE_SAMPLE_DIS_MEAN << mTrueSampleDisMean << - IMGCMP_STR_TRUE_SAMPLE_DIS_STDDEV << mTrueSampleDisStddev << - IMGCMP_STR_TRUE_SAMPLE_DIS_MIN << mTrueSampleDisMin << - IMGCMP_STR_TRUE_SAMPLE_DIS_MAX << mTrueSampleDisMax << - IMGCMP_STR_FALSE_SAMPLE_MIN_DIS << getFalseSampleMinDis() << - IMGCMP_STR_DIS_THRE << mDisThre << - IMGCMP_STR_TRAIN_DIS << mDisMat << - IMGCMP_STR_AVER_DIAMETER << meanDiameter << - IMGCMP_STR_INSIDE_RADIUS << rInner; - - setFilePath(filePath); - - return true; -} - -bool ImageCompareModel::readFromFile(string filePath) -{ - FileStorage fs(filePath, FileStorage::READ); - if (!fs.isOpened()) - { - return false; - } - - fs[IMGCMP_STR_ALIGN_BASE_IMAGE] >> mAlignBaseImg; - fs[IMGCMP_STR_COMPARE_BASE_IMAGE] >> mCompareBaseImg; - fs[IMGCMP_STR_WEIGHT_MAT] >> mWeightMat; - fs[IMGCMP_STR_INSIDE_AVE_IMAGE] >> mInSideBaseImg; - fs[IMGCMP_STR_INSIDE_COMP_AVE_IMAGE] >> mInsideCompareBaseImg; - fs[IMGCMP_STR_INSIDE_WEIGHT] >> mInsideWeightMat; - fs[IMGCMP_STR_INSIDE_TEMPL] >> innerTempl; - mMatchValScale = (double)fs[IMGCMP_STR_MATCH_VAL_SCALE]; - - FileNode fn = fs[IMGCMP_STR_TARGET_MEAN_VAL]; - if (!fn.empty()) - { - mTargetMeanVal = (int)fn; - } - - fn = fs[IMGCMP_STR_TARGET_STDDEV_VAL]; - if (!fn.empty()) - { - mTargetStddevVal = (int)fn; - } - - fn = fs[IMGCMP_STR_REPEAT_NUM]; - if (!fn.empty()) - { - mRepeatNum = (int)fn; - } - else - { - //mRepeatNum = computeRepeatNum(); - } - - fn = fs[IMGCMP_STR_NAME]; - if (!fn.empty()) - { - mName = (string)fn; - } - - fn = fs[IMGCMP_STR_TRUE_SAMPLE_DIS_MEAN]; - if (!fn.empty()) - { - mTrueSampleDisMean = (double)fn; - } - fn = fs[IMGCMP_STR_TRUE_SAMPLE_DIS_STDDEV]; - if (!fn.empty()) - { - mTrueSampleDisStddev = (double)fn; - } - fn = fs[IMGCMP_STR_TRUE_SAMPLE_DIS_MIN]; - if (!fn.empty()) - { - mTrueSampleDisMin = (double)fn; - } - fn = fs[IMGCMP_STR_TRUE_SAMPLE_DIS_MAX]; - if (!fn.empty()) - { - mTrueSampleDisMax = (double)fn; - } - fn = fs[IMGCMP_STR_FALSE_SAMPLE_MIN_DIS]; - if (!fn.empty()) - { - setFalseSampleMinDis((double)fn); - } - fn = fs[IMGCMP_STR_DIS_THRE]; - if (!fn.empty()) - { - mDisThre = (double)fn; - } - - fn = fs[IMGCMP_STR_AVER_DIAMETER]; - if (!fn.empty()) - { - meanDiameter = (int)fn; - } - - fn = fs[IMGCMP_STR_INSIDE_RADIUS]; - if (!fn.empty()) - { - rInner = (float)fn; - } - - setFilePath(filePath); - - genMask(); - - return true; -} - -void ImageCompareModel::preProcessImage(Mat& img, Mat &insideImg) const -{ - preProcessImage(img, m8uMaskImg, mTargetMeanVal, mTargetStddevVal, mHighlightsThreshold); - if (insideImg.empty()) - { - return; - } - preProcessImage(insideImg, m8uInsideMaskImg, mTargetMeanVal, mTargetStddevVal, mHighlightsThreshold); -} - -void ImageCompareModel::preProcessImage(Mat& img, const Mat& mask, double tarMean, - double tarStddev, int highlightsThreshold) const -{ - if (img.channels() > 1) - { - img = getFirstChannel(img); - } - if (img.type() != CV_32FC1) - { - converToType(img, CV_32FC1); - } - - Mat gaussImg; - GaussianBlur(img, gaussImg, Size(3, 3), 5.0); - img = gaussImg; - - Mat dilatedMask; - dilate(mask, dilatedMask, Mat::ones(Size(3, 3), CV_32FC1)); - - Mat hightlightsMask = img < highlightsThreshold; - Mat imgMask = hightlightsMask & dilatedMask; - - Scalar meanScalar, stddevScalar; - meanStdDev(img, meanScalar, stddevScalar, imgMask); - img = (img - meanScalar.val[0]) * tarStddev / stddevScalar.val[0] + tarMean; - - converToType(imgMask, CV_32FC1); - imgMask /= 255.0; - Mat imgNorm = cocentricNorm(img, Point2f(img.cols / 2.0, img.rows / 2.0), - imgMask, 125); -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vImgNorm = imgNorm / 255.0; -#endif - img = imgNorm; -} - -void ImageCompareModel::preProcessImage(Mat& img, const Mat& mask, - const Mat& weightMat, double dstMean, double dstStddev, int highlightsThreshold) const -{ - if (img.channels() > 1) - { - img = getFirstChannel(img); - } - if (img.type() != CV_32FC1) - { - converToType(img, CV_32FC1); - } - - Mat gaussImg; - GaussianBlur(img, gaussImg, Size(3, 3), 5.0); - img = gaussImg; - - Mat hightlightsMask = img < highlightsThreshold; - Mat imgMask = hightlightsMask & mask & (weightMat > 0); - - Scalar meanScalar, stddevScalar; - meanStdDev(img, meanScalar, stddevScalar, imgMask); - img = (img - meanScalar.val[0]) * dstStddev / stddevScalar.val[0] + dstMean; - //img.setTo(0, img < 0); - converToType(hightlightsMask, CV_32FC1); - //converToType(imgMask, CV_32FC1); - Mat imgNorm = cocentricNorm(img, Point2f(img.cols / 2.0, img.rows / 2.0), - weightMat.mul(hightlightsMask), 125); -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vImgNorm = imgNorm / 255.0; -#endif - img = imgNorm; -} - -void ImageCompareModel::preProcessImage0(Mat& img) const -{ - -} - -double ImageCompareModel::compare(Mat img0, Mat img1, Mat* pRImg0, Mat* pRImg1) -{ - if (img0.size() != img1.size() && img0.size() != mAlignBaseImg.size()) - { - return -1; - } - - double bestMatchVal = DBL_MAX; - int bestAngle = -1; - Mat bestImg1; - double bestDD = 0; - - double w = 0; - - Point2f center((float)img1.cols / 2.0, (float)img1.rows / 2.0); - Mat rImg0 = rotateMatch(img0).mBestRImg; - Mat rImg1 = rotateMatch(img1).mBestRImg; - Mat dMat = rImg0 - rImg1; - converToType(dMat, CV_32FC1); - dMat = dMat.mul(mWeightMat); - - if (pRImg0) - { - *pRImg0 = rImg0; - } - if (pRImg1) - { - *pRImg1 = rImg1; - } - - return genMatchValue(dMat); -} - -double ImageCompareModel::compare(Mat srcImage, Mat* pRImg /*= NULL*/, int levelNum /*= 1*/, - bool isFilterSize /*= true*/, int flag, double md_diameter, double md_height) -{ - if (mIsEnableCache) - { - auto cacheIter = mDisCache.find(srcImage.data); - if (cacheIter != mDisCache.end()) - { - return cacheIter->second; - } - } -/* CircleDetector cd; - cd.setAlgoType(CircleDetector::PeakCircle); - cd.setEdgeWidth(3); - //cd.setPolarity(Polarity::White2Black); - cd.setPolarity(Polarity::Either); - cd.setFindBy(FindBy::Best); - //cd.setFindBy(FindBy::Last); - cd.setRadii(MIN_CIRCLE_RADII, MAX_CIRCLE_RADII); - cd.setACThres(5); - Vec3f bestCircle; - cd.detectBest(srcImage, Point2f(srcImage.cols / 2, srcImage.rows / 2), bestCircle, nullptr); - -#ifdef DEBUG_VIEW_INTERNAL_MAT - vector vecs; - vecs.push_back(srcImage); - vecs.push_back(srcImage); - vecs.push_back(srcImage); - Mat rr; - merge(vecs, rr); - - circle(rr, Point2f(bestCircle[0], bestCircle[1]), bestCircle[2], Scalar(255, 0, 0), 2); -#endif - - if (bestCircle[2] < 3 || bestCircle[0] == 0 || bestCircle[1] == 0) - return DBL_MAX; - */ -// int x_Axis = bestCircle[0] - MAX_CIRCLE_RADII; -// int y_Axis = bestCircle[1] - MAX_CIRCLE_RADII; - - int x_Axis = srcImage.cols / 2 - MAX_CIRCLE_RADII; - int y_Axis = srcImage.rows / 2 - MAX_CIRCLE_RADII; - - int r_Axis = 2 * MAX_CIRCLE_RADII; - - if (x_Axis <= 0 || y_Axis <= 0) - return DBL_MAX; - if (r_Axis <= 0) - return DBL_MAX; - if (r_Axis >= srcImage.cols || r_Axis >= srcImage.rows) - return DBL_MAX; -// if (srcImage.cols < (bestCircle[0] + MAX_CIRCLE_RADII) || srcImage.rows < (bestCircle[1] + MAX_CIRCLE_RADII)) -// return DBL_MAX; - - if (srcImage.cols < (srcImage.cols / 2 + MAX_CIRCLE_RADII) || srcImage.rows < (srcImage.rows / 2 + MAX_CIRCLE_RADII)) - return DBL_MAX; - - Rect rect(x_Axis, y_Axis, r_Axis, r_Axis); - Mat srcCenterMat; - srcImage(rect).copyTo(srcCenterMat); - Mat img, centerMat; - resizeMat(srcImage, img); - resizeMat(srcCenterMat, centerMat); - Mat rawImg = img.clone(); - int nRadiusDiff = 15; - if (mAlignBaseImg.size() != img.size() || mInSideBaseImg.size() !=centerMat.size()) - { - if (isFilterSize \ - && abs(mAlignBaseImg.size().width - img.size().width) > nRadiusDiff \ - || abs(mInSideBaseImg.size().width - centerMat.size().width) > 3) - { - return DBL_MAX; - } - resize(img, img, mAlignBaseImg.size()); - resize(centerMat, centerMat, mInSideBaseImg.size()); - } - - Mat matchImg = img.clone(); - Mat matchInsideImg = centerMat.clone(); - - preProcessImage(matchImg, matchInsideImg); - - if (!mpMultiScaleModel) - { - initMultiScaleModel(); - } - m_parallelFlag = 0; - RotateMatchResult rmr = rotateMatch(matchImg, levelNum); - Mat rImg = rmr.mBestRImg; - m_parallelFlag = 1; - RotateMatchResult rmmInside = rotateMatch(matchInsideImg, 1); - Mat rInsideImg = rmmInside.mBestRImg; - if (rImg.empty() || rInsideImg.empty()) - { - return DBL_MAX; - } - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vRImg = rImg / 255.0; - Mat vInsideMat = rInsideImg / 255.0; -#endif - - double bestAngle = rmr.mBestAngle; - Mat cmpImg = rotateImage(img, Point2f(img.cols / 2.0, img.rows / 2.0), - bestAngle); - - // remove highlights - Mat hightlightsMask = cmpImg < mHighlightsThreshold; - converToType(hightlightsMask, CV_32FC1); - hightlightsMask /= 255.0; - - Mat unifiedMask = m32fMaskImg.mul(hightlightsMask).mul(mWeightMat); - //Mat ii = mWeightMat / 255.0; - preProcessImage(cmpImg, m8uMaskImg, mWeightMat, mTargetMeanVal, - mTargetStddevVal, mHighlightsThreshold); - - cmpImg.setTo(0, cmpImg < 0); - - converToType(cmpImg, CV_32FC1); - normSectors_tarImg(cmpImg, unifiedMask, imgCen(cmpImg), 1, - mCompareBaseImg); - - double bestInsideAngle = rmmInside.mBestAngle; - Mat camInsideMat = rotateImage(centerMat, Point2f(centerMat.cols / 2.0, centerMat.rows / 2.0), - bestInsideAngle); - -// float offset = 5; -// float startX = mAlignBaseImg.cols / 2.0 - rInner - offset; -// float startY = mAlignBaseImg.rows / 2.0 - rInner - offset; -// Rect rect(startX, startY, 2*(rInner + offset), 2*(rInner + offset)); -// Mat innerPartMat = camInsideMat(rect); -// Mat rstMat; -// cv::matchTemplate(innerTempl, innerPartMat, rstMat, CV_TM_SQDIFF_NORMED); -// double minVal; -// Point minLoc; -// minMaxLoc(rstMat, &minVal, NULL, &minLoc, NULL); -//#ifdef DEBUG_VIEW_INTERNAL_MAT -// Mat test1 = innerPartMat.clone(); -// Mat test2 = innerPartMat.clone(); -// vector imgs; -// imgs.push_back(test2); -// imgs.push_back(test1); -// imgs.push_back(innerPartMat); -// Mat rst; -// merge(imgs, rst); -// cv::rectangle(rst, Rect(minLoc.x, minLoc.y, innerTempl.cols, innerTempl.rows), Scalar(0, 0, 255)); -//#endif -// //debug -// - Mat highLightInsideMask = camInsideMat < mHighlightsThreshold; - converToType(highLightInsideMask, CV_32FC1); - highLightInsideMask /= 255.0; - Mat unifiedInsideMask = m32fInsideMaskImg.mul(highLightInsideMask).mul(mInsideWeightMat); - preProcessImage(camInsideMat, m8uInsideMaskImg, mInsideWeightMat, mTargetMeanVal, - mTargetStddevVal, mHighlightsThreshold); - Mat vcamInside = camInsideMat / 255.0; - camInsideMat.setTo(0, camInsideMat < 0); - //mInsideCompareBaseImg.setTo(0, mInsideCompareBaseImg < 0); - normSectors_tarImg(camInsideMat, unifiedInsideMask, imgCen(camInsideMat), 1, mInsideCompareBaseImg); - // - mInsideCompareBaseImg.setTo(0, mInsideCompareBaseImg < 0); -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vRotatedImg0 = cmpImg / 255.0; - Mat vrotatedInsideImage = camInsideMat / 255.0; - cv::imwrite("F:\\temp\\insideAfterSector.png", camInsideMat); -#endif - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vRotatedImg1 = mCompareBaseImg / 255.0; - Mat vrotatedInsideBase = mInsideCompareBaseImg / 255.0; - cv::imwrite("F:\\temp\\insideAfterSectorCompareBase.png", mInsideCompareBaseImg); -#endif - - cmpImg.setTo(0, cmpImg < 10); - //camInsideMat.setTo(0, camInsideMat < 10); - if (pRImg) - { - *pRImg = cmpImg; - } - m_parallelFlag = 0; - double ret = genMatchValue(cmpImg, mCompareBaseImg, unifiedMask, flag, rawImg.rows, md_diameter, md_height);//óֵ - - m_parallelFlag = 1; - double retInside = genMatchValue(camInsideMat, mInsideCompareBaseImg, unifiedInsideMask, 0, rawImg.rows, md_diameter, md_height);//óֵ - - ret = 0.6*ret + 0.4*retInside; - - if (ret > mDisThre) - { - return DBL_MAX; - } - - if (mIsEnableCache) - { - mDisCache[img.data] = ret; - if (mDisCache.size() > IMGCMP_CACHE_MAX_SIZE) - { - mDisCache.clear(); - } - } - return ret; -} - -void ImageCompareModel::train(const vector& vec) -{ -#ifdef _DEBUG - std::cout << getName() << std::endl; -#endif _DEBUG - if (0 == vec.size()) { - return; - } - -// CircleDetector cd; -// cd.setAlgoType(CircleDetector::PeakCircle); -// cd.setEdgeWidth(3); -// //cd.setPolarity(Polarity::White2Black); -// cd.setPolarity(Polarity::Either); -// cd.setFindBy(FindBy::Best); -// //cd.setFindBy(FindBy::Last); -// cd.setRadii(MIN_CIRCLE_RADII, MAX_CIRCLE_RADII); -// cd.setACThres(5); - vector centerMatVec; - vector tmpVec; - for (int i = 0; i < vec.size(); i++) - { - Mat originalMat = vec[i]; - Vec3f bestCircle; - Point2f p = Point2f(originalMat.cols / 2.0, originalMat.rows / 2.0); -// cd.detectBest(originalMat, Point2f(originalMat.cols / 2.0, originalMat.rows / 2.0), bestCircle, nullptr); -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat img1 = vec.front().clone(); - Mat img2 = vec.front().clone(); - vector vecs; - vecs.push_back(originalMat); - vecs.push_back(originalMat); - vecs.push_back(originalMat); - Mat rr; - merge(vecs, rr); - - circle(rr, Point2f(bestCircle[0], bestCircle[1]), bestCircle[2], Scalar(255, 0, 0), 2); - vector imgVec; - resizeVecMat(vec, imgVec); - vector vecss; - vecss.push_back(originalMat); - vecss.push_back(originalMat); - vecss.push_back(originalMat); - Mat rrr; - merge(vecss, rrr); - - // circle(rrr, Point2f(bestCircle[0] / COLS_SCALE, bestCircle[1] / COLS_SCALE), rInner, Scalar(255, 0, 0), 1); -#endif // DEBUG_VIEW_INTERNAL_MAT - - //bob edit -// if (bestCircle[2] > 0.00000001) -// { -// float startX = bestCircle[0] - MAX_CIRCLE_RADII;//Բ⾶̶ֱ -// float startY = bestCircle[1] - MAX_CIRCLE_RADII; -// Rect rect(startX, startY, MAX_CIRCLE_RADII * 2, MAX_CIRCLE_RADII * 2); -// Mat origianlCenterMat; -// originalMat(rect).copyTo(origianlCenterMat); -// centerMatVec.push_back(origianlCenterMat); -// tmpVec.push_back(vec[i]); -// } -// else -// { -// int a = 0; -// } - - float startX = originalMat.cols / 2.0 - MAX_CIRCLE_RADII;//Բ⾶̶ֱ - float startY = originalMat.rows / 2.0 - MAX_CIRCLE_RADII; - Rect rect(startX, startY, MAX_CIRCLE_RADII * 2, MAX_CIRCLE_RADII * 2); - Mat origianlCenterMat; - originalMat(rect).copyTo(origianlCenterMat); - centerMatVec.push_back(origianlCenterMat); - tmpVec.push_back(vec[i]); - - /*bob end edit*/ - -// if (bestCircle[2] > 0.00000001) -// { -// float startX = bestCircle[0] - bestCircle[2]; -// float startY = bestCircle[1] - bestCircle[2]; -// Rect rect(startX, startY, bestCircle[2]*2, bestCircle[2]*2); -// Mat origianlCenterMat; -// originalMat(rect).copyTo(origianlCenterMat); -// centerMatVec.push_back(origianlCenterMat); -// } -// else -// { -// -// } - } - vector scaledCenterVec; - resizeVecMat(centerMatVec, scaledCenterVec); - if (scaledCenterVec.size() <= 0) - return; - if (tmpVec.size() <= 0) - return; - - vector imgVec; - resizeVecMat(tmpVec, imgVec); - mAlignBaseImg = imgVec.front(); - mInSideBaseImg = scaledCenterVec.front(); - genMask(); - //Mat baseTempl = imgVec.front(); - //float realR = rInner + 2; - //float hf_width = sqrt(realR*realR / 2.0); - //float startx = baseTempl.cols / 2 - hf_width; - //float starty = baseTempl.rows / 2 - hf_width; - //Rect rect(startx, starty, 2*hf_width, 2*hf_width); - //innerTempl = baseTempl(rect); - preProcessImage(mAlignBaseImg, mInSideBaseImg);//Ԥ վ - Mat sumOutsideMat = Mat::zeros(mAlignBaseImg.size(), CV_32FC1); - Mat sumInsideMat = Mat::zeros(mInSideBaseImg.size(), CV_32FC1); - Mat minOutsideMat(mAlignBaseImg.size(), mAlignBaseImg.type()); - Mat minInsideMat(mInSideBaseImg.size(), mInSideBaseImg.type()); - minOutsideMat.setTo(FLT_MAX); - minInsideMat.setTo(FLT_MAX); - vector rImgVec; - vector rInsideImgVec; - vector rmrVec; - vector rmrVecInside; - vector resizedImgVec; - vector resizedCenterVec; - //vector resizedWarp; - vector diametersVec; - for (int i = 0; i < imgVec.size(); ++i) - { - diametersVec.push_back(imgVec[i].rows); - Mat img = imgVec[i].clone(); - if (img.size() != mAlignBaseImg.size()) - { - Mat resizedImg; - resize(img, resizedImg, mAlignBaseImg.size()); - //resize(warpImage, warpImage, mAlignBaseImg.size()); - img = resizedImg; - } - - Mat centerMat = scaledCenterVec[i]; - if (centerMat.size() != mInSideBaseImg.size()) - { - Mat resizedCenterMat; - resize(centerMat, resizedCenterMat, minInsideMat.size()); - centerMat = resizedCenterMat; - } - resizedImgVec.push_back(img); - resizedCenterVec.push_back(centerMat); - //resizedWarp.push_back(warpImage); - //Mat insideImg = img.clone(); - preProcessImage(img, centerMat); - m_parallelFlag = 0; - RotateMatchResult rmr = rotateMatch(img);//תƥ ƥɵĽǶȼͼƬ - rmrVec.push_back(rmr); - m_parallelFlag = 1; - RotateMatchResult rmrInside = rotateMatch(centerMat); - rmrVecInside.push_back(rmrInside); - - Mat rImg = rmr.mBestRImg; - //rImgVec.push_back(rImg); - - Mat rInsideImg = rmrInside.mBestRImg; - rInsideImgVec.push_back(rInsideImg); - //minMat = min(minMat, rImg); - minOutsideMat = min(minOutsideMat, rImg);//Ȩͼ ȥë - sumOutsideMat += rImg; - - minInsideMat = min(minInsideMat, rInsideImg); - sumInsideMat += rInsideImg; - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat viewRImg = rImg / 255.0; - Mat viewRInsideImg = rInsideImg / 255.0; - Mat viewImage = minOutsideMat / 255.0; - Mat viewInside = minInsideMat / 255.0; -#endif - } - meanDiameter = mean(diametersVec)[0]; - - Mat avgMat = sumOutsideMat / imgVec.size(); - mAlignBaseImg = avgMat; - - Mat avgInsideMat = sumInsideMat / imgVec.size(); - mInSideBaseImg = avgInsideMat; -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vAvgMat = avgMat / 255.0; - Mat vAvgInsideMat = avgInsideMat / 255.0; -#endif - //mWeightMat = minMat; - mWeightMat = minOutsideMat; - mWeightMat /= 255.0; - mInsideWeightMat = minInsideMat; - mInsideWeightMat /= 255.0; - /*luffy_base::luffy_imageProc::*/meanvarnorm(mWeightMat, mWeightMat,//Ȩؽ һ - mTargetMeanVal, 150, m8uMaskImg); - mWeightMat.setTo(0, mWeightMat < 10); - Scalar meanScalar, stddevScalar; - meanStdDev(mInsideWeightMat, meanScalar, stddevScalar, m8uInsideMaskImg); - mInsideWeightMat = mInsideWeightMat* (127 / meanScalar.val[0]); - //luffy_base::luffy_imageProc::meanvarnorm(mInsideWeightMat, mInsideWeightMat, - // mTargetMeanVal, 50, m8uInsideMaskImg); - mInsideWeightMat.setTo(0, mInsideWeightMat < 0); - - { - if(mRepeatNum <= 0) - { - mRepeatNum = computeRepeatNum(); - } - selfRotateMin(mWeightMat, mWeightMat, mRepeatNum); - } - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vWeightMat = mWeightMat / 255.0; - Mat vBaseMat = mAlignBaseImg / 255.0; - // Mat vMinMat = minMat / 255.0; - Mat vMinMat = minOutsideMat / 255.0; - - Mat vInsideWeight = mInsideWeightMat / 255.0; - Mat vInsidebaseMat = mInSideBaseImg / 255.0; - Mat vMinInsideMat = minInsideMat / 255.0; - -#endif - - sumOutsideMat.setTo(0); - sumInsideMat.setTo(0); - for (int i = 0; i < rmrVec.size(); ++i) - { - double bestAngle = rmrVec[i].mBestAngle; - Mat img = resizedImgVec[i]; - Mat rotatedImg = rotateImage(img, Point2f(img.cols/2.0, img.rows/2.0), - bestAngle); - - preProcessImage(rotatedImg, m8uMaskImg, mWeightMat, mTargetMeanVal, - mTargetStddevVal, mHighlightsThreshold); - - double bestInsidePart = rmrVecInside[i].mBestAngle; - //Mat i_Mat = resizedImgVec[i]; - Mat centerMat = resizedCenterVec[i]; - Mat rotatedInsideMat = rotateImage(centerMat, Point2f(centerMat.cols / 2.0, centerMat.rows / 2.0), bestInsidePart); - - preProcessImage(rotatedInsideMat, m8uInsideMaskImg, mInsideWeightMat, mTargetMeanVal, - mTargetStddevVal, mHighlightsThreshold); - - sumOutsideMat += rotatedImg; - //rotatedInsideMat.setTo(0, rotatedInsideMat < 0); - sumInsideMat += rotatedInsideMat; - } - mCompareBaseImg = sumOutsideMat / resizedImgVec.size();//õƥͼ - mInsideCompareBaseImg = sumInsideMat / resizedImgVec.size(); -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vCompareBaseImg = mCompareBaseImg / 255.0; - vWeightMat = mWeightMat / 255.0; - Mat vcompareInsideBaseImg = mInsideCompareBaseImg / 255.0; - vInsideWeight = mInsideWeightMat / 255.0; - //cv::imwrite("F:\\temp\\insideWeight.png", mInsideWeightMat); - //cv::imwrite("F:\\temp\\insideBase.png", mInSideBaseImg); - //cv::imwrite("F:\\temp\\insideCompareBase.png", mInsideCompareBaseImg); -#endif - - trueSampleWeightRecon(resizedImgVec, resizedCenterVec, rmrVec, rmrVecInside); - mWeightMat = falseReConMat.clone(); - mInsideWeightMat = insideWeightRecon.clone(); -} - -void ImageCompareModel::trueSampleWeightRecon(const vector& resizedVec, - const vector& resizedCenterVec, - vector rmrVec, - vector rmrVecInside) -{ - falseReConMat = mWeightMat.clone(); - insideWeightRecon = mInsideWeightMat.clone(); - for (int i = 0; i < resizedVec.size(); i++) - { - const Mat &img = resizedVec[i]; - double bestAngle = rmrVec[i].mBestAngle; - //preProcessImage(processedImg, insideMatchImg); - Mat rotatedImg = rotateImage(img, Point2f(img.cols / 2.0, img.rows / 2.0), - bestAngle); - - Mat hightlightsMask = rotatedImg < mHighlightsThreshold; - converToType(hightlightsMask, CV_32FC1); - hightlightsMask /= 255.0; - - Mat unifiedMask = m32fMaskImg.mul(hightlightsMask).mul(mWeightMat); - - preProcessImage(rotatedImg, m8uMaskImg, mWeightMat, mTargetMeanVal, - mTargetStddevVal, mHighlightsThreshold); - - rotatedImg.setTo(0, rotatedImg < 0); - converToType(rotatedImg, CV_32FC1); - normSectors_tarImg(rotatedImg, unifiedMask, imgCen(rotatedImg), 1, mCompareBaseImg); - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vRotatedImg1 = rotatedImg / 255.0; -#endif - rotatedImg.setTo(0, rotatedImg < 10); - - ////// FOR INSIDE CIRCLE - double insideBestAngle = rmrVecInside[i].mBestAngle; - const Mat & centerMat = resizedCenterVec[i]; - Mat rotatedInsideImg = rotateImage(centerMat, Point2f(centerMat.cols / 2.0, centerMat.rows / 2.0), - insideBestAngle); - - Mat highLightInsideMask = rotatedInsideImg < mHighlightsThreshold; - converToType(highLightInsideMask, CV_32FC1); - highLightInsideMask /= 255.0; - Mat unifiedInsideMask = m32fInsideMaskImg.mul(highLightInsideMask).mul(mInsideWeightMat); - preProcessImage(rotatedInsideImg, m8uInsideMaskImg, mInsideWeightMat, mTargetMeanVal, - mTargetStddevVal, mHighlightsThreshold); - Mat vcamInside = rotatedInsideImg / 255.0; - rotatedInsideImg.setTo(0, rotatedInsideImg < 0); - //mInsideCompareBaseImg.setTo(0, mInsideCompareBaseImg < 0); - normSectors_tarImg(rotatedInsideImg, unifiedInsideMask, imgCen(rotatedInsideImg), 1, mInsideCompareBaseImg); - trueWeightRecon(rotatedImg, mCompareBaseImg, rotatedInsideImg, mInsideCompareBaseImg); - } -} - -void ImageCompareModel::trueWeightRecon(const Mat& rImg, const Mat& baseImg, - const Mat& insideRimg, const Mat& insideBaseImg) -{ - Mat dMat = abs(rImg - baseImg); -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat tt = dMat / 255.0; - Mat m1 = rImg / 255.0; - Mat b1 = baseImg / 255.0; -#endif // DEBUG_VIEW_INTERNAL_MAT - - //Mat mData = dMat.mul(m32fMaskImg).mul(mWeightMat); - Mat mData; - dMat.copyTo(mData, dMat > 1000); - - double outterVal = sum(mData).val[0]; - if (outterVal != 0) - { - mData = minMaxNorm(mData, 0, 255.0); - } - - - Mat i_dMat = abs(insideRimg - insideBaseImg); -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat i_tt = i_dMat / 255.0; - Mat i_m1 = insideRimg / 255.0; - Mat i_b1 = insideBaseImg / 255.0; - Mat i_maskR = i_m1.mul(m32fInsideMaskImg); - Mat i_masB = i_b1.mul(m32fInsideMaskImg); - -#endif // DEBUG_VIEW_INTERNAL_MAT - Mat i_mData; - i_mData.setTo(0); - //Mat test = i_dMat / 255; - //Mat imgtest = i_dMat.mul(m32fInsideMaskImg) / 255; - Mat innerDmat = i_dMat.mul(m32fInsideMaskImg).mul(mInsideWeightMat); - innerDmat = minMaxNorm(innerDmat, 0, 255.0); - - weightMapping(mData, 255.0, innerDmat, 255.0); -} - -void ImageCompareModel::weightMapping(const Mat& mData, double maxVal, const Mat& i_mData, double i_maxVal) -{ - for (int i = 0; i < mData.rows; i++) - { - float* pData = (float*)mData.row(i).data; - float*pWeight = (float*)falseReConMat.row(i).data; - - for (int j = 0; j < mData.cols; j++) - { - double pixVal = pData[j]; - - if (pixVal != 0) - { - double affineCoeff = descendFunction(pixVal, maxVal); - pWeight[j] *= affineCoeff; - } - - - - - } - } - - - for (int i = 0; i < i_mData.rows; i++) - { - float* i_pData = (float*)i_mData.row(i).data; - float*i_pWeight = (float*)insideWeightRecon.row(i).data; - - for (int j = 0; j < i_mData.cols; j++) - { - double i_pixVal = i_pData[j]; - - if (i_pixVal != 0) - { - double affineCoeff = descendFunction(i_pixVal, i_maxVal); - i_pWeight[j] *= affineCoeff; - } - } - } -} -double ImageCompareModel::descendFunction(double pixVal, double maxVal) -{ - return (-1.0 / maxVal)*pixVal + 1.0; - //return -1 * pow(pixVal, 2) + 1; -} - - -void ImageCompareModel::calculateAllParams(const vector& imgVec) -{ - mDisThre = DBL_MAX; - Mat disMat(1, imgVec.size(), CV_64FC1); - for (int i = 0; i < imgVec.size(); ++i) - { - const Mat& img = imgVec[i]; - double dis = compare(img, NULL, 1, false, 0); - disMat.at(i) = dis; - //disMat.copyTo(mDisMat); - } - - if (disMat.cols == 1) - { - mTrueSampleDisStddev = 0; - mTrueSampleDisMean = disMat.at(0); - } - else - { - Scalar m, s; - meanStdDev(disMat, m, s); - mTrueSampleDisStddev = s.val[0]; - mTrueSampleDisMean = m.val[0]; - } - disMat.copyTo(mDisMat); - minMaxIdx(disMat, &mTrueSampleDisMin, &mTrueSampleDisMax); -} - -void ImageCompareModel::computeDisThre(const vector& imgVec, double* pMinDis, double md_diameter, double md_height) -{ - if (imgVec.empty()) - { - return; - } - mDisThre = DBL_MAX; - vector disVec; - std::map imgs; - for_each(imgVec.begin(), imgVec.end(), [&](Mat img) - { - double dis = compare(img, NULL, 3, false, 1, md_diameter, md_height); - disVec.push_back(dis); - imgs[dis] = img; - }); - double minDis = *(min_element(disVec.begin(), disVec.end())); - setFalseSampleMinDis(minDis); - - if (pMinDis) - { - *pMinDis = minDis; - } - if (minDis > mTrueSampleDisMax) - { - mDisThre = mTrueSampleDisMax*0.3 + minDis*0.7; - //mDisThre = mTrueSampleDisMax*0.15 + minDis*0.85 + mTrueSampleDisStddev; - //mDisThre = minDis; - if (mDisThre > mTrueSampleDisMax*1.8) - { - mDisThre = mTrueSampleDisMax*1.8; - } - } - else - { - mDisThre = DBL_MAX; - std::cout << "max distance in training > min distance in testing" << std::endl; - } -} - -void ImageCompareModel::genUniformSepIdx(int num, int startIdx, int endIdx, vector& cenVec) -{ - float step = (endIdx - startIdx) / (num); - for (int i = 0; i < num; i++) - { - cenVec.push_back(floorf(step*i + startIdx)); - } -} - -void ImageCompareModel::genAngleRanges(vector cenVec, vector& rangeVec, int localRange) -{ - rangeVec.clear(); - for_each(cenVec.begin(), cenVec.end(), [&](int cen) - { - Range r; - r.start = cen - localRange; - r.end = cen + localRange + 1; - rangeVec.push_back(r); - }); -} - -void ImageCompareModel::genCandidateAngleRanges(vector disVec, - float angleStep, vector& rangeVec) -{ - auto minDisIter = min_element(disVec.begin(), disVec.end()); - int startIdx = minDisIter - disVec.begin(); - - rotate(disVec.begin(), minDisIter, disVec.end()); - - Mat disVecMat(1, disVec.size(), CV_32FC1, &(disVec[0])); - Mat normDisVecMat; - /*luffy_base::luffy_imageProc::*/meanvarnorm(disVecMat, normDisVecMat, 0, 1.0); - - set canNums; - genCandidateRepeatNums(canNums); - vector cenVec; - int repeatNum = recognizeLowerExtremes(normDisVecMat, canNums, 5, &cenVec); -#ifdef _TEST - if (repeatNum <= 0) - { - std::cout << "repeatNum < 0" << std::endl; - //waitKey(); - } -#endif - if (repeatNum < 0) - { - rangeVec.clear(); - return; - cenVec.clear(); - cenVec.push_back(disVec.size() / 2); - genAngleRanges(cenVec, rangeVec, disVec.size() / 2); - } - else - { - if (cenVec.size() >= 2 && diffAngleRaw(cenVec.front(), cenVec.back()) < 2) - { - cenVec.pop_back(); - } - - for_each(cenVec.begin(), cenVec.end(), [&](int& cen) - { - cen += startIdx; - cen *= angleStep; - cen = normAngle(cen); - }); - for (auto i = cenVec.begin(); i != cenVec.end(); ++i) - { - if (*i < startIdx*angleStep) - { - rotate(cenVec.begin(), i, cenVec.end()); - break; - } - } -#ifdef _TEST - for (int i = 0; i < cenVec.size() - 1; ++i) - { - float curVal = cenVec[i]; - float nxtVal = cenVec[i + 1]; - if (nxtVal <= curVal) - { - std::cout << "assert nxtVal <= curVal failed" << std::endl; - waitKey(); - } - } -#endif - genAngleRanges(cenVec, rangeVec, 10); - } - -} - -void ImageCompareModel::genCandidateAngleRanges(const Mat& disMat, - float angleStep, vector& rangeVec, float rangeScale /*= 1*/) -{ - for (int i = 0; i < disMat.rows; ++i) - { - Mat disVec = disMat.row(i); - double minVal, maxVal; - Point minPt, maxPt; - minMaxLoc(disVec, &minVal, &maxVal, &minPt, &maxPt); - Range &r = rangeVec[i]; - float cenAngle = r.start + angleStep*minPt.x; - float angleRangeWidth = r.end - r.start; - - r.start = floorf(cenAngle - angleRangeWidth * 0.5 * rangeScale); - r.end = floorf(cenAngle + angleRangeWidth * 0.5 * rangeScale); - } -} - -void ImageCompareModel::selfRotateMin(const Mat& img, Mat& weightMat, int repeatNum) -{ - Point2f cen(img.cols / 2.0, img.rows / 2.0); - float angleStep = 360.0 / repeatNum; - Mat dSumMat = Mat::ones(img.size(), img.type()) * 255; - //Mat dSumMat = Mat::ones(img.size(), img.type()); - for (int i = 1; i < repeatNum; ++i) - { - Mat rotatedImg = rotateImage(img, cen, i*angleStep); - Mat dilatedImg; - dilate(rotatedImg, dilatedImg, Mat::ones(3, 3, CV_32FC1)); - dSumMat = min(dSumMat, dilatedImg); - } - weightMat = dSumMat; -} - -double ImageCompareModel::genMatchValue(const Mat& dMat) const -{ - double v = norm(dMat, NORM_L2); - - double ret = scaleMatchValue(v); - - return ret; -} - -double ImageCompareModel::genMatchValue(const Mat& rImg, const Mat& baseImg, - const Mat& maskImg, int flag, int diameter, double md_diameter, double md_height) const -{ - Mat dMat = rImg - baseImg; - //Mat testMask = maskImg.mul(m32fMaskImg); - dMat = abs(dMat.mul(maskImg)); - //dMat = abs(dMat.mul(testMask)); -#ifdef DEBUG_VIEW_INTERNAL_MAT - //Mat vRImg = rImg.mul(m32fMaskImg) / 255.0; - Mat vDMat0 = abs(dMat) / 255.0; - //Mat vBase = baseImg.mul(m32fMaskImg) / 255.0; - Mat vDMat = abs(dMat) / 255.0 / 255.0; - - //Mat vinsideImg = rImg.mul(m32fInsideMaskImg) / 255.0; - //Mat vinsideBase = baseImg.mul(m32fInsideMaskImg) / 255.0; - - // Mat vMask = maskImg / 255.0; - //Mat vMask = testMask / 255.0; -#endif - Mat minmaxScaleMat; - Mat mMask; - if (m_parallelFlag != 1) - { - minmaxScaleMat = minMaxNorm(dMat, 0, 255, m8uMaskImg); - converToType(minmaxScaleMat, CV_8UC1); - mMask = lowerMajorityMask(minmaxScaleMat, m8uMaskImg, 0.98); - printLog("myLog.txt", "finish outside mMask Part"); - } - else - { - minmaxScaleMat = minMaxNorm(dMat, 0, 255, m8uInsideMaskImg); - converToType(minmaxScaleMat, CV_8UC1); - mMask = lowerMajorityMask(minmaxScaleMat, m8uInsideMaskImg, 0.97); - printLog("myLog.txt", "finish inside mMask Part"); - } - - converToType(mMask, CV_32FC1); - mMask /= 255.0; - - dMat = dMat.mul(mMask); - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vDMat1 = abs(dMat) / 255.0 / 255.0; -#endif - Mat vii = mMask.mul(maskImg); - Mat ii = mMask.mul(maskImg) / 255.0; - double s = sum(mMask.mul(maskImg)).val[0]; - double ret = genMatchValue(dMat) / s; - - if (flag == 1) - { - double matchedVal = ret; - ret = penltyCoeff(matchedVal, meanDiameter, diameter, md_diameter, md_height);//ͷ - printf("the matched value %f", ret); - } - printLog("myLog.txt", "finish detect, return val"); - return ret; -} - -double ImageCompareModel::scaleMatchValue(double val) const -{ - return val*mMatchValScale; -} - - -ImageCompareModel* ImageCompareModel::scale(float s) -{ - Mat baseImage; - resize(mAlignBaseImg, baseImage, Size(), s, s, INTER_CUBIC); - Mat weightMat; - resize(mWeightMat, weightMat, Size(), s, s, INTER_CUBIC); - - ImageCompareModel* pRet = new ImageCompareModel; - *pRet = *this; - pRet->setBaseImg(baseImage); - pRet->setWeightMat(weightMat); - - //pRet->genMask(); - pRet->genOutterMask(); - -// Mat mask8uImg; -// resize(m8uMaskImg, mask8uImg, Size(), s, s, INTER_NEAREST); -// Mat mask32fImg; -// resize(m32fMaskImg, mask32fImg, Size(), s, s, INTER_NEAREST); -// -// pRet->set8uMaskImg(mask8uImg); -// pRet->set32fMaskImg(mask32fImg); - - return pRet; -} - -ImageCompareModel::RotateMatchResult ImageCompareModel::rotateMatch(const Mat& img, int levelNum /*= 1*/, float angleStep /*= 1.0*/, - float startAngle /*= 0*/, float endAngle /*= 360*/) const -{ -#ifdef _TEST - static int idx = 0; - std::cout << idx << " "; -#endif - RotateData* pData = new RotateData; - vector angleRangeVec; - if (levelNum > 1) - { - MultiScaleImage msi; - msi.setLevelNum(3); - msi.setBaseLevel(img); - msi.genMultiScale(); - ImageCompareData imgCmpData(&msi); - imgCmpData.setStartAngle(startAngle); - imgCmpData.setEndAngle(endAngle); - - mpMultiScaleModel->proc(&imgCmpData); - - *pData = *imgCmpData.getRotateData(); - } - else - { - rotateMatchData(img, pData, angleStep, startAngle, endAngle); - } - -#ifdef _TEST - if(1) - { - //if (idx == 15) - { - RotateData* pTestData = new RotateData; - rotateMatchData(img, pTestData, angleStep, startAngle, endAngle); - -// 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 - stringstream ss; - ss << "multi_scale_comp_plot"; - CvPlot::clear(ss.str()); - CvPlot::plot(ss.str(), &(pTestData->mDisValVec[0]), - pTestData->mDisValVec.size()); -#endif - - float baseAngle = pTestData->bestAngle(); - float curAngle = pData->bestAngle(); - std::cout << baseAngle << " " << curAngle << " " << baseAngle - curAngle << std::endl; - delete pTestData; - if (abs(diffAngleRaw(baseAngle, curAngle)) > 1) - { - waitKey(); - } - } - idx++; - } -#endif - - RotateMatchResult rmr; - - if (pData->mDisValVec.empty()) - { - delete pData; - return rmr; - } - else - { - size_t bestIndex = min_element(pData->mDisValVec.begin(), pData->mDisValVec.end()) - pData->mDisValVec.begin(); - - Mat ret = pData->mRImgVec[bestIndex]; - rmr.mBestRImg = ret; - rmr.mBestAngle = pData->bestAngle(); - - delete pData; - - return rmr; - } -} - -void ImageCompareModel::rotateMatchData(const Mat& _img, RotateData* pData, - float angleStep /*= 1.0*/, float startAngle /*= 0*/, float endAngle /*= 360*/) const -{ - //Mat img = _img.clone(); - if (_img.empty()) - return; - Point2f center(_img.cols / 2.0, _img.rows / 2.0); - int nNum = (endAngle - startAngle) / angleStep; - RotateData& data = *pData; - data.init(_img.clone(), center, angleStep, nNum); - data.mStartAngle = startAngle; - data.mEndAngle = endAngle; - - parallel_for_(Range(0, nNum), ImageCompareModelInvoker(this, pData)); -} - -void ImageCompareModel::rotateMatchData(const Mat& img, RotateData* pData, - float angleStep /*= 1.0*/, const vector& angleRangeVec) const -{ - float minDis = FLT_MAX; - RotateData bestData; - for_each(angleRangeVec.begin(), angleRangeVec.end(), [&](const Range& r) - { - float startAngle = r.start; - float endAngle = r.end; - rotateMatchData(img, pData, angleStep, startAngle, endAngle); - float localMinDis = *min_element(pData->mDisValVec.begin(), pData->mDisValVec.end()); - if (localMinDis < minDis) - { - minDis = localMinDis; - bestData = *pData; - } - }); - *pData = bestData; -} - -void ImageCompareModel::rotateMatchData(const Mat& img, RotateData* pData, - const vector& angleRangeVec, float angleStep, Mat& disMat) const -{ - if (angleRangeVec.empty()) - { - return; - } - disMat.create(angleRangeVec.size(), angleRangeVec.front().size(), CV_32FC1); - pData->mRImgVec.resize(angleRangeVec.size()); - pData->mDisValVec.resize(angleRangeVec.size(), FLT_MAX); - double minDis = DBL_MAX; - for (int i = 0; i < angleRangeVec.size(); ++i) - { - Range r = angleRangeVec[i]; - Mat disVec = disMat.row(i); - RotateData rotateData; - float startAngle = r.start; - float endAngle = r.end; - rotateMatchData(img, &rotateData, angleStep, startAngle, endAngle); - std::copy(rotateData.mDisValVec.begin(), rotateData.mDisValVec.end(), - (float*)disVec.data); - double localMinDis, localMaxDis; - Point minPt, maxPt; - minMaxLoc(disVec, &localMinDis, &localMaxDis, &minPt, &maxPt); - if (localMinDis < minDis) - { - minDis = localMinDis; - *pData = rotateData; - } - } -} - -void ImageCompareModel::genCandidateRepeatNums(set& canNums) -{ - canNums.clear(); - - for (int i = 4; i < 25; ++i) - { - canNums.insert(i); - } -} - -bool isValidExtremas(const Mat& vec, const vector& lessExtremaIdxVec, - const vector& moreExtremaIdxVec) -{ - float* pVec = (float*)vec.data; - auto lessIdxIter = lessExtremaIdxVec.begin(); - auto moreIdxIter = moreExtremaIdxVec.begin(); - while (lessIdxIter != lessExtremaIdxVec.end()) - { - auto leftLessIdxIter = lessIdxIter; - auto leftMoreIdxIter = moreIdxIter; - auto rightLessIdxIter = lessIdxIter; - rightLessIdxIter++; - if (rightLessIdxIter == lessExtremaIdxVec.end()) - { - break; - } - auto rightMoreIdxIter = leftMoreIdxIter; - while (*rightLessIdxIter > *rightMoreIdxIter) - { - rightMoreIdxIter++; - } - - float leftLessExtrema = pVec[*leftLessIdxIter]; - float rightLessExtrema = pVec[*rightLessIdxIter]; - float localMaxVal = *std::max_element(pVec + *leftLessIdxIter, - pVec + *rightLessIdxIter + 1); - float valRange = localMaxVal - min(leftLessExtrema, rightLessExtrema); - float valTor = valRange*0.05; - float slope = (rightLessExtrema - leftLessExtrema) / (*rightLessIdxIter - *leftLessIdxIter); - - leftMoreIdxIter++; - while (leftMoreIdxIter != rightMoreIdxIter) - { - float interVal = leftLessExtrema + slope*(*leftMoreIdxIter - *leftLessIdxIter); - float curExtremaVal = pVec[*leftMoreIdxIter]; - if (curExtremaVal < interVal + valTor) - { - return false; - } - leftMoreIdxIter++; - } - - lessIdxIter++; - moreIdxIter = rightMoreIdxIter; - } - - return true; -} - - -int ImageCompareModel::recognizeLowerExtremes(const Mat& vec, - set canNums, int extremeRefineRange /*= 5*/, vector *pExtremaIdxVec /*= 0*/) -{ - unsigned int size = vec.cols; - set validNs; - float* pVec = (float*)vec.data; - - double vecMinVal, vecMaxVal; - minMaxIdx(vec, &vecMinVal, &vecMaxVal); - -// 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 - CvPlot::clear("recognizeLowerExtreams"); - CvPlot::plot("recognizeLowerExtreams", (float*)vec.data, vec.cols); -#endif -#endif - - map > repeatNumLocalExtremaIdxMap; - map repeatNumLocalExtremaValMap; - for (auto iter = canNums.rbegin(); iter != canNums.rend(); ++iter) - { - unsigned int n = *iter; - - Mat extremaValVec; - vector extremaIdxVec; - uniformLocalMinExtremas(vec, extremaValVec, extremaIdxVec, - n, extremeRefineRange); - - float* pExtremaVecVec = (float*)extremaValVec.data; - - float curVal, nxtVal; - bool isValid = true; - - Mat preLocalVec; - - for (unsigned int i = 0; i < extremaIdxVec.size() - 1; ++i) - { - unsigned int curIdx = extremaIdxVec[i]; - unsigned int nxtIdx = extremaIdxVec[i + 1]; - curVal = pVec[curIdx]; - nxtVal = pVec[nxtIdx]; - - // no smaller value between two neighbor extremes - if (anyInRange(pVec + curIdx + 1, pVec + nxtIdx, - -FLT_MAX, min(curVal, nxtVal))) - { - isValid = false; - break; - } - - if (!preLocalVec.empty()) - { - Mat curLocalVec = vec.colRange(curIdx, nxtIdx + 1); - if (curLocalVec.size() != preLocalVec.size()) - { - resize(curLocalVec, curLocalVec, preLocalVec.size()); - } - float sim = compareHist(curLocalVec, preLocalVec, CV_COMP_CORREL); - if (sim < 0) - { - isValid = false; - break; - } - } - - preLocalVec = vec.colRange(curIdx, nxtIdx + 1); - } - if (!isValid) - { - continue; - } - - set nToBeErased; - for_each(validNs.begin(), validNs.end(), [&](int preN) - { - if (preN % n != 0 || !isValid) - { - return; - } - vector preExtremaIdxVec = repeatNumLocalExtremaIdxMap[preN]; - if (isValidExtremas(vec, extremaIdxVec, preExtremaIdxVec)) - { - nToBeErased.insert(preN); - } - else - { - isValid = false; - } - }); - if (!isValid) - { - continue; - } - if (nToBeErased.size() == validNs.size()) - { - validNs.clear(); - } - else - { - for_each(nToBeErased.begin(), nToBeErased.end(), [&](int toBeErasedN) - { - validNs.erase(toBeErasedN); - }); - } - - validNs.insert(n); - repeatNumLocalExtremaIdxMap[n] = extremaIdxVec; - repeatNumLocalExtremaValMap[n] = extremaValVec; - if (pExtremaIdxVec) - { - *pExtremaIdxVec = extremaIdxVec; - } - } - if (validNs.size() == 0) - { - return -1; - } - if (validNs.size() > 1) - { - return -2; - } - - return *(validNs.begin()); -} - -int ImageCompareModel::recognizeRepeatedLocalExtremas(const Mat& vec, - const set& canNums, int refineRange /*= 5*/, - vector *pIdxVec /*= 0*/) -{ - assert(vec.type() == CV_32FC1); - float* pVecData = (float*)vec.data; - - for_each(canNums.begin(), canNums.end(), [&](int n) - { - Mat localMinExtremaValVec; - vector localMinExtremaIdxVec; - uniformLocalMinExtremas(vec, localMinExtremaValVec, localMinExtremaIdxVec, - n, refineRange); - - float* pExtremaVecVec = (float*)localMinExtremaValVec.data; - - // get locally top 10% values - - }); - - return -1; -} - -int ImageCompareModel::computeRepeatNum(const Mat& _img) -{ - Mat img; - cv::GaussianBlur(_img, img, Size(3, 3), 5.0); - vector vec; - selfRotationSimilarityFeature(img, vec, Point2f(img.cols / 2.0, img.rows / 2.0)); - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat viewImg = img / 255.0 /255.0; - Mat view_Img = _img / 255.0 /255.0; -#endif - - vector normVec(vec); - Mat vecMat(1, vec.size(), CV_32FC1, &(vec[0])); - Mat normVecMat(1, normVec.size(), CV_32FC1, &(normVec[0])); - meanvarnorm(vecMat, normVecMat, 0, 1.0); - -#ifdef DEBUG_VIEW_PLOT - Mat dftVec; - dft(normVec, dftVec); - dftVec = abs(dftVec); - - Mat dVecMat = normVecMat.clone(); - genSobelImage(dVecMat); - Mat dDftVec; - dft(dVecMat, dDftVec); - - Mat ddVecMat = dVecMat.clone(); - genSobelImage(ddVecMat); - Mat ddDftVec; - dft(ddVecMat, ddDftVec); - -// 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 - CvPlot::plot("normVec", (float*)&(normVec[0]), normVec.size()); - CvPlot::plot("dVec", (float*)dVecMat.data, dVecMat.cols); - CvPlot::plot("ddVec", (float*)ddVecMat.data, ddVecMat.cols); - CvPlot::plot("ddft", (float*)dDftVec.data, 50); - CvPlot::plot("dft", (float*)dftVec.data, 50); - CvPlot::plot("dddft", (float*)ddDftVec.data, 50); -#endif - - waitKey(); -#endif - - set canNums; - genCandidateRepeatNums(canNums); - return recognizeLowerExtremes(normVecMat, canNums); -} - -int ImageCompareModel::computeRepeatNum() -{ - if (mWeightMat.empty() || mAlignBaseImg.empty()) - { - return 0; - } - - Mat img = mAlignBaseImg.mul(mWeightMat); - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat viewImg = img / 255.0 / 255.0; -#endif - - return computeRepeatNum(img); -} - -void ImageCompareModel::initMultiScaleModel() -{ - if (mpMultiScaleModel) - { - delete mpMultiScaleModel; - } - mpMultiScaleModel = new MultiScaleImageCompareModel; - mpMultiScaleModel->setLevelNum(3); - mpMultiScaleModel->setBaseLevel(this); - mpMultiScaleModel->genMultiScale(); -} - -void ImageCompareModelInvoker::operator()(const cv::Range& range) const -{ - int i0 = range.start; - int i1 = range.end; - assert(abs(i1 - i0) == 1); - m_pModel->parallelDetect(i0, m_pData); -} - -void ImageCompareModel::parallelDetect(int index, void *p) const -{ - RotateData *pData = (RotateData *)p; - Mat t = getRotationMatrix2D(pData->mCenter, pData->angle(index), 1.0); - Mat rImg; - warpAffine(pData->mImgSrc, rImg, t, pData->mImgSrc.size()); - - // need add insideImage base image; - - // .... - Mat imgRes; - if (m_parallelFlag!=1) - { - if (rImg.size() != mAlignBaseImg.size()) - { - resize(rImg, rImg, mAlignBaseImg.size()); - } - imgRes = rImg - mAlignBaseImg; - if (!m32fMaskImg.empty()) - { - if (m32fMaskImg.size() != imgRes.size()) - resize(imgRes, imgRes, m32fMaskImg.size()); - imgRes = imgRes.mul(m32fMaskImg); - if (!mWeightMat.empty()) - { - if (mWeightMat.size() != imgRes.size()) - resize(imgRes, imgRes, mWeightMat.size()); - imgRes.mul(mWeightMat); - } - } - } - else - { - if (rImg.size() != mInSideBaseImg.size()) - { - resize(rImg, rImg, mInSideBaseImg.size()); - } - - imgRes = rImg - mInSideBaseImg; - if (!m32fInsideMaskImg.empty()) - { - if (m32fInsideMaskImg.size() != imgRes.size()) - resize(imgRes, imgRes, m32fInsideMaskImg.size()); - imgRes = imgRes.mul(m32fInsideMaskImg); - if (!mInsideWeightMat.empty()) - { - if (mInsideWeightMat.size() != imgRes.size()) - resize(imgRes, imgRes, mInsideWeightMat.size()); - imgRes.mul(mInsideWeightMat); - } - } - } - - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vRImg, vBaseImg; - vRImg = rImg / 255.0; - vBaseImg = mAlignBaseImg / 255.0; - Mat vImgRes = imgRes / 255.0; - Mat vWeightMat = mWeightMat / 255.0; - Mat viewInsideMat = mInSideBaseImg / 255.0; -#endif - double val = 0; - if(!imgRes.empty()) - val = norm(imgRes); - -#ifdef DEBUG_VIEW_INTERNAL_MAT - vImgRes = imgRes / 255.0; -#endif - pData->mDisValVec[index] = val; - pData->mRImgVec[index] = rImg; -} -double ImageCompareModel::filterTrainImage(const Mat&img) -{ - if (img.empty()) - { - return DBL_MAX; - } - mDisThre = DBL_MAX; - double dis = compare(img, NULL, 3, false); - /*if (dis < mTrueSampleDisMax) - { - dis = mTrueSampleDisMax; - } - double absDiff = abs(dis - mTrueSampleDisMax);*/ - return dis; -} -void ImageCompareModel::weightOptimization(const vector& falseSamples) -{ - if (falseSamples.size() <= 0) - return; - reConMat = mWeightMat.clone(); - vector falseVec; - resizeVecMat(falseSamples, falseVec); - for (int i = 0; i < falseVec.size(); i++) - { - Mat falseSample = falseVec[i].clone(); - preWeightReconstruction(falseSample, reConMat); - } - mWeightMat = reConMat; -} - -void ImageCompareModel::preWeightReconstruction(Mat img, Mat &reConImg) -{ - if (mAlignBaseImg.size().height <= 0 || mAlignBaseImg.size().width <= 0) - { - //mAlignBaseImg = img.clone(); - return; - } - if (mAlignBaseImg.size() != img.size()) - { - resize(img, img, mAlignBaseImg.size()); - } - - Mat matchImg = img.clone(); - preProcessImage(matchImg, Mat()); - - if (!mpMultiScaleModel) - { - initMultiScaleModel(); - } - RotateMatchResult rmr = rotateMatch(matchImg, 1); - Mat rImg = rmr.mBestRImg; - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat ttt = mAlignBaseImg / 255.0; - Mat vRImg = rImg / 255.0; -#endif - - double bestAngle = rmr.mBestAngle; - Mat cmpImg = rotateImage(img, Point2f(img.cols / 2.0, img.rows / 2.0), - bestAngle); - - // remove highlights - Mat hightlightsMask = cmpImg < mHighlightsThreshold; - converToType(hightlightsMask, CV_32FC1); - hightlightsMask /= 255.0; - - Mat unifiedMask = m32fMaskImg.mul(hightlightsMask).mul(mWeightMat); - - preProcessImage(cmpImg, m8uMaskImg, mWeightMat, mTargetMeanVal, - mTargetStddevVal, mHighlightsThreshold); - - cmpImg.setTo(0, cmpImg < 0); - converToType(cmpImg, CV_32FC1); - normSectors_tarImg(cmpImg, unifiedMask, imgCen(cmpImg), 1, - mCompareBaseImg); - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vRotatedImg0 = cmpImg / 255.0; -#endif - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vRotatedImg1 = mCompareBaseImg / 255.0; -#endif - - cmpImg.setTo(0, cmpImg < 10); - - weightReconstruction(cmpImg, mCompareBaseImg, unifiedMask, reConImg); - -} - -void ImageCompareModel::weightReconstruction(const Mat& rImg, const Mat& baseImg, const Mat& maskImg, Mat &reConImg) -{ - Mat dMat = abs(rImg - baseImg); - Mat test = dMat / 255.0; - Mat norImg = Mat::ones(dMat.size(), dMat.type()) * 255; - dMat = min(dMat, norImg); - Mat w(dMat.size(), dMat.type(), Scalar::all(0)); - dMat.copyTo(w, dMat < 0.5); - w = minMaxNorm(w, 0, 1.0); - for (int i = 0; i < reConImg.rows; i++) - { - float* pData = (float*)reConImg.row(i).data; - float* pWeight = (float*)w.row(i).data; - for (int j = 0; j < reConImg.cols; j++) - { - if (pWeight[j]!=0) - { - //pData[j] *= pWeight[j]; - pWeight[j] = -1 * pow(pWeight[j] - 1, 2) + 1; - pData[j] *= pWeight[j]; - } - } - } -} -double ImageCompareModel::penltyCoeff(double matchedVal, int diameterMean, int targetDiameter, double modelDiamter, double modelHeight) const -{ - int diff = abs(diameterMean - targetDiameter); - double modelDiameterDiff = abs(modelDiamter - realWidth); - double modelHeightDiff = abs(modelHeight - realHeight); - - if (diff >=10) - { - return matchedVal*(diff / 100.0 + 1) * (modelHeightDiff / 100.0 + 1) * (modelDiameterDiff / 100.0 + 1); - } - else - { - return matchedVal; - } -} - -cv::Mat ImageCompareModel::genInsideMask(const Mat& img, Point2f center, float innerR /*= -1*/, float outterR /*= -1*/, int type /*= CV_32FC1*/) -{ - Mat mask(img.size(), CV_8UC1); - mask.setTo(0); - if (innerR == -1) - { - // default is 30 - innerR = img.rows*0.178; - //innerR = img.rows; - } - if (outterR == -1) - { - // default is max radius - 10 - outterR = img.rows*0.425; - } - //outterR = r; - /*Mat img1 = img.clone(); - - img1.convertTo(img1, CV_8UC1); - float r = allocateInnerRadius(img1); - rInner = r;*/ - circle(mask, center, outterR, Scalar(255), -1); - circle(mask, center, innerR, Scalar(0), -1); - if (type != CV_8UC1) - { - converToType(mask, type); - mask /= 255; - } - return mask; -} - -float ImageCompareModel::allocateInnerRadius(cv::Mat subImage) -{ - -// //// find global center -// const int &roughRadius = subImage.cols *0.08; -// const Point center(subImage.cols / 2.0, subImage.rows / 2.0); -// Rect rect(center.x - roughRadius, center.y - roughRadius, 2 * roughRadius, 2 * roughRadius); -// Mat centerMat = subImage(rect); -// Mat test = subImage(rect).clone(); -// genSobelImage(centerMat); -// centerMat.convertTo(centerMat, CV_8UC1); -// Mat bMat = centerMat > 100; -// //cv::threshold(centerMat, bMat, 0, 255, CV_THRESH_OTSU); -// Mat mask(bMat.size(), CV_8UC1); -// mask.setTo(0); -// //circle(mask, center, roughRadius, Scalar(255), -1); -// //cv::Mat bImage = subImage.mul(mask / 255) > 100; -// Mat dilatedImgBin; -// Mat erodeMat; -// dilate(bMat, dilatedImgBin, Mat::ones(3, 3, CV_32FC1)); -// erode(dilatedImgBin, erodeMat, Mat::ones(3, 3, CV_32FC1)); -// closeOper(erodeMat, Mat::ones(1, 3, CV_32FC1)); -// Mat vMat = erodeMat.clone(); -// vector> contours; -// findContours(erodeMat, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE); -// for (int i = 0; i < contours.size(); i++) { -// const vector &pt = contours.at(i); -// if (pt.size() < 10) { -// continue; -// } -// Rect rt = boundingRect(pt); -// if (rt.width < 5 || rt.height < 5) { -// continue; -// } -// drawContours(mask, contours, i, Scalar::all(255), -1); -// } -// -// using namespace luffy_base; -// Mat hit; vector pts; -// luffy_hit::firstHit4Circle(mask, hit, pts, Point(mask.cols / 2, mask.rows / 2), 0, mask.cols / 2, 360, luffy_hit::emHitOut2In); -// luffy_imageProc::RansacParam rs(0.01, 1, 100, 80, 100);//0421 -// vector pts2 = luffy_imageProc::fitModelbyRansac(pts, luffy_imageProc::emModelCircle, &rs); -// float fRadius; -// Point2f ptCenter; -// bool bFind = luffy_imageProc::lsCircleFit(pts2, fRadius, ptCenter); -//#ifdef _DEBUG -// Mat insideMat(mask.size(), mask.type(), Scalar::all(0)); -// int offset = 2; -// cv::circle(insideMat, ptCenter, fRadius, Scalar(1), -1); -// Mat ddst = insideMat.mul(test); -//#endif -// const Point globalCenter(ptCenter.x + center.x - roughRadius, ptCenter.y + center.y - roughRadius); -// -// -// -// //// find minR -// cv::Mat binaryImg = subImage > 25; -// const int innerRadius = binaryImg.rows*0.05; -// const int outterRadius = binaryImg.cols*0.22; -// Mat mmask(binaryImg.size(), CV_8UC1); -// mmask.setTo(0); -// circle(mmask, globalCenter, outterRadius, Scalar(1), -1); -// Mat dilatedImgBin1; -// Mat erodeMat1; -// dilate(binaryImg, dilatedImgBin1, Mat::ones(9, 9, CV_32FC1)); -// erode(dilatedImgBin1, erodeMat1, Mat::ones(9, 9, CV_32FC1)); -// openOper(erodeMat1, Mat::ones(1, 13, CV_32FC1)); -// circle(erodeMat1, globalCenter, innerRadius, Scalar(255), -1); -// Mat tarMat = mmask.mul(erodeMat1) > 0; -// -// vector maxCon; -// vector> m_contours; -// findContours(tarMat, m_contours, RETR_EXTERNAL, CHAIN_APPROX_NONE); -// maxCon = m_contours.front(); -// for (const vector& contour : m_contours) -// { -// if (contour.size() > maxCon.size()) -// { -// maxCon = contour; -// } -// } -// float minDis = FLT_MAX; -// Point initialPoint = maxCon.front(); -// for (int i = 0; i < maxCon.size(); i++) -// { -// const Point& p = maxCon[i]; -// float dis = pointDis(p, globalCenter); -// if (dis < minDis) -// { -// minDis = dis; -// initialPoint = p; -// } -// } -//#ifdef _DEBUG -// Mat m_Mat(tarMat.size(), tarMat.type(), Scalar::all(0)); -// //int offset = 2; -// cv::circle(m_Mat, globalCenter, minDis, Scalar(1), -1); -// Mat d_dst = m_Mat.mul(subImage); -//#endif -// vector rst; -// rst.resize(3); -// rst[0] = minDis - 3; -// rst[1] = globalCenter.x; -// rst[2] = globalCenter.y; -// return rst; - if (subImage.size() != mAlignBaseImg.size()) - { - resize(subImage, subImage, mAlignBaseImg.size()); - } - - cv::Mat binaryImg = subImage > 30; - const int innerRadius = binaryImg.rows*0.05; - const int outterRadius = binaryImg.cols*0.22; - const Point center(binaryImg.cols / 2.0, binaryImg.rows / 2.0); - Mat mask(binaryImg.size(), CV_8UC1); - mask.setTo(0); - circle(mask, center, outterRadius, Scalar(1), -1); - Mat dilatedImgBin; - Mat erodeMat; - dilate(binaryImg, dilatedImgBin, Mat::ones(9, 9, CV_32FC1)); - erode(dilatedImgBin, erodeMat, Mat::ones(9, 9, CV_32FC1)); - openOper(erodeMat, Mat::ones(1, 13, CV_32FC1)); - circle(erodeMat, center, innerRadius, Scalar(255), -1); - Mat tarMat = mask.mul(erodeMat) > 0; - - vector maxCon; - vector> contours; - findContours(tarMat, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE); - maxCon = contours.front(); - for (const vector& contour : contours) - { - if (contour.size() > maxCon.size()) - { - maxCon = contour; - } - } - float minDis = FLT_MAX; - Point initialPoint = maxCon.front(); - for (int i = 0; i < maxCon.size(); i++) - { - const Point& p = maxCon[i]; - float dis = pointDis(p, center); - if (dis < minDis) - { - minDis = dis; - initialPoint = p; - } - } -#ifdef _DEBUG - Mat insideMat(tarMat.size(), tarMat.type(), Scalar::all(0)); - int offset = 2; - cv::circle(insideMat, center, minDis - offset, Scalar(1), -1); - Mat ddst = insideMat.mul(subImage); -#endif - return minDis - 2; -} - -float ImageCompareModel::allocateRadius(cv::Mat subImage) -{ - -// //// find global center -// const int &roughRadius = subImage.cols *0.08; -// const Point center(subImage.cols / 2.0, subImage.rows / 2.0); -// Rect rect(center.x - roughRadius, center.y - roughRadius, 2 * roughRadius, 2*roughRadius); -// Mat centerMat = subImage(rect); -// Mat test = subImage(rect).clone(); -// genSobelImage(centerMat); -// centerMat.convertTo(centerMat, CV_8UC1); -// Mat bMat = centerMat > 100; -// //cv::threshold(centerMat, bMat, 0, 255, CV_THRESH_OTSU); -// Mat mask(bMat.size(), CV_8UC1); -// mask.setTo(0); -// //circle(mask, center, roughRadius, Scalar(255), -1); -// //cv::Mat bImage = subImage.mul(mask / 255) > 100; -// Mat dilatedImgBin; -// Mat erodeMat; -// dilate(bMat, dilatedImgBin, Mat::ones(3, 3, CV_32FC1)); -// erode(dilatedImgBin, erodeMat, Mat::ones(3, 3, CV_32FC1)); -// closeOper(erodeMat, Mat::ones(1, 3, CV_32FC1)); -// Mat vMat = erodeMat.clone(); -// vector> contours; -// findContours(erodeMat, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE); -// for (int i = 0; i < contours.size(); i++) { -// const vector &pt = contours.at(i); -// if (pt.size() < 5) { -// continue; -// } -// Rect rt = boundingRect(pt); -// if (rt.width < 5 || rt.height < 5) { -// continue; -// } -// drawContours(mask, contours, i, Scalar::all(255), -1); -// } -// -// using namespace luffy_base; -// Mat hit; vector pts; -// luffy_hit::firstHit4Circle(mask, hit, pts, Point(mask.cols / 2, mask.rows / 2), 0, mask.cols / 2, 360, luffy_hit::emHitOut2In); -// luffy_imageProc::RansacParam rs(0.01, 1, 100, 80, 100);//0421 -// vector pts2 = luffy_imageProc::fitModelbyRansac(pts, luffy_imageProc::emModelCircle, &rs); -// float fRadius; -// Point2f ptCenter; -// bool bFind = luffy_imageProc::lsCircleFit(pts2, fRadius, ptCenter); -//#ifdef _DEBUG -// Mat insideMat(mask.size(), mask.type(), Scalar::all(0)); -// //int offset = 2; -// cv::circle(insideMat, ptCenter, fRadius, Scalar(1), -1); -// Mat ddst = insideMat.mul(test); -//#endif -// const Point globalCenter(ptCenter.x + center.x - roughRadius, ptCenter.y + center.y - roughRadius); -// -// -// -// //// find minR -// cv::Mat binaryImg = subImage > 25; -// const int innerRadius = binaryImg.rows*0.05; -// const int outterRadius = binaryImg.cols*0.22; -// Mat mmask(binaryImg.size(), CV_8UC1); -// mmask.setTo(0); -// circle(mmask, globalCenter, outterRadius, Scalar(1), -1); -// Mat dilatedImgBin1; -// Mat erodeMat1; -// dilate(binaryImg, dilatedImgBin1, Mat::ones(9, 9, CV_32FC1)); -// erode(dilatedImgBin1, erodeMat1, Mat::ones(9, 9, CV_32FC1)); -// openOper(erodeMat1, Mat::ones(1, 13, CV_32FC1)); -// circle(erodeMat1, globalCenter, innerRadius, Scalar(255), -1); -// Mat tarMat =mmask.mul(erodeMat1) > 0; -// -// vector maxCon; -// vector> m_contours; -// findContours(tarMat, m_contours, RETR_EXTERNAL, CHAIN_APPROX_NONE); -// maxCon = m_contours.front(); -// for (const vector& contour : m_contours) -// { -// if (contour.size() > maxCon.size()) -// { -// maxCon = contour; -// } -// } -// float minDis = FLT_MAX; -// Point initialPoint = maxCon.front(); -// for (int i = 0; i < maxCon.size(); i++) -// { -// const Point& p = maxCon[i]; -// float dis = pointDis(p, globalCenter); -// if (dis < minDis) -// { -// minDis = dis; -// initialPoint = p; -// } -// } -//#ifdef _DEBUG -// Mat m_Mat(tarMat.size(), tarMat.type(), Scalar::all(0)); -// //int offset = 2; -// cv::circle(m_Mat, globalCenter, minDis, Scalar(1), -1); -// Mat d_dst = m_Mat.mul(subImage); -//#endif -// //return minDis - 2; -// vector rst; -// rst.resize(3); -// rst[0] = minDis - 3; -// rst[1] = globalCenter.x; -// rst[2] = globalCenter.y; -// return rst; - - if (subImage.size() != mAlignBaseImg.size()) - { - resize(subImage, subImage, mAlignBaseImg.size()); - } - cv::Mat binaryImg = subImage > 30; - const int innerRadius = binaryImg.rows*0.05; - const int outterRadius = binaryImg.cols*0.22; - const Point center(binaryImg.cols / 2.0, binaryImg.rows / 2.0); - Mat mask(binaryImg.size(), CV_8UC1); - mask.setTo(0); - circle(mask, center, outterRadius, Scalar(1), -1); - Mat dilatedImgBin; - Mat erodeMat; - dilate(binaryImg, dilatedImgBin, Mat::ones(9, 9, CV_32FC1)); - erode(dilatedImgBin, erodeMat, Mat::ones(9, 9, CV_32FC1)); - openOper(erodeMat, Mat::ones(1, 13, CV_32FC1)); - circle(erodeMat, center, innerRadius, Scalar(255), -1); - Mat tarMat = mask.mul(erodeMat) > 0; - - vector maxCon; - vector> contours; - findContours(tarMat, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE); - maxCon = contours.front(); - for (const vector& contour : contours) - { - if (contour.size() > maxCon.size()) - { - maxCon = contour; - } - } - float minDis = FLT_MAX; - Point initialPoint = maxCon.front(); - for (int i = 0; i < maxCon.size(); i++) - { - const Point& p = maxCon[i]; - float dis = pointDis(p, center); - if (dis < minDis) - { - minDis = dis; - initialPoint = p; - } - } - #ifdef _DEBUG - Mat insideMat(tarMat.size(), tarMat.type(), Scalar::all(0)); - int offset = 2; - cv::circle(insideMat, center, minDis - offset, Scalar(1), -1); - Mat ddst = insideMat.mul(subImage); - #endif - return minDis - 2; -} - -void ImageCompareModel::genOutterMask() -{ - m32fMaskImg = genMask(mAlignBaseImg, Point2f(mAlignBaseImg.cols / 2.0, mAlignBaseImg.rows / 2.0)); - m8uMaskImg = genMask(mAlignBaseImg, Point2f(mAlignBaseImg.cols / 2.0, mAlignBaseImg.rows / 2.0), - -1.0, -1.0, CV_8UC1); -} - -void ImageCompareModel::resizeVecMat(vector srcVec, vector &dstVec) -{ - if (srcVec.size() <= 0) - return; - dstVec.resize(srcVec.size()); - int nWidth = ((int)((float)srcVec.front().cols / COLS_SCALE / 4)) * 4; - for (int i = 0; i < srcVec.size(); i++) - { - const Mat& mat = srcVec[i]; - Mat dstMat; - cv::resize(mat, dstMat, cv::Size(nWidth, nWidth)); - dstVec[i] = dstMat; - } -} - -void ImageCompareModel::resizeMat(Mat src, Mat &dst) -{ - int nWidth = ((int)((float)src.cols / COLS_SCALE / 4)) * 4; - cv::resize(src, dst, cv::Size(nWidth, nWidth)); -} - -void ImageCompareModel::printLog(string root, string log, double n) const -{ -#ifdef DEBUG_VIEW_INTERNAL_MAT - ofstream write; - write.open(root, ios::app); - time_t seconds = time(NULL); - struct tm *p; - p = localtime(&seconds); - char strTime[100] = { 0 }; - sprintf(strTime, "%02d-%02d %02d:%02d:%02d:", 1 + p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec); - std::ostringstream str; - str << log; - if (n != 0) - { - str << n; - } - write << "time:" << string(strTime); - write << str.str() << "\n"; - write.close(); -#endif -} - diff --git a/molunCar/ImageCompareModel.h b/molunCar/ImageCompareModel.h deleted file mode 100644 index 59aacf2..0000000 --- a/molunCar/ImageCompareModel.h +++ /dev/null @@ -1,373 +0,0 @@ -/*! \file ImageCompareModel.h - - Copyright (C) 2014 Hangzhou Leaper. - - Created by bang.jin at 2017/02/04. - -*/ - -#pragma once -#include -#include -#include -#include -#include -#include -#include "MultiScaleObj.h" -#include "ICompareModel.h" -/*#include "CircleDetector.h"*/ -#define COLS_SCALE (float)(1200.0/ 416.0) -using std::set; -using std::map; -using std::fstream; -using std::string; -using namespace cv; - -class MultiScaleImageCompareModel; -class ImageCompareModel : public ICompareModel -{ -public: - class RotateMatchResult - { - public: - Mat mBestRImg; - double mBestAngle; - }; - class RotateData - { - public: - RotateData() {}; - RotateData(const Mat &img, Point pt, double dAngleStep, int size) - : mImgSrc(img) - , mStartAngle(0) - , mEndAngle(360) - { - init(img, pt, dAngleStep, size); - }; - void init(const Mat& img, Point pt, double dAngleStep, int size) - { - mImgSrc = img; - mStartAngle = 0; - mEndAngle = 360.0; - mRImgVec.clear(); - mRImgVec.resize(size); - mDisValVec.clear(); - mDisValVec.resize(size, FLT_MAX); - mCenter = pt; - mAngleStep = dAngleStep; - } - double angle(int index) - { - return index * mAngleStep + mStartAngle; - } - double bestAngle() - { - if (mDisValVec.empty()) - { - return -DBL_MAX; - } - size_t bestIndex = min_element(mDisValVec.begin(), - mDisValVec.end()) - mDisValVec.begin(); - double bestAngle = angle(bestIndex); - return bestAngle; - } - Mat bestRImg() - { - if (mRImgVec.empty()) - { - return Mat(); - } - size_t bestIndex = min_element(mDisValVec.begin(), - mDisValVec.end()) - mDisValVec.begin(); - return mRImgVec[bestIndex]; - } - double mAngleStep; - Mat mImgSrc; - Point mCenter; - vector mRImgVec; - vector mDisValVec; - - float mStartAngle, mEndAngle; - }; - -public: - static cv::Point2f refineCircleCen(const Mat& img, Point2f cen); - static Mat genWeightImage(const Mat& img, Point2f center, float innerR = -1, - float outterR = -1); - static void selfRotationSimilarityFeature(const Mat& img, vector& vec, Point2f cen = Point2f(-1, -1)); - Mat genMask(const Mat& img, Point2f center, float innerR = -1, float outterR = -1, int type = CV_32FC1); - - Mat genInsideMask(const Mat& img, Point2f center, float innerR = -1, float outterR = -1, int type = CV_32FC1); - - static void genCandidateRepeatNums(set& canNums); - virtual int computeRepeatNum(const Mat& img); - static int recognizeLowerExtremes(const Mat& vec, set canNums, int extremeRefineRange = 5, vector *pExtemeIdxVec = 0); - static int recognizeRepeatedLocalExtremas(const Mat& vec, const set& canNums, int extremeRefineRange = 5, vector *pExtremeIdxVec = 0); - static void genUniformSepIdx(int num, int startIdx, int endIdx, vector& cenVec); - static void genAngleRanges(vector cenVec, vector& rangeVec, int localRange); - static void genCandidateAngleRanges(vector disVec, float angleStep, vector& rangeVec); - static void genCandidateAngleRanges(const Mat& disMat, float angleStep, vector& rangeVec, float rangeScale = 1); - static void selfRotateMin(const Mat& img, Mat& weightMat, int repeatNum); - float allocateInnerRadius(cv::Mat subImage); - float allocateRadius(cv::Mat subImage); - void resizeVecMat(vector srcVec, vector &dstVec); - void resizeMat(Mat src, Mat &dst); -public: - ImageCompareModel() : - mMatchValScale(1.0), - mTargetMeanVal(127), - mTargetStddevVal(50), - mHighlightsThreshold(256), - mRepeatNum(0), - mName("unnamed"), - mDisThre(DBL_MAX), - mTrueSampleDisMin(DBL_MAX), - mTrueSampleDisMax(DBL_MIN), - mTrueSampleDisMean(-1), - mTrueSampleDisStddev(-1), - mIsEnableCache(false), - mpMultiScaleModel(NULL), - meanDiameter(0), - realWidth(0), - realHeight(0), - rInner(DBL_MAX) - {}; - ImageCompareModel(const ImageCompareModel& model) - : mAlignBaseImg(model.getBaseImg().clone()) - , mWeightMat(model.getWeightMat().clone()) - , mMatchValScale(model.getMatchValScale()) - , mInSideBaseImg(model.getInsideBaseImg().clone()) - , mInsideWeightMat(model.getInsideWeightImg().clone()) - { - genMask(); - } - ~ImageCompareModel() {}; - - void printInfo(); - void saveImages(string dirPath); - bool save2file(string filePath); - bool readFromFile(string filePath); - - void operator = (const ImageCompareModel& model) - { - mAlignBaseImg = model.getBaseImg().clone(); - mWeightMat = model.getWeightMat().clone(); - mInSideBaseImg = model.getInsideBaseImg().clone(); - mInsideWeightMat = model.getInsideWeightImg().clone(); - mMatchValScale = model.getMatchValScale(); - mTargetMeanVal = model.getTargetMeanVal(); - mTargetStddevVal = model.getTargetStddevVal(); - mName = model.getName(); - mTrueSampleDisStddev = model.getDisStdDev(); - mTrueSampleDisMean = model.getDisMean(); - mTrueSampleDisMax = model.getDisMax(); - mTrueSampleDisMin = model.getDisMin(); - meanDiameter = model.getMeanDiamter(); - rInner = model.getInnerR(); - } - - void genMask(); - void genOutterMask(); - void preProcessImage(Mat& img, Mat &insideImg) const; - void preProcessImage(Mat& img, const Mat& mask, double dstMean, double dstStddev, int highlightsThreshold) const; - void preProcessImage(Mat& img, const Mat& mask, const Mat& weightMat, double dstMean, - double dstStddev, int highlightsThreshold) const; - void preProcessImage0(Mat& img) const; - void weightOptimization(const vector& falseSamples); - //! һͼͱ׼ͼmBaseImgתƥ䣬òֵ - /*! - \param Mat img ͼ - \param Mat * pRImg ͼתƥ - \param bool isFilterSize Ƿͼߴ - \return double ֵ - \see compare(Mat, Mat, Mat*, Mat*) - */ - double compare(Mat srcImage, Mat* pRImg = NULL, int levelNum = 1, bool isFilterSize = true, int flag = 0, - double md_diameter = 0, double md_height = 0); - - //! ѵõ׼ͼmBaseImg - /*! - \param const vector & imgVec ͬѵͼ - \return void - */ - void train(const vector& vec); - void calculateAllParams(const vector& imgVec); - void trueSampleWeightRecon(const vector& resizedVec, const vector& resizedCenterVec, vector rmrVec, - vector rmrVecInside); - void trueWeightRecon(const Mat& rImg, const Mat& baseImg, const Mat& insideRimg, const Mat& insideBaseImg); - void weightMapping(const Mat& weight, double maxVal, const Mat& i_mData, double i_maxVal); - //void falseWeightmapping(Mat &img); - double descendFunction(double pixVal, double maxVal); - double penltyCoeff(double matchedVal, int diameterMean, int targetDiameterm, double modelDiamter, double modelHeight) const; - //! ݸֵжһµͼǷڸ - /*! - \param const vector & imgVec ڸѵͼ - \return void - */ - void computeDisThre(const vector& imgVec, double* pMinDis = NULL, double md_diameter = 0, double md_height = 0); - - double filterTrainImage(const Mat &img); - - //! мrotate - /*! - \param int index ǰindex - \param void *p ָ - */ - void parallelDetect(int index, void *p) const; - - - //! ȡ׼ͼ - /*! - \return cv::Mat ׼ͼ - */ - Mat getInsideBaseImg() const { return mInSideBaseImg; } - Mat getInsideWeightImg() const { return mInsideWeightMat; } - float getInnerR() const { return rInner; } - - Mat getBaseImg() const { return mAlignBaseImg; } - - void setBaseImg(const Mat& img) { mAlignBaseImg = img; } - - Mat getWeightMat() const { return mWeightMat; } - void setWeightMat(Mat val) { mWeightMat = val; } - - double getMatchValScale() const { return mMatchValScale; } - void setMatchValScale(double val) { mMatchValScale = val; } - - int getTargetStddevVal() const { return mTargetStddevVal; } - void setTargetStddevVal(int val) { mTargetStddevVal = val; } - int getTargetMeanVal() const { return mTargetMeanVal; } - void setTargetMeanVal(int val) { mTargetMeanVal = val; } - - int getRepeatNum() const { return mRepeatNum; } - void setRepeatNum(int val) { mRepeatNum = val; } - - string getName() const { return mName; } - void setName(string val) { mName = val; } - - double getDisStdDev() const { return mTrueSampleDisStddev; } - double getDisMean() const { return mTrueSampleDisMean; } - double getDisMin() const { return mTrueSampleDisMin; } - double getDisMax() const { return mTrueSampleDisMax; } - - double getFalseSampleMinDis() const { return mFalseSampleMinDis; } - double getMeanDiamter() const { return meanDiameter; } - //! ȡһִreadFromFileʱļ· - /*! - \return string ļ· - */ - string getFilePath() const { return mFilePath; } - - double getDisThre() const { return mDisThre; } - void setDisThre(double val) { mDisThre = val; } - - //! û档ὫÿεcompareӿimgdataָΪkey洢 - // ֵ - /*! - \return void - */ - void setIsEnableCache(bool val) { mIsEnableCache = val; } - bool getIsEnableCache() const { return mIsEnableCache; } - - void clearDisCache() { mDisCache.clear(); } - - ImageCompareModel* scale(float s); - - RotateMatchResult rotateMatch(const Mat& img, int levelNum = 1, float angleStep = 1.0, - float startAngle = 0, float endAngle = 360) const; - void rotateMatchData(const Mat& img, RotateData* pData, const vector& angleRangeVec, float angleStep, - Mat& disMat) const; - void rotateMatchData(const Mat& img, RotateData* pData, float angleStep = 1.0, - float startAngle = 0, float endAngle = 360) const; - void rotateMatchData(const Mat& img, RotateData* pData, float angleStep, - const vector& angleRangeVec) const; - - cv::Mat getM8uMaskImg() const { return m8uMaskImg; } - void setM8uMaskImg(cv::Mat val) { m8uMaskImg = val; } - cv::Mat getM32fMaskImg() const { return m32fMaskImg; } - void setM32fMaskImg(cv::Mat val) { m32fMaskImg = val; } - - int computeRepeatNum(); - void setRealWidth(int val){ realWidth = val; } - void setRealHeight(int val){ realHeight = val; } - int getRealWidth(){ return realWidth; } - int getRealHeight(){ return realHeight; } - void printLog(string root, string log, double n = 0) const; - -protected: - //! δɣͼֱͱ׼ͼmBaseImgתƥ䣬òֵ - /*! - \param Mat img0 Ƚϵͼimg0 - \param Mat img1 Ƚϵͼimg1 - \param Mat * pRImg0 img0ͱ׼ͼmBaseImgתƥĽrimg0 - \param Mat * pRImg1 img1ͱ׼ͼmBaseImgתƥĽrimg1 - \return double ֵȡֵСΪmMatchValScale*norm(rimg0 - rimg1)/(cols*rows) - */ - double compare(Mat img0, Mat img1, Mat* pRImg0 = NULL, Mat* pRImg1 = NULL); - - void setFilePath(string val) { mFilePath = val; } - - double genMatchValue(const Mat& rImg, const Mat& baseImg, const Mat& maskImg, int flag, int diameter, double md_diameter, double md_height) const; - double genMatchValue(const Mat& dMat) const; - double scaleMatchValue(double val) const; - void weightReconstruction(const Mat& rImg, const Mat& baseImg, const Mat& maskImg, Mat &reConImg); - void preWeightReconstruction(Mat img, Mat &reConImg); - - void setFalseSampleMinDis(double iVal) { mFalseSampleMinDis = iVal; } - - double mMatchValScale; - int mTargetMeanVal, mTargetStddevVal, mHighlightsThreshold; - int mRepeatNum; - - Mat mAlignBaseImg, mCompareBaseImg; - Mat mWeightMat; - Mat m32fMaskImg, m8uMaskImg; - Mat mDisMat; - Mat reConMat; - Mat falseReConMat; - Mat insideWeightRecon; - Mat innerTempl; - double mDisThre{ DBL_MAX }; - string mName; - double falseMinDis; - int meanDiameter; - int realWidth; - int realHeight; - // INSIDE PART - Mat mInSideBaseImg, mInsideCompareBaseImg; - Mat mInsideWeightMat; - Mat m32fInsideMaskImg, m8uInsideMaskImg; - float rInner; - float x_aix; - float y_aix; - - - - // some training data - double mTrueSampleDisStddev, mTrueSampleDisMean, mTrueSampleDisMax{DBL_MAX}, mTrueSampleDisMin; - double mFalseSampleMinDis; - - // temp data - string mFilePath; - void initMultiScaleModel(); - MultiScaleImageCompareModel* mpMultiScaleModel; - - // cache - bool mIsEnableCache; - map mDisCache; -public: - static int m_parallelFlag; -private: -}; - -class ImageCompareModelInvoker : public cv::ParallelLoopBody -{ -public: - ImageCompareModelInvoker(const ImageCompareModel *pModel, void* pData) - : m_pModel(pModel), m_pData(pData) - {} -private: - const ImageCompareModel *m_pModel; - void *m_pData; - virtual void operator() (const cv::Range& range) const; -}; \ No newline at end of file diff --git a/molunCar/MultiScaleImageCompareModel.cpp b/molunCar/MultiScaleImageCompareModel.cpp deleted file mode 100644 index 12685c4..0000000 --- a/molunCar/MultiScaleImageCompareModel.cpp +++ /dev/null @@ -1,146 +0,0 @@ -#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 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(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(ss.str(), &(testRotateData.mDisValVec[0]), - testRotateData.mDisValVec.size()); - } -#endif -#endif - - downLevel(); - } -} diff --git a/molunCar/MultiScaleImageCompareModel.h b/molunCar/MultiScaleImageCompareModel.h deleted file mode 100644 index a59c780..0000000 --- a/molunCar/MultiScaleImageCompareModel.h +++ /dev/null @@ -1,74 +0,0 @@ -/*! \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 -#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 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_ - diff --git a/molunCar/MultiScaleObj.cpp b/molunCar/MultiScaleObj.cpp deleted file mode 100644 index 12256ad..0000000 --- a/molunCar/MultiScaleObj.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "MultiScaleObj.h" -#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]; -} diff --git a/molunCar/MultiScaleObj.h b/molunCar/MultiScaleObj.h deleted file mode 100644 index b6d4dfe..0000000 --- a/molunCar/MultiScaleObj.h +++ /dev/null @@ -1,87 +0,0 @@ -/*! \file MultiScaleObj.h - - Copyright (C) 2014 Ƽ޹˾. - - Created by bang.jin at 2017/02/20. -*/ - -#ifndef __MultiScaleObj_h_ -#define __MultiScaleObj_h_ - -#include -#include -#include - -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 mMultiScaleImages; - MultiScaleImageProc* mpProc; -private: -}; - -#endif // __MultiScaleObj_h_ diff --git a/molunCar/StdUtils.h b/molunCar/StdUtils.h deleted file mode 100644 index f912043..0000000 --- a/molunCar/StdUtils.h +++ /dev/null @@ -1,457 +0,0 @@ -/*! \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 -#endif - -#if (defined _WINDOWS) || (defined WIN32) -#define USE_WIN_API 1 -#endif - -/*#include "CyclopsLock.h"*/ - -#include -#include -#include -#include -#include -#include -#include - -/*#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 -T sum(_Iter s, _Iter e) -{ - if (s == e) - { - return T(); - } - T ret = *s; - s++; - while (s != e) - { - ret += *s; - s++; - } - return ret; -} - -template -_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 -_Iter findSumTopNPercentEle(_Iter s, _Iter e, float nPersent) -{ - T sumVal = sum(s, e); - T threVal = sumVal*nPersent; - sumVal = 0; - while (s != e) - { - sumVal += *s; - if (sumVal > threVal) - { - s++; - return s; - } - s++; - } - return e; -} - -template -void clearAndResetVec(vector* vec, int n) -{ - if (vec) { - vec->clear(); - vec->reserve(n); - } -} - -template -void genIncVec(vector& 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 -_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 -void add(_It s, _It e, const _Ty& val) -{ - while (s != e) - { - *s += val; - s++; - } -} - -template -bool allInRange(_It s, _It e, _Ty minVal, _Ty maxVal) -{ - while (s != e) - { - if (*s < minVal || *s > maxVal) - { - return false; - } - ++s; - } - return true; -} - -template -bool anyInRange(_It s, _It e, _Ty minVal, _Ty maxVal) -{ - while (s != e) - { - if (*s >= minVal && *s <= maxVal) - { - return true; - } - ++s; - } - return false; -} - -template -bool anyIn(_It s, _It e, _Ty v) -{ - while (s != e) - { - if (*s == v) - { - return true; - } - ++s; - } - return false; -} - -template -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 -_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 -string joinStr(_Ty0 s0, _Ty1 s1) -{ - stringstream ss; - ss << s0 << s1; - return ss.str(); -} -template -string joinStr(_Ty0 s0, _Ty1 s1, _Ty2 s2) -{ - stringstream ss; - ss << s0 << s1 << s2; - return ss.str(); -} -template -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(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(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, 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(); - it = mLookupTable.insert(std::make_pair(name, ptr)).first; - } - return it->second; - } - -private: - ObjectFactory() {} - std::map mLookupTable; - //CyclopsLock mLock; -}; - -template -inline T minMax(T val, T minVal, T maxVal) { - return std::min(maxVal, std::max(minVal, val)); -} - -#endif // __StdUtils_h_ - diff --git a/molunCar/TransSolver.cpp b/molunCar/TransSolver.cpp deleted file mode 100644 index e0393ca..0000000 --- a/molunCar/TransSolver.cpp +++ /dev/null @@ -1,303 +0,0 @@ -#include "TransSolver.h" -#include "CVUtils.h" - -#define M_LOW_TOLERANCE 0.000001 - -Matx33d affineTrans(const vector& src, const vector& 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; -} - -cv::Matx33d rigidTrans(const vector& src, const vector& dst, - Mat* pCenRotScaleMat) -{ - if (dst.empty() || src.empty()) { - return Mat(); - } - - vector 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; - - if (pCenRotScaleMat) - { - *pCenRotScaleMat = Mat(qm); - } - - return ret; -} - -bool cmpPointVec(const vector& vec0, const vector& 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 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 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 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 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(0, 2) = (rand() % 1000) / 1000.0; - mat23.at(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 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 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 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)); - } - } -} diff --git a/molunCar/TransSolver.h b/molunCar/TransSolver.h deleted file mode 100644 index d51df67..0000000 --- a/molunCar/TransSolver.h +++ /dev/null @@ -1,25 +0,0 @@ -/*! \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 -#include - -using namespace cv; -using std::vector; - -Matx33d affineTrans(const vector& src, const vector& dst); - -Matx33d rigidTrans(const vector& src, const vector& dst, Mat* pCenRotScaleMat = NULL); - -void testTransSolver(); - -#endif // __TransSolver_h_ - diff --git a/molunCar/cvdrawutils.cpp b/molunCar/cvdrawutils.cpp deleted file mode 100644 index d525f77..0000000 --- a/molunCar/cvdrawutils.cpp +++ /dev/null @@ -1,182 +0,0 @@ -#include "cvdrawutils.h" -#include "CVUtils.h" -//#include "DetectRoi.h" - -cv::Mat drawLines(const Mat& img, const vector& 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& 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& 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(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& pointVec) -{ -#ifdef LP_DISABLE_DRAW - return Mat(); -#else - vector 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& 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); -} - diff --git a/molunCar/cvdrawutils.h b/molunCar/cvdrawutils.h deleted file mode 100644 index 0f81521..0000000 --- a/molunCar/cvdrawutils.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef cvdrawutils_h__ -#define cvdrawutils_h__ - -#include -#include -#include -#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& pointVec, int grayVal = 255, int xRadius = 0, int yRadius = 0); - -Mat drawPointsWithKeyPoints(const Mat& img, const vector& pointVec); - -Mat drawLines(const Mat& img, const vector& segPointVec); - -Mat drawLines(const Mat& img, const vector& 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& 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__ diff --git a/molunCar/cvmatutils.cpp b/molunCar/cvmatutils.cpp deleted file mode 100644 index f0ba267..0000000 --- a/molunCar/cvmatutils.cpp +++ /dev/null @@ -1,217 +0,0 @@ -#include "cvmatutils.h" -#include -#include - -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 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; -} diff --git a/molunCar/cvmatutils.h b/molunCar/cvmatutils.h deleted file mode 100644 index 3f52934..0000000 --- a/molunCar/cvmatutils.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef _cvmatutils_h_ -#define _cvmatutils_h_ - -#include -#include -#include -#include -#include - -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_ diff --git a/molunCar/pointpair.h b/molunCar/pointpair.h deleted file mode 100644 index 4d52f32..0000000 --- a/molunCar/pointpair.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef pointpair_h__ -#define pointpair_h__ - -#include -#include -#include - -using std::vector; -using std::pair; -using namespace cv; - -template -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 PointPair; -typedef _PointPair PointfPair; - -void convertPointPair2PointfPair(const vector& vec0, - vector& vec1); - -template -double pointDis(const _Point& i, const _Point& j) -{ - return norm(i - j); -} - -template -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 -double pointPairLen(const _PointPair& p) -{ - return pointDis(p.first, p.second); -} - -template -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__ diff --git a/qilunCar/CVUtils.cpp b/qilunCar/CVUtils.cpp deleted file mode 100644 index df3dfea..0000000 --- a/qilunCar/CVUtils.cpp +++ /dev/null @@ -1,3383 +0,0 @@ -#include "CVUtils.h" -#include "DynamicProgramSearch.h" -#include "StdUtils.h" - -// #include "cvmatutils.h" -// #include "cvdrawutils.h" -#include "TransSolver.h" - -namespace CyclopsUtils { - -Mat gDummyMat; -Scalar gDummyScalar; - -bool localMeanVarNorm(const Mat& srcMat, Mat& dstMat, int winRadius, double tarMean/* = 120*/, double tarStd /*= 30*/) -{ - int width = srcMat.cols; - int height = srcMat.rows; - - if (winRadius * 2 + 1 >= width || winRadius * 2 + 1 >= height) - { - return false; - } - - dstMat = srcMat.clone(); - - Mat sumMat, sqSumMat; - cv::integral(srcMat, sumMat, sqSumMat, CV_64F); - int area = (2 * winRadius + 1)*(2 * winRadius + 1); - for (int i = winRadius; i < height - winRadius; i++) - { - const uchar *pData = srcMat.ptr(i); - uchar *tarData = dstMat.ptr(i); - double *pSumY1 = (double *)sumMat.ptr(i - winRadius); - double *pSumY2 = (double *)sumMat.ptr(i + winRadius + 1); - double *pSqSumY1 = (double *)sqSumMat.ptr(i - winRadius); - double *pSqSumY2 = (double *)sqSumMat.ptr(i + winRadius + 1); - for (int j = winRadius; j < width - winRadius; j++) - { - double sumX1Y1 = pSumY1[j - winRadius]; - double sumX2Y2 = pSumY2[j + winRadius + 1]; - double sumX1Y2 = pSumY2[j - winRadius]; - double sumX2Y1 = pSumY1[j + winRadius + 1]; - double sqSumX1Y1 = pSqSumY1[j - winRadius]; - double sqSumX2Y2 = pSqSumY2[j + winRadius + 1]; - double sqSumX1Y2 = pSqSumY2[j - winRadius]; - double sqSumX2Y1 = pSqSumY1[j + winRadius + 1]; - double val = sumX2Y2 + sumX1Y1 - sumX1Y2 - sumX2Y1; - double meanVal = val / area; - double sqSum = sqSumX2Y2 + sqSumX1Y1 - sqSumX1Y2 - sqSumX2Y1; - double stdVar = sqrt((sqSum - 2 * val*meanVal + area * meanVal * meanVal) / area); - double s = tarStd / stdVar; - double t = tarMean - meanVal * s; - - int value = pData[j] * s + t; - - if (value > 255) - { - tarData[j] = 255; - } - else - { - tarData[j] = value; - } - } - } - - return true; -} - -void meanvarnorm(Mat& src, Mat &dst, double avg, double var, Mat mask /*= Mat()*/) -{ - Scalar m, v; - cv::meanStdDev(src, m, v, mask); - // (I - m)*var/v + avg = I*var/v - m*var/v + avg - double s = var / v.val[0]; - double t = avg - m.val[0] * var / v.val[0]; - dst = src * s + t; -} - -Mat gridThre(const Mat& img, int gridWidth, int gridHeight, float threStdDevScale, - LogicOper oper /*= LP_LOGIC_SMALLER*/, - float majority /*= 0.8*/) -{ - Mat ret = Mat::zeros(img.size(), CV_8UC1); - int gridXNum = img.cols / gridWidth + 1; - int gridYNum = img.rows / gridHeight + 1; - for (int gy = 0; gy < gridYNum - 1; ++gy) - { - int y = gy*gridHeight; - for (int gx = 0; gx < gridXNum - 1; ++gx) - { - int x = gx*gridWidth; - Rect roi(x, y, gridWidth, gridHeight); - Mat roiImg(img, roi); - double mean, stddev; - meanStdDev(roiImg, Mat(), &mean, &stddev, majority); - Mat threImg; - switch (oper) - { - case LP_LOGIC_SMALLER: - threImg = roiImg < (mean + stddev*threStdDevScale); - break; - case LP_LOGIC_LARGER: - threImg = roiImg > (mean + stddev*threStdDevScale); - break; - } - - threImg.copyTo(Mat(ret, roi)); - } - } - for (int gy = 0; gy < gridYNum; ++gy) - { - int y = gy*gridHeight; - Rect roi(img.cols - gridWidth, y, gridWidth, gridHeight); - roi &= Rect(0, 0, img.cols, img.rows); - if (roi.width == 0 || roi.height == 0) - { - continue; - } - Mat roiImg(img, roi); - double mean, stddev; - meanStdDev(roiImg, Mat(), &mean, &stddev, majority); - Mat threImg; - switch (oper) - { - case LP_LOGIC_SMALLER: - threImg = roiImg < (mean + stddev*threStdDevScale); - break; - case LP_LOGIC_LARGER: - threImg = roiImg > (mean + stddev*threStdDevScale); - break; - } - threImg.copyTo(Mat(ret, roi)); - } - return ret; -} -Mat gridWhiteThre(const Mat& img, int gridWidth, int gridHeight, float threStdDevScale, float majority /*= 0.8*/) -{ - return gridThre(img, gridWidth, gridHeight, threStdDevScale, LP_LOGIC_LARGER, majority); -} -Mat gridBlackThre(const Mat& img, int gridWidth, int gridHeight, float threStdDevScale, float majority /*= 0.8*/) -{ - return gridThre(img, gridWidth, gridHeight, threStdDevScale, LP_LOGIC_SMALLER, majority); - - Mat ret = Mat::zeros(img.size(), CV_8UC1); - int gridXNum = img.cols / gridWidth + 1; - int gridYNum = img.rows / gridHeight + 1; - for (int gy = 0; gy < gridYNum - 1; ++gy) - { - int y = gy*gridHeight; - for (int gx = 0; gx < gridXNum - 1; ++gx) - { - int x = gx*gridWidth; - Rect roi(x, y, gridWidth, gridHeight); - Mat roiImg(img, roi); - double mean, stddev; - meanStdDev(roiImg, Mat(), &mean, &stddev, majority); - Mat threImg = roiImg < (mean + stddev*threStdDevScale); - threImg.copyTo(Mat(ret, roi)); - } - } - for(int gy = 0; gy < gridYNum; ++gy) - { - int y = gy*gridHeight; - Rect roi((gridXNum - 1)*gridWidth, y, gridWidth, gridHeight); - roi &= Rect(0, 0, img.cols, img.rows); - if (roi.width == 0 || roi.height == 0) - { - continue; - } - Mat roiImg(img, roi); - double mean, stddev; - meanStdDev(roiImg, Mat(), &mean, &stddev, (float)0.8); - Mat threImg = roiImg < (mean + stddev*threStdDevScale); - threImg.copyTo(Mat(ret, roi)); - } - return ret; -} - -void converToType(cv::Mat& mat, int mattype) -{ - cv::Mat _mat; - mat.convertTo(_mat, mattype); - mat = _mat; -} - -void genScharrImage(Mat& img) -{ - Mat sobelx, sobely; - Sobel(img, sobelx, CV_32FC1, 1, 0, CV_SCHARR); - Sobel(img, sobely, CV_32FC1, 0, 1, CV_SCHARR); - img = sobelx.mul(sobelx) + sobely.mul(sobely); - Mat tempImg; - img.convertTo(tempImg, CV_32FC1); - Mat tempImg0; - sqrt(tempImg, tempImg0); - img = tempImg0; -} - -void genSobelImage(Mat& img, Mat* pSobelx /*= NULL*/, Mat* pSobely /*= NULL*/) -{ - Mat sobelx, sobely; - Sobel(img, sobelx, CV_32FC1, 1, 0, BORDER_REPLICATE); - Sobel(img, sobely, CV_32FC1, 0, 1, BORDER_REPLICATE); - img = sobelx.mul(sobelx) + sobely.mul(sobely); - Mat tempImg; - img.convertTo(tempImg, CV_32FC1); - Mat tempImg0; - sqrt(tempImg, tempImg0); - img = tempImg0; - - if (pSobelx) - { - *pSobelx = sobelx; - } - if (pSobely) - { - *pSobely = sobely; - } -} - -cv::Mat genXDeriLineKernel(int w, int type, double absVal) -{ - assert(w % 2 == 1); - - Mat leftKernel = Mat::ones(1, w / 2, type)*absVal; - Mat rightKernel = Mat::ones(1, w / 2, type)*absVal*(-1); - Mat kernel = Mat::zeros(1, w, type); - leftKernel.copyTo(kernel.colRange(0, w / 2)); - rightKernel.copyTo(kernel.colRange(w / 2 + 1, w)); - return kernel; -} - -cv::Mat genXDeriMat(const Mat& img, int w, double absVal) -{ - assert(w % 2 == 1); - int kernelRadius = w / 2; - - Mat xKernel = genXDeriLineKernel(kernelRadius * 2 + 1, CV_32FC1, 1); - Mat xDeriMat; - sepFilter2D(img, xDeriMat, CV_32FC1, xKernel, Mat::ones(1, 1, CV_32FC1)); - - return xDeriMat; -} - -cv::Mat normEachRow(const Mat& img) -{ - Mat ret(img.rows, img.cols, img.type()); - for (int y = 0; y < img.rows; y++) - { - Mat rowMat = img.row(y); - double minVal, maxVal; - cv::minMaxIdx(rowMat, &minVal, &maxVal); - rowMat = rowMat / maxVal; - rowMat.copyTo(ret.row(y)); - } - return ret; -} - -cv::Mat genGradientDir4EachRow(const Mat& img) -{ - assert(img.cols >= 2); - - Mat xDeriMat = genXDeriMat(img, 3, 1); - Mat threMat; - threshold(xDeriMat, threMat, 0, 1, cv::THRESH_BINARY); - - return threMat; -} - -void findMatElementsEquals(const Mat& img, vector& pointVec, float val, int xPadding) -{ - assert(img.type() == CV_32FC1); - - for (int y = 0; y < img.rows; ++y) - { - float* pRowData = (float*)img.row(y).data; - float* pRowDataStart = pRowData; - float* pRowDataEnd = pRowData + img.cols - xPadding; - pRowData += xPadding; - while (pRowData != pRowDataEnd) - { - if (abs(*pRowData - val) < 0.0001) - { - pointVec.push_back(Point(pRowData - pRowDataStart, y)); - } - pRowData++; - } - } -} - -double localMatSum(const Mat& mat, const Rect& roi) -{ - Mat localMat(mat, roi); - return sum(localMat).val[0]; -} - -cv::Mat normCanvas(const Mat& img) -{ - Mat canvas; - double maxVal, minVal; - minMaxIdx(img, &minVal, &maxVal); - if (maxVal <= 1.0) - { - img.convertTo(canvas, CV_8UC1, 255); - } - else - { - img.convertTo(canvas, CV_8UC1); - } - return canvas; -} - -void findEdgePointsEachRow(const Mat& img, vector& edgePointVec, int xPadding) -{ - // img is a binary image. - // an edge point in a row satisfies: - // 1) left neighbor pixels are all black (0) or white (1); - // 2) right neighbor pixels are all white or black. - - // find candidate turning points - Mat sumKernelMat = Mat::ones(1, 2, img.type()); - Mat sumMat; - sepFilter2D(img, sumMat, img.type(), sumKernelMat, Mat::ones(1, 1, img.type())); - vector turningPointVec; - - // for pixels ... 0, 0, 1, 1 ..., turning point is - // * - findMatElementsEquals(sumMat, turningPointVec, 1.0, xPadding); - - // filter turning points - vector filteredTurningPointVec; - int localRadius = 30; - int localSumTor = 5; - for (size_t i = 0; i < turningPointVec.size(); ++i) - { - Point pt(turningPointVec[i]); - Rect leftRoi(pt.x - localRadius, pt.y, localRadius, 1); - double leftSum = localMatSum(img, leftRoi); - Rect rightRoi(pt.x, pt.y, localRadius, 1); - double rightSum = localMatSum(img, rightRoi); - if (leftSum > rightSum && abs(leftSum - localRadius) < localSumTor && rightSum < 0.0001) - { - filteredTurningPointVec.push_back(pt); - } - else if (leftSum < rightSum && leftSum < 0.0001 && abs(rightSum - localRadius) < localSumTor) - { - filteredTurningPointVec.push_back(pt); - } - } - - - Mat canvas;// = cv::drawPoints(img, filteredTurningPointVec, 125, 10); - - - edgePointVec = filteredTurningPointVec; -} - -Mat sumEachRow2(const Mat& img) -{ -#define _sumEachRow2(t)\ -if (img.channels() == 1) return sumEachRow(img);\ -else if (img.channels() == 2) return sumEachRowN(img);\ -else if (img.channels() == 3) return sumEachRowN(img);\ -else if (img.channels() == 4) return sumEachRowN(img);\ -else { _ASSERTE(false && "not implemented"); return gDummyMat; } - - switch (img.depth()) - { - case CV_8U: - _sumEachRow2(unsigned char); - case CV_16S: - _sumEachRow2(short); - case CV_32S: - _sumEachRow2(int); - case CV_32F: - _sumEachRow2(float); - case CV_64F: - _sumEachRow2(double); - default: - _ASSERTE(false && "not implemented"); - } - return gDummyMat; -} - -Mat sumEachCol2(const Mat& img) -{ -#define _sumEachCol2(t)\ -if (img.channels() == 1) return sumEachCol(img);\ -else if (img.channels() == 2) return sumEachColN(img);\ -else if (img.channels() == 3) return sumEachColN(img);\ -else if (img.channels() == 4) return sumEachColN(img);\ -else { _ASSERTE(false && "not implemented"); return gDummyMat; } - - switch (img.depth()) - { - case CV_8U: - _sumEachCol2(unsigned char); - case CV_16S: - _sumEachCol2(short); - case CV_32S: - _sumEachCol2(int); - case CV_32F: - _sumEachCol2(float); - case CV_64F: - _sumEachCol2(double); - default: - _ASSERTE(false && "not implemented"); - } - return gDummyMat; -} - -cv::Mat thresholdEachRowLocally(const Mat& img, int localRange /*= 501*/, int C /*= 10*/) -{ - Mat ret = img.clone(); - for (int y = 0; y < img.rows; ++y) - { - Mat rowMat = img.row(y); - uchar* pData = (uchar*)rowMat.data; - cv::adaptiveThreshold(rowMat, ret.row(y), 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, localRange, C); - } - return ret; -} - -cv::Mat thresholdEachRow(const Mat& img, float threScale /*= 0.5*/) -{ - Mat ret = img.clone(); - for (int y = 0; y < img.rows; ++y) - { - Mat rowMat = img.row(y); - double rowSum = sum(rowMat).val[0]; - double rowAvg = rowSum / img.cols * threScale; - Mat rowThre = ret.row(y); - threshold(rowMat, rowThre, rowAvg, 255, THRESH_BINARY); - } - return ret; -} - -cv::Mat thresholdEachRow(const Mat& img, const Mat& rowThre, float threScale) -{ - Mat ret = Mat::zeros(img.rows, img.cols, img.type()); - for (int y = 0; y < img.rows; ++y) - { - Mat retRow = ret.row(y); - uchar* pRetData = retRow.data; - Mat imgRow = img.row(y); - uchar* pData = imgRow.data; - double* pThreData = (double*)rowThre.data; - for (int x = 0; x < img.cols; ++x) - { - if (*pData < (*pThreData)*threScale) - { - *pRetData = 0; - } - else - { - *pRetData = 255; - } - pData++; - pThreData++; - pRetData++; - } - } - return ret; -} - -void convertPointPair2PointfPair(const vector& vec0, vector& vec1) -{ - vec1.clear(); - for (auto i = vec0.begin(); i != vec0.end(); ++i) - { - PointfPair pointfPair(i->first, i->second); - pointfPair.setAver(i->aver()); - pointfPair.setStr(i->getStr()); - vec1.push_back(pointfPair); - } -} - -double pointPairDis(const PointPair& i, const PointPair& j) -{ - double dis0 = pointDis(i.first, j.first); - double dis1 = pointDis(i.second, j.second); - return (dis0 + dis1) / 2.0; -} - -void segEachRow(const Mat& img, vector& pointPairVec, int xPadding) -{ - for (int y = 0; y < img.rows; ++y) - { - Mat rowMat = img.row(y); - uchar* pRowData = rowMat.data; - uchar* pRowStart = pRowData; - uchar* pRowEnd = rowMat.data + img.cols - xPadding; - pRowData += xPadding; - int leftX = -1; - while (pRowData != pRowEnd) - { - uchar val = *pRowData; - if (val == 0 && leftX == -1) - { - leftX = pRowData - pRowStart; - } - else if (val != 0 && leftX >= 0) - { - Point leftPt(leftX, y); - Point rightPt(pRowData - pRowStart - 1, y); - PointPair pointPair(leftPt, rightPt); - pointPairVec.push_back(pointPair); - leftX = -1; - } - pRowData++; - } - } -} - -void fillPointPairVal(const Mat& img, std::string filePath, vector& pointPairVec) -{ - for (auto i = pointPairVec.begin(); i != pointPairVec.end(); ++i) - { - Mat mat(img, Rect(i->first.x, i->first.y, i->second.x - i->first.x, 1)); - i->setAver(sum(mat).val[0] / (double)mat.cols); - std::stringstream ss; - ss << filePath << " x: " << i->first.x << " y: " << i->first.y; - i->setStr(ss.str()); - } -} - -cv::Mat getFirstChannel(const Mat& img) -{ - vector channels; - split(img, channels); - return channels.front(); -} -Mat getChannel(const Mat& img, int i) -{ - if (i < 0 || i >= img.channels()) - { - return Mat(); - } - vector channels; - split(img, channels); - - return channels[i]; -} - -void mulEachRow(Mat& img, const Mat& scaleRow) -{ - for (int i = 0; i < img.rows; ++i) - { - Mat row = img.row(i); - uchar* pRowData = (uchar*)row.data; - double* pScaleData = (double*)scaleRow.data; - for (int j = 0; j < row.cols; ++j) - { - *pRowData *= *pScaleData; - ++pRowData; - ++pScaleData; - } - } -} - -void genRandomPoints(const Mat& img, vector& points, RNG rng, int sampleCnt /* = 1000 */) -{ - sampleCnt = cv::min(sampleCnt, img.rows * img.cols ); - for (int i = 0; i < sampleCnt; ++i) - { - Vec3b* pData = (Vec3b*)img.row(rng.uniform(0, img.rows)).data; - Vec3b& d = pData[rng.uniform(0, img.cols)]; - - Point p; - p.x = d[0]; - p.y = d[1]; - points.push_back(p); - } -} - -void plot8uVec(const Mat& vec, float scale /*= 1.0*/) -{ - - Mat canvas = Mat::zeros(100 * scale, 100 * scale, CV_8UC1); - Rect rect(0, 0, canvas.cols * scale, canvas.rows * scale); - - int size = cv::max(vec.rows, vec.cols); - uchar* pVecData = vec.data; - for (int i = 0; i < size; ++i) - { - Point pt(i * scale, canvas.rows - 1 - pVecData[i] * scale); - if (rect.contains(pt)) - { - canvas.at(pt.y, pt.x) = 255; - } - } - imshow("plot8uVec", canvas); -} - -void plot32fVec(const Mat& vec, float scale /*= 1.0*/) -{ - Mat canvas = Mat::zeros(100 * scale, 100 * scale, CV_8UC1); - Rect rect(0, 0, canvas.cols * scale, canvas.rows * scale); - int size = cv::max(vec.rows, vec.cols); - float* pVecData = (float*)vec.data; - for (int i = 0; i < size; ++i) - { - Point pt(i * scale, canvas.rows - 1 - pVecData[i] * scale); - if (rect.contains(pt)) - { - canvas.at(pt.y, pt.x) = 255; - } - } - imshow("plot32fVec", canvas); -} - -cv::Mat calcHist(const Mat& img, const Mat& mask, int histSize /*= 256*/, int minVal, int maxVal) -{ - Mat histMat; - float fRange[] = { minVal, maxVal }; - const float* fHistRange = { fRange }; - - cv::calcHist(&img, 1, NULL, mask, histMat, 1, &histSize, &fHistRange); - return histMat; -} - -Mat resize(const Mat& img, float s, int interMethod /*= cv::INTER_LINEAR*/) -{ - Mat ret; - Size newSize(img.cols*s, img.rows*s); - if (newSize.width == 0 || newSize.height == 0) - { - return img; - } - resize(img, ret, Size(), s, s, interMethod); - return ret; -} - -void writeFile(const Mat& mat, std::string filePath, std::string matName /*= "mat"*/) -{ - FileStorage fs; - fs.open(filePath, FileStorage::WRITE); - fs << matName << mat; - fs.release(); -} - -cv::Mat readFile(std::string filePath, std::string matName) -{ - FileStorage fs; - fs.open(filePath, FileStorage::READ); - Mat ret; - fs[matName] >> ret; - return ret; -} - -void gaussianBlurEachRow(const Mat& src, Mat& dst, int ksize /*= 3*/) -{ - dst = Mat::zeros(src.rows, src.cols, src.type()); - for (int y = 0; y < src.rows; y++) - { - Mat dstRow = dst.row(y); - Mat srcRow = src.row(y); - cv::GaussianBlur(srcRow, dstRow, cv::Size(ksize, 1), 1.0); - } -} - -void medianBlurEachRow(const Mat& src, Mat& dst, int ksize /*= 3*/) -{ - dst = Mat::zeros(src.rows, src.cols, src.type()); - for (int y = 0; y < src.rows; y++) - { - Mat dstRow = dst.row(y); - Mat srcRow = src.row(y); - cv::medianBlur(srcRow, dstRow, 1); - } -} - -double maxLaplacianX(const Mat& rowMat, float scale /*= 1.0*/) -{ - Mat sRowMat; - Mat lapMat; - - if (scale != 1.0) - { - resize(rowMat, sRowMat, Size(), scale, 1.0, INTER_CUBIC); - Laplacian(sRowMat, lapMat, CV_32FC1, 3); - } - else - { - Laplacian(rowMat, lapMat, CV_32FC1); - } - double minVal, maxVal; - int minIdx, maxIdx; - minMaxIdx(lapMat, &minVal, &maxVal, &minIdx, &maxIdx); - return maxIdx / scale; -} - -double minLaplacianX(const Mat& rowMat, float scale /*= 1.0*/) -{ - Mat sRowMat; - Mat lapMat; - - if (scale != 1.0) - { - resize(rowMat, sRowMat, Size(), scale, 1.0, INTER_CUBIC); - Laplacian(sRowMat, lapMat, CV_32FC1, 3); - } - else - { - Laplacian(rowMat, lapMat, CV_32FC1); - } - double minVal, maxVal; - int minIdx, maxIdx; - minMaxIdx(lapMat, &minVal, &maxVal, &minIdx, &maxIdx); - return minIdx / scale; -} - -void Laplacian1D(const Mat& src, Mat& dst, int ddepth, int ksize /*= 1*/) -{ - assert(src.rows == 1); - Mat kernel; - float K1[3] = { 1, -2, 1 }; - float K3[5] = { 1, 2, -6, 2, 1 }; - float K5[7] = { 1, 1, 1, -6, 1, 1, 1 }; - float K7[9] = { 1, 1, 1, 1, -8, 1, 1, 1, 1 }; - float K9[11] = { 1, 1, 1, 1, 1, -10, 1, 1, 1, 1, 1 }; - switch (ksize) - { - case 1: - kernel = Mat(1, 3, CV_32F, K1); - break; - case 3: - kernel = Mat(1, 5, CV_32F, K3); - break; - case 5: - kernel = Mat(1, 7, CV_32F, K5); - break; - case 7: - kernel = Mat(1, 9, CV_32F, K7); - break; - case 9: - kernel = Mat(1, 11, CV_32F, K9); - break; - default: - assert(0); - break; - } - filter2D(src, dst, ddepth, kernel); -} - - -void _filterKeyPointsByNeighborDistance(vector& vec, float ndis) -{ - vector ret; - for (size_t i = 0; i < vec.size(); ++i) - { - KeyPoint kp0 = vec[i]; - bool isDiscard = false; - for (size_t j = i + 1; j < vec.size(); ++j) - { - KeyPoint kp1 = vec[j]; - float dis = pointDis(kp0.pt, kp1.pt); - if (dis < ndis) - { - if (kp0.response < kp1.response) - { - isDiscard = true; - break; - } - } - } - if (!isDiscard) - { - ret.push_back(kp0); - } - } - vec = ret; -} - -void filterKeyPointsByNeighborDistance(vector& vec, float ndis) -{ - _filterKeyPointsByNeighborDistance(vec, ndis); - vec = vector(vec.rbegin(), vec.rend()); - _filterKeyPointsByNeighborDistance(vec, ndis); -} - -float IC_Angle_u8(const Mat& image, const int half_k, Point2f pt, - const vector & u_max) -{ - int m_01 = 0, m_10 = 0; - - const uchar* center = &image.at(cvRound(pt.y), cvRound(pt.x)); - - // Treat the center line differently, v=0 - for (int u = -half_k; u <= half_k; ++u) - m_10 += u * center[u]; - - // Go line by line in the circular patch - int step = (int)image.step1(); - for (int v = 1; v <= half_k; ++v) - { - // Proceed over the two lines - int v_sum = 0; - int d = u_max[v]; - for (int u = -d; u <= d; ++u) - { - int val_plus = center[u + v*step], val_minus = center[u - v*step]; - v_sum += (val_plus - val_minus); - m_10 += u * (val_plus + val_minus); - } - m_01 += v * v_sum; - } - - return fastAtan2((float)m_01, (float)m_10); -} - -float IC_Angle_f32(const Mat& image, const int half_k, Point2f pt, - const vector & u_max) -{ - float m_01 = 0, m_10 = 0; - - const float* center = &image.at(cvRound(pt.y), cvRound(pt.x)); - - // Treat the center line differently, v=0 - for (int u = -half_k; u <= half_k; ++u) - m_10 += u * center[u]; - - // Go line by line in the circular patch - int step = (int)image.step1(); - for (int v = 1; v <= half_k; ++v) - { - // Proceed over the two lines - float v_sum = 0; - int d = u_max[v]; - for (int u = -d; u <= d; ++u) - { - float val_plus = center[u + v*step], val_minus = center[u - v*step]; - v_sum += (val_plus - val_minus); - m_10 += u * (val_plus + val_minus); - } - m_01 += v * v_sum; - } - - return fastAtan2((float)m_01, (float)m_10); -} - -float IC_Angle(const Mat& image, const int half_k, Point2f pt, - const vector & u_max) -{ - if (image.type() == CV_8UC1) - { - return IC_Angle_u8(image, half_k, pt, u_max); - } - else if (image.type() == CV_32FC1) - { - return IC_Angle_f32(image, half_k, pt, u_max); - } - else - { - std::cout << "image type " << image.type() << " is not supported" << std::endl; - return FLT_MAX; - } -} - -void computeOrientation(const Mat& image, vector& keypoints, - int halfPatchSize, const vector& umax) -{ - // Process each keypoint - for (vector::iterator keypoint = keypoints.begin(), - keypointEnd = keypoints.end(); keypoint != keypointEnd; ++keypoint) - { - keypoint->angle = IC_Angle(image, halfPatchSize, keypoint->pt, umax); - } -} - -void genUMax(vector& umax, int halfPatchSize) -{ - umax.resize(halfPatchSize + 2); - - int v, v0, vmax = cvFloor(halfPatchSize * sqrt(2.f) / 2 + 1); - int vmin = cvCeil(halfPatchSize * sqrt(2.f) / 2); - for (v = 0; v <= vmax; ++v) - umax[v] = cvRound(sqrt((double)halfPatchSize * halfPatchSize - v * v)); - - // Make sure we are symmetric - for (v = halfPatchSize, v0 = 0; v >= vmin; --v) - { - while (umax[v0] == umax[v0 + 1]) - ++v0; - umax[v] = v0; - ++v0; - } -} - -void filterKeyPointsByRotationInvariants(vector& vec, const Mat& img, - FeatureDetector* pFeatDetector, float tor) -{ - Point2f cen(img.cols / 2.0, img.rows / 2.0); - -// no longer supported in opencv3.4.1 -#if (CV_MAJOR_VERSION < 3) - int patchSize = pFeatDetector->getInt("patchSize"); -#else - int patchSize = pFeatDetector->descriptorSize(); -#endif - int halfPatchSize = patchSize / 2; - vector umax; - genUMax(umax, halfPatchSize); - - for (int i = 0; i < 360; ++i) - { - Mat trans = getRotationMatrix2D(cen, i, 1.0); - Mat transedImg; - warpAffine(img, transedImg, trans, Size(img.cols, img.rows)); - computeOrientation(img, vec, halfPatchSize, umax); - } -} - -double localIC_Angle(const Mat& img, Point2f center, int patchSize) -{ - int halfPatchSize = patchSize / 2; - vector umax; - genUMax(umax, halfPatchSize); - - return IC_Angle(img, halfPatchSize, center, umax); -} - -double localAngle_WeightedCen(const Mat& img, Point2f center) -{ -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vImg = img/255.0; -#endif - Point2f weightedCen(0, 0); - float sum = 0; - for (int y = 0; y < img.rows; ++y) - { - float* pRowData = (float*)img.row(y).data; - for (int x = 0; x < img.cols; ++x) - { - float val = pRowData[x]; - if (val == 0) - { - continue; - } - weightedCen.x += x*val; - weightedCen.y += y*val; - sum += val; - } - } - weightedCen.x /= sum; - weightedCen.y /= sum; - - weightedCen = weightedCen - center; - - return fastAtan2(weightedCen.y, weightedCen.x); -} - -double localAngle_(const Mat& img, Point2f center, Mat mask) -{ -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vImg = img / 255.0; -#endif - Scalar meanScalar, stddevScalar; - meanStdDev(img, meanScalar, stddevScalar, mask); - Mat meanNormImg = img - meanScalar.val[0]; - float thre = stddevScalar.val[0] * 4; - meanNormImg.setTo(0, meanNormImg < thre); - meanNormImg.setTo(1, meanNormImg > thre); - return localAngle_WeightedCen(meanNormImg, center); -} - -void upperMajorityMask(const Mat& img, Mat& mask, float majority) -{ - Mat hist; - majorityHistUpper(img, Mat(), hist, majority); - float* pHistData = (float*)hist.data; - int histSize = hist.rows > hist.cols ? hist.rows : hist.cols; - float* pEndHistData = pHistData + histSize; - int idx = 0; - while (pHistData != pEndHistData) - { - if (*pHistData) - { - break; - } - idx++; - pHistData++; - } - mask = (img >= idx); -} - -void lowerMajorityHist(const Mat& img, const Mat& mask, Mat& hist, float majority) -{ - hist = calcHist(img, mask); - - // suppose there is only one peak - float* pHistData = (float*)hist.data; - float curRatio = 1.0; - int totalNum = sum(hist).val[0]; - - float* pFront = pHistData; - float* pTail = pHistData + 254; - while (pFront != pTail) - { - if (*pTail == 0) - { - pTail--; - continue; - } - - { - curRatio -= *pTail / totalNum; - *pTail = 0; - pTail--; - } - if (curRatio <= majority) - { - break; - } - } - -} - -void majorityHistLower(const Mat& img, const Mat& mask, Mat& hist, float majority) -{ - hist = calcHist(img, mask); - - // suppose there is only one peak - float* pHistData = (float*)hist.data; - float curRatio = 1.0; - int totalNum = sum(hist).val[0]; - - float* pFront = pHistData; - float* pTail = pHistData + 254; - while (pFront != pTail) - { - if (*pTail == 0) - { - pTail--; - continue; - } - - { - curRatio -= *pTail / totalNum; - *pTail = 0; - pTail--; - } - if (curRatio <= majority) - { - break; - } - } - -} - -void majorityHistUpper(const Mat& img, const Mat& mask, Mat& hist, float majority) -{ - hist = calcHist(img, mask); - - // suppose there is only one peak - float* pHistData = (float*)hist.data; - float curRatio = 1.0; - int totalNum = sum(hist).val[0]; - - float* pFront = pHistData; - float* pTail = pHistData + 254; - while (pFront != pTail) - { - if (*pFront == 0) - { - pFront++; - continue; - } - - { - curRatio -= *pFront / totalNum; - *pFront = 0; - pFront++; - } - if (curRatio <= majority) - { - break; - } - } - -} -void majorityHist(const Mat& img, const Mat& mask, Mat& hist, float majority) -{ - hist = calcHist(img, mask); - - // suppose there is only one peak - float* pHistData = (float*)hist.data; - float curRatio = 1.0; - int totalNum = sum(hist).val[0]; - - float* pFront = pHistData; - float* pTail = pHistData + 254; - while (pFront != pTail) - { - if (*pFront == 0) - { - pFront++; - continue; - } - if (*pTail == 0) - { - pTail--; - continue; - } - if (*pFront < *pTail) - { - curRatio -= *pFront / totalNum; - *pFront = 0; - pFront++; - } - else - { - curRatio -= *pTail / totalNum; - *pTail = 0; - pTail--; - } - if (curRatio <= majority) - { - break; - } - } - - -} - -Mat lowerMajorityMask(const Mat& img, const Mat& mask, float majority) -{ - Mat hist; - lowerMajorityHist(img, mask, hist, majority); - float* pHistData = (float*)hist.data; - - Mat ret = mask.clone(); - - for (int i = 0; i < img.rows; ++i) - { - uchar* pRowData = (uchar*)img.row(i).data; - uchar* pMaskRowData = (uchar*)ret.row(i).data; - for (int j = 0; j < img.cols; ++j) - { - uchar val = pRowData[j]; - if (!pHistData[val]) - { - pMaskRowData[j] = 0; - } - } - } - - return ret; -} - -void meanStdDev(const Mat& img, const Mat& mask, - double* pMean, double* pStdDev, float majority, int type) -{ - Mat hist; - switch (type) - { - default: - case 0: - majorityHist(img, mask, hist, majority); - break; - case 1: - majorityHistLower(img, mask, hist, majority); - break; - case 2: - majorityHistUpper(img, mask, hist, majority); - break; - } - - // suppose there is only one peak - Mat rowHist;// = toRowVec(hist); - float* pHistData = (float*)rowHist.data; - - histMeanStddev(rowHist, pMean, pStdDev); -} - -float interpolate(float* pY, int n, float stepX, float x) -{ - int lIdx = (int)(x/stepX); - int rIdx = lIdx + 1; - if (rIdx > n - 1) - { - return pY[n - 1]; - } - assert(lIdx >= 0 && lIdx < n && rIdx >= 0 && rIdx < n); - float s = (x - lIdx*stepX)/stepX; - float ly = pY[lIdx]; - float ry = pY[rIdx]; - return ly + (ry - ly)*s; -} - -cv::Mat cocentricNorm(const Mat& img, Point2f center, const Mat& weightMat, float dstMeanVal) -{ - assert(weightMat.empty() || weightMat.type() == CV_32FC1); - - int w = img.cols; - int h = img.rows; - vector corners; - corners.push_back(Point2f(0, 0)); - corners.push_back(Point2f(0, h)); - corners.push_back(Point2f(w, h)); - corners.push_back(Point2f(w, 0)); - vector cornerDisVec; - for_each(corners.begin(), corners.end(), [&](const Point2f& pt) - { - double dis = pointDis(center, pt); - cornerDisVec.push_back(dis); - }); - - auto farthestCornerDis = max_element(cornerDisVec.begin(), cornerDisVec.end()); - float maxRadius = *farthestCornerDis; - - int radiusNum = floorf(maxRadius); - //radiusNum = 20; - float radiusStep = (maxRadius / radiusNum); - Mat cocentricSumMat = Mat::zeros(1, radiusNum, CV_32FC1); - float* pSumData = (float*)cocentricSumMat.data; - Mat cocentricWeightSumMat = Mat::zeros(1, radiusNum, CV_32FC1); - float* pWeightSumData = (float*)cocentricWeightSumMat.data; - Mat radiusMat(img.rows, img.cols, CV_32FC1); - - for (int y = 0; y < h; y++) - { - const Mat& imgRow = img.row(y); - float* pImgRowData = (float*)imgRow.data; - float* pRadiusRowData = (float*)radiusMat.row(y).data; - - float* pWeightRowData = NULL; - if (!weightMat.empty()) - { - pWeightRowData = (float*)weightMat.row(y).data; - } - - for (int x = 0; x < w; x++) - { - //std::cout << x << " " << y << std::endl; - float weight; - if (pWeightRowData) - { - weight = pWeightRowData[x]; - } - else - { - weight = 1.0; - } - float val = pImgRowData[x] * weight; - float radius = pointDis(Point2f(x, y), center); - pRadiusRowData[x] = radius; - int radiusIdx0 = (int)(radius / radiusStep); - assert(radiusIdx0 >= 0); - int radiusIdx1 = radiusIdx0 + 1; - if (radiusIdx0 >= radiusNum - 1) - { - pSumData[radiusNum - 1] += val; - pWeightSumData[radiusNum - 1] += weight; - } - else - { - float s = (radius - radiusStep*radiusIdx0) / radiusStep; - pSumData[radiusIdx0] += val*s; - pSumData[radiusIdx1] += val*(1 - s); - pWeightSumData[radiusIdx0] += s*weight; - pWeightSumData[radiusIdx1] += (1 - s)*weight; - } - } - } - - for (int i = 0; i < radiusNum; ++i) - { - //float radius = (i*radiusStep + radiusStep) / 2; - if (pWeightSumData[i] == 0) - { - - } - else - { - pSumData[i] /= pWeightSumData[i]; - } - } - - Mat retMat = Mat::zeros(img.rows, img.cols, img.type()); - Mat normMask = Mat::zeros(img.rows, img.cols, img.type()); - for (int y = 0; y < h; y++) - { - float* pImgRowData = (float*)img.row(y).data; - float* pRetRowData = (float*)retMat.row(y).data; - float* pRadiusData = (float*)radiusMat.row(y).data; - float *pNormData = (float *)normMask.row(y).data; - for (int x = 0; x < w; x++) - { - float val = pImgRowData[x]; - float radius = pRadiusData[x]; - float mean = interpolate(pSumData, radiusNum, radiusStep, radius); - if (mean == 0) - { - continue; - } - float newVal = (float)val * dstMeanVal / mean; - - // if (newVal - dstMeanVal > -30) - //{ - pRetRowData[x] = newVal; - //pNormData[x] = 255; - // } - //else - //{ - // continue; - //} - - } - } - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat viewRetMat = retMat/255.0; -#endif - /*Mat retNromMask = normMask.mul(retMat); - Mat normTest = retNromMask / 255.0;*/ - - return retMat; - //return normTest; -} - -cv::Mat meanNorm(const Mat& img, const Mat& mask, float dstMeanVal, float majority /*= 1.0*/, PixelSelectionMethod method /*= LP_PIXEL_SELECT_ALL*/) -{ - double meanVal = 0; - if (method == LP_PIXEL_SELECT_ALL) - { - meanVal = mean(img, mask).val[0]; - } - else if (method == LP_PIXEL_SELECT_MAJORITY_FAST || - method == LP_PIXEL_SELECT_MAJORITY) - { - meanStdDev(img, mask, &meanVal, NULL, majority); - } - return img + (int)(dstMeanVal - meanVal); -} - -// cv::Mat getRoiImg(const Mat& img, vector ptVec, int radius) -// { -// Rect defectRoi(genRectCenRadius(ptVec, radius)); -// -// defectRoi &= Rect(0, 0, img.cols, img.rows); -// return Mat(img, defectRoi); -// } - -// cv::Mat getRoiImg(const Mat& img, Point2i cen, int radius) -// { -// Rect defectRoi(genRectCenRadius(cen, radius)); -// -// defectRoi &= Rect(0, 0, img.cols, img.rows); -// return Mat(img, defectRoi); -// } - -cv::Mat filterY(const Mat& img, float* kernel, int size, int ddepth /*= CV_32FC1*/) -{ - Mat kernelMat(size, 1, CV_32FC1, kernel); - - Mat ret; - cv::filter2D(img, ret, ddepth, kernelMat); - - return ret; -} - -float circleDegree(const vector& contour) -{ - Rect br = boundingRect(contour); - float r = sqrt((float)(br.width*br.width / 4 + br.height*br.height / 4)); - float circleArea = CV_PI*r*r; - float area = contourArea(contour); - if (circleArea < 0.00001) - { - return 0; - } - return area / circleArea; -} - -float lpContourArea(const vector& contour) -{ - double area = 0; - if (contour.size() == 1) - { - area = 1; - } - else if (contour.size() != 0) - { - area = contourArea(contour); - area += arcLength(contour, true); - } - return area; -} - -cv::Mat minMaxNorm(const Mat& img, double tarMin, double tarMax, const Mat& mask /*= Mat()*/) -{ - double minVal, maxVal; - minMaxIdx(img, &minVal, &maxVal, 0, 0, mask); - double s = ((tarMax - tarMin) / (maxVal - minVal)); - return img * s + (tarMin - minVal * s); -} - -double longShortRatio(const Size& s) -{ - if (s.width > s.height) - { - if (s.height < 0.000001) - { - return 0; - } - return (double)s.width / (double)s.height; - } - else - { - if (s.width < 0.000001) - { - return 0; - } - return (double)s.height / (double)s.width; - } -} - -void closeShapesToConvex(const Mat& mask, Mat& closedMask) -{ - closedMask.create(mask.rows, mask.cols, mask.type()); - closedMask.setTo(0); - - Mat canvas; - mask.copyTo(canvas); - vector< vector > contours; - findContours(canvas, contours, RETR_LIST, cv::CHAIN_APPROX_NONE); - vector< vector > convextContours; - for (size_t i = 0; i < contours.size(); ++i) - { - const vector& contour = contours[i]; - vector convexContour; - convexHull(contour, convexContour); - convextContours.push_back(convexContour); - } - fillPoly(closedMask, convextContours, Scalar(255, 255, 255)); -} - -cv::Mat genCircleMask(int rows, int cols, int type, - Point cen, double r, const Scalar& color, int thickness, int lineType /*= 8*/, int shift /*= 0*/) -{ - Mat mask = Mat::zeros(rows, cols, type); - circle(mask, cen, r, color, thickness, lineType, shift); - return mask; -} - -void openOper(Mat& img, int w) -{ - Mat kernel(w, w, CV_8UC1); - kernel.setTo(1); - openOper(img, kernel); -} - -void openOper(Mat& img, const Mat& kernel) -{ - erode(img, img, kernel); - dilate(img, img, kernel); -} - -void closeOper(Mat& img, int w) -{ - Mat kernel(w, w, CV_8UC1); - kernel.setTo(1); - closeOper(img, kernel); -} - -void closeOper(Mat& img, const Mat& kernel) -{ - dilate(img, img, kernel); - erode(img, img, kernel); -} - -CV_WRAP GroupMatcher::GroupMatcher( - int normType /*= NORM_L2*/, bool crossCheck /*= false*/) - : BFMatcher(normType, crossCheck) -{ - -} - -Ptr GroupMatcher::clone(bool emptyTrainData /*= false*/) const -{ - return new GroupMatcher(); -} - -// no longer supported in opencv3.4.1 -#if (CV_MAJOR_VERSION < 3) -AlgorithmInfo* GroupMatcher::info() const -{ - return NULL; -} -#endif - -void GroupMatcher::knnMatchImpl(const Mat& queryDescriptors, - vector >& matches, - int k, - const vector& masks /*= vector()*/, - bool compactResult /*= false*/) -{ - BFMatcher::knnMatchImpl(queryDescriptors, matches, k, masks, - compactResult); - - -} - -void GroupMatcher::radiusMatchImpl(const Mat& queryDescriptors, - vector >& matches, - float maxDistance, - const vector& masks /*= vector()*/, - bool compactResult /*= false*/) -{ - BFMatcher::radiusMatchImpl(queryDescriptors, - matches, maxDistance, masks, compactResult); -} - - -Mat getContourBoundedRoiImg(const Mat& src, const vector& contour, Rect* pRoiRect /* = NULL*/) -{ - Rect cr = boundingRect(contour); - Mat cmask(cr.height, cr.width, CV_8UC1); - cmask.setTo(0); - cv::fillPoly(cmask, vector< vector >(1, contour), Scalar(255, 255, 255), 8, 0, cr.tl()*(-1.0)); - Mat localMask; - Mat(src, cr).copyTo(localMask); - if (pRoiRect) - { - *pRoiRect = cr; - } - return localMask & cmask; -} - -void filterContours(const vector< vector >& contours, const Mat& srcImg, - vector< vector >& filteredContours, - int minArea, double minLength, double minLongShortRatio, - double maxCircleDegree, vector* pAreaMaxContour) -{ - int areaMaxIdx = -1; - double maxarea = -1; - for (int j = 0; j < contours.size(); ++j) - { - const vector& contour = contours[j]; - if (contour.size() < 5) - { - continue; - } - - int area = -1; - if (!srcImg.empty()) - { - Mat localMask = getContourBoundedRoiImg(srcImg, contour); - area = countNonZero(localMask); - } - else - { - area = contourArea(contour); - } - - RotatedRect rr = minAreaRect(contour); - - double l = max(rr.size.width, rr.size.height); - if (area < minArea && l < minLength) - { - continue; - } - - double cd = circleDegree(contour); - if (cd > maxCircleDegree) - { - continue; - } - - double lsr = longShortRatio(rr.size); - if (lsr < minLongShortRatio) - { - continue; - } - - if (area > maxarea) - { - maxarea = area; - areaMaxIdx = j; - } - - filteredContours.push_back(contour); - } - - if (areaMaxIdx >= 0 && pAreaMaxContour) - { - *pAreaMaxContour = contours[areaMaxIdx]; - } -} - -void filterContours(Mat hsvColorThresImg, - int minArea, double minLength, double minLongShortRatio, - double maxCircleDegree, vector* pAreaMaxContour /*= NULL*/) -{ - vector< vector > contours; - Mat canvas = hsvColorThresImg.clone(); - findContours(canvas, contours, RETR_LIST, CHAIN_APPROX_NONE); - canvas.setTo(0); - - vector< vector > filteredContours; - filterContours(contours, hsvColorThresImg, filteredContours, - minArea, minLength, minLongShortRatio, maxCircleDegree, pAreaMaxContour); - - // redraw - cv::fillPoly(canvas, filteredContours, Scalar(255, 255, 255)); - hsvColorThresImg &= canvas; -} - - -int filterSmallAndFindMaxContours(vector< vector >& contours, double minArea) -{ - vector< vector > filteredContours; - int maxindex = -1; - double maxarea = -1; - for (int j = 0; j < contours.size(); ++j) - { - const vector& contour = contours[j]; - double area = contourArea(contour); - if (area > minArea) - { - filteredContours.push_back(contour); - } - - if (area > maxarea) - { - maxarea = area; - maxindex = j; - } - } - contours = filteredContours; - return maxindex; -} - - -void filterContours(Mat& img, double minArea) -{ - Mat canvas; - img.copyTo(canvas); - - vector< vector > contours; - findContours(canvas, contours, RETR_LIST, cv::CHAIN_APPROX_NONE); - filterSmallAndFindMaxContours(contours, minArea); - canvas.setTo(0); - cv::fillPoly(canvas, contours, Scalar(255, 255, 255)); - - img = canvas; -} - - -Mat genInRangeMask(const Mat& src, std::map>& colorRanges) -{ - Mat mask = Mat::zeros(src.rows, src.cols, CV_8UC1); - - for (auto iter = colorRanges.begin(); iter != colorRanges.end(); ++iter) - { - int key = iter->first; - Scalar low = iter->second.first; - Scalar high = iter->second.second; - Mat imgThresholded; - inRange(src, low, high, imgThresholded); - mask |= imgThresholded; - } - - return mask; -} - -void localCloseOper(Mat& img, vector< vector >& contours, float longerScale) -{ - Mat tmp = img.clone(); - for (int i = 0; i < contours.size(); ++i) - { - const vector& contour = contours[i]; - RotatedRect rr = minAreaRect(contour); - int longer = cv::max(rr.size.width, rr.size.height)*longerScale; - - Rect br = boundingRect(contour); - br.x -= longer*1.5; - br.y -= longer*1.5; - br.width += longer * 3; - br.height += longer * 3; - - br.x = cv::max(0, br.x); - br.y = cv::max(0, br.y); - br.width = cv::min(img.cols - br.x - 1, br.width); - br.height = cv::min(img.rows - br.y - 1, br.height); - - Mat roiMat = Mat(img, br).clone(); - closeOper(roiMat, Mat::ones(longer, 1, CV_8UC1)); - br.x -= 1; - br.y -= 1; - br.x = cv::max(0, br.x); - br.y = cv::max(0, br.y); - - roiMat.copyTo(Mat(tmp, br)); - } - img |= tmp; -} - -Mat genWithCopiedCols(const Mat& m, int multiples = 3) -{ - Mat ret(m.rows, m.cols * multiples, m.type()); - for (int i = 0; i < multiples; ++i) - { - m.copyTo(ret.colRange(i*m.cols, i*m.cols + m.cols)); - } - return ret; -} - - - -double matDisWithReversedRows(const Mat& m0, const Mat& m1) -{ - assert(m0.rows == m1.rows); - assert(m0.cols == m1.cols); - - int rows = m0.rows; - int cols = m0.cols; - - Mat rowDisVec(rows, 1, CV_64FC1); - double* pRowDisVec = (double*)rowDisVec.data; - for (int i = 0; i < rows; ++i) - { - Mat row0 = 255 - m0.row(i); - Mat row1 = 255 - m1.row(rows - i - 1); - //Mat weightedRow0 = 255 - row0; - //*pRowDisVec = ((row0 - row1).dot(weightedRow0)); - Mat row0f; - row0.convertTo(row0f, CV_32FC1); - Mat row1f; - row1.convertTo(row1f, CV_32FC1); - *pRowDisVec = compareHist(row0f, row1f, CV_COMP_CORREL); - pRowDisVec++; - } - - Mat kernel = cv::getGaussianKernel(rows * 2, 1).rowRange(rows, rows * 2); - - return rowDisVec.dot(kernel); -} - -double matDis(const Mat& m0, const Mat& m1) -{ - assert(m0.rows == m1.rows); - assert(m0.cols == m1.cols); - - int rows = m0.rows; - int cols = m0.cols; - - Mat rowDisVec(rows, 1, CV_64FC1); - double* pRowDisVec = (double*)rowDisVec.data; - for (int i = 0; i < rows; ++i) - { - Mat row0 = 255 - m0.row(i); - Mat row1 = 255 - m1.row(i); - - Mat row0f; - row0.convertTo(row0f, CV_32FC1); - Mat row1f; - row1.convertTo(row1f, CV_32FC1); - *pRowDisVec = compareHist(row0f, row1f, CV_COMP_CORREL); - pRowDisVec++; - } - - Mat kernel = cv::getGaussianKernel(rows * 2, 1).rowRange(rows, rows * 2); - - return rowDisVec.dot(kernel); -} - -int searchBestMatchDx(int searchRadius, int startCol, int endCol, const Mat& curRow, const Mat& preRowMid) -{ - vector valVec; - for (int dx = -searchRadius; dx <= searchRadius; dx++) - { - int curStartCol = startCol + dx; - int curEndCol = endCol + dx; - Mat curRowMid = curRow.colRange(curStartCol, curEndCol); - double val = -matDisWithReversedRows(curRowMid, preRowMid); - valVec.push_back(val); - } - auto minIter = std::min_element(valVec.begin(), valVec.end()); - int bestDx = minIter - valVec.begin() - searchRadius; - - return bestDx; -} - -Mat searchBestMatchSubRowMat(const Mat& img, int startRow, int rowWidth, int searchRadius, const Mat& preRowMid) -{ - Mat curRow = genWithCopiedCols(img.rowRange(startRow, rowWidth + startRow), 3); - int startCol = img.cols; - int endCol = img.cols * 2; - - int bestDx = searchBestMatchDx(searchRadius, startCol, endCol, curRow, preRowMid); - - return curRow.colRange(startCol + bestDx, endCol + bestDx); -} - -void xEnergeyMat(const Mat& img, Mat& energyMat, - int kernelWidth = 12, int backgroundThre = 40, int method = 2) -{ - switch (method) - { - case 0: - { - // sobel edge - Mat sobelMat; - cv::Sobel(img, sobelMat, CV_32FC1, 1, 0); - sobelMat = cv::abs(sobelMat); - energyMat = sobelMat; - } - break; - case 1: - { - // edge with first derivative - Mat kernel = cv::getGaussianKernel(kernelWidth, 4).t(); - Mat halfKernel(kernel.colRange(0, kernel.cols / 2)); - halfKernel *= -1.0; - filter2D(img, energyMat, CV_32FC1, kernel); - energyMat = abs(energyMat); - } - break; - case 2: - { - // edge with second derivative - Mat kernel = cv::getGaussianKernel(kernelWidth, 4).t(); - Mat halfKernel(kernel.colRange(0, kernel.cols / 2)); - halfKernel *= -1.0; - filter2D(img, energyMat, CV_32FC1, kernel); - energyMat = abs(energyMat); - - Mat secondEnergyMat; - filter2D(energyMat, secondEnergyMat, CV_32FC1, kernel); - secondEnergyMat = abs(secondEnergyMat); - - energyMat = secondEnergyMat; - } - break; - case 3: - { - // darker edge with first derivative - Mat kernel = cv::getGaussianKernel(kernelWidth, 4).t(); - Mat gaussMat; - filter2D(img, gaussMat, CV_32FC1, kernel); - gaussMat = 255.0 - gaussMat; - Mat halfKernel(kernel.colRange(0, kernel.cols / 2)); - halfKernel *= -1.0; - filter2D(img, energyMat, CV_32FC1, kernel); - energyMat = abs(energyMat) + gaussMat*0.2; - } - case 4: - { - // darker edge with thresholding - Mat threMat = img < backgroundThre; - converToType(threMat, CV_32FC1); - - Mat kernel = cv::getGaussianKernel(kernelWidth, 4).t(); - - Mat halfKernel(kernel.colRange(0, kernel.cols / 2)); - halfKernel *= -1.0; - filter2D(img, energyMat, CV_32FC1, kernel); - energyMat = abs(energyMat) + threMat; - } - break; - } -} - -void findBoundaryY(const Mat& img, vector& vec, vector& energyVec, - int gradientKernelWidth = 12, - int smoothKernelWidth = 32, - float smoothWeight = 3.0, - int backgroundThre = 40, - int energyType = 4) -{ - // generate energy mat (sobel) - Mat energyMat; - xEnergeyMat(img, energyMat, gradientKernelWidth, backgroundThre, energyType); - - int n = 4; - Mat energyMatBack = energyMat.clone(); - - Mat smoothImg, showMat; - { - Mat kernel = cv::getGaussianKernel(smoothKernelWidth, 4.0).t(); - filter2D(img, smoothImg, CV_32FC1, kernel); - } - - float w = pow(10, smoothWeight); - dynamicProgramYWithSmooth(energyMat, n, w/255.0, smoothImg); - findMaxYPath(energyMat, vec, energyVec, n); - - recoverPathEnergy(energyVec); -} - -void findBoundaryY(const Mat& img0, const Mat& img1, int targetWidth, - vector& vec, vector& energyVec) -{ - // generate energy mat - Mat energyMat0, energyMat1; - xEnergeyMat(img0, energyMat0); - xEnergeyMat(img1, energyMat1); - - // generate smooth mat (gauss) - Mat smoothImg0, smoothImg1, showMat; - { - Mat kernel = cv::getGaussianKernel(31, 4.0).t(); - filter2D(img0, smoothImg0, CV_32FC1, kernel); - filter2D(img1, smoothImg1, CV_32FC1, kernel); - } - - int n = 4; - float sw = 100.0 / 255.0; - dynamicProgramYWithSmooth(energyMat0, energyMat1, - smoothImg0, smoothImg1, targetWidth, n, sw); - - findMaxYPath(energyMat0, vec, energyVec, n); - - recoverPathEnergy(energyVec); -} - -// assuming with two boundaries (left and right) -void autoAlignEachRowGloballyWithIndependentBoundaries(Mat& img) -{ - // divide into two part: left and right - Mat leftImg(img.colRange(0, img.cols / 2)); - Mat rightImg(img.colRange(img.cols / 2, img.cols)); - - // search a boundary for each part - vector leftVec, rightVec; - vector leftEnergyVec, rightEnergyVec; - findBoundaryY(leftImg, leftVec, leftEnergyVec); - findBoundaryY(rightImg, rightVec, rightEnergyVec); - - // draw path - Mat canvas = img.clone(); - drawPointsY(leftVec, canvas, 0, 0, 255); - drawPointsY(rightVec, canvas, canvas.cols / 2, 0, 255); - - // align centers of each row - int rightBaseX = img.cols / 2; - int centerX = (leftVec[0] + rightVec[0] + rightBaseX) / 2; - Mat ret = img.clone(); - ret.setTo(0); - - // move each row to align - for (int i = 0; i < img.rows; ++i) - { - int curCenterX = (leftVec[i] + rightVec[i] + rightBaseX) / 2; - int dx = centerX - curCenterX; - Mat curRow = genWithCopiedCols(img.row(i), 3); - curRow.colRange(img.cols - dx, img.cols * 2 - dx).copyTo(ret.row(i)); - } - - ret.copyTo(img); -} - -void autoAlignEachRowWithWeightedXCen(Mat& img, int tarCenX, vector& dxVec) -{ - dxVec.resize(img.rows, 0); - - for (int i = 0; i < img.rows; ++i) - { - Mat r = img.row(i); - uchar* p = r.data; - uchar* ep = p + r.cols; - int j = 0; - float wx = 0; - float ws = 0; - while (p != ep) - { - float w = (*p) * (*p); - ws += w; - wx += j*w; - j++; - p++; - } - wx /= ws; - int dx = floorf(tarCenX - wx); - dxVec[i] = dx; - } - - alignEachRow(img, dxVec); -} - -void alignEachRow(Mat& img, const vector& dxVec) -{ - Mat ret = img.clone(); - ret.setTo(0); - - for (int i = 0; i < img.rows; ++i) - { - Mat curRow = genWithCopiedCols(img.row(i), 3); - int dx = dxVec[i]; - curRow.colRange(img.cols - dx, img.cols * 2 - dx).copyTo(ret.row(i)); - } - - ret.copyTo(img); -} - -void autoAlignEachRowGloballyWithWidthConstraint(Mat& img, int tarCenX, vector& dxVec) -{ - // divide into two part: left and right - Mat leftImg(img.colRange(0, img.cols / 2)); - Mat rightImg(img.colRange(img.cols / 2, img.cols)); - - // search a boundary for each part - vector leftVec, rightVec; - vector leftEnergyVec, rightEnergyVec; - findBoundaryY(leftImg, leftVec, leftEnergyVec); - findBoundaryY(rightImg, rightVec, rightEnergyVec); - - // draw path - Mat canvas = img.clone(); - drawPointsY(leftVec, canvas, 0, 0, 255); - drawPointsY(rightVec, canvas, canvas.cols / 2, 0, 255); - - float avrLeft = sum(leftVec.begin(), leftVec.end()) / leftVec.size(); - float avrRight = sum(rightVec.begin(), rightVec.end()) / rightVec.size(); - int tarWidth = avrRight + leftImg.cols - avrLeft; - - leftVec.clear(); - leftEnergyVec.clear(); - findBoundaryY(leftImg, rightImg, tarWidth, leftVec, leftEnergyVec); - - rightVec = leftVec; - add(rightVec.begin(), rightVec.end(), tarWidth); - - drawPointsY(leftVec, canvas, 0, 0, 180); - drawPointsY(rightVec, canvas, 0, 0, 180); - - // align centers of each row - int centerX = leftVec[0] + tarWidth / 2; - if (tarCenX >= 0) - { - centerX = tarCenX; - } - Mat ret = img.clone(); - ret.setTo(0); - - // move each row to align - dxVec.resize(img.rows, 0); - for (int i = 0; i < img.rows; ++i) - { - int curCenterX = leftVec[i] + tarWidth / 2; - int dx = centerX - curCenterX; - dxVec[i] = dx; - Mat curRow = genWithCopiedCols(img.row(i), 3); - curRow.colRange(img.cols - dx, img.cols * 2 - dx).copyTo(ret.row(i)); - } - - ret.copyTo(img); -} - -void autoAlignEachRowLocally(Mat& img, int searchRadius /*= 5*/, int rowWidth /*= 1*/, const Mat& preImg /*= Mat()*/) -{ - Mat ret = img.clone(); - ret.setTo(0); - - Mat preRow; - if (!preImg.empty()) - { - preRow = genWithCopiedCols(preImg.rowRange(0, rowWidth), 3); - } - else - { - preRow = genWithCopiedCols(img.rowRange(0, rowWidth), 3); - } - - Mat preRowMid = preRow.colRange(img.cols, img.cols * 2); - if (!preImg.empty()) - { - preRowMid = searchBestMatchSubRowMat(img, 0, rowWidth, searchRadius, preRowMid); - } - preRowMid.copyTo(ret.rowRange(0, rowWidth)); - - for (int i = rowWidth; i <= img.rows - rowWidth; i += rowWidth) - { - preRowMid = searchBestMatchSubRowMat(img, i, rowWidth, searchRadius, preRowMid); - - preRowMid.copyTo(ret.rowRange(i, i + rowWidth)); - } - - ret.copyTo(img); -} - -void autoAlignEachRowWithAutoThreshold(Mat& img, int tarCenX, vector& dxVec) -{ - dxVec.resize(img.rows, 0); - - for (int i = 0; i < img.rows; ++i) - { - Mat row(img.row(i)); - Mat trow; - threshold(row, trow, 0, 255, THRESH_OTSU); - uchar* p = trow.data; - uchar* ep = p + trow.cols; - int l, r; - while (p != ep) - { - if (*p) - { - l = p - trow.data; - break; - } - p++; - } - p = ep - 1; - do - { - if (*p) - { - r = p - trow.data; - break; - } - p--; - } while (p != trow.data); - int curCenX = floorf((l + r) / 2.0); - dxVec[i] = tarCenX - curCenX; - } - - alignEachRow(img, dxVec); -} - -void alignEachRowRightBound(Mat& img, int tarCen, vector& dxVec, - int gradientKernelWidth /*= 12*/, - int smoothBoundaryKernelWidth /*= 32*/, - float smoothBoundaryWeight /*= 3.0*/, - int backgroundThre /*= 40*/) -{ - // right part - Mat rightImg(img.colRange(img.cols / 2, img.cols)); - - // search a boundary - vector rightVec; - vector rightEnergyVec; - findBoundaryY(rightImg, rightVec, rightEnergyVec, gradientKernelWidth, - smoothBoundaryKernelWidth, smoothBoundaryWeight, backgroundThre); - - // draw path - Mat canvas = img.clone(); - drawPointsY(rightVec, canvas, canvas.cols / 2, 0, 255); - - // align centers of each row - int rightBaseX = img.cols / 2; - int centerX = tarCen; - Mat ret = img.clone(); - ret.setTo(0); - - // move each row to align - for (int i = 0; i < img.rows; ++i) - { - int dx = img.cols - rightVec[i] - rightBaseX - 1; - dxVec.push_back(dx); - Mat curRow = genWithCopiedCols(img.row(i), 3); - curRow.colRange(img.cols - dx, img.cols * 2 - dx).copyTo(ret.row(i)); - } - - ret.copyTo(img); -} - -cv::Mat genDirColorImg(const Mat& img, Mat* pValueMat /*= NULL*/) -{ - Mat hsvImg(img.rows, img.cols, CV_8UC3); - vector channels(3); - channels[0] = img; - channels[1] = Mat::zeros(img.rows, img.cols, CV_8UC1); - channels[2] = channels[1]; - channels[1].setTo(255); - if (pValueMat) - { - channels[2] = *pValueMat; - } - else - { - channels[2].setTo(255); - } - merge(channels, hsvImg); - Mat rgbImg; - cvtColor(hsvImg, rgbImg, COLOR_HSV2BGR); - return rgbImg; -} - -void genSobelDir(Mat& img) -{ - Mat srcImg = img.clone(); - Mat sobelX, sobelY; - genSobelImage(srcImg, &sobelX, &sobelY); - img = genSobelDir(sobelX, sobelY); -} - -cv::Mat genSobelDir(const Mat& sobelX, const Mat& sobelY) -{ - Mat img(sobelX.rows, sobelX.cols, CV_8UC1); - for (int i = 0; i < img.rows; ++i) - { - Mat row = img.row(i); - float* pDataX = (float*)sobelX.row(i).data; - float* pDataY = (float*)sobelY.row(i).data; - uchar* pData = row.data; - for (int j = 0; j < img.cols; ++j) - { - float dx = pDataX[j]; - float dy = pDataY[j]; - float angle = 0; - if (dx == 0 && dy == 0) - { - angle = 0; - } - else - { - angle = atan2f(dy, dx); - if (angle < 0) - { - angle += 2.0 * M_PI; - } - } - pData[j] = floorf((angle / M_PI) * 90); - } - } - return img; -} - -void genContrastImg(const Mat& img, Mat& contrastImg, const Mat& kernelMat) -{ - Mat maxMat, minMat; - dilate(img, maxMat, kernelMat); - erode(img, minMat, kernelMat); - - contrastImg = maxMat - minMat; -} - -void genContrastImg(const Mat& img, Mat& contrastImg, int ksize) -{ - Mat kernelMat(ksize, ksize, CV_8UC1); - genContrastImg(img, contrastImg, kernelMat); -} - -void genYContrastImg(const Mat& img, Mat& constrastImg, int ksize) -{ - Mat kernelMat(ksize, 1, CV_8UC1); - genContrastImg(img, constrastImg, kernelMat); -} - -void genHalfContrastImg(const Mat& img, Mat& contrastImg, const Mat& kernelMat) -{ - assert(img.type() == CV_8UC1); - - uchar* pData = img.data; - int wstep = img.step; - int kernelXStep = kernelMat.cols; - int kernelYStep = kernelMat.rows; - - contrastImg.create(img.rows / kernelXStep, img.cols / kernelYStep, CV_8UC1); - uchar* pContrastData = contrastImg.data; - int wContrastStep = contrastImg.step; - - for (int y = 0; y < img.rows; y += kernelYStep) - { - uchar* pRowData = pData; - uchar* pContrastRowData = pContrastData; - for (int x = 0; x < img.cols; x += kernelXStep) - { - Mat roiMat(kernelMat.rows, kernelMat.cols, CV_8UC1, pRowData); - roiMat.step = wstep; - - - - pRowData += kernelXStep; - pContrastRowData += 1; - } - pData += wstep*kernelYStep; - pContrastData += wContrastStep; - } -} - -void genHalfContrastImg(const Mat& img, Mat& contrastImg, int ksize) -{ - -} - -void cvtColor(Mat& img, int t) -{ - Mat tImg; - cvtColor(img, tImg, t); - img = tImg; -} - -cv::Mat rotateImage(const Mat& img, Point2f cen, float degree) -{ - Mat t = getRotationMatrix2D(cen, degree, 1.0); - Mat rImg; - warpAffine(img, rImg, t, img.size(), INTER_CUBIC, BORDER_CONSTANT); - return rImg; -} - -cv::Mat normAngle(const Mat& img, Mat mask) -{ - Point2f cen(img.cols / 2.0, img.rows / 2.0); - double angle = localAngle_(img, cen, mask); - return rotateImage(img, cen, -angle); -} - -float normAngle(float angle) -{ - angle = angle - (int)(angle / 360.0) * 360; - if (angle < 0) - { - angle += 360.0; - } - return angle; -} - -void printMatInfo(const Mat& m, int baseIndentNum /*= 0*/, int indent /*= 4*/) -{ - printIndent(baseIndentNum, indent); - std::cout << "rows: " << m.rows << ", " << - "cols: " << m.cols << ", " << - "channels: " << m.channels() << ", " << - "elementSize: " << m.elemSize() << "; "; -} - -string templateMatchMethod2Str(int method) -{ - switch (method) - { - case cv::TM_SQDIFF: - return "TM_SQDIFF"; - case cv::TM_SQDIFF_NORMED: - return "TM_SQDIFF_NORMED"; - case cv::TM_CCORR: - return "TM_CCORR"; - case cv::TM_CCORR_NORMED: - return "TM_CCORR_NORMED"; - case cv::TM_CCOEFF: - return "TM_CCOEFF"; - case cv::TM_CCOEFF_NORMED: - return "TM_CCOEFF_NORMED"; - default: - return ""; - } -} - -void printIndent(int indentNum, int indent /*= 4*/) -{ - for (int i = 0; i < indentNum; i++) - { - for (int j = 0; j < indent; j++) - { - std::cout << " "; - } - } -} - -Mat genSimpleXGradient(const Mat& m) -{ - Mat kernel(1, 2, CV_32FC1); - float* p = (float*)kernel.data; - p[0] = -1; - p[1] = 1; - Mat dm; - filter2D(m, dm, CV_32FC1, kernel, - Point(-1, -1), 0, BORDER_REFLECT); - return dm; -} - -void uniformLocalMinExtremas(const Mat& vec, Mat& localExtremaValVec, - vector& idxVec, int n, int refineRange) -{ - idxVec.resize(n); - - float step = (float)(vec.cols - 1) / (float)n; - float* pVec = (float*)vec.data; - localExtremaValVec.create(1, n + 1, CV_32FC1); - float* pExtremaValVec = (float*)localExtremaValVec.data; - - float* pVecData = (float*)vec.data; - for (int i = 0; i < n; ++i) - { - int idx = floorf(step*i); - int sIdx = idx - refineRange; - int eIdx = idx + refineRange; - sIdx = max(0, sIdx); - eIdx = min(vec.cols - 1, eIdx) + 1; - float* pExtrema = std::min_element(pVec + sIdx, pVec + eIdx); - idxVec[i] = pExtrema - pVec; - pExtremaValVec[i] = *pExtrema; - } - - pExtremaValVec[n] = pExtremaValVec[0]; -} - -void equalizeHist(const Mat& src, Mat& dst, const Mat& mask /*= Mat()*/) -{ - if (mask.empty()) - { - cv::equalizeHist(src, dst); - return; - } - Mat hist = calcHist(src, mask); - hist *= 255.0 / countNonZero(mask); - - float* pHistData = (float*)hist.data; - Mat mapHist = Mat::zeros(hist.rows, hist.cols, CV_32FC1); - float* pMapHistData = (float*)mapHist.data; - pMapHistData[0] = pHistData[0]; - for (int i = 1; i < 256; ++i) - { - pMapHistData[i] = pMapHistData[i - 1] + pHistData[i]; - } - - dst.create(src.size(), src.type()); - for (int y = 0; y < dst.rows; ++y) - { - uchar* pDstData = dst.row(y).data; - uchar* pSrcData = src.row(y).data; - for (int x = 0; x < dst.cols; ++x) - { - pDstData[x] = pMapHistData[pSrcData[x]]; - } - } -} - -void removeHighlights(const Mat& src, Mat& dst, float thre) -{ - dst = Mat::zeros(src.size(), src.type()); - Mat hightlightMask = src < thre; - src.copyTo(dst, hightlightMask); -} - -void genSectorSumVec(const Mat& img, const Mat& weightMat, Mat& hist, - Mat& weightHist, const Point2f& cen, float angleStep, - Mat* pAngMat /*= NULL*/, Mat* pMagMat /*= NULL*/) -{ - int count = floorf(360.0 / angleStep); - hist = Mat::zeros(1, count, CV_32FC1); - weightHist = Mat::zeros(1, count, CV_32FC1); - float* pData = (float*)img.data; - float* pWeightData = (float*)weightMat.data; - float* pHistData = (float*)hist.data; - float* pWeightHistData = (float*)weightHist.data; - float *x = new float[img.cols]; - for (int i = 0; i < img.cols; ++i) x[i] = i - cen.x; - Mat xRow(1, img.cols, CV_32FC1, x); - Mat magMat(img.rows, img.cols, CV_32FC1); - Mat angMat(img.rows, img.cols, CV_32FC1); - for (int i = 0; i < img.rows; ++i) - { - Mat yRow = Mat::ones(xRow.size(), xRow.type())*(i - cen.y); - - Mat magRow, angRow; - cartToPolar(xRow, yRow, magRow, angRow, true); - magRow.copyTo(magMat.row(i)); - angRow.copyTo(angMat.row(i)); - - float* pAngleData = (float*)angRow.data; - float* pRadiusData = (float*)magRow.data; - for (int j = 0; j < img.cols; ++j) - { - if (i == 100 && j == 90) - { - int a = 0; - } - float val = pData[j]; - float weight = pWeightData[j]; - float radius = pRadiusData[j]; - if (radius == 0) - { - continue; - } - float angle = pAngleData[j]; - - val *= weight; - - float angleRange = 28.6479 / radius; - float langle = angle - angleRange; - float rangle = angle + angleRange; - - int lIntAngle = (int)(langle); - int rIntAngle = (int)rangle; - int li = normAngle(lIntAngle); - int ri = normAngle(rIntAngle); - float totalRange = angleRange*2.0; - //pHistData[li] += val*(langle - ceil(langle)) / totalRange; - pHistData[li] += val*(1 - langle + lIntAngle) / totalRange; - //pWeightHistData[li] += weight*(langle - ceil(langle)) / totalRange; - pWeightHistData[li] += weight*(1 - langle + lIntAngle) / totalRange; - pHistData[ri] += val*(rangle - rIntAngle) / totalRange; - pWeightHistData[ri] += weight*(rangle - rIntAngle) / totalRange; - lIntAngle++; -#if defined(LITTLE_CPP11) - if (_isnan(pHistData[li]) || _isnan(pHistData[ri])) -#else - if (isnan(pHistData[li]) || isnan(pHistData[ri])) -#endif - { - waitKey(); - } - while (lIntAngle < rIntAngle) - { - li = normAngle(lIntAngle); - pHistData[li] += val / totalRange; - pWeightHistData[li] += weight / totalRange; - lIntAngle++; - } - } - pData += img.step1(); - pWeightData += weightMat.step1(); - } - - if (pAngMat) - { - *pAngMat = angMat; - } - if (pMagMat) - { - *pMagMat = magMat; - } - - free(x); -} - -Mat matDivideNonzero(const Mat& m0, const Mat& m1) -{ - // m0/m1 - Mat m1copy = m1.clone(); - m0.copyTo(m1copy, m1copy < 0.0000001); - return m0 / m1copy; -} - - -Mat matDivideNonzero(float m0, const Mat& m1) -{ - // m0/m1 - Mat m1copy = m1.clone(); - m1copy.setTo(m0, m1 < 0.0000001); - return m0 / m1copy; -} - - -void normSectors(Mat& _img, Mat weightMat, const Point2f& cen, - float angleStep, float tarVal) -{ - if (weightMat.empty()) - { - weightMat = Mat::ones(_img.size(), CV_32FC1); - } - Mat img = _img; - if (img.channels() != 1) - { - img = getFirstChannel(img); - } - if (img.type() != CV_32FC1) - { - converToType(img, CV_32FC1); - } - int count = floorf(360.0 / angleStep); - Mat hist = Mat::zeros(1, count, CV_32FC1); - Mat weightHist = Mat::zeros(1, count, CV_32FC1); - Mat magMat(img.rows, img.cols, CV_32FC1); - Mat angMat(img.rows, img.cols, CV_32FC1); - - genSectorSumVec(img, weightMat, hist, weightHist, cen, angleStep, - &angMat, &magMat); - - hist = matDivideNonzero(hist, weightHist); - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vAngleMat = angMat / 360; - Mat vMagMat = magMat / sqrt(img.cols*img.cols / 4.0 + img.rows*img.rows / 4.0); - Mat vHist = hist; - vHist = minMaxNorm(vHist, 0, 1.0); - Mat vWeightHist = weightHist; - vWeightHist = minMaxNorm(vWeightHist, 0, 1.0); -#endif - - Mat scaleHist = matDivideNonzero(tarVal, hist); - - applySectorScales(img, scaleHist, angMat); - - _img = img; -} - -void normSectors_tarImg(Mat& img, Mat weightMat, const Point2f& cen, float angleStep, - const Mat& tarImg) -{ - Mat hist, weightHist, angMat, magMat; - genSectorSumVec(img, weightMat, hist, weightHist, cen, angleStep, - &angMat, &magMat); - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vHist0 = minMaxNorm(hist, 0, 1.0); - Mat vWeightHist = minMaxNorm(weightHist, 0, 1.0); -#endif - - hist = matDivideNonzero(hist, weightHist); - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vHist1 = hist / 255.0; -#endif - - Mat tarHist; - genSectorSumVec(tarImg, weightMat, tarHist, weightHist, cen, angleStep); - tarHist = matDivideNonzero(tarHist, weightHist); - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vTarHist = tarHist/255.0; -#endif - - normSectorsMeans_tarHist(img, hist, cen, angleStep, tarHist, angMat); -} - -void normSectorsMeans_tarHist(Mat& img, const Mat& hist, - const Point2f& cen, float angleStep, const Mat& tarHist, const Mat& angMat) -{ - Mat scaleHist = matDivideNonzero(tarHist, hist); - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vScaleHist = minMaxNorm(scaleHist, 0, 1.0); -#endif - applySectorScales(img, scaleHist, angMat); -} - -void applySectorScales(Mat& img, const Mat& scaleHist, const Mat& angMat) -{ - float* pData = (float*)img.data; - float* pHistData = (float*)scaleHist.data; - for (int i = 0; i < img.rows; ++i) - { - Mat angRow = angMat.row(i); - - float* pAngleData = (float*)angRow.data; - for (int j = 0; j < img.cols; ++j) - { - float angle = pAngleData[j]; - int base = (int)angle; - float s = pHistData[base]; - pData[j] *= s; - } - pData += img.step1(); - } -} - -cv::Point2f imgCen(const Mat& img) -{ - return Point2f(img.cols / 2.0, img.rows / 2.0); -} - -cv::Mat getForeImage(const Mat & src, const Mat &backgroundImg) -{ - Mat resizedBackgroundImg = backgroundImg; - if (backgroundImg.size() != src.size()) { - resize(backgroundImg, resizedBackgroundImg, src.size()); - } - return (src - resizedBackgroundImg); -} -#define ALG_RESIZE_IMAGE_WIDTH 416.0 - -// cv::Mat findCircleObject(const Mat &src, const Mat& backgroundImg, -// int nThres /*= 20*/, luffy_base::luffyCircle *pCircle /*= NULL*/) -// { -// if (src.empty() || backgroundImg.empty() || src.rows < 500) { -// return Mat(); -// } -// -// assert(backgroundImg.type() == CV_8UC1); -// Mat imgTmp, imgBinary; -// const cv::Size cSize = cv::Size(ALG_RESIZE_IMAGE_WIDTH, floorf(ALG_RESIZE_IMAGE_WIDTH / (float)src.cols*(float)src.rows)); -// cv::resize(src, imgTmp, cSize); -// Mat foregroundImg = getForeImage(imgTmp, backgroundImg); -// -// using namespace luffy_base; -// luffy_threshold::Threshold(foregroundImg, imgBinary, nThres); -// -// Mat dilatedImgBin; -// dilate(imgBinary, dilatedImgBin, Mat::ones(7, 7, CV_32FC1)); -// erode(dilatedImgBin, imgBinary, Mat::ones(7, 7, CV_32FC1)); -// -// openOper(imgBinary, Mat::ones(1, 13, CV_32FC1)); -// -// vector> conts; -// cv::findContours(imgBinary, conts, RETR_EXTERNAL, CHAIN_APPROX_NONE); -// imgBinary.setTo(0); -// for (int i = 0; i < conts.size(); i++) { -// const vector &pt = conts.at(i); -// if (pt.size() < 20) { -// continue; -// } -// Rect rt = boundingRect(pt); -// if (rt.width < 5 || rt.height < 5) { -// continue; -// } -// drawContours(imgBinary, conts, i, Scalar::all(255), -1); -// } -// Mat hit; vector pts; -// luffy_hit::firstHit4Circle(imgBinary, hit, pts, Point(cSize.width / 2, cSize.height / 2), 0, cSize.width / 2, 360, luffy_hit::emHitOut2In); -// -// //luffy_imageProc::RansacParam rs(0.02, 2.5, 70, 100, 220); -// luffy_imageProc::RansacParam rs(0.001, 1.5, 2240, 100, 420); -// vector pts2 = luffy_imageProc::fitModelbyRansac(pts, luffy_imageProc::emModelCircle, &rs); -// -// #ifdef _DEBUG -// Mat imgColor; -// cv::cvtColor(imgTmp, imgColor, CV_GRAY2BGR); -// for (int i = 0; i < pts.size(); i++) { -// imgColor.at(pts.at(i))[0] = 255;//B -// imgColor.at< cv::Vec3b >(pts.at(i))[1] = 0;//G -// imgColor.at< cv::Vec3b >(pts.at(i))[2] = 0;//R -// } -// for (int i = 0; i < pts2.size(); i++) { -// imgColor.at(pts2.at(i))[0] = 0;//B -// imgColor.at< cv::Vec3b >(pts2.at(i))[1] = 0;//G -// imgColor.at< cv::Vec3b >(pts2.at(i))[2] = 255;//R -// } -// #endif -// -// float fRadius; -// Point2f ptCenter; -// bool bFind = luffy_imageProc::lsCircleFit(pts2, fRadius, ptCenter); -// -// if (!bFind) { -// return Mat(); -// } -// Mat dst; -// const int nOffset = 1; -// fRadius += nOffset; -// Rect rt(ptCenter.x - fRadius + nOffset, ptCenter.y - fRadius + nOffset, 2 * fRadius, 2 * fRadius); -// rt &= Rect(0, 0, imgTmp.cols, imgTmp.rows); -// Mat test; -// imgTmp(rt).copyTo(test); -// static int nCount = cv::getTickCount(); -// //QString str = "d://image//" + QString::number(cv::getTickCount()); -// //QString strTest = str + "_1.jpg"; -// //cv::imwrite(strTest.toLatin1().data(), test); -// // -// if (pCircle) { -// float fScale = src.cols / ALG_RESIZE_IMAGE_WIDTH; -// Mat matBig = src - backgroundImg; -// pCircle->fRadius = fRadius * fScale; -// pCircle->ptCenter = Point(ptCenter.x * fScale, ptCenter.y * fScale); -// Mat matBinary; -// luffy_threshold::Threshold(matBig, matBinary, nThres); -// Mat hit; vector pts; -// luffy_hit::firstHit4Circle(matBinary, hit, pts, pCircle->ptCenter, 0, pCircle->fRadius + 10, 360, luffy_hit::emHitOut2In); -// luffy_imageProc::RansacParam rs(0.01, 2.5, 100, 100, 220); -// vector pts2 = luffy_imageProc::fitModelbyRansac(pts, luffy_imageProc::emModelCircle, &rs); -// float fRadius2; -// Point2f ptCenter2; -// bool bFind = luffy_imageProc::lsCircleFit(pts2, fRadius2, ptCenter2); -// if (bFind) { -// pCircle->fRadius = fRadius2; -// pCircle->ptCenter = ptCenter2; -// Rect rt(ptCenter2.x - fRadius2 + nOffset, ptCenter2.y - fRadius2 + nOffset, 2 * fRadius2, 2 * fRadius2); -// src(rt).copyTo(dst); -// int nWidth = ((int)((double)dst.cols / fScale / 4)) * 4; -// cv::resize(dst, dst, cv::Size(nWidth, nWidth)); -// //QString strTest = str + "_2.jpg"; -// //cv::imwrite(strTest.toLatin1().data(), dst); -// } -// } -// if (dst.empty()) { -// imgTmp(rt).copyTo(dst); -// } -// -// return dst; -// } - -bool ensureGrayImg(const Mat& img, Mat& gray) -{ - if (img.channels() == 3) - { - cvtColor(img, gray, COLOR_BGR2GRAY); - return true; - } - else if (img.channels() == 4) - { - cvtColor(img, gray, COLOR_BGRA2GRAY); - return true; - } - else if (img.channels() == 1) - { - gray = img; - return false; - } - else - { - assert(false && "unsupported image conversion."); - return false; - } -} - -double hsvDis(const Vec3b& v0, const Vec3b& v1) -{ - float h0 = v0[0] * 2.0 * 0.01745; - float s0 = v0[1] * (v0[2] / 255.0) * 2.0; - float h1 = v1[0] * 2.0 * 0.01745; - float s1 = v1[1] * (v1[2] / 255.0) * 2.0; - - double dVal = norm(Vec3f(cos(h0)*s0, sin(h0)*s0, v0[2]), - Vec3f(cos(h1)*s1, sin(h1)*s1, v1[2])); - - return dVal; -} - -cv::Mat genHSVColorDisMat(const Mat& m0, const Mat& m1) -{ - Scalar mean, stddev; - meanStdDev(m1, mean, stddev); - Vec3b baseColor(mean.val[0], mean.val[1], mean.val[2]); - return genHSVColorDisMat(m0, baseColor); -} - -cv::Mat genHSVColorDisMat(const Mat& m, Vec3b baseColor) -{ - Mat ret = Mat::zeros(m.size(), CV_32FC1); - uchar* pRet = ret.data; - uchar* pData0 = m.data; - for (int i = 0; i < m.rows; ++i) - { - float* pRet32f = (float*)pRet; - Vec3b* pData32f0 = (Vec3b*)pData0; - for (int j = 0; j < m.cols; ++j) - { - Vec3b& v0 = pData32f0[j]; - pRet32f[j] = (float)hsvDis(v0, baseColor); - } - - pRet += ret.step; - pData0 += m.step; - } - return ret; -} - -cv::Mat genHSVColorDisMat(const Mat& m) -{ - Scalar mean, stddev; - meanStdDev(m, mean, stddev); - return genHSVColorDisMat(m, Vec3b(mean.val[0], mean.val[1], mean.val[2])); -} - -cv::Mat genBlueGreenRatioMat(const Mat& m, float alpha /*= 50.0*/, float beta /*= -17.0*/) -{ - vector channels; - split(m, channels); - Mat blue32f, green32f; - channels[0].convertTo(blue32f, CV_32FC1); - channels[1].convertTo(green32f, CV_32FC1, 1.0, -beta); - Mat ratioMat = green32f / blue32f; - Mat ratioMat8u; - ratioMat.convertTo(ratioMat8u, CV_8UC1, alpha); - return ratioMat8u; -} - -Mat genColorFuncDisMat(const Mat& m, float a, float b, float c) -{ - vector channels; - split(m, channels); - Mat blue32f, green32f; - channels[0].convertTo(blue32f, CV_32FC1); - channels[1].convertTo(green32f, CV_32FC1); - Mat sqrBlue = blue32f.mul(blue32f, a); - Mat bBlue = blue32f*b; - //Mat dis = ((sqrBlue + bBlue) - green32f); - Mat dis = (green32f - sqrBlue + c) / blue32f; - Mat ret; - dis.convertTo(ret, CV_8UC1, 255); - return ret; -} - -void setChannel(Mat& img, int i, Mat chnMat) -{ - vector channels; - split(img, channels); - channels[i] = chnMat; - merge(channels, img); -} - -Rect loadRect(std::string filepath) -{ - std::ifstream fin; - fin.open(filepath, std::ios_base::in); - double x, y, w, h; - fin >> x; - fin >> y; - fin >> w; - fin >> h; - return Rect(x, y, w, h); -} - -Rect rectInImage(const Mat& img, const Point& pt, const Size& rectSize, int xPadding /*= 0*/, int yPadding /*= 0*/) -{ - assert(rectSize.width % 2 == 1); - assert(rectSize.height % 2 == 1); - - Rect imgRect(xPadding, yPadding, img.cols - xPadding, img.rows - yPadding); - Rect rect(pt.x - rectSize.width / 2, pt.y - rectSize.height / 2, - rectSize.width, rectSize.height); - - return imgRect & rect; -} - -Rect extRectTopLeftFix(const Rect& r, int w) -{ - return Rect(r.x, r.y, r.width + w * 2, r.height + w * 2); -} - -Rect extRectCenFix(const Rect& r, int w) -{ - return Rect(r.x - w, r.y - w, r.width + 2 * w, r.height + 2 * w); -} - -inline float isLeft(Point2f p0, Point2f p1, Point2f p) -{ - return ((p1.x - p0.x) * (p.y - p0.y) - (p.x - p0.x) * (p1.y - p0.y)); -} - -bool isPntInRotatedRect(const RotatedRect& rr, const Point2f& pnt) -{ - Point2f pts[4]; - rr.points(pts); - return (isLeft(pts[0], pts[1], pnt) > 0 && isLeft(pts[1], pts[2], pnt) > 0 && - isLeft(pts[2], pts[3], pnt) > 0 && isLeft(pts[3], pts[0], pnt) > 0); -} - -inline bool _isOnLineSegment(const Point2f& pt, const Vec4f& line) -{ - float xRange = line.val[2] - line.val[0]; - float yRange = line.val[3] - line.val[1]; - float dx0 = pt.x - line.val[0]; - float dy0 = pt.y - line.val[1]; - if (abs(dx0) > abs(dy0)) - { - float dx1 = line.val[2] - pt.x; - if (dx0 > 0 && dx1 > 0 || dx0 < 0 && dx1 < 0) - { - return true; - } - else - { - return false; - } - } - else - { - float dy1 = line.val[3] - pt.y; - if (dy0 > 0 && dy1 > 0 || dy0 < 0 && dy1 < 0) - { - return true; - } - else - { - return false; - } - } -} - -bool intersection(Point2f o1, Point2f p1, Point2f o2, Point2f p2, Point2f &r, bool bounded /*= false*/) -{ - Point2f x = o2 - o1; - Point2f d1 = p1 - o1; - Point2f d2 = p2 - o2; - - float cross = d1.x*d2.y - d1.y*d2.x; - if (abs(cross) < /*EPS*/1e-8) - return false; - - double t1 = (x.x * d2.y - x.y * d2.x) / cross; - r = o1 + d1 * t1; - - if (bounded) - { - Vec4f l0(o1.x, o1.y, p1.x, p1.y); - Vec4f l1(o2.x, o2.y, p2.x, p2.y); - return _isOnLineSegment(r, l0) | _isOnLineSegment(r, l1); - } - - return true; -} - -bool intersection(const Vec4f& l1, const Vec4f& l2, Point2f& r, bool bounded /*= false*/) -{ - float d1x = l1.val[2] - l1.val[0]; - float d1y = l1.val[3] - l1.val[1]; - float d2x = l2.val[2] - l2.val[0]; - float d2y = l2.val[3] - l2.val[1]; - - float xx = l2.val[0] - l1.val[0]; - float xy = l2.val[1] - l1.val[1]; - - float cross = d1x * d2y - d1y * d2x; - if (abs(cross) < 1e-8) - { - return false; - } - - double t1 = (xx * d2y - xy * d2x) / cross; - r = Point2f(l1.val[0] + d1x * t1, l1.val[1] + d1y * t1); - - if (bounded) - { - return _isOnLineSegment(r, l1) | _isOnLineSegment(r, l2); - } - - return true; -} - -bool intersection(const Vec4f& l, const vector& vertexes, vector& interPtVec, bool bounded /*= false*/) -{ - for (int i = 0; i < vertexes.size(); ++i) - { - Point2f prePt;//= vertexes[i - 1]; - if (i == 0) - { - prePt = vertexes.back(); - } - else - { - prePt = vertexes[i - 1]; - } - Point2f curPt = vertexes[i]; - Vec4f ll(prePt.x, prePt.y, curPt.x, curPt.y); - Point2f interPt; - if (intersection(l, ll, interPt, bounded)) - { - interPtVec.push_back(interPt); - } - } - return interPtVec.size() > 0; -} - -template -int _intersection(const Vec& line, const Vec& circle, Point_& r1, Point_& r2) -{ - double dx = line[2] - line[0]; - double dy = line[3] - line[1]; - - double A = dx * dx + dy * dy; - double B = 2 * (dx * (line[0] - circle[0]) + dy * (line[1] - circle[1])); - double C = (line[0] - circle[0]) * (line[0] - circle[0]) + (line[1] - circle[1]) * (line[1] - circle[1]) - circle[2] * circle[2]; - - double det = B * B - 4 * A * C; - if ((A <= DBL_EPSILON) || (det < 0)) - { - return 0; - } - else if (det == 0) - { - double t = -B / (2 * A); - r1.x = line[0] + t * dx; - r1.y = line[1] + t * dy; - return 1; - } - else - { - double sqrt_det = sqrt(det); - double t1 = (-B + sqrt_det) / (2 * A); - double t2 = (-B - sqrt_det) / (2 * A); - r1.x = line[0] + t1 * dx; - r1.y = line[1] + t1 * dy; - r2.x = line[0] + t2 * dx; - r2.y = line[1] + t2 * dy; - return 2; - } -} - -int intersection(const Vec4f& line, const Vec3f& circle, Point2f& r1, Point2f& r2) -{ - return _intersection(line, circle, r1, r2); -} - -int intersection(const Vec4d& line, const Vec3d& circle, Point2d& r1, Point2d& r2) -{ - return _intersection(line, circle, r1, r2); -} - -Point2f getNearestIntersectionOfMultiLines(const vector& lines) -{ - int count = lines.size(); - vector linePnts; - linePnts.reserve(count); - vector lineNorms; - lineNorms.reserve(count); - for (int i = 0; i < count; ++i) - { - const Vec4f& l = lines[i]; - linePnts.push_back(Point2f((l[0] + l[2]) / 2., (l[1] + l[3]) / 2.)); - double dist = distance(l[0], l[1], l[2], l[3]); - lineNorms.push_back(Vec2f((-(l[1] - l[3])) / dist, (l[0] - l[2]) / dist)); - } - - return getNearestIntersectionOfMultiLines(linePnts, lineNorms); -} - -Point2f getNearestIntersectionOfMultiLines(const vector& linePnts, const vector& lineAngles, bool useDegree) -{ - int count = lineAngles.size(); - vector lineNorms; - lineNorms.reserve(count); - for (int i = 0; i < count; ++i) - { - float radian = useDegree ? lineAngles[i] / 180 * CV_PI : lineAngles[i]; - lineNorms.push_back(Vec2f(-sin(radian), cos(radian))); - } - - return getNearestIntersectionOfMultiLines(linePnts, lineNorms); -} - -Point2f getNearestIntersectionOfMultiLines(const vector& linePnts, const vector& lineNorms) -{ - _ASSERTE(linePnts.size() == lineNorms.size()); - if (linePnts.size() != lineNorms.size()) return Point2f(); - - int count = linePnts.size(); - Matx22d sum_ninit; - Matx21d sum_ninitpi; - for (int i = 0; i < count; ++i) - { - const Point2f& pnt = linePnts[i]; - Vec2d pi(pnt.x, pnt.y); - const Vec2f& ni = lineNorms[i]; - Matx22d ninit = ni * ni.t(); - Matx21d ninitpi = ninit * pi; - sum_ninit += ninit; - sum_ninitpi += ninitpi; - } - - Matx21d x = sum_ninit.inv() * sum_ninitpi; - return Point2f(x(0, 0), x(1, 0)); -} - -void transPoints(const vector& vec, vector& oVec, const Matx23f& mat) -{ - oVec.resize(vec.size()); - for (size_t i = 0; i < vec.size(); ++i) - { - Point2f p = vec[i]; - Point2f tp = mat * Vec3f(p.x, p.y, 1.0); - oVec[i] = Point2f(tp.x, tp.y); - } -} - -void transPoints(vector& vec, const Matx33d& mat) -{ - for (size_t i = 0; i < vec.size(); ++i) - { - Point2d p = vec[i]; - Point3d tp = mat * p; - vec[i] = Point2d(tp.x / tp.z, tp.y / tp.z); - } -} - -void transPoints(vector& vec, const Mat& mat) -{ - Matx33d matx = Matx33d::eye(); - Mat matx_(3, 3, CV_64FC1, matx.val); - - if (mat.rows == 2 && mat.cols == 3) - { - mat.copyTo(matx_.rowRange(0, 2)); - } - else if (mat.rows == 3 && mat.cols == 3) - { - mat.copyTo(matx_); - } - else - { - std::cout << "not supported transformation mat with its size as " \ - << mat.rows << "x" << mat.cols << std::endl; - return; - } - transPoints(vec, matx); -} - -Matx23f getRotationMatrix23f(Point2f center, float angle, float scale, float xOffset, float yOffset) -{ - Matx23f rotMat; - float* pRotVal = rotMat.val; - float a_pi = -angle * CV_PI / 180; - float alpha = cos(a_pi)*scale; - float beta = sin(a_pi)*scale; - pRotVal[0] = alpha; - pRotVal[1] = beta; - pRotVal[2] = -alpha * center.x - beta * center.y + xOffset; - pRotVal[3] = -beta; - pRotVal[4] = alpha; - pRotVal[5] = beta * center.x - alpha * center.y + yOffset; - - return rotMat; -} - -void getRigidTransform_(const Point2f& u1, const Point2f& u2, const Point2f& v1, const Point2f& v2, - double& x0, double& y0, double& angle, double& scale) -{ - vector srcPtVec(2), dstPtVec(2); - srcPtVec[0] = Point2d(u1.x, u1.y); - srcPtVec[1] = Point2d(u2.x, u2.y); - dstPtVec[0] = Point2d(v1.x, v1.y); - dstPtVec[1] = Point2d(v2.x, v2.y); - - Mat srMat; - Matx33d t = rigidTrans(srcPtVec, dstPtVec, &srMat); - - double t0 = t.val[0]; - double t1 = t.val[1]; - double l = sqrt(t0 * t0 + t1 * t1); - if (abs(l) > FLT_EPSILON) - { - t0 /= l; - t1 /= l; - scale = 1.0 / l; - angle = acos(t0) / CV_PI * 180; - angle = normAngle(angle); - } - else - { - angle = 0; - scale = 1.0; - } - - Point2d vCen = v1 + v2; - - x0 = vCen.x / 2.; - y0 = vCen.y / 2.; -} - -void getRigidTransform(const Point2f& u1, const Point2f& u2, const Point2f& v1, const Point2f& v2, - double& x0, double& y0, double& angle, double& scale) -{ - float theta_u = atan2f(u2.y - u1.y, u2.x - u1.x); - float theta_v = atan2f(v2.y - v1.y, v2.x - v1.x); - angle = (theta_v - theta_u) * 180 / CV_PI; - angle = normAngle(angle); - - float sin_a = sin(angle / 180 * CV_PI); - float cos_a = cos(angle / 180 * CV_PI); - - double f = (u2.x - u1.x) * cos_a - (u2.y - u1.y) * sin_a; - if (abs(f) > FLT_EPSILON) - { - scale = (v2.x - v1.x) / f; - } - else - { - scale = sqrt(pow(u2.x - u1.x, 2) + pow(u2.y - u1.y, 2)) / sqrt(pow(v2.x - v1.x, 2) + pow(v2.y - v1.y, 2)); - } - - x0 = v1.x - u1.x * scale * cos_a + u1.y * scale * sin_a; - y0 = v1.y - u1.x * scale * sin_a - u1.y * scale * cos_a; -} - -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) -{ - getRigidTransform(u1 - cen1, u2 - cen1, v1 - cen2, v2 - cen2, x0, y0, angle, 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) -{ - getRigidTransform(u1 - cen1, ua, v1 - cen2, va, x0, y0, angle, scale); -} - -void getRigidTransform(const Point2f& u1, float ua, - const Point2f& v1, float va, - double& x0, double& y0, double& angle, double& scale) -{ - getRigidTransform(u1, u1 + Point2f(cos(ua / 180 * CV_PI), sin(ua / 180 * CV_PI)), - v1, v1 + Point2f(cos(va / 180 * CV_PI), sin(va / 180 * CV_PI)), - x0, y0, angle, 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) -{ - getRigidTransform(u1 - cen1, ua, v1 - cen2, va, s, x0, y0, angle, scale); -} - -void getRigidTransform(const Point2f& u1, float ua, - const Point2f& v1, float va, - float s, - double& x0, double& y0, double& angle, double& scale) -{ - getRigidTransform(u1, u1 + Point2f(cos(ua / 180 * CV_PI), sin(ua / 180 * CV_PI)), - v1, v1 + Point2f(cos(va / 180 * CV_PI), sin(va / 180 * CV_PI)) * s, - x0, y0, angle, scale); -} - -Mat applyPerspectiveTransform(const Mat& img, std::vector& transVertexes, int flags) -{ - if (img.empty()) return gDummyMat; - - int w = img.cols, h = img.rows; -#if defined(LITTLE_CPP11) - std::vector pnts1(4); - pnts1[0] = Point2f(0, 0); - pnts1[1] = Point2f(w - 1, 0); - pnts1[2] = Point2f(w - 1, h - 1); - pnts1[3] = Point2f(0, h - 1); -#else - std::vector pnts1 = { - Point2f(0, 0), Point2f(w - 1, 0), Point2f(w - 1, h - 1), Point2f(0, h - 1) - }; -#endif - Mat H = findHomography(pnts1, transVertexes); - Mat img_warp; - warpPerspective(img, img_warp, H, img.size(), flags); - return img_warp; -} - -float isSameDir(Vec4f& l1, Vec4f& l2, float err_tol) -{ - Vec2f l1_dir = normalize(Vec2f(l1[0] - l1[2], l1[1] - l1[3])); - Vec2f l2_dir = normalize(Vec2f(l2[0] - l2[2], l2[1] - l2[3])); - - float ret = validate_diff(l1_dir, l2_dir, err_tol); - - return ret <= err_tol ? 0 : ret; -} - -float isCollinear(Vec4f& l1, Vec4f& l2, float err_tol) -{ - float a1 = l1[0] * (l1[3] - l2[1]) + l1[2] * (l2[1] - l1[1]) + l2[0] * (l1[1] - l1[3]); - float a2 = l2[0] * (l2[3] - l1[3]) + l2[2] * (l1[3] - l2[1]) + l1[2] * (l2[1] - l2[3]); - float a = (a1 + a2) / 2; - - Vec2f l1v(l1[0] - l1[2], l1[1] - l1[3]); - float l1_len = sqrt(l1v.ddot(l1v)); - - a /= l1_len; - - return a <= err_tol ? 0 : a; -} - -// * -// * * -// * * -// * * -// * * -// * * -// This is like arch. -// vec must be a row vector. -bool isLikeArch(const Mat& vec, double tor) -{ - int n = vec.cols - 1; - - Mat dvec = genSimpleXGradient(vec); - - // left half extremes must be monotonically increasing - // right half extremes must be monotonically decreasing - Mat leftDVec, rightDVec; - if (n % 2 == 1) - { - leftDVec = dvec.colRange(1, n / 2 + 1); - rightDVec = dvec.colRange(n / 2 + 2, n + 1); - } - else - { - leftDVec = dvec.colRange(1, n / 2 + 1); - rightDVec = dvec.colRange(n / 2 + 1, n + 1); - } - if (countNonZero(leftDVec < -tor) != 0 || - countNonZero(rightDVec > tor) != 0) - { - return false; - } - return true; -} - -bool isLikeHorizontalLine(const Mat& vec, double tor) -{ - Scalar mean, stddev; - meanStdDev(vec, mean, stddev); - Mat dvec = vec - mean.val[0]; - dvec = abs(dvec); - double minVal, maxVal; - minMaxIdx(dvec, &minVal, &maxVal); - return maxVal < tor; -} - - -}; diff --git a/qilunCar/CVUtils.h b/qilunCar/CVUtils.h deleted file mode 100644 index 1b23b0a..0000000 --- a/qilunCar/CVUtils.h +++ /dev/null @@ -1,834 +0,0 @@ -/*! \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 -#include - -#include -#include -#include -#include -#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_ Sized; -typedef Size_ 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 -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& 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& dxVec); -void autoAlignEachRowWithAutoThreshold(Mat& img, int tarCenX, vector& dxVec); -void alignEachRow(Mat& img, const vector& dxVec); -void autoAlignEachRowGloballyWithWidthConstraint(Mat& img, int tarCenX, vector& 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 >& 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& contour); - - -float circleDegree(const vector& 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 -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& pointVec, float val, int xPadding); - -double localMatSum(const Mat& mat, const Rect& roi); - -void findEdgePointsEachRow(const Mat& img, vector& edgePointVec, int xPadding); - -template -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 -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 >(i); - for (int j = 0; j < cn; ++j) - d[j] = s[j] / iMat.cols; - } - return oVec; -} - -Mat sumEachRow2(const Mat& img); - -template -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 -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 >(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& pointPairVec, int xPadding); - -void fillPointPairVal(const Mat& img, std::string filePath, vector& 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& 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 -Mat calcHist(const vector& 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& vec, float dis); - -void filterKeyPointsByRotationInvariants(vector& 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 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 >& matches, int k, - const vector& masks = vector(), bool compactResult = false); - virtual void radiusMatchImpl(const Mat& queryDescriptors, vector >& matches, float maxDistance, - const vector& masks = vector(), 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 ptVec, int radius); - - -Mat filterY(const Mat& img, float* kernel, int size, int ddepth = CV_32FC1); - -Mat getContourBoundedRoiImg(const Mat& src, const vector& contour, Rect* pRoiRect = NULL); - -void filterContours(Mat hsvColorThresImg, - int minArea, double minLength, double minLongShortRatio, - double maxCircleDegree, vector* pAreaMaxContour = NULL); -void filterContours(Mat& img, double minArea); -void filterContours(const vector< vector >& contours, const Mat& srcImg, - vector< vector >& filteredContours, int minArea, double minLength, - double minLongShortRatio, double maxCircleDegree, vector* pAreaMaxContour = NULL); -int filterSmallAndFindMaxContours(vector< vector >& contours, double minArea); -Mat genInRangeMask(const Mat& src, std::map>& 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& 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 -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 -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(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 -vector cvtMat2Vec(const Mat& img) -{ - _ASSERTE(!img.empty()); - int count = img.cols * img.rows; - - std::vector 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(i), rowStep); - vals_p += img.cols; - } - } - - return vals; -} - -template -std::list cvtMat2List(const Mat& img) -{ - _ASSERTE(!img.empty()); - int rows = img.rows; - int cols = img.cols; - int count = cols * rows; - - std::list vals; - for (int i = 0; i < rows; ++i) { - const S* img_p = img.ptr(i); - for (int j = 0; j < cols; ++j) { - vals.push_back((S)(img_p[j])); - } - } - - return vals; -} - -template -T getNthElement(const Mat& img, int n) -{ - _ASSERTE(!img.empty()); - int count = img.cols * img.rows; - _ASSERTE(n < count); - - std::vector vals = cvtMat2Vec(img); - - std::nth_element(vals.begin(), vals.begin() + n, vals.end()); - - return vals[n]; -} - -int getLocalMaximun(const Mat& vec, double thres, std::vector* pMaxIdxVec); -int getLocalMinimun(const Mat& vec, double thres, std::vector* pMaxIdxVec); - -enum EnumAbnormalType { - AbTypePositive = 0, - AbTypeNegative, - AbTypeBoth -}; -int detectAbnormal(const Mat& vec, int kernelSize, EnumAbnormalType abnormalType, double abnormalThreshold, - Mat* pScores = nullptr, std::vector* 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_ Rectd; -typedef Rect_ Rectf; - -template -bool isImageRoiRectValid(const Rect_<_Ty>& rect) -{ - return rect.x >= 0 && rect.y >= 0 && rect.width > 0 && rect.height > 0; -} - - -template -string rect2str(const Rect_<_Ty>& rect) -{ - stringstream ss; - ss << rect.x << ", " << rect.y << ", " << rect.width << ", " << rect.height; - return ss.str(); -} -template -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 -Rect genRectCenRadius(_Point cen, int radius) -{ - return Rect(cen.x - radius, - cen.y - radius, - radius * 2 + 1, - radius * 2 + 1); -} -template -Rect genRectLeftTopRadius(_Point p, int radius) -{ - return Rect(p.x, - p.y, - radius * 2, - radius * 2); -} - -template -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& 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& vertexes, vector& 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& lines); -Point2f getNearestIntersectionOfMultiLines(const vector& linePnts, const vector& lineNorms); -Point2f getNearestIntersectionOfMultiLines(const vector& linePnts, const vector& 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& vec, const Mat& mat); -void transPoints(vector& vec, const Matx33d& mat); -void transPoints(const vector& vec, vector& 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& 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_ - diff --git a/qilunCar/DynamicProgramSearch.cpp b/qilunCar/DynamicProgramSearch.cpp deleted file mode 100644 index 8321526..0000000 --- a/qilunCar/DynamicProgramSearch.cpp +++ /dev/null @@ -1,243 +0,0 @@ -#include "DynamicProgramSearch.h" -#include - -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(sy, j); - if (maxVal < val) - { - maxVal = val; - } - } - - disMat.at(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(i, sx); - if (maxVal < val) - { - maxVal = val; - } - } - - disMat.at(y, x) += maxVal; - } - } -} - -void findMaxXPath(const Mat& disMat, vector& vec, vector& 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(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& vec, vector& 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(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& 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(y, x); - } - for (int j = sj; j <= ej; j++) - { - float disVal = disMat.at(sy, j); - float sVal = 0; - if (!smoothMat.empty()) - { - sVal = smoothMat.at(sy, j); - } - float energyVal = disVal + (255 - abs(sVal - baseSVal))*sw; - if (maxVal < energyVal) - { - maxVal = energyVal; - } - } - - disMat.at(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(y, x); - } - float baseSVal1 = 0; - if (!smoothMat1.empty()) - { - baseSVal1 = smoothMat1.at(y, x + targetWidth - smoothMat0.cols); - } - for (int j = sj0; j <= ej0; j++) - { - float disVal0 = disMat0.at(sy, j); - int j1 = j + targetWidth - disMat0.cols; - float disVal1 = disMat1.at(sy, j1); - float sVal0 = 0; - if (!smoothMat0.empty()) - { - sVal0 = smoothMat0.at(sy, j); - } - float sVal1 = 0; - if (!smoothMat1.empty()) - { - sVal1 = smoothMat1.at(sy, j1); - } - float energyVal = disVal0 + disVal1 + - (255 - abs(sVal0 - baseSVal0))*sw + - (255 - abs(sVal1 - baseSVal1))*sw; - if (maxVal < energyVal) - { - maxVal = energyVal; - } - } - - disMat0.at(y, x) += maxVal; - } - } -} - diff --git a/qilunCar/DynamicProgramSearch.h b/qilunCar/DynamicProgramSearch.h deleted file mode 100644 index 7cc7bdd..0000000 --- a/qilunCar/DynamicProgramSearch.h +++ /dev/null @@ -1,129 +0,0 @@ -#ifndef _DynamicProgramSearch_h_ -#define _DynamicProgramSearch_h_ - -#include -//#include "CVUtils.h" - -using namespace cv; - -using std::vector; - -void dynamicProgramYWithSmooth(Mat& disMat, int n = 2, float sw = 1.0, const Mat& smoothMat = Mat()); -void dynamicProgramYWithSmooth(Mat& disMat0, Mat& disMat1, - const Mat& smoothMat0, const Mat& smoothMat1, int targetWidth, int n, float sw); - -void dynamicProgramY(Mat& disMat, int n = 2); -void dynamicProgramX(Mat& disMat, int n = 2); - -void findMaxXPath(const Mat& disMat, vector& vec, vector& energyVec, - int n = 2); -void findMaxYPath(const Mat& disMat, vector& vec, vector& energyVec, - int n = 2); - -void recoverPathEnergy(vector& vec); - -inline float ptLineDisY(const Vec4f& line, const Point& pt) -{ - float p0x = line.val[2]; - float p0y = line.val[3]; - float p1x = line.val[0] + p0x; - float p1y = line.val[1] + p0y; - - float px = pt.x; - float py = pt.y; - - float y = p0y + (p1y - p0y) / (p1x - p0x) * (px - p0x); - - float dy = y - py; - if (dy > 0) - { - return dy; - } - else - { - return -dy; - } -} -// 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; -} - -inline float ptLineDis(const Vec4f& line, const Point& pt) -{ - float a = line.val[1]; - float b = -line.val[0]; - float c = -a*line.val[2] - b*line.val[3]; - return (a * (float)pt.x + b * (float)pt.y + c) * _InvSqrt(a*a + b*b); -} - - -inline float ptLineDis(const Vec4f& line, const Point2f& pt) -{ - float a = line.val[1]; - float b = -line.val[0]; - float c = -a*line.val[2] - b*line.val[3]; - return (a * pt.x + b * pt.y + c) * _InvSqrt(a*a + b*b); -} - -inline float ptLineDis(const Vec4f& line, const vector& ptVec) -{ - float ret = 0; - for (int i = 0; i < ptVec.size(); ++i) - { - const Point& pt(ptVec[i]); - float d = ptLineDis(line, pt); - ret += abs(d); - } - return ret; -} - -template -void drawPointsX(vector& xVec, Mat& img, int sx, int sy, int color = 255, int w = 1) -{ - for (int x = 0; x < xVec.size(); ++x) - { - int y = xVec[x] + sy; - img.at<_T>(y, x + sx) = color; - for (int i = 1; i <= w / 2; ++i) - { - if (y - i >= 0) - { - img.at<_T>(y - i, x + sx) = color; - } - if (y + i < img.rows) - { - img.at<_T>(y + i, x + sx) = color; - } - } - } -} - -template -void drawPointsY(vector& yVec, Mat& img, int sx, int sy, int color = 255, int w = 1) -{ - for (int y = 0; y < yVec.size(); ++y) - { - int x = yVec[y] + sx; - img.at<_T>(y + sy, x) = color; - for (int i = 1; i <= w / 2; ++i) - { - if (x - i >= 0) - { - img.at<_T>(y + sy, x - i) = color; - } - if (x + i < img.cols) - { - img.at<_T>(y + sy, x + i) = color; - } - } - } -} - -#endif // _DynamicProgramSearch_h_ diff --git a/qilunCar/ImageCompareModel.cpp b/qilunCar/ImageCompareModel.cpp deleted file mode 100644 index 6ac6a23..0000000 --- a/qilunCar/ImageCompareModel.cpp +++ /dev/null @@ -1,1650 +0,0 @@ -/*! \file ImageCompareModel.cpp - - Copyright (C) 2014 Hangzhou Leaper. - - Created by bang.jin at 2017/02/04. - -*/ - -#include "ImageCompareModel.h" -#include "CVUtils.h" -#include "MultiScaleImageCompareModel.h" -#include - -//#define DEBUG_VIEW_PLOT -// #define DEBUG_VIEW_PLOT - - -#define IMGCMP_STR_NAME "name" -#define IMGCMP_STR_IMAGE_COMPARE_MODEL "imageCompareModel" -#define IMGCMP_STR_ALIGN_BASE_IMAGE "alignBaseImage" -#define IMGCMP_STR_COMPARE_BASE_IMAGE "compareBaseImage" -#define IMGCMP_STR_WEIGHT_MAT "weightMat" -#define IMGCMP_STR_MATCH_VAL_SCALE "matchValScale" -#define IMGCMP_STR_TARGET_MEAN_VAL "targetMeanVal" -#define IMGCMP_STR_TARGET_STDDEV_VAL "targetStddevVal" -#define IMGCMP_STR_REPEAT_NUM "repeatNum" -#define IMGCMP_STR_TRUE_SAMPLE_DIS_MEAN "trueSampleDisMean" -#define IMGCMP_STR_TRUE_SAMPLE_DIS_STDDEV "trueSampleDisStddev" -#define IMGCMP_STR_TRUE_SAMPLE_DIS_MIN "trueSampleDisMin" -#define IMGCMP_STR_TRUE_SAMPLE_DIS_MAX "trueSampleDisMax" -#define IMGCMP_STR_DIS_THRE "disThre" -#define IMGCMP_STR_FALSE_SAMPLE_MIN_DIS "falseSampleMinDis" -#define IMGCMP_STR_TRAIN_DIS "trainDis" -#define IMGCMP_STR_SMALLEST_MATCH_DIS "falseMinDis" -#define IMGCMP_STR_AVER_DIAMETER "averageDiameter" - -#define IMGCMP_CACHE_MAX_SIZE 100 -using namespace std; - - -// void meanvarnorm(Mat& src, Mat &dst, double avg, double var, Mat mask = Mat()) -// { -// Scalar m, v; -// cv::meanStdDev(src, m, v, mask); -// // (I - m)*var/v + avg = I*var/v - m*var/v + avg -// double s = var / v.val[0]; -// double t = avg - m.val[0] * var / v.val[0]; -// dst = src * s + t; -// } - -float angleNorm(float angle) -{ - angle = angle - (int)(angle / 360.0) * 360; - if (angle < 0) - { - angle += 360.0; - } - return angle; -} -float angleDis(float angle0, float angle1) -{ - angle0 = angleNorm(angle0); - angle1 = angleNorm(angle1); - float dis = angle0 - angle1; - float ldis = dis; - if (dis < 0) - { - ldis = dis + 360; - } - else if (dis > 0) - { - ldis = dis - 360; - } - if (abs(ldis) < abs(dis)) - { - dis = ldis; - } - return dis; -} - -cv::Point2f ImageCompareModel::refineCircleCen(const Mat& img, Point2f cen) -{ - int r = 2; - vector vec; - double minDiff = DBL_MAX; - Point2f bestCenter; - vector bestDftVec; - for (float y = cen.y - r; y <= cen.y + r; y += 0.5) - { - for (float x = cen.x - r; x <= cen.x + r; x += 0.5) - { - std::cout << "newCenter: " << x << "-" << y << ", "; - - Point2f newCenter(x, y); - - vector vec; - selfRotationSimilarityFeature(img, vec, newCenter); - - vector dftVec; - dft(vec, dftVec); - -// CvPlot::plot("refineCenter", &(vec[0]), vec.size()); - - float diffVal = sum(vec.begin(), vec.end()); - -// CvPlot::clear("dft"); -// CvPlot::plot("dft", &(dftVec[0]), 25); -// -// float diffVal = dftVec[9]; - - vec.push_back(diffVal); - - if (minDiff > diffVal) - { - minDiff = diffVal; - bestCenter = newCenter; - bestDftVec = dftVec; - } - -// CvPlot::clear("bestDft"); -// CvPlot::plot("bestDft", &(bestDftVec[0]), 25); - - std::cout << "diff: " << diffVal << ", " - " minDiff: " << minDiff << ", " - " bestCenter: " << bestCenter.x << "-" << bestCenter.y << - std::endl; - } - } - - return bestCenter; -} - -cv::Mat ImageCompareModel::genWeightImage(const Mat& img, Point2f center, - float innerR /*= -1*/, float outterR /*= -1*/) -{ - if (innerR == -1) - { - // default is 30 - innerR = img.rows*0.175; - } - if (outterR == -1) - { - // default is max radius - 10 - outterR = img.rows*0.475; - } - - Mat weightImg; - weightImg.create(img.size(), CV_32FC1); - weightImg.setTo(0); - - uchar* pData = weightImg.data; - for (int y = 0; y < weightImg.rows; y++) - { - float* pFData = (float*)weightImg.row(y).data; - for (int x = 0; x < weightImg.cols; x++) - { - float& val = pFData[x]; - float dx = center.x - x; - float dy = center.y - y; - float r = sqrt(dx*dx + dy*dy); - if (r > outterR || r < innerR) - { - val = 0; - } - else - { - val = min(outterR - r, r - innerR); - } - } - } - - return weightImg; -} - -void ImageCompareModel::selfRotationSimilarityFeature( - const Mat& img, vector& vec, Point2f center /*= Point2f(-1, -1)*/) -{ - float angleStep = 1.0; - if (center.x < 0 || center.y < 0) - { - center = Point2f(img.cols / 2.0, img.rows / 2.0); - } - - double bestVal = DBL_MAX; - Mat bestRImg; - Mat fImg; - img.convertTo(fImg, CV_32FC1); - - Mat weightImg = genWeightImage(img, center); - fImg = fImg.mul(weightImg); - - double sumVal = sum(weightImg).val[0]; - - Mat baseImg; - { - Mat t = getRotationMatrix2D(center, 1.0, 1.0); - Mat rImg; - warpAffine(fImg, rImg, t, fImg.size(), CV_INTER_CUBIC); - t = getRotationMatrix2D(center, -1.0, 1.0); - warpAffine(rImg, baseImg, t, rImg.size(), CV_INTER_CUBIC); - } - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat viewBaseImg = baseImg / 255.0/25.0; - Mat viewfImg = fImg / 255.0/25.0; -#endif - - for (float a = 0; a <= 360.0; a += angleStep) - { - Mat t = getRotationMatrix2D(center, a, 1.0); - Mat rImg; - warpAffine(fImg, rImg, t, fImg.size(), CV_INTER_CUBIC); - - Mat diffImg = baseImg - rImg; - //diffImg = diffImg.mul(weightImg); - double diffVal = norm(diffImg)/sumVal; - vec.push_back(diffVal); - } -} - -cv::Mat ImageCompareModel::genMask(const Mat& img, Point2f center, - float innerR /*= -1*/, float outterR /*= -1*/, int type /*= CV_32FC1*/) -{ - Mat mask(img.size(), CV_8UC1); - mask.setTo(0); - if (innerR == -1) - { - // default is 30 - innerR = img.rows*0.178; - } - if (outterR == -1) - { - // default is max radius - 10 - outterR = img.rows*0.425; - } - circle(mask, center, outterR, Scalar(255), -1); - circle(mask, center, innerR, Scalar(0), -1); - if (type != CV_8UC1) - { - converToType(mask, type); - mask /= 255; - } - return mask; -} - -void ImageCompareModel::genMask() -{ - m32fMaskImg = genMask(mAlignBaseImg, Point2f(mAlignBaseImg.cols / 2.0, mAlignBaseImg.rows / 2.0)); - m8uMaskImg = genMask(mAlignBaseImg, Point2f(mAlignBaseImg.cols / 2.0, mAlignBaseImg.rows / 2.0), - -1.0, -1.0, CV_8UC1); -} - -void ImageCompareModel::printInfo() -{ - std::cout << IMGCMP_STR_IMAGE_COMPARE_MODEL << ": "; - std::cout << std::endl; - - printProperty(1, IMGCMP_STR_NAME, mName); - - printIndent(1); - std::cout << IMGCMP_STR_ALIGN_BASE_IMAGE << ": "; - std::cout << std::endl; - printMatInfo(mAlignBaseImg, 2); - std::cout << std::endl; - - printIndent(1); - std::cout << IMGCMP_STR_WEIGHT_MAT << ": "; - std::cout << std::endl; - printMatInfo(mWeightMat, 2); - std::cout << std::endl; - - printProperty(1, IMGCMP_STR_MATCH_VAL_SCALE, mMatchValScale); - printProperty(1, IMGCMP_STR_TARGET_MEAN_VAL, mTargetMeanVal); - printProperty(1, IMGCMP_STR_TARGET_STDDEV_VAL, mTargetStddevVal); - printProperty(1, IMGCMP_STR_REPEAT_NUM, mRepeatNum); - printProperty(1, IMGCMP_STR_DIS_THRE, mDisThre); - printProperty(1, IMGCMP_STR_TRUE_SAMPLE_DIS_STDDEV, mTrueSampleDisStddev); - printProperty(1, IMGCMP_STR_TRUE_SAMPLE_DIS_MEAN, mTrueSampleDisMean); - printProperty(1, IMGCMP_STR_TRUE_SAMPLE_DIS_MAX, mTrueSampleDisMax); - printProperty(1, IMGCMP_STR_TRUE_SAMPLE_DIS_MIN, mTrueSampleDisMin); - - printProperty(1, "filePath", mFilePath); - printProperty(1, "isEnableCache", mIsEnableCache); -} - -void ImageCompareModel::saveImages(string dirPath) -{ - imwrite(dirPath + "/base.png", mAlignBaseImg); - imwrite(dirPath + "/weight.png", mWeightMat); -} - -bool ImageCompareModel::save2file(string filePath) -{ - FileStorage fs(filePath, FileStorage::WRITE); - if (!fs.isOpened()) - { - return false; - } - - fs << IMGCMP_STR_NAME << mName << - IMGCMP_STR_ALIGN_BASE_IMAGE << mAlignBaseImg << - IMGCMP_STR_COMPARE_BASE_IMAGE << mCompareBaseImg << - IMGCMP_STR_WEIGHT_MAT << mWeightMat << - IMGCMP_STR_MATCH_VAL_SCALE << mMatchValScale << - IMGCMP_STR_TARGET_MEAN_VAL << mTargetMeanVal << - IMGCMP_STR_TARGET_STDDEV_VAL << mTargetStddevVal << - IMGCMP_STR_REPEAT_NUM << mRepeatNum << - IMGCMP_STR_TRUE_SAMPLE_DIS_MEAN << mTrueSampleDisMean << - IMGCMP_STR_TRUE_SAMPLE_DIS_STDDEV << mTrueSampleDisStddev << - IMGCMP_STR_TRUE_SAMPLE_DIS_MIN << mTrueSampleDisMin << - IMGCMP_STR_TRUE_SAMPLE_DIS_MAX << mTrueSampleDisMax << - IMGCMP_STR_FALSE_SAMPLE_MIN_DIS << getFalseSampleMinDis() << - IMGCMP_STR_DIS_THRE << mDisThre << - IMGCMP_STR_TRAIN_DIS <> mAlignBaseImg; - fs[IMGCMP_STR_COMPARE_BASE_IMAGE] >> mCompareBaseImg; - fs[IMGCMP_STR_WEIGHT_MAT] >> mWeightMat; - mMatchValScale = (double)fs[IMGCMP_STR_MATCH_VAL_SCALE]; - - FileNode fn = fs[IMGCMP_STR_TARGET_MEAN_VAL]; - if (!fn.empty()) - { - mTargetMeanVal = (int)fn; - } - - fn = fs[IMGCMP_STR_TARGET_STDDEV_VAL]; - if (!fn.empty()) - { - mTargetStddevVal = (int)fn; - } - - fn = fs[IMGCMP_STR_REPEAT_NUM]; - if (!fn.empty()) - { - mRepeatNum = (int)fn; - } - else - { - //mRepeatNum = computeRepeatNum(); - } - - fn = fs[IMGCMP_STR_NAME]; - if (!fn.empty()) - { - mName = (string)fn; - } - - fn = fs[IMGCMP_STR_TRUE_SAMPLE_DIS_MEAN]; - if (!fn.empty()) - { - mTrueSampleDisMean = (double)fn; - } - fn = fs[IMGCMP_STR_TRUE_SAMPLE_DIS_STDDEV]; - if (!fn.empty()) - { - mTrueSampleDisStddev = (double)fn; - } - fn = fs[IMGCMP_STR_TRUE_SAMPLE_DIS_MIN]; - if (!fn.empty()) - { - mTrueSampleDisMin = (double)fn; - } - fn = fs[IMGCMP_STR_TRUE_SAMPLE_DIS_MAX]; - if (!fn.empty()) - { - mTrueSampleDisMax = (double)fn; - } - fn = fs[IMGCMP_STR_FALSE_SAMPLE_MIN_DIS]; - if (!fn.empty()) - { - setFalseSampleMinDis((double)fn); - } - fn = fs[IMGCMP_STR_DIS_THRE]; - if (!fn.empty()) - { - mDisThre = (double)fn; - } - - fn = fs[IMGCMP_STR_AVER_DIAMETER]; - if (!fn.empty()) - { - meanDiameter = (int)fn; - } - - - setFilePath(filePath); - - genMask(); - - return true; -} - -void ImageCompareModel::preProcessImage(Mat& img) const -{ - preProcessImage(img, m8uMaskImg, mTargetMeanVal, mTargetStddevVal, mHighlightsThreshold); -} - -void ImageCompareModel::preProcessImage(Mat& img, const Mat& mask, double tarMean, - double tarStddev, int highlightsThreshold) const -{ - if (img.channels() > 1) - { - img = getFirstChannel(img); - } - if (img.type() != CV_32FC1) - { - converToType(img, CV_32FC1); - } - - Mat gaussImg; - GaussianBlur(img, gaussImg, Size(3, 3), 5.0); - img = gaussImg; - - Mat dilatedMask; - dilate(mask, dilatedMask, Mat::ones(Size(3, 3), CV_32FC1)); - - Mat hightlightsMask = img < highlightsThreshold; - Mat imgMask = hightlightsMask & dilatedMask; - - Scalar meanScalar, stddevScalar; - meanStdDev(img, meanScalar, stddevScalar, imgMask); - img = (img - meanScalar.val[0]) * tarStddev / stddevScalar.val[0] + tarMean; - - converToType(imgMask, CV_32FC1); - imgMask /= 255.0; - Mat imgNorm = cocentricNorm(img, Point2f(img.cols / 2.0, img.rows / 2.0), - imgMask, 125); -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vImgNorm = imgNorm / 255.0; -#endif - img = imgNorm; -} - -void ImageCompareModel::preProcessImage(Mat& img, const Mat& mask, - const Mat& weightMat, double dstMean, double dstStddev, int highlightsThreshold) const -{ - if (img.channels() > 1) - { - img = getFirstChannel(img); - } - if (img.type() != CV_32FC1) - { - converToType(img, CV_32FC1); - } - - Mat gaussImg; - GaussianBlur(img, gaussImg, Size(3, 3), 5.0); - img = gaussImg; - - Mat hightlightsMask = img < highlightsThreshold; - Mat imgMask = hightlightsMask & mask & (weightMat > 0); - - Scalar meanScalar, stddevScalar; - meanStdDev(img, meanScalar, stddevScalar, imgMask); - img = (img - meanScalar.val[0]) * dstMean / stddevScalar.val[0] + dstMean; - - converToType(hightlightsMask, CV_32FC1); - - Mat imgNorm = cocentricNorm(img, Point2f(img.cols / 2.0, img.rows / 2.0), - weightMat.mul(hightlightsMask), 125); -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vImgNorm = imgNorm / 255.0; -#endif - img = imgNorm; -} - -void ImageCompareModel::preProcessImage0(Mat& img) const -{ - -} - -double ImageCompareModel::compare(Mat img0, Mat img1, Mat* pRImg0, Mat* pRImg1) -{ - if (img0.size() != img1.size() && img0.size() != mAlignBaseImg.size()) - { - return -1; - } - - double bestMatchVal = DBL_MAX; - int bestAngle = -1; - Mat bestImg1; - double bestDD = 0; - - double w = 0; - - Point2f center((float)img1.cols / 2.0, (float)img1.rows / 2.0); - Mat rImg0 = rotateMatch(img0).mBestRImg; - Mat rImg1 = rotateMatch(img1).mBestRImg; - Mat dMat = rImg0 - rImg1; - converToType(dMat, CV_32FC1); - dMat = dMat.mul(mWeightMat); - - if (pRImg0) - { - *pRImg0 = rImg0; - } - if (pRImg1) - { - *pRImg1 = rImg1; - } - - return genMatchValue(dMat); -} - -double ImageCompareModel::compare(Mat img, Mat* pRImg /*= NULL*/, int levelNum /*= 1*/, - bool isFilterSize /*= true*/, int flag, double md_diameter, double md_height) -{ - if (mIsEnableCache) - { - auto cacheIter = mDisCache.find(img.data); - if (cacheIter != mDisCache.end()) - { - return cacheIter->second; - } - } - Mat rawImg = img.clone(); - int nRadiusDiff = 15; - if (mAlignBaseImg.size() != img.size()) - { - if (isFilterSize && abs(mAlignBaseImg.size().width- img.size().width) > nRadiusDiff) - { - return DBL_MAX; - } - resize(img, img, mAlignBaseImg.size()); - } - - Mat matchImg = img.clone(); - preProcessImage(matchImg); - - if (!mpMultiScaleModel) - { - initMultiScaleModel(); - } - RotateMatchResult rmr = rotateMatch(matchImg, levelNum); - Mat rImg = rmr.mBestRImg; - - if (rImg.empty()) - { - return DBL_MAX; - } - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vRImg = rImg / 255.0; -#endif - - double bestAngle = rmr.mBestAngle; - Mat cmpImg = rotateImage(img, Point2f(img.cols / 2.0, img.rows / 2.0), - bestAngle); - - // remove highlights - Mat hightlightsMask = cmpImg < mHighlightsThreshold; - converToType(hightlightsMask, CV_32FC1); - hightlightsMask /= 255.0; - - Mat unifiedMask = m32fMaskImg.mul(hightlightsMask).mul(mWeightMat); - - preProcessImage(cmpImg, m8uMaskImg, mWeightMat, mTargetMeanVal, - mTargetStddevVal, mHighlightsThreshold); - - cmpImg.setTo(0, cmpImg < 0); - converToType(cmpImg, CV_32FC1); - normSectors_tarImg(cmpImg, unifiedMask, imgCen(cmpImg), 1, - mCompareBaseImg); - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vRotatedImg0 = cmpImg / 255.0; -#endif - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vRotatedImg1 = cmpImg / 255.0; -#endif - - cmpImg.setTo(0, cmpImg < 10); - if (pRImg) - { - *pRImg = cmpImg; - } - - double ret = genMatchValue(cmpImg, mCompareBaseImg, unifiedMask, flag, rawImg.rows, md_diameter, md_height); - - /*if (flag == 1) - { - double matchedVal = ret; - ret = penltyCoeff(matchedVal, meanDiameter, rawImg.rows); - printf("the matched value %f", ret); - }*/ - - if (mIsEnableCache) - { - mDisCache[img.data] = ret; - if (mDisCache.size() > IMGCMP_CACHE_MAX_SIZE) - { - mDisCache.clear(); - } - } - return ret; -} - - - -void ImageCompareModel::train(const vector& imgVec) -{ -#ifdef _DEBUG - cout << getName() << endl; -#endif _DEBUG - if (0 == imgVec.size()) { - return; - } - mAlignBaseImg = imgVec.front(); - genMask(); - preProcessImage(mAlignBaseImg); - Mat sumMat = Mat::zeros(mAlignBaseImg.size(), CV_32FC1); - Mat minMat(mAlignBaseImg.size(), mAlignBaseImg.type()); - minMat.setTo(FLT_MAX); - vector rImgVec; - vector rmrVec; - vector resizedImgVec; - vector diametersVec; - for (int i = 0; i < imgVec.size(); ++i) - { - diametersVec.push_back(imgVec[i].rows); - Mat img = imgVec[i].clone(); - if (img.size() != mAlignBaseImg.size()) - { - Mat resizedImg; - resize(img, resizedImg, mAlignBaseImg.size()); - img = resizedImg; - } - resizedImgVec.push_back(img); - preProcessImage(img); - - RotateMatchResult rmr = rotateMatch(img); - rmrVec.push_back(rmr); - - Mat rImg = rmr.mBestRImg; - rImgVec.push_back(rImg); - minMat = min(minMat, rImg); - sumMat += rImg; - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat viewRImg = rImg / 255.0; - Mat viewMinMat = minMat / 255.0; -#endif - } - meanDiameter = mean(diametersVec)[0]; - - Mat avgMat = sumMat / imgVec.size(); - mAlignBaseImg = avgMat; -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vAvgMat = avgMat / 255.0; -#endif - mWeightMat = minMat; - - mWeightMat /= 255.0; - /*luffy_base::luffy_imageProc::*/meanvarnorm(mWeightMat, mWeightMat, - mTargetMeanVal, 150, m8uMaskImg); - mWeightMat.setTo(0, mWeightMat < 10); - { - if(mRepeatNum <= 0) - { - mRepeatNum = computeRepeatNum(); - } - selfRotateMin(mWeightMat, mWeightMat, mRepeatNum); - } - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vWeightMat = mWeightMat / 255.0; - Mat vBaseMat = mAlignBaseImg / 255.0; - Mat vMinMat = minMat / 255.0; -#endif - - sumMat.setTo(0); - for (int i = 0; i < rmrVec.size(); ++i) - { - double bestAngle = rmrVec[i].mBestAngle; - Mat img = resizedImgVec[i]; - Mat rotatedImg = rotateImage(img, Point2f(img.cols/2.0, img.rows/2.0), - bestAngle); - preProcessImage(rotatedImg, m8uMaskImg, mWeightMat, mTargetMeanVal, - mTargetStddevVal, mHighlightsThreshold); - - sumMat += rotatedImg; - } - mCompareBaseImg = sumMat / resizedImgVec.size(); - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vCompareBaseImg = mCompareBaseImg / 255.0; - vWeightMat = mWeightMat / 255.0; -#endif - - trueSampleWeightRecon(resizedImgVec, rmrVec); - mWeightMat = falseReConMat.clone(); -} - -void ImageCompareModel::trueSampleWeightRecon(const vector& resizedVec, vector rmrVec) -{ - falseReConMat = mWeightMat.clone(); - for (int i = 0; i < resizedVec.size(); i++) - { - const Mat &img = resizedVec[i]; - double bestAngle = rmrVec[i].mBestAngle; - Mat processedImg = img.clone(); - preProcessImage(processedImg); - Mat rotatedImg = rotateImage(processedImg, Point2f(img.cols / 2.0, img.rows / 2.0), - bestAngle); - - Mat hightlightsMask = rotatedImg < mHighlightsThreshold; - converToType(hightlightsMask, CV_32FC1); - hightlightsMask /= 255.0; - - Mat unifiedMask = m32fMaskImg.mul(hightlightsMask).mul(mWeightMat); - - preProcessImage(rotatedImg, m8uMaskImg, mWeightMat, mTargetMeanVal, - mTargetStddevVal, mHighlightsThreshold); - - rotatedImg.setTo(0, rotatedImg < 0); - converToType(rotatedImg, CV_32FC1); - normSectors_tarImg(rotatedImg, unifiedMask, imgCen(rotatedImg), 1, - mCompareBaseImg); - - Mat vRotatedImg0 = rotatedImg / 255.0; - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vRotatedImg1 = rotatedImg / 255.0; -#endif - - rotatedImg.setTo(0, rotatedImg < 10); - trueWeightRecon(rotatedImg, mCompareBaseImg); - } -} - -void ImageCompareModel::trueWeightRecon(const Mat& rImg, const Mat& baseImg) -{ - Mat dMat = abs(rImg - baseImg); - //Mat norImg = Mat::ones(dMat.size(), dMat.type()) * 255; - //dMat = max(dMat, 254); - Mat mData; - dMat.copyTo(mData, dMat > 1000); - mData = minMaxNorm(mData, 0, 255); - //mData.copyTo(mData, mData > 0.9); - double minVal, maxVal; - minMaxIdx(mData, &minVal, &maxVal); - weightMapping(mData, maxVal); -} - -void ImageCompareModel::weightMapping(const Mat& mData, double maxVal) -{ - for (int i = 0; i < mData.rows; i++) - { - float* pData = (float*)mData.row(i).data; - float*pWeight = (float*)falseReConMat.row(i).data; - for (int j = 0; j < mData.cols; j++) - { - double pixVal = pData[j]; - - if (pixVal != 0) - { - double affineCoeff = descendFunction(pixVal, maxVal); - pWeight[j] *= affineCoeff; - } - - } - } -} -double ImageCompareModel::descendFunction(double pixVal, double maxVal) -{ - return (-1.0 / maxVal)*pixVal + 1.0; - //return -1 * pow(pixVal, 2) + 1; -} - - -void ImageCompareModel::calculateAllParams(const vector& imgVec) -{ - mDisThre = DBL_MAX; - Mat disMat(1, imgVec.size(), CV_64FC1); - for (int i = 0; i < imgVec.size(); ++i) - { - const Mat& img = imgVec[i]; - double dis = compare(img, NULL, 1, false, 0); - disMat.at(i) = dis; - //disMat.copyTo(mDisMat); - } - - if (disMat.cols == 1) - { - mTrueSampleDisStddev = 0; - mTrueSampleDisMean = disMat.at(0); - } - else - { - Scalar m, s; - meanStdDev(disMat, m, s); - mTrueSampleDisStddev = s.val[0]; - mTrueSampleDisMean = m.val[0]; - } - disMat.copyTo(mDisMat); - minMaxIdx(disMat, &mTrueSampleDisMin, &mTrueSampleDisMax); -} - -void ImageCompareModel::computeDisThre(const vector& imgVec, double* pMinDis, double md_diameter, double md_height) -{ - if (imgVec.empty()) - { - return; - } - mDisThre = DBL_MAX; - vector disVec; - for_each(imgVec.begin(), imgVec.end(), [&](Mat img) - { - double dis = compare(img, NULL, 3, false, 1, md_diameter, md_height); - disVec.push_back(dis); - }); - double minDis = *(min_element(disVec.begin(), disVec.end())); - setFalseSampleMinDis(minDis); - - if (pMinDis) - { - *pMinDis = minDis; - } - if (minDis > mTrueSampleDisMax) - { - mDisThre = mTrueSampleDisMax*0.2 + minDis*0.8; - //mDisThre = mTrueSampleDisMax*0.15 + minDis*0.85 + mTrueSampleDisStddev; - //mDisThre = minDis; - if (mDisThre > mTrueSampleDisMax*1.8) - { - mDisThre = mTrueSampleDisMax*1.8; - } - } - else - { - mDisThre = DBL_MAX; - std::cout << "max distance in training > min distance in testing" << std::endl; - } -} - -void ImageCompareModel::genUniformSepIdx(int num, int startIdx, int endIdx, vector& cenVec) -{ - float step = (endIdx - startIdx) / (num); - for (int i = 0; i < num; i++) - { - cenVec.push_back(floorf(step*i + startIdx)); - } -} - -void ImageCompareModel::genAngleRanges(vector cenVec, vector& rangeVec, int localRange) -{ - rangeVec.clear(); - for_each(cenVec.begin(), cenVec.end(), [&](int cen) - { - Range r; - r.start = cen - localRange; - r.end = cen + localRange + 1; - rangeVec.push_back(r); - }); -} - -void ImageCompareModel::genCandidateAngleRanges(vector disVec, - float angleStep, vector& rangeVec) -{ - auto minDisIter = min_element(disVec.begin(), disVec.end()); - int startIdx = minDisIter - disVec.begin(); - - rotate(disVec.begin(), minDisIter, disVec.end()); - - Mat disVecMat(1, disVec.size(), CV_32FC1, &(disVec[0])); - Mat normDisVecMat; - /*luffy_base::luffy_imageProc::*/meanvarnorm(disVecMat, normDisVecMat, 0, 1.0); - - set canNums; - genCandidateRepeatNums(canNums); - vector cenVec; - int repeatNum = recognizeLowerExtremes(normDisVecMat, canNums, 5, &cenVec); -#ifdef _TEST - if (repeatNum <= 0) - { - std::cout << "repeatNum < 0" << std::endl; - //waitKey(); - } -#endif - if (repeatNum < 0) - { - rangeVec.clear(); - return; - cenVec.clear(); - cenVec.push_back(disVec.size() / 2); - genAngleRanges(cenVec, rangeVec, disVec.size() / 2); - } - else - { - if (cenVec.size() >= 2 && angleDis(cenVec.front(), cenVec.back()) < 2) - { - cenVec.pop_back(); - } - - for_each(cenVec.begin(), cenVec.end(), [&](int& cen) - { - cen += startIdx; - cen *= angleStep; - cen = angleNorm(cen); - }); - for (auto i = cenVec.begin(); i != cenVec.end(); ++i) - { - if (*i < startIdx*angleStep) - { - rotate(cenVec.begin(), i, cenVec.end()); - break; - } - } -#ifdef _TEST - for (int i = 0; i < cenVec.size() - 1; ++i) - { - float curVal = cenVec[i]; - float nxtVal = cenVec[i + 1]; - if (nxtVal <= curVal) - { - std::cout << "assert nxtVal <= curVal failed" << std::endl; - waitKey(); - } - } -#endif - genAngleRanges(cenVec, rangeVec, 10); - } - -} - -void ImageCompareModel::genCandidateAngleRanges(const Mat& disMat, - float angleStep, vector& rangeVec, float rangeScale /*= 1*/) -{ - for (int i = 0; i < disMat.rows; ++i) - { - Mat disVec = disMat.row(i); - double minVal, maxVal; - Point minPt, maxPt; - minMaxLoc(disVec, &minVal, &maxVal, &minPt, &maxPt); - Range &r = rangeVec[i]; - float cenAngle = r.start + angleStep*minPt.x; - float angleRangeWidth = r.end - r.start; - - r.start = floorf(cenAngle - angleRangeWidth * 0.5 * rangeScale); - r.end = floorf(cenAngle + angleRangeWidth * 0.5 * rangeScale); - } -} - -void ImageCompareModel::selfRotateMin(const Mat& img, Mat& weightMat, int repeatNum) -{ - Point2f cen(img.cols / 2.0, img.rows / 2.0); - float angleStep = 360.0 / repeatNum; - Mat dSumMat = Mat::ones(img.size(), img.type())*255; - for (int i = 1; i < repeatNum; ++i) - { - Mat rotatedImg = rotateImage(img, cen, i*angleStep); - Mat dilatedImg; - dilate(rotatedImg, dilatedImg, Mat::ones(3, 3, CV_32FC1)); - dSumMat = min(dSumMat, dilatedImg); - } - weightMat = dSumMat; -} - -double ImageCompareModel::genMatchValue(const Mat& dMat) const -{ - double v = norm(dMat, NORM_L2); - - double ret = scaleMatchValue(v); - - return ret; -} - -double ImageCompareModel::genMatchValue(const Mat& rImg, const Mat& baseImg, - const Mat& maskImg, int flag, int diameter, double md_diameter, double md_height) const -{ - Mat dMat = rImg - baseImg; - dMat = abs(dMat.mul(maskImg)); - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vRImg = rImg / 255.0; - Mat vDMat0 = abs(dMat) / 255.0; - Mat vBase = baseImg / 255.0; - Mat vDMat = abs(dMat) / 255.0 / 255.0; - Mat vMask = maskImg / 255.0; -#endif - - Mat minmaxScaleMat = minMaxNorm(dMat, 0, 255, m8uMaskImg); - converToType(minmaxScaleMat, CV_8UC1); - Mat mMask = lowerMajorityMask(minmaxScaleMat, m8uMaskImg, 0.97); - converToType(mMask, CV_32FC1); - mMask /= 255.0; - - dMat = dMat.mul(mMask); - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vDMat1 = abs(dMat) / 255.0 / 255.0; -#endif - - double s = sum(mMask.mul(maskImg)).val[0]; - - double ret = genMatchValue(dMat) / s; - - if (flag == 1) - { - double matchedVal = ret; - ret = penltyCoeff(matchedVal, meanDiameter, diameter, md_diameter, md_height); - printf("the matched value %f", ret); - } - - if (ret > mDisThre) - { - return DBL_MAX; - } - else - { - return ret; - } -} - -double ImageCompareModel::scaleMatchValue(double val) const -{ - return val*mMatchValScale; -} - - -ImageCompareModel* ImageCompareModel::scale(float s) -{ - Mat baseImage; - resize(mAlignBaseImg, baseImage, Size(), s, s, INTER_CUBIC); - Mat weightMat; - resize(mWeightMat, weightMat, Size(), s, s, INTER_CUBIC); - - ImageCompareModel* pRet = new ImageCompareModel; - *pRet = *this; - pRet->setBaseImg(baseImage); - pRet->setWeightMat(weightMat); - - pRet->genMask(); - -// Mat mask8uImg; -// resize(m8uMaskImg, mask8uImg, Size(), s, s, INTER_NEAREST); -// Mat mask32fImg; -// resize(m32fMaskImg, mask32fImg, Size(), s, s, INTER_NEAREST); -// -// pRet->set8uMaskImg(mask8uImg); -// pRet->set32fMaskImg(mask32fImg); - - return pRet; -} - -ImageCompareModel::RotateMatchResult ImageCompareModel::rotateMatch(const Mat& img, int levelNum /*= 1*/, float angleStep /*= 1.0*/, - float startAngle /*= 0*/, float endAngle /*= 360*/) const -{ -#ifdef _TEST - static int idx = 0; - std::cout << idx << " "; -#endif - RotateData* pData = new RotateData; - vector angleRangeVec; - if (levelNum > 1) - { - MultiScaleImage msi; - msi.setLevelNum(3); - msi.setBaseLevel(img); - msi.genMultiScale(); - ImageCompareData imgCmpData(&msi); - imgCmpData.setStartAngle(startAngle); - imgCmpData.setEndAngle(endAngle); - - mpMultiScaleModel->proc(&imgCmpData); - - *pData = *imgCmpData.getRotateData(); - } - else - { - rotateMatchData(img, pData, angleStep, startAngle, endAngle); - } - -#ifdef _TEST - if(1) - { - //if (idx == 15) - { - RotateData* pTestData = new RotateData; - rotateMatchData(img, pTestData, angleStep, startAngle, endAngle); - - stringstream ss; - ss << "multi_scale_comp_plot"; - CvPlot::clear(ss.str()); - CvPlot::plot(ss.str(), &(pTestData->mDisValVec[0]), - pTestData->mDisValVec.size()); - - float baseAngle = pTestData->bestAngle(); - float curAngle = pData->bestAngle(); - std::cout << baseAngle << " " << curAngle << " " << baseAngle - curAngle << std::endl; - delete pTestData; - if (abs(angleDis(baseAngle, curAngle)) > 1) - { - waitKey(); - } - } - idx++; - } -#endif - - RotateMatchResult rmr; - - if (pData->mDisValVec.empty()) - { - delete pData; - return rmr; - } - else - { - size_t bestIndex = min_element(pData->mDisValVec.begin(), pData->mDisValVec.end()) - pData->mDisValVec.begin(); - - Mat ret = pData->mRImgVec[bestIndex]; - rmr.mBestRImg = ret; - rmr.mBestAngle = pData->bestAngle(); - - delete pData; - - return rmr; - } -} - -void ImageCompareModel::rotateMatchData(const Mat& _img, RotateData* pData, - float angleStep /*= 1.0*/, float startAngle /*= 0*/, float endAngle /*= 360*/) const -{ - Mat img = _img.clone(); - Point2f center(img.cols / 2.0, img.rows / 2.0); - int nNum = (endAngle - startAngle) / angleStep; - RotateData& data = *pData; - data.init(_img, center, angleStep, nNum); - data.mStartAngle = startAngle; - data.mEndAngle = endAngle; - - parallel_for_(Range(0, nNum), ImageCompareModelInvoker(this, pData)); -} - -void ImageCompareModel::rotateMatchData(const Mat& img, RotateData* pData, - float angleStep /*= 1.0*/, const vector& angleRangeVec) const -{ - float minDis = FLT_MAX; - RotateData bestData; - for_each(angleRangeVec.begin(), angleRangeVec.end(), [&](const Range& r) - { - float startAngle = r.start; - float endAngle = r.end; - rotateMatchData(img, pData, angleStep, startAngle, endAngle); - float localMinDis = *min_element(pData->mDisValVec.begin(), pData->mDisValVec.end()); - if (localMinDis < minDis) - { - minDis = localMinDis; - bestData = *pData; - } - }); - *pData = bestData; -} - -void ImageCompareModel::rotateMatchData(const Mat& img, RotateData* pData, - const vector& angleRangeVec, float angleStep, Mat& disMat) const -{ - if (angleRangeVec.empty()) - { - return; - } - disMat.create(angleRangeVec.size(), angleRangeVec.front().size(), CV_32FC1); - pData->mRImgVec.resize(angleRangeVec.size()); - pData->mDisValVec.resize(angleRangeVec.size(), FLT_MAX); - double minDis = DBL_MAX; - for (int i = 0; i < angleRangeVec.size(); ++i) - { - Range r = angleRangeVec[i]; - Mat disVec = disMat.row(i); - RotateData rotateData; - float startAngle = r.start; - float endAngle = r.end; - rotateMatchData(img, &rotateData, angleStep, startAngle, endAngle); - std::copy(rotateData.mDisValVec.begin(), rotateData.mDisValVec.end(), - (float*)disVec.data); - double localMinDis, localMaxDis; - Point minPt, maxPt; - minMaxLoc(disVec, &localMinDis, &localMaxDis, &minPt, &maxPt); - if (localMinDis < minDis) - { - minDis = localMinDis; - *pData = rotateData; - } - } -} - -void ImageCompareModel::genCandidateRepeatNums(set& canNums) -{ - canNums.clear(); - - for (int i = 4; i < 25; ++i) - { - canNums.insert(i); - } -} - -bool isValidExtremas(const Mat& vec, const vector& lessExtremaIdxVec, - const vector& moreExtremaIdxVec) -{ - float* pVec = (float*)vec.data; - auto lessIdxIter = lessExtremaIdxVec.begin(); - auto moreIdxIter = moreExtremaIdxVec.begin(); - while (lessIdxIter != lessExtremaIdxVec.end()) - { - auto leftLessIdxIter = lessIdxIter; - auto leftMoreIdxIter = moreIdxIter; - auto rightLessIdxIter = lessIdxIter; - rightLessIdxIter++; - if (rightLessIdxIter == lessExtremaIdxVec.end()) - { - break; - } - auto rightMoreIdxIter = leftMoreIdxIter; - while (*rightLessIdxIter > *rightMoreIdxIter) - { - rightMoreIdxIter++; - } - - float leftLessExtrema = pVec[*leftLessIdxIter]; - float rightLessExtrema = pVec[*rightLessIdxIter]; - float localMaxVal = *max_element(pVec + *leftLessIdxIter, - pVec + *rightLessIdxIter + 1); - float valRange = localMaxVal - min(leftLessExtrema, rightLessExtrema); - float valTor = valRange*0.05; - float slope = (rightLessExtrema - leftLessExtrema) / (*rightLessIdxIter - *leftLessIdxIter); - - leftMoreIdxIter++; - while (leftMoreIdxIter != rightMoreIdxIter) - { - float interVal = leftLessExtrema + slope*(*leftMoreIdxIter - *leftLessIdxIter); - float curExtremaVal = pVec[*leftMoreIdxIter]; - if (curExtremaVal < interVal + valTor) - { - return false; - } - leftMoreIdxIter++; - } - - lessIdxIter++; - moreIdxIter = rightMoreIdxIter; - } - - return true; -} - - -int ImageCompareModel::recognizeLowerExtremes(const Mat& vec, - set canNums, int extremeRefineRange /*= 5*/, vector *pExtremaIdxVec /*= 0*/) -{ - unsigned int size = vec.cols; - set validNs; - float* pVec = (float*)vec.data; - - double vecMinVal, vecMaxVal; - minMaxIdx(vec, &vecMinVal, &vecMaxVal); - -#ifdef DEBUG_VIEW_PLOT - CvPlot::clear("recognizeLowerExtreams"); - CvPlot::plot("recognizeLowerExtreams", (float*)vec.data, vec.cols); -#endif - - map > repeatNumLocalExtremaIdxMap; - map repeatNumLocalExtremaValMap; - for (auto iter = canNums.rbegin(); iter != canNums.rend(); ++iter) - { - unsigned int n = *iter; - - Mat extremaValVec; - vector extremaIdxVec; - uniformLocalMinExtremas(vec, extremaValVec, extremaIdxVec, - n, extremeRefineRange); - - float* pExtremaVecVec = (float*)extremaValVec.data; - - float curVal, nxtVal; - bool isValid = true; - - Mat preLocalVec; - - for (unsigned int i = 0; i < extremaIdxVec.size() - 1; ++i) - { - unsigned int curIdx = extremaIdxVec[i]; - unsigned int nxtIdx = extremaIdxVec[i + 1]; - curVal = pVec[curIdx]; - nxtVal = pVec[nxtIdx]; - - // no smaller value between two neighbor extremes - if (anyInRange(pVec + curIdx + 1, pVec + nxtIdx, - -FLT_MAX, min(curVal, nxtVal))) - { - isValid = false; - break; - } - - if (!preLocalVec.empty()) - { - Mat curLocalVec = vec.colRange(curIdx, nxtIdx + 1); - if (curLocalVec.size() != preLocalVec.size()) - { - resize(curLocalVec, curLocalVec, preLocalVec.size()); - } - float sim = compareHist(curLocalVec, preLocalVec, CV_COMP_CORREL); - if (sim < 0) - { - isValid = false; - break; - } - } - - preLocalVec = vec.colRange(curIdx, nxtIdx + 1); - } - if (!isValid) - { - continue; - } - - set nToBeErased; - for_each(validNs.begin(), validNs.end(), [&](int preN) - { - if (preN % n != 0 || !isValid) - { - return; - } - vector preExtremaIdxVec = repeatNumLocalExtremaIdxMap[preN]; - if (isValidExtremas(vec, extremaIdxVec, preExtremaIdxVec)) - { - nToBeErased.insert(preN); - } - else - { - isValid = false; - } - }); - if (!isValid) - { - continue; - } - if (nToBeErased.size() == validNs.size()) - { - validNs.clear(); - } - else - { - for_each(nToBeErased.begin(), nToBeErased.end(), [&](int toBeErasedN) - { - validNs.erase(toBeErasedN); - }); - } - - validNs.insert(n); - repeatNumLocalExtremaIdxMap[n] = extremaIdxVec; - repeatNumLocalExtremaValMap[n] = extremaValVec; - if (pExtremaIdxVec) - { - *pExtremaIdxVec = extremaIdxVec; - } - } - if (validNs.size() == 0) - { - return -1; - } - if (validNs.size() > 1) - { - return -2; - } - - return *(validNs.begin()); -} - -int ImageCompareModel::recognizeRepeatedLocalExtremas(const Mat& vec, - const set& canNums, int refineRange /*= 5*/, - vector *pIdxVec /*= 0*/) -{ - assert(vec.type() == CV_32FC1); - float* pVecData = (float*)vec.data; - - for_each(canNums.begin(), canNums.end(), [&](int n) - { - Mat localMinExtremaValVec; - vector localMinExtremaIdxVec; - uniformLocalMinExtremas(vec, localMinExtremaValVec, localMinExtremaIdxVec, - n, refineRange); - - float* pExtremaVecVec = (float*)localMinExtremaValVec.data; - - // get locally top 10% values - - }); - - return -1; -} - -int ImageCompareModel::computeRepeatNum(const Mat& _img) -{ - Mat img; - cv::GaussianBlur(_img, img, Size(3, 3), 5.0); - vector vec; - selfRotationSimilarityFeature(img, vec, Point2f(img.cols / 2.0, img.rows / 2.0)); - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat viewImg = img / 255.0 /255.0; - Mat view_Img = _img / 255.0 /255.0; -#endif - - vector normVec(vec); - Mat vecMat(1, vec.size(), CV_32FC1, &(vec[0])); - Mat normVecMat(1, normVec.size(), CV_32FC1, &(normVec[0])); - /*luffy_base::luffy_imageProc::*/meanvarnorm(vecMat, normVecMat, 0, 1.0); - -#ifdef DEBUG_VIEW_PLOT - Mat dftVec; - dft(normVec, dftVec); - dftVec = abs(dftVec); - - Mat dVecMat = normVecMat.clone(); - genSobelImage(dVecMat); - Mat dDftVec; - dft(dVecMat, dDftVec); - - Mat ddVecMat = dVecMat.clone(); - genSobelImage(ddVecMat); - Mat ddDftVec; - dft(ddVecMat, ddDftVec); - - CvPlot::plot("normVec", (float*)&(normVec[0]), normVec.size()); - CvPlot::plot("dVec", (float*)dVecMat.data, dVecMat.cols); - CvPlot::plot("ddVec", (float*)ddVecMat.data, ddVecMat.cols); - CvPlot::plot("ddft", (float*)dDftVec.data, 50); - CvPlot::plot("dft", (float*)dftVec.data, 50); - CvPlot::plot("dddft", (float*)ddDftVec.data, 50); - - waitKey(); -#endif - - set canNums; - genCandidateRepeatNums(canNums); - return recognizeLowerExtremes(normVecMat, canNums); -} - -int ImageCompareModel::computeRepeatNum() -{ - if (mWeightMat.empty() || mAlignBaseImg.empty()) - { - return 0; - } - - Mat img = mAlignBaseImg.mul(mWeightMat); - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat viewImg = img / 255.0 / 255.0; -#endif - - return computeRepeatNum(img); -} - -void ImageCompareModel::initMultiScaleModel() -{ - if (mpMultiScaleModel) - { - delete mpMultiScaleModel; - } - mpMultiScaleModel = new MultiScaleImageCompareModel; - mpMultiScaleModel->setLevelNum(3); - mpMultiScaleModel->setBaseLevel(this); - mpMultiScaleModel->genMultiScale(); -} - -void ImageCompareModelInvoker::operator()(const cv::Range& range) const -{ - int i0 = range.start; - int i1 = range.end; - //assert(abs(i1 - i0) == 1); - m_pModel->parallelDetect(i0, m_pData); -} - -void ImageCompareModel::parallelDetect(int index, void *p) const -{ - RotateData *pData = (RotateData *)p; - Mat t = getRotationMatrix2D(pData->mCenter, pData->angle(index), 1.0); - Mat rImg; - warpAffine(pData->mImgSrc, rImg, t, pData->mImgSrc.size()); - if (rImg.size() != mAlignBaseImg.size()) - { - resize(rImg, rImg, mAlignBaseImg.size()); - } - - Mat imgRes = rImg - mAlignBaseImg; - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vRImg, vBaseImg; - vRImg = rImg / 255.0; - vBaseImg = mAlignBaseImg / 255.0; - Mat vImgRes = imgRes / 255.0; - Mat vWeightMat = mWeightMat / 255.0; -#endif - - imgRes = imgRes.mul(m32fMaskImg); - - if (!mWeightMat.empty()) - { - imgRes.mul(mWeightMat); - } - double val = norm(imgRes); - -#ifdef DEBUG_VIEW_INTERNAL_MAT - vImgRes = imgRes / 255.0; -#endif - pData->mDisValVec[index] = val; - pData->mRImgVec[index] = rImg; -} -double ImageCompareModel::filterTrainImage(const Mat&img) -{ - if (img.empty()) - { - return DBL_MAX; - } - mDisThre = DBL_MAX; - double dis = compare(img, NULL, 3, false); - /*if (dis < mTrueSampleDisMax) - { - dis = mTrueSampleDisMax; - } - double absDiff = abs(dis - mTrueSampleDisMax);*/ - return dis; -} -void ImageCompareModel::weightOptimization(const vector& falseSamples) -{ - reConMat = mWeightMat.clone(); - for (int i = 0; i < falseSamples.size(); i++) - { - Mat falseSample = falseSamples[i].clone(); - preWeightReconstruction(falseSample, reConMat); - } - mWeightMat = reConMat; -} - -void ImageCompareModel::preWeightReconstruction(Mat img, Mat &reConImg) -{ - - if (mAlignBaseImg.size() != img.size()) - { - resize(img, img, mAlignBaseImg.size()); - } - - Mat matchImg = img.clone(); - preProcessImage(matchImg); - - if (!mpMultiScaleModel) - { - initMultiScaleModel(); - } - RotateMatchResult rmr = rotateMatch(matchImg, 1); - Mat rImg = rmr.mBestRImg; - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vRImg = rImg / 255.0; -#endif - - double bestAngle = rmr.mBestAngle; - Mat cmpImg = rotateImage(img, Point2f(img.cols / 2.0, img.rows / 2.0), - bestAngle); - - // remove highlights - Mat hightlightsMask = cmpImg < mHighlightsThreshold; - converToType(hightlightsMask, CV_32FC1); - hightlightsMask /= 255.0; - - Mat unifiedMask = m32fMaskImg.mul(hightlightsMask).mul(mWeightMat); - - preProcessImage(cmpImg, m8uMaskImg, mWeightMat, mTargetMeanVal, - mTargetStddevVal, mHighlightsThreshold); - - cmpImg.setTo(0, cmpImg < 0); - converToType(cmpImg, CV_32FC1); - normSectors_tarImg(cmpImg, unifiedMask, imgCen(cmpImg), 1, - mCompareBaseImg); - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vRotatedImg0 = cmpImg / 255.0; -#endif - -#ifdef DEBUG_VIEW_INTERNAL_MAT - Mat vRotatedImg1 = cmpImg / 255.0; -#endif - - cmpImg.setTo(0, cmpImg < 10); - - weightReconstruction(cmpImg, mCompareBaseImg, unifiedMask, reConImg); - -} - -void ImageCompareModel::weightReconstruction(const Mat& rImg, const Mat& baseImg, const Mat& maskImg, Mat &reConImg) -{ - Mat dMat = abs(rImg - baseImg); - Mat norImg = Mat::ones(dMat.size(), dMat.type()) * 255; - dMat = min(dMat, norImg); - Mat w; - dMat.copyTo(w, dMat < 0.5); - - w = minMaxNorm(w, 0, 1.0); - for (int i = 0; i < reConImg.rows; i++) - { - float* pData = (float*)reConImg.row(i).data; - float* pWeight = (float*)w.row(i).data; - for (int j = 0; j < reConImg.cols; j++) - { - if (pWeight[j]!=0) - { - //pData[j] *= pWeight[j]; - pWeight[j] = -1 * pow(pWeight[j] - 1, 2) + 1; - pData[j] *= pWeight[j]; - } - } - } - -} -double ImageCompareModel::penltyCoeff(double matchedVal, int diameterMean, int targetDiameter, double modelDiamter, double modelHeight) const -{ - int diff = abs(diameterMean - targetDiameter); - double modelDiameterDiff = abs(modelDiamter - realWidth); - double modelHeightDiff = abs(modelHeight - realHeight); - - if (diff >=10) - { - return matchedVal*(diff / 100.0 + 1) * (modelHeightDiff / 100.0 + 1) * (modelDiameterDiff / 100.0 + 1); - } - else - { - return matchedVal; - } - - -} \ No newline at end of file diff --git a/qilunCar/ImageCompareModel.h b/qilunCar/ImageCompareModel.h deleted file mode 100644 index 0b1073e..0000000 --- a/qilunCar/ImageCompareModel.h +++ /dev/null @@ -1,349 +0,0 @@ -/*! \file ImageCompareModel.h - - Copyright (C) 2014 Hangzhou Leaper. - - Created by bang.jin at 2017/02/04. - -*/ - -#pragma once -#include -#include -#include -#include -#include -#include -#include "MultiScaleObj.h" -#include "ICompareModel.h" -using std::set; -using std::map; -using std::fstream; -using std::string; -using namespace cv; - -class MultiScaleImageCompareModel; -class ImageCompareModel:public ICompareModel -{ -public: - class RotateMatchResult - { - public: - Mat mBestRImg; - double mBestAngle; - }; - class RotateData - { - public: - RotateData() {}; - RotateData(const Mat &img, Point pt, double dAngleStep, int size) - : mImgSrc(img) - , mStartAngle(0) - , mEndAngle(360) - { - init(img, pt, dAngleStep, size); - }; - void init(const Mat& img, Point pt, double dAngleStep, int size) - { - mImgSrc = img; - mStartAngle = 0; - mEndAngle = 360.0; - mRImgVec.clear(); - mRImgVec.resize(size); - mDisValVec.clear(); - mDisValVec.resize(size, FLT_MAX); - mCenter = pt; - mAngleStep = dAngleStep; - } - double angle(int index) - { - return index*mAngleStep + mStartAngle; - } - double bestAngle() - { - if (mDisValVec.empty()) - { - return -DBL_MAX; - } - size_t bestIndex = min_element(mDisValVec.begin(), - mDisValVec.end()) - mDisValVec.begin(); - double bestAngle = angle(bestIndex); - return bestAngle; - } - Mat bestRImg() - { - if (mRImgVec.empty()) - { - return Mat(); - } - size_t bestIndex = min_element(mDisValVec.begin(), - mDisValVec.end()) - mDisValVec.begin(); - return mRImgVec[bestIndex]; - } - double mAngleStep; - Mat mImgSrc; - Point mCenter; - vector mRImgVec; - vector mDisValVec; - - float mStartAngle, mEndAngle; - }; - -public: - static cv::Point2f refineCircleCen(const Mat& img, Point2f cen); - static Mat genWeightImage(const Mat& img, Point2f center, float innerR = -1, - float outterR = -1); - static void selfRotationSimilarityFeature(const Mat& img, - vector& vec, Point2f cen = Point2f(-1, -1)); - static Mat genMask(const Mat& img, Point2f center, float innerR = -1, - float outterR = -1, - int type = CV_32FC1); - static void genCandidateRepeatNums(set& canNums); - int computeRepeatNum(const Mat& img); - static int recognizeLowerExtremes(const Mat& vec, set canNums, int extremeRefineRange = 5, vector *pExtemeIdxVec = 0); - static int recognizeRepeatedLocalExtremas(const Mat& vec, const set& canNums, int extremeRefineRange = 5, vector *pExtremeIdxVec = 0); - static void genUniformSepIdx(int num, int startIdx, int endIdx, vector& cenVec); - static void genAngleRanges(vector cenVec, vector& rangeVec, int localRange); - static void genCandidateAngleRanges(vector disVec, - float angleStep, vector& rangeVec); - static void genCandidateAngleRanges(const Mat& disMat, float angleStep, - vector& rangeVec, float rangeScale = 1); - static void selfRotateMin(const Mat& img, Mat& weightMat, int repeatNum); - - -public: - ImageCompareModel() : - mMatchValScale(1.0), - mTargetMeanVal(127), - mTargetStddevVal(50), - mHighlightsThreshold(256), - mRepeatNum(0), - mName("unnamed"), - mDisThre(DBL_MAX), - mTrueSampleDisMin(DBL_MAX), - mTrueSampleDisMax(DBL_MIN), - mTrueSampleDisMean(-1), - mTrueSampleDisStddev(-1), - mIsEnableCache(false), - mpMultiScaleModel(NULL), - meanDiameter(0), - realWidth(0), - realHeight(0) - {}; - ImageCompareModel(const ImageCompareModel& model) - : mAlignBaseImg(model.getBaseImg().clone()) - , mWeightMat(model.getWeightMat().clone()) - , mMatchValScale(model.getMatchValScale()) - { - genMask(); - } - ~ImageCompareModel() {}; - - void printInfo(); - - void saveImages(string dirPath); - bool save2file(string filePath); - bool readFromFile(string filePath); - - void operator = (const ImageCompareModel& model) - { - mAlignBaseImg = model.getBaseImg().clone(); - mWeightMat = model.getWeightMat().clone(); - mMatchValScale = model.getMatchValScale(); - mTargetMeanVal = model.getTargetMeanVal(); - mTargetStddevVal = model.getTargetStddevVal(); - mName = model.getName(); - mTrueSampleDisStddev = model.getDisStdDev(); - mTrueSampleDisMean = model.getDisMean(); - mTrueSampleDisMax = model.getDisMax(); - mTrueSampleDisMin = model.getDisMin(); - meanDiameter = model.getMeanDiamter(); - } - - void genMask(); - - void preProcessImage(Mat& img) const; - void preProcessImage(Mat& img, const Mat& mask, double dstMean, double dstStddev, int highlightsThreshold) const; - void preProcessImage(Mat& img, const Mat& mask, const Mat& weightMat, double dstMean, - double dstStddev, int highlightsThreshold) const; - void preProcessImage0(Mat& img) const; - void weightOptimization(const vector& falseSamples); - //! һͼͱ׼ͼmBaseImgתƥ䣬òֵ - /*! - \param Mat img ͼ - \param Mat * pRImg ͼתƥ - \param bool isFilterSize Ƿͼߴ - \return double ֵ - \see compare(Mat, Mat, Mat*, Mat*) - */ - double compare(Mat img, Mat* pRImg = NULL, int levelNum = 1, bool isFilterSize = true, int flag = 0, - double md_diameter = 0, double md_height = 0); - - //! ѵõ׼ͼmBaseImg - /*! - \param const vector & imgVec ͬѵͼ - \return void - */ - void train(const vector& imgVec); - void calculateAllParams(const vector& imgVec); - void trueSampleWeightRecon(const vector& resizedVec, vector rmrVec); - void trueWeightRecon(const Mat& rImg, const Mat& baseImg); - void weightMapping(const Mat& weight, double maxVal); - //void falseWeightmapping(Mat &img); - double descendFunction(double pixVal, double maxVal); - double penltyCoeff(double matchedVal, int diameterMean, int targetDiameterm, double modelDiamter, double modelHeight) const; - //! ݸֵжһµͼǷڸ - /*! - \param const vector & imgVec ڸѵͼ - \return void - */ - void computeDisThre(const vector& imgVec, double* pMinDis = NULL, double md_diameter = 0, double md_height = 0); - - double filterTrainImage(const Mat &img); - - //! мrotate - /*! - \param int index ǰindex - \param void *p ָ - */ - void parallelDetect(int index, void *p) const; - - //! ȡ׼ͼ - /*! - \return cv::Mat ׼ͼ - */ - Mat getBaseImg() const { return mAlignBaseImg; } - - void setBaseImg(const Mat& img) { mAlignBaseImg = img; } - - Mat getWeightMat() const { return mWeightMat; } - void setWeightMat(Mat val) { mWeightMat = val; } - - double getMatchValScale() const { return mMatchValScale; } - void setMatchValScale(double val) { mMatchValScale = val; } - - int getTargetStddevVal() const { return mTargetStddevVal; } - void setTargetStddevVal(int val) { mTargetStddevVal = val; } - int getTargetMeanVal() const { return mTargetMeanVal; } - void setTargetMeanVal(int val) { mTargetMeanVal = val; } - - int getRepeatNum() const { return mRepeatNum; } - void setRepeatNum(int val) { mRepeatNum = val; } - - string getName() const { return mName; } - void setName(string val) { mName = val; } - - double getDisStdDev() const { return mTrueSampleDisStddev; } - double getDisMean() const { return mTrueSampleDisMean; } - double getDisMin() const { return mTrueSampleDisMin; } - double getDisMax() const { return mTrueSampleDisMax; } - - double getFalseSampleMinDis() const { return mFalseSampleMinDis; } - double getMeanDiamter() const { return meanDiameter; } - //! ȡһִreadFromFileʱļ· - /*! - \return string ļ· - */ - string getFilePath() const { return mFilePath; } - - double getDisThre() const { return mDisThre; } - void setDisThre(double val) { mDisThre = val; } - - //! û档ὫÿεcompareӿimgdataָΪkey洢 - // ֵ - /*! - \return void - */ - void setIsEnableCache(bool val) { mIsEnableCache = val; } - bool getIsEnableCache() const { return mIsEnableCache; } - - void clearDisCache() { mDisCache.clear(); } - - ImageCompareModel* scale(float s); - - RotateMatchResult rotateMatch(const Mat& img, int levelNum = 1, float angleStep = 1.0, - float startAngle = 0, float endAngle = 360) const; - void rotateMatchData(const Mat& img, RotateData* pData, const vector& angleRangeVec, float angleStep, - Mat& disMat) const; - void rotateMatchData(const Mat& img, RotateData* pData, float angleStep = 1.0, - float startAngle = 0, float endAngle = 360) const; - void rotateMatchData(const Mat& img, RotateData* pData, float angleStep, - const vector& angleRangeVec) const; - - cv::Mat getM8uMaskImg() const { return m8uMaskImg; } - void setM8uMaskImg(cv::Mat val) { m8uMaskImg = val; } - cv::Mat getM32fMaskImg() const { return m32fMaskImg; } - void setM32fMaskImg(cv::Mat val) { m32fMaskImg = val; } - - int computeRepeatNum(); - - void setRealWidth(int val){ realWidth = val; } - void setRealHeight(int val){ realHeight = val; } - int getRealWidth(){ return realWidth; } - int getRealHeight(){ return realHeight; } - - -protected: - //! δɣͼֱͱ׼ͼmBaseImgתƥ䣬òֵ - /*! - \param Mat img0 Ƚϵͼimg0 - \param Mat img1 Ƚϵͼimg1 - \param Mat * pRImg0 img0ͱ׼ͼmBaseImgתƥĽrimg0 - \param Mat * pRImg1 img1ͱ׼ͼmBaseImgתƥĽrimg1 - \return double ֵȡֵСΪmMatchValScale*norm(rimg0 - rimg1)/(cols*rows) - */ - double compare(Mat img0, Mat img1, Mat* pRImg0 = NULL, Mat* pRImg1 = NULL); - - void setFilePath(string val) { mFilePath = val; } - - double genMatchValue(const Mat& rImg, const Mat& baseImg, const Mat& maskImg, int flag, int diameter, double md_diameter, double md_height) const; - double genMatchValue(const Mat& dMat) const; - double scaleMatchValue(double val) const; - void weightReconstruction(const Mat& rImg, const Mat& baseImg, const Mat& maskImg, Mat &reConImg); - void preWeightReconstruction(Mat img, Mat &reConImg); - - void setFalseSampleMinDis(double iVal) { mFalseSampleMinDis = iVal; } - - double mMatchValScale; - int mTargetMeanVal, mTargetStddevVal, mHighlightsThreshold; - int mRepeatNum; - - Mat mAlignBaseImg, mCompareBaseImg; - Mat mWeightMat; - Mat m32fMaskImg, m8uMaskImg; - Mat mDisMat; - Mat reConMat; - Mat falseReConMat; - double mDisThre; - string mName; - double falseMinDis; - int meanDiameter; - int realWidth; - int realHeight; - - - // some training data - double mTrueSampleDisStddev, mTrueSampleDisMean, mTrueSampleDisMax, mTrueSampleDisMin; - double mFalseSampleMinDis; - - // temp data - string mFilePath; - void initMultiScaleModel(); - MultiScaleImageCompareModel* mpMultiScaleModel; - - // cache - bool mIsEnableCache; - map mDisCache; -private: -}; - -class ImageCompareModelInvoker : public cv::ParallelLoopBody -{ -public: - ImageCompareModelInvoker(const ImageCompareModel *pModel, void* pData) - : m_pModel(pModel), m_pData(pData) - {} -private: - const ImageCompareModel *m_pModel; - void *m_pData; - virtual void operator() (const cv::Range& range) const; -}; \ No newline at end of file diff --git a/qilunCar/MultiScaleImageCompareModel.cpp b/qilunCar/MultiScaleImageCompareModel.cpp deleted file mode 100644 index d98364d..0000000 --- a/qilunCar/MultiScaleImageCompareModel.cpp +++ /dev/null @@ -1,125 +0,0 @@ -#include "MultiScaleImageCompareModel.h" -#include "ImageCompareModel.h" -//#include "../3rd/cvplot/cvplot.h" - - -void MultiScaleImageCompareModel::setBaseLevel(const ImageCompareModel* pModel) -{ - ImageCompareModel* p = new ImageCompareModel; - *p = *pModel; - p->genMask(); - clear(); - mMultiScaleModels.resize(1); - mMultiScaleModels[0] = p; -} - -void MultiScaleImageCompareModel::genMultiScale() -{ - resetMaxLevel(); - while (getLevel() >= 1) - { - ImageCompareModel* pScaledModel = mMultiScaleModels.back()->scale(mScaleStep); - mMultiScaleModels.push_back(pScaledModel); - 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 angleRangeVec(1, Range(0, 360)); - - ImageCompareModel::RotateData* pRotateData = pCmpData->getRotateData(); - while (getLevel() >= 0) - { - const ImageCompareModel* pModel = mMultiScaleModels[getLevel()]; - assert(pModel); - Mat img = pMSImg->getImg(getLevel()); - 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 - -#ifdef DEBUG_VIEW_PLOT - { - stringstream ss; - ss << "multi_scale_comp_plot" << getLevel(); - CvPlot::clear(ss.str()); - CvPlot::plot(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(ss.str(), &(testRotateData.mDisValVec[0]), - testRotateData.mDisValVec.size()); - } -#endif - - downLevel(); - } -} diff --git a/qilunCar/MultiScaleImageCompareModel.h b/qilunCar/MultiScaleImageCompareModel.h deleted file mode 100644 index a59c780..0000000 --- a/qilunCar/MultiScaleImageCompareModel.h +++ /dev/null @@ -1,74 +0,0 @@ -/*! \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 -#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 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_ - diff --git a/qilunCar/MultiScaleObj.cpp b/qilunCar/MultiScaleObj.cpp deleted file mode 100644 index 12256ad..0000000 --- a/qilunCar/MultiScaleObj.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "MultiScaleObj.h" -#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]; -} diff --git a/qilunCar/MultiScaleObj.h b/qilunCar/MultiScaleObj.h deleted file mode 100644 index 44d1930..0000000 --- a/qilunCar/MultiScaleObj.h +++ /dev/null @@ -1,87 +0,0 @@ -/*! \file MultiScaleObj.h - - Copyright (C) 2014 杭州利珀科技有限公司. - - Created by bang.jin at 2017/02/20. -*/ - -#ifndef __MultiScaleObj_h_ -#define __MultiScaleObj_h_ - -#include -#include -#include - -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 mMultiScaleImages; - MultiScaleImageProc* mpProc; -private: -}; - -#endif // __MultiScaleObj_h_ diff --git a/qilunCar/StdUtils.h b/qilunCar/StdUtils.h deleted file mode 100644 index 9bb5b7a..0000000 --- a/qilunCar/StdUtils.h +++ /dev/null @@ -1,454 +0,0 @@ -/*! \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 -#endif - -#if (defined _WINDOWS) || (defined WIN32) -#define USE_WIN_API 1 -#endif - - -#include -#include -#include -#include -#include -#include -#include - -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 -T sum(_Iter s, _Iter e) -{ - if (s == e) - { - return T(); - } - T ret = *s; - s++; - while (s != e) - { - ret += *s; - s++; - } - return ret; -} - -template -_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 -_Iter findSumTopNPercentEle(_Iter s, _Iter e, float nPersent) -{ - T sumVal = sum(s, e); - T threVal = sumVal*nPersent; - sumVal = 0; - while (s != e) - { - sumVal += *s; - if (sumVal > threVal) - { - s++; - return s; - } - s++; - } - return e; -} - -template -void clearAndResetVec(vector* vec, int n) -{ - if (vec) { - vec->clear(); - vec->reserve(n); - } -} - -template -void genIncVec(vector& 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 -_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 -void add(_It s, _It e, const _Ty& val) -{ - while (s != e) - { - *s += val; - s++; - } -} - -template -bool allInRange(_It s, _It e, _Ty minVal, _Ty maxVal) -{ - while (s != e) - { - if (*s < minVal || *s > maxVal) - { - return false; - } - ++s; - } - return true; -} - -template -bool anyInRange(_It s, _It e, _Ty minVal, _Ty maxVal) -{ - while (s != e) - { - if (*s >= minVal && *s <= maxVal) - { - return true; - } - ++s; - } - return false; -} - -template -bool anyIn(_It s, _It e, _Ty v) -{ - while (s != e) - { - if (*s == v) - { - return true; - } - ++s; - } - return false; -} - -template -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 -_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 -string joinStr(_Ty0 s0, _Ty1 s1) -{ - stringstream ss; - ss << s0 << s1; - return ss.str(); -} -template -string joinStr(_Ty0 s0, _Ty1 s1, _Ty2 s2) -{ - stringstream ss; - ss << s0 << s1 << s2; - return ss.str(); -} -template -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(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(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, 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(); - it = mLookupTable.insert(std::make_pair(name, ptr)).first; - } - return it->second; - } - -private: - ObjectFactory() {} - std::map mLookupTable; - //CyclopsLock mLock; -}; - -template -inline T minMax(T val, T minVal, T maxVal) { - return std::min(maxVal, std::max(minVal, val)); -} - -#endif // __StdUtils_h_ - diff --git a/qilunCar/TransSolver.cpp b/qilunCar/TransSolver.cpp deleted file mode 100644 index 2d57b20..0000000 --- a/qilunCar/TransSolver.cpp +++ /dev/null @@ -1,303 +0,0 @@ -#include "TransSolver.h" -//#include "CVUtils.h" - -#define M_LOW_TOLERANCE 0.000001 - -Matx33d affineTrans(const vector& src, const vector& 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; -} - -cv::Matx33d rigidTrans(const vector& src, const vector& dst, - Mat* pCenRotScaleMat) -{ - if (dst.empty() || src.empty()) { - return Mat(); - } - - vector 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; - - if (pCenRotScaleMat) - { - *pCenRotScaleMat = Mat(qm); - } - - return ret; -} - -bool cmpPointVec(const vector& vec0, const vector& 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 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 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 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 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(0, 2) = (rand() % 1000) / 1000.0; - mat23.at(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 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 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 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)); - } - } -} diff --git a/qilunCar/TransSolver.h b/qilunCar/TransSolver.h deleted file mode 100644 index 282a772..0000000 --- a/qilunCar/TransSolver.h +++ /dev/null @@ -1,26 +0,0 @@ -/*! \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 -#include - -using namespace cv; -using std::vector; - -Matx33d affineTrans(const vector& src, const vector& dst); - -Matx33d rigidTrans(const vector& src, const vector& dst, - Mat* pCenRotScaleMat = NULL); - -void testTransSolver(); - -#endif // __TransSolver_h_ - diff --git a/qilunCar/cvdrawutils.cpp b/qilunCar/cvdrawutils.cpp deleted file mode 100644 index 83124b9..0000000 --- a/qilunCar/cvdrawutils.cpp +++ /dev/null @@ -1,181 +0,0 @@ -#include "cvdrawutils.h" -#include "CVUtils.h" - -cv::Mat drawLines(const Mat& img, const vector& 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& 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& 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(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& pointVec) -{ -#ifdef LP_DISABLE_DRAW - return Mat(); -#else - vector 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& 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); -} - diff --git a/qilunCar/cvdrawutils.h b/qilunCar/cvdrawutils.h deleted file mode 100644 index 0f81521..0000000 --- a/qilunCar/cvdrawutils.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef cvdrawutils_h__ -#define cvdrawutils_h__ - -#include -#include -#include -#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& pointVec, int grayVal = 255, int xRadius = 0, int yRadius = 0); - -Mat drawPointsWithKeyPoints(const Mat& img, const vector& pointVec); - -Mat drawLines(const Mat& img, const vector& segPointVec); - -Mat drawLines(const Mat& img, const vector& 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& 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__ diff --git a/qilunCar/cvmatutils.cpp b/qilunCar/cvmatutils.cpp deleted file mode 100644 index f0ba267..0000000 --- a/qilunCar/cvmatutils.cpp +++ /dev/null @@ -1,217 +0,0 @@ -#include "cvmatutils.h" -#include -#include - -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 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; -} diff --git a/qilunCar/cvmatutils.h b/qilunCar/cvmatutils.h deleted file mode 100644 index 3f52934..0000000 --- a/qilunCar/cvmatutils.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef _cvmatutils_h_ -#define _cvmatutils_h_ - -#include -#include -#include -#include -#include - -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_ diff --git a/qilunCar/pointpair.h b/qilunCar/pointpair.h deleted file mode 100644 index 4d52f32..0000000 --- a/qilunCar/pointpair.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef pointpair_h__ -#define pointpair_h__ - -#include -#include -#include - -using std::vector; -using std::pair; -using namespace cv; - -template -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 PointPair; -typedef _PointPair PointfPair; - -void convertPointPair2PointfPair(const vector& vec0, - vector& vec1); - -template -double pointDis(const _Point& i, const _Point& j) -{ - return norm(i - j); -} - -template -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 -double pointPairLen(const _PointPair& p) -{ - return pointDis(p.first, p.second); -} - -template -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__ diff --git a/src/tpMain/cryptokey/lpCryptokey.cpp b/src/tpMain/cryptokey/lpCryptokey.cpp index b2ca685..3d8b640 100644 --- a/src/tpMain/cryptokey/lpCryptokey.cpp +++ b/src/tpMain/cryptokey/lpCryptokey.cpp @@ -78,13 +78,13 @@ bool lpCheckKey::checkLinese() std::string cpuID = lpHardwareInfo::instance()->getCpuID(); std::string BoardID = lpHardwareInfo::instance()->getMotherBoardID(); std::string macID = lpHardwareInfo::instance()->getMacAddress(); - if (hardDriveID.size() > 0) - { - m_SerialNo = lpCryptokey::genSerialNumber(QString(hardDriveID.c_str())+QString(cpuID.c_str())); - } - else { - m_SerialNo = lpCryptokey::genSerialNumber(QString(BoardID.c_str()) + QString(macID.c_str())); - } +// if (hardDriveID.size() > 0) +// { +// m_SerialNo = lpCryptokey::genSerialNumber(QString(hardDriveID.c_str())+QString(cpuID.c_str())); +// } +// else { + m_SerialNo = lpCryptokey::genSerialNumber(/*QString(BoardID.c_str()) +*/ QString(macID.c_str())); +// } QSettings settingKey("Leaper_Register"); QString strKey = settingKey.value("key").toString(); bool bRegister = settingKey.value("register",false).toBool();