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

1808 lines
52 KiB
C++

#include "ValveDetector.h"
#include <algorithm>
#include "patterndetector.h"
using namespace luffy_base;
ValveDetector::ValveDetector()
{
luffy_triangle::createNewTrigValue(3600);
}
ValveDetector::~ValveDetector()
{
}
enum detectMode
{
shootWheelExist = 0,
shootTargetMatch = 1
};
void remove(Mat &img, int fValveWidth) {
int nStep = 20;
int nOffset = 30;
float fThres = 0.8;
Mat imgDst;
cv::threshold(img, imgDst, 1, 255.0, THRESH_OTSU);
Mat imgHalf;
Rect ret = Rect(0, imgDst.rows / 2 + nOffset, imgDst.cols, imgDst.rows / 2 - nOffset);
if (ret.y > imgDst.rows || (imgDst.rows / 2 + nOffset + imgDst.rows / 2 - nOffset) > imgDst.rows)
return;
imgDst(ret).copyTo(imgHalf);
Mat imgProj;
luffy_projection::project2axis(imgHalf, imgProj, luffy_projection::emProjX, cv::NORM_MINMAX);
Mat imgBlob(1, imgProj.cols, CV_8UC1);
imgBlob.setTo(0);
float *pProj = imgProj.ptr<float>(0);
uchar *pBlob = imgBlob.ptr<uchar>(0);
for (int i = 0; i < imgProj.cols; i++) {
if (pProj[i] >= fThres) {
pBlob[i] = 255;
int offset = 120;
int nIndex = 0;
bool bLineMode = false;
for (int j = 0; j < offset; j++) {
int nX = i + offset - j;
nX = nX % imgProj.cols;
if (bLineMode) {
pBlob[nX] = 255;
}
else {
if (pProj[nX] >= fThres) {
bLineMode = true;
nIndex = i + offset - j;
}
}
}
if (bLineMode) {
if (nIndex >= imgProj.cols) {
break;
}
else {
i = nIndex;
}
}
}
}
for (int i = 0; i < imgProj.cols; i++){
if (pBlob[i] != 0) {
img.col(i).setTo(0);
}
}
}
Point getNextMinMax(Mat *img, Point maxLoc, double minVal, InputParam InputParameter)
{
int templateH = InputParameter.barTemplate.rows;
int templateW = InputParameter.barTemplate.cols;
int startX = maxLoc.x - templateW / 2;
int startY = 0;
int endX = maxLoc.x + templateW / 2;
int endY = img->rows - 1;
if (startX < 0 || startY < 0)
{
startX = 0;
startY = 0;
}
if (endX > img->cols - 1 || endY >img->rows - 1)
{
endX = img->cols - 1;
endY = img->rows - 1;
}
for (int y = startY; y < endY + 1; y++)
{
float* fPtr = (float*)img->row(y).data;
for (int x = startX; x <= endX; x++)
{
fPtr[x] = minVal;
}
}
double minValue, maxValue;
Point iminLoc, imaxLoc;
minMaxLoc(*img, &minValue, &maxValue, &iminLoc, &imaxLoc);
return imaxLoc;
}
void findCandidateValsInMat(const Mat &_img, vector<Point> &canPoints, InputParam InputParameter)
{
Mat result = _img.clone();
double minVal, maxVal;
Point minLoc, maxLoc;
minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc);
canPoints.push_back(maxLoc);
int barNum = InputParameter.barNum;
if (barNum <=0)
{
qWarning() << "burNum cannot be negatIve or ZERO";
return;
}
int maxLength = InputParameter.nMaxAngle;
int interval = maxLength / barNum;
for (int i = 1; i < barNum; i++)
{
int nextLoc = maxLoc.x + (i*interval);
if (nextLoc >= maxLength)
{
nextLoc = nextLoc % maxLength;
}
canPoints.push_back(Point(nextLoc, 0));
}
/*Point next_maxPoint;
next_maxPoint = getNextMinMax(&result, maxLoc, minVal, InputParameter);
canPoints.push_back(next_maxPoint);
next_maxPoint = getNextMinMax(&result, next_maxPoint, minVal, InputParameter);
canPoints.push_back(next_maxPoint);
next_maxPoint = getNextMinMax(&result, next_maxPoint, minVal, InputParameter);
canPoints.push_back(next_maxPoint);
next_maxPoint = getNextMinMax(&result, next_maxPoint, minVal, InputParameter);
canPoints.push_back(next_maxPoint);*/
/*next_maxPoint = getNextMinMax(&result, next_maxPoint, minVal, InputParameter);
canPoints.push_back(next_maxPoint);*/
}
void findOffsets(InputParam in, const vector<Point> & canVec, vector<double> & detectOffset)
{
int barNum = in.barNum;
if (barNum <=0)
{
qWarning() << "barNum cannot be negative or ZERO";
return;
}
int maxLength = in.nMaxAngle;
int withinOffset = in.withinOffset;
int width = in.barTemplate.cols;
for (int i = 0; i < barNum; i++)
{
float barX = canVec[i].x + width / 2.0;
float holeX = barX + withinOffset;
if (holeX > maxLength)
{
//holeX = holeX % maxLength;
holeX = fmod(holeX, (double)maxLength);
}
detectOffset.push_back(holeX);
}
}
void creatMask(const Mat &img2Rect, const vector<double> &offsetVec, InputParam paramIn, Mat &iMask)
{
int smallMove = 20;
for (int i = 0; i < offsetVec.size(); i++)
{
int holeX = offsetVec[i];
int width = paramIn.imgTemplate.cols + 2*smallMove;
int startX = holeX - paramIn.imgTemplate.cols / 2 - smallMove;
if (startX < 0)
{
int offset = abs(startX);
startX = paramIn.nMaxAngle - offset;
//iMask(Rect(startX, 0, offset, img2Rect.rows)).setTo(255);
}
if (startX + paramIn.imgTemplate.cols + 2*smallMove> paramIn.nMaxAngle)
{
width = paramIn.nMaxAngle - startX;
int offset = startX + paramIn.imgTemplate.cols + 2*smallMove- paramIn.nMaxAngle;
iMask(Rect(0, 0, offset, img2Rect.rows)).setTo(255);
}
Rect candidateRoi(startX, 0, width, img2Rect.rows);
iMask(candidateRoi).setTo(255);
}
}
void genSobelImage1(Mat& img, Mat* pSobelx /*= NULL*/, Mat* pSobely /*= NULL*/)
{
Mat sobelx, sobely;
Sobel(img, sobelx, CV_32FC1, 1, 0);
Sobel(img, sobely, CV_32FC1, 0, 1);
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 getSobelDir(const Mat& sobelX, const Mat& sobelY)
{
Mat img(sobelX.rows, sobelX.cols, CV_16UC1);
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;
ushort* pData = (ushort*)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) * 180);
}
}
return img;
}
void genSobelDir1(Mat& img)
{
Mat srcImg = img.clone();
Mat sobelX, sobelY;
genSobelImage1(srcImg, &sobelX, &sobelY);
img = getSobelDir(sobelX, sobelY);
}
void histMeanStddev(const Mat& hist, double* pMean, double* pStddev)
{
float * pData = (float*)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));
}
//void rotateMatchData(const Mat& _img, Mat &templ, RotateData* pData, float angleStep, float startAngle, float endAngle)
//{
// 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(templ, pData));
//}
//
//void parallelDetect(int index, void *p, Mat templ)
//{
// RotateData *pData = (RotateData *)p;
// Mat t = getRotationMatrix2D(pData->mCenter, pData->angle(index), 1.0);
// Mat rImg;
// warpAffine(pData->mImgSrc, rImg, t, pData->mImgSrc.size());
//
// Mat imgRes = templ - rImg;
// double val = norm(imgRes);
// pData->mDisValVec[index] = val;
// pData->mRImgVec[index] = rImg;
//}
//void ImageCompareModelInvoker::operator()(const cv::Range& range) const
//{
// int i0 = range.start;
// int i1 = range.end;
// assert(abs(i1 - i0) == 1);
// parallelDetect(i0, m_pData, temp);
//}
double tempScoreShoot(Mat &_img, Mat &template_img, detectMode mode)
{
qDebug() << "tempScoreShoot";
double dis = 0.0;
Mat templateDir = template_img.clone();
Mat temporaryDir = _img.clone();
//temporaryDir = temporaryDir(Rect(0, 30, temporaryDir.cols, temporaryDir.rows - 30));
Mat normTemplateDir, normTemporaryDir;
Mat blurredTempl, blurredTempo;
cv::GaussianBlur(templateDir, blurredTempl, Size(3, 3), 5.0);
cv::GaussianBlur(temporaryDir, blurredTempo, Size(3, 3), 5.0);
luffy_imageProc::meanvarnorm(blurredTempl, normTemplateDir, 120, 50);
luffy_imageProc::meanvarnorm(blurredTempo, normTemporaryDir, 120, 50);
normTemplateDir.convertTo(normTemplateDir, CV_16UC1);
normTemporaryDir.convertTo(normTemporaryDir, CV_16UC1);
genSobelDir1(normTemplateDir);
genSobelDir1(normTemporaryDir);
Mat templateHist, temporaryHist, magHist;
float range[] = { 0, 360 };
const float * histRange = { range };
int histSize = 36;
calcHist(&normTemplateDir, 1, 0, Mat(), templateHist, 1, &histSize, &histRange, true, false);
calcHist(&normTemporaryDir, 1, 0, Mat(), temporaryHist, 1, &histSize, &histRange, true, false);
#ifdef VEIW_HISTGRAM
Mat dstImage = Mat::zeros(512, 800, CV_8UC3);
//normalize(templateHist, templateHist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
//normalize(temporaryHist, temporaryHist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
double max = 0;
double max1 = 0;
minMaxLoc(templateHist, NULL, &max, 0, 0);
minMaxLoc(temporaryHist, NULL, &max1, 0, 0);
max = MAX(max, max1);
double bin_w = (double)dstImage.cols / histSize; // the interval of every bin
double bin_u = (double)dstImage.rows / max; //// the maximal height
// draw histGram
for (int i = 0; i < histSize; i++)
{
Point p0 = Point(i*bin_w, dstImage.rows);
int val = templateHist.at<float>(i);
int val1 = temporaryHist.at<float>(i);
Point p1 = Point((i + 1)*bin_w, dstImage.rows - val*bin_u);
Point p2 = Point((i + 1)*bin_w, dstImage.rows - val1*bin_u);
rectangle(dstImage, p0, p1, Scalar(0, 255), 1, 8, 0);
rectangle(dstImage, p0, p2, Scalar(0, 0, 255), 1, 8, 0);
//imshow("image", dstImage);
}
char string[12];
int yAxis = 0;
for (int i = 1; yAxis < max; i++)
{
yAxis = i*max / 10;
itoa(yAxis, string, 10);
cv::putText(dstImage, string, Point(0, dstImage.rows - yAxis*bin_u), 1, 1, Scalar(0, 255, 255));
}
int xAxis = 0;
for (int i = 1; xAxis < 360; i++)
{
xAxis = i * 20;
itoa(xAxis, string, 10);
cv::putText(dstImage, string, Point(xAxis*(dstImage.cols / 360), dstImage.rows), 1, 1, Scalar(0, 255, 255));
}
#endif // VEIW_HISTGRAM
switch (mode)
{
case shootWheelExist:
{
/* double templMean, templStddev, tempoMean, tempoStddev;
transpose(templateHist, templateHist);
transpose(temporaryHist, temporaryHist);
histMeanStddev(templateHist, &templMean, &templStddev);
histMeanStddev(temporaryHist, &tempoMean, &tempoStddev);
double meanDiff = abs(templMean - tempoMean);
double stddevDiff = abs(templStddev - tempoStddev);
if (meanDiff > 1.5 || stddevDiff > 1.5)
{
qDebug() << "there is no wheel exist";
return 0;
}
else
{
qDebug() << "wheel exists";
return 1;
}*/
}
case shootTargetMatch:
{
qDebug() << "start get matchScore:" ;
double templCount = cv::sum(templateHist.rowRange(12, 25)).val[0];
double temporCount = cv::sum(temporaryHist.rowRange(12, 25)).val[0];
dis = temporCount / templCount;
if (dis > 0.60)
{
if (dis > 1)
{
dis = 1;
qDebug() << "matchScore:" << dis;
return dis;
}
else
{
qDebug() << "matchScore:" << dis;
return dis;
}
}
qDebug() << "fail to find the targetMatch";
return 0;
}
}
qDebug() << "end tempScoreShoot";
return 0;
}
//template<typename _Point>
//double pointDis(const _Point& i, const _Point& j)
//{
// return norm(i - j);
//}
//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( 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<Point2f> 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<double> 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;
// }
// }
// // CvPlot::plot<float>("sum", pSumData, radiusNum);
// // CvPlot::plot<float>("count", pCountData, radiusNum);
// // waitKey();
// }
//
// 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, CV_32FC1);
// 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;
// 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;
// pRetRowData[x] = newVal;
// }
// }
//
// Mat viewRetMat = retMat / 255.0;
//
//
// return retMat;
//}
//bool ValveDetector::isValid(Mat target, Mat templ, Point2f pt, int validThresh)
//{
// qDebug() << "detect if image is valid";
// if (target.type() != CV_32FC1)
// {
// target.convertTo(target, CV_32FC1);
// }
// templ.convertTo(templ, CV_32FC1);
// int templW = templ.cols;
// int templH = templ.rows;
// Mat imgRoi;
// target(Rect(pt.x - templW / 2, pt.y - templH / 2, templW, templH)).copyTo(imgRoi);
// Mat circleMask(imgRoi.size(), CV_32FC1, Scalar::all(0));
// cv::circle(circleMask, Point(imgRoi.cols / 2, imgRoi.rows / 2), imgRoi.cols / 2, Scalar(1), -1);
// imgRoi = imgRoi.mul(circleMask);
// templ = templ.mul(circleMask);
//
// resize(imgRoi, imgRoi, Size(imgRoi.cols / 2, imgRoi.cols / 2), INTER_LINEAR);
// resize(templ, templ, Size(templ.cols / 2, templ.cols / 2), INTER_LINEAR);
//
// Mat bullredTempl, blurredRoi;
// cv::GaussianBlur(imgRoi, bullredTempl, Size(3, 3), 5.0);
// cv::GaussianBlur(templ, blurredRoi, Size(3, 3), 5.0);
// Mat innerMask(bullredTempl.size(), CV_8UC1, Scalar::all(0));
// cv::circle(innerMask, Point(bullredTempl .cols / 2, bullredTempl.rows / 2), bullredTempl.cols / 2, Scalar(255), -1);
// Mat normTempl, normRoi;
// luffy_imageProc::meanvarnorm(bullredTempl, normTempl, 60, 30, innerMask); // 50
// luffy_imageProc::meanvarnorm(blurredRoi, normRoi, 60, 30, innerMask);
// innerMask.convertTo(innerMask, CV_32FC1);
//
// RotateData* pData = new RotateData();
// rotateMatchData(normRoi, normTempl, pData, 1, 0, 90);
//
// double result = 0;
// Mat rstImg;
// if (pData->mDisValVec.empty())
// {
// delete pData;
// qDebug() << "the distance of centers is empty";
// result = FLT_MAX;
// }
// else
// {
// size_t bestIndex = min_element(pData->mDisValVec.begin(), pData->mDisValVec.end()) - pData->mDisValVec.begin();
//
// result = pData->mDisValVec[bestIndex];
// qDebug() << "found the minimal value of distance:" << result;
// delete pData;
// }
// if (result < validThresh)
// {
// qDebug() << "image is valid";
// return true;
// }
// else
// {
// qDebug() << "image is not valid";
// return false;
// }
//}
cv::Mat LoopRoi(Mat &src, int x, int nWidth) {
Mat dst;
if (x + nWidth > src.cols) {
if (src.type() == CV_8UC1)
{
dst.create(Size(nWidth, src.rows), CV_8UC1);
}
else
{
dst.create(Size(nWidth, src.rows), CV_32FC1);
}
src(Rect(x, 0, src.cols - x, src.rows)).copyTo(dst(Rect(0, 0, src.cols - x, src.rows)));
src(Rect(0, 0, nWidth - src.cols + x, src.rows)).copyTo(dst(Rect(src.cols - x, 0, nWidth - src.cols + x, src.rows)));
}
else {
Rect roi(x, 0, nWidth, src.rows);
src(roi).copyTo(dst);
}
return dst;
}
cv::Point2f ValveDetector::getCenterPoints(Mat &_Img, const Mat &centerTempl, InputParam paramIn, Point2f pt, Mat & rstMat)
{//<2F><><EFBFBD>Ķ<EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD> 0<>ر<EFBFBD> 1<><31><EFBFBD><EFBFBD>
if (0 == paramIn.nCenterAlg) {
return pt;
}
if (paramIn.wheelType == 1)
{
if (paramIn.backGround.empty())
{
return pt;
}
else
{
Record_List roiRecord = paramIn.roi.records;
int nRoiCount = roiRecord.size();
if (nRoiCount > 0)
{
Item_List itemRoi = roiRecord.front();
int width = abs(itemRoi.front().second.at(2));
int height = abs(itemRoi.front().second.at(3));
int corr_x = itemRoi.front().second.at(0) - width / 2.0;
int corr_y = itemRoi.front().second.at(1) - height / 2.0;
Rect rect = Rect(corr_x, corr_y, width, height);
Mat roiMat = _Img(rect);
Mat backCandidateMat = paramIn.backGround(rect);
//Mat forMat = abs(roiMat - backCandidateMat);
luffy_base::luffyCircle pCircle;
findCircleObject(roiMat, backCandidateMat, paramIn.backgroundThresh, &pCircle);
rstMat = findCircleObject(_Img, paramIn.backGround, paramIn.backgroundThresh, NULL);
float axis_x = corr_x + pCircle.ptCenter.x;
float axis_y = corr_y + pCircle.ptCenter.y;
return Point2f(axis_x, axis_y);
}
}
luffy_base::luffyCircle pCircle;
rstMat = findCircleObject(_Img, paramIn.backGround, paramIn.backgroundThresh, &pCircle);
qDebug() << "get image";
return pCircle.ptCenter;
}
else
{
Mat centerMatch;
int nOffset = 80; //need
int templW = centerTempl.cols;
int templH = centerTempl.rows;
int nStartX = pt.x - templW / 2 - nOffset;
int nStartY = pt.y - templH / 2 - nOffset;
if (nStartX<0||nStartY<0)
return Point2f(0, 0);
if ((2 * nOffset + templH)>_Img.rows)
return Point2f(0, 0);
if ((2 * nOffset + templW)>_Img.cols)
return Point2f(0, 0);
if ((2 * nOffset + templH+nStartY) > _Img.rows)
return Point2f(0, 0);
if ((2 * nOffset + templW+nStartX) > _Img.cols)
return Point2f(0, 0);
Mat imgRoi;
_Img(Rect(pt.x - templW / 2 - nOffset, pt.y - templH / 2 - nOffset, 2 * nOffset + templW, 2 * nOffset + templH)).copyTo(imgRoi);
matchTemplate(imgRoi, centerTempl, centerMatch, CV_TM_CCOEFF_NORMED);
Point p;
double v = luffy_math::getMinMaxData(centerMatch, luffy_math::emDataMax, &p);
int localCenterX = p.x + templW / 2;
int localCenterY = p.y + templH / 2;
int newCenterX = pt.x - templW / 2 - nOffset + localCenterX;
int newCenterY = pt.y - templH / 2 - nOffset + localCenterY;
/*Mat img1 = _Img.clone();
Mat img2 = _Img.clone();
Mat img3 = _Img.clone();
vector<Mat> imgs;
imgs.push_back(img1);
imgs.push_back(img2);
imgs.push_back(img3);
Mat rst;
merge(imgs, rst);
cv::circle(rst, Point(newCenterX, newCenterY), 3, Scalar(255), -1);*/
return Point2f(newCenterX, newCenterY);
}
}
cv::Mat ValveDetector::getForeImage(const Mat & src, const Mat &backgroundImg)
{
Mat resizedBackgroundImg = backgroundImg;
if (backgroundImg.size() != src.size()) {
resize(backgroundImg, resizedBackgroundImg, src.size());
}
qDebug() << src.cols << "" << src.rows << "" << resizedBackgroundImg.cols << "" << resizedBackgroundImg.rows;
qDebug() << src.channels() << "" << resizedBackgroundImg.channels();
Mat h = src - resizedBackgroundImg;
qDebug() << "h pass";
return (src - resizedBackgroundImg);
}
cv::Mat ValveDetector::findCircleObject(const Mat &src, const Mat& backgroundImg, int nThres, luffy_base::luffyCircle *pCircle)
{
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);// 0421
using namespace luffy_base;
luffy_threshold::Threshold(foregroundImg, imgBinary, nThres);//0421
//luffy_threshold::Threshold(imgTmp, imgBinary, nThres);
Mat dilatedImgBin;
dilate(imgBinary, dilatedImgBin, Mat::ones(7, 7, CV_32FC1));
erode(dilatedImgBin, imgBinary, Mat::ones(7, 7, CV_32FC1));
erode(imgBinary, imgBinary, Mat::ones(1, 13, CV_32FC1));
dilate(imgBinary, imgBinary, Mat::ones(1, 13, CV_32FC1));
vector<vector<Point>> conts;
cv::findContours(imgBinary, conts, RETR_EXTERNAL, CHAIN_APPROX_NONE);
imgBinary.setTo(0);
for (int i = 0; i < conts.size(); i++) {
const vector<Point> &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<Point> pts;
luffy_hit::firstHit4Circle(imgBinary, hit, pts, Point(cSize.width / 2, cSize.height / 2), 0, cSize.width / 2, 360, luffy_hit::emHitOut2In);
qDebug() << "image8";
//luffy_imageProc::RansacParam rs(0.02, 2.5, 70, 100, 220);
luffy_imageProc::RansacParam rs(0.01, 3, 200, 150, 240);//0421
vector<Point> 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<cv::Vec3b>(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<cv::Vec3b>(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);
qDebug() << "image9";
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);
imgTmp(rt).copyTo(dst);
static int nCount = cv::getTickCount();
if (pCircle) {
float fScale = src.cols / ALG_RESIZE_IMAGE_WIDTH;
Mat matBig = src - backgroundImg;//0421
//Mat matBig = src;
pCircle->fRadius = fRadius * fScale;
pCircle->ptCenter = Point(ptCenter.x * fScale, ptCenter.y * fScale);
Mat matBinary;
luffy_threshold::Threshold(matBig, matBinary, nThres);
Mat hit; vector<Point> 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, 200, 150, 220);
vector<Point> 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);
if (rt.x < 0 || rt.y < 0 || rt.x + rt.width > matBinary.cols || rt.y + rt.height > matBinary.rows) {
return Mat();
}
rt &= Rect(0, 0, matBinary.cols, matBinary.rows);
src(rt).copyTo(dst);
int nWidth = ((int)((double)dst.cols / fScale / 4)) * 4;
cv::resize(dst, dst, cv::Size(nWidth, nWidth));
}
}
return dst;
}
bool isRequiredModel(Mat &_img, InputParam &paramIn)
{
int notSatisified = 0;
Mat imgRect = _img.clone();
Mat rstImage;
luffy_match::LoopMatMatch(imgRect, imgRect, luffy_match::emLoopMatX, rstImage);
int interval = floor(paramIn.nMaxAngle / paramIn.barNum);
double minVal, maxVal;
Point minLoc, maxLoc;
cv::minMaxLoc(rstImage, &minVal, &maxVal, &minLoc, &maxLoc);
vector<int> loc;
loc.push_back(maxLoc.x);
Point getMaxLoc;
for (int i = 1; i < paramIn.barNum + 1; i++)
{
getMaxLoc = getNextMinMax(&rstImage, maxLoc, 0, paramIn);
maxLoc = getMaxLoc;
loc.push_back(getMaxLoc.x);
}
std::sort(loc.begin(), loc.end());
for (int j = 0; j < loc.size(); j++)
{
if (j + 1 >= 7)
{
break;
}
int diff = loc[j + 1] - loc[j];
int interDiff = abs(diff - interval);
if (interDiff > 10)
{
notSatisified++;
}
}
if (notSatisified > 2)
{
return false;
}
else
{
return true;
}
}
void getTargetPosAndVal(const Mat &img, InputParam &in, double &val, int &nPos)
{
vector<int> diffVec;
vector<int> vec;
vec.resize(in.barNum);
diffVec.resize(in.barNum);
Mat result = img.clone();
double minVal, maxVal;
Point minLoc, maxLoc;
minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc);
int maxLength = in.nMaxAngle;
int interval = in.nMaxAngle / in.barNum;
int barX = maxLoc.x + in.barTemplate.cols / 2;
barX = barX % maxLength;
int valveOffset = in.nValveOffset;
diffVec[0] = abs(barX - valveOffset);
vec[0] = barX;
for (int i = 1; i < diffVec.size(); i++)
{
int vOffset = barX + interval*i;
if (vOffset >=in.nMaxAngle)
{
vOffset = vOffset % maxLength;
}
diffVec[i] = abs(vOffset - valveOffset);
vec[i] = vOffset;
}
size_t valIndex = std::min_element(diffVec.begin(), diffVec.end()) - diffVec.begin();
nPos = vec[valIndex];
val = maxVal;
//nPos = barX;
}
//int matchValveScoreShoot(const vector<Mat>& rois, const Mat &templ, int candidateIndex)
//{
// cv::SurfFeatureDetector Detector(400);
// vector<KeyPoint> roiKeyPoint, templkeyPoint;
// Detector.detect(templ, templkeyPoint);
//
// SurfDescriptorExtractor Descriptor;
// Mat roiDesc, templDesc;
// Descriptor.compute(templ, templkeyPoint, templDesc);
// int Tnum = templkeyPoint.size();
// if (Tnum <3)
// {
// qDebug() << "num of template keyPoints is less than 3, need to be returned";
// return -1;
// }
// qDebug() << "the template keyPoints num ;" << Tnum;
// int tarIndex = -1;
// for (int i = 0; i < rois.size(); ++i)
// {
// const Mat &roi = rois[i];
// Detector.detect(roi, roiKeyPoint);
// Descriptor.compute(roi, roiKeyPoint, roiDesc);
// int keyNum = roiKeyPoint.size();
// if (keyNum < 3)
// {
// qDebug() << "the Point num is less than 2, need to be returned;" << keyNum;
// continue;
// }
// else
// {
// qDebug() << "the Point num success";
// }
// /*BFMatcher matcher(NORM_L2, true);
// vector<DMatch> matches;
// matcher.match(templateDesc, imageDesc2, matches);
// Mat img_match;
// drawMatches(templateMat, keyPointTemplate, rightImage, keyPoint2, matches, img_match);*/
// /*BFMatcher matcher;
// vector<DMatch> matchePoints;
// matcher.match(templDesc, roiDesc, matchePoints);*/
// /*vector<DMatch> GoodMatchePoints;
//
// double maxDis = 0, minDis = 100;
// for (int j = 0; j < matchePoints.size(); ++j)
// {
// double dis = matchePoints[j].distance;
// if (dis < minDis)
// {
// minDis = dis;
// }
//
// if (dis > maxDis)
// {
// maxDis = dis;
// }
// }
//
// for (int k = 0; k < matchePoints.size(); ++k)
// {
// if (matchePoints[k].distance < 1.2*minDis)
// {
// GoodMatchePoints.push_back(matchePoints[k]);
// }
// }*/
// FlannBasedMatcher matcher;
// vector<vector<DMatch> > matchePoints;
// vector<DMatch> GoodMatchePoints;
//
// vector<Mat> train_desc(1, templDesc);
// matcher.add(train_desc);
// qDebug() << "start training";
// matcher.train();
// qDebug() << "finish training";
//
// matcher.knnMatch(roiDesc, matchePoints, 2);
// qDebug()<<"finish match";
//
// //vector<DMatch> GoodMatchePoints;
// for (int j = 0; j < matchePoints.size(); j++)
// {
// if (matchePoints[j][0].distance < 0.6 * matchePoints[j][1].distance)
// {
// GoodMatchePoints.push_back(matchePoints[j][0]);
// }
// }
// int maxVal = -1;
// int num = 0;
//
// Mat ShowResult;
// int x = GoodMatchePoints.size();
// if (GoodMatchePoints.size() <= 0)
// {
// continue;
// }
// else
// {
// if (x > maxVal)
// {
// maxVal = GoodMatchePoints.size();
// tarIndex = i;
// }
// }
// //Mat ShowResult;
// //drawMatches(roi, roiKeyPoint, templ, templkeyPoint, GoodMatchePoints, ShowResult);
// }
//
// return tarIndex;
//}
int roiCandidateMatch(const vector<Mat> &vec, Mat templ)
{
vector<float> candidateVal;
candidateVal.resize(vec.size());
for (int i = 0; i < vec.size(); ++i)
{
Mat roi = vec[i];
Mat roiMatch;
luffy_match::LoopMatMatch(roi, templ, luffy_match::emLoopMatX, roiMatch);
Point pt3;
double v3 = luffy_math::getMinMaxData(roiMatch, luffy_math::emDataMax, &pt3);
candidateVal[i] = v3;
}
auto val = std::max_element(candidateVal.begin(), candidateVal.end());
int index = std::distance(candidateVal.begin(), val);
return index;
}
bool imageRotateMatch(Mat & imgSrc, InputParam &paramIn, OutputParam &paramOut, vector<double> candidatePoints)
{
float templateAngle = paramIn.nValveOffset / paramIn.nMaxAngle * 360;
Mat imgTemplate = paramIn.imgTemplate;
vector<Mat> templates;
templates.resize(360);
int rotateOffset = 15;
int x = imgTemplate.cols / 2 - rotateOffset;
int y = imgTemplate.rows / 2 - rotateOffset;
int width = imgTemplate.cols - 2 * x;
int height = imgTemplate.rows - 2 * y;
Rect rect = Rect(x, y, width, height);
for (int i = templateAngle, j = 0; i < 360 + templateAngle, j < 360; ++i, ++j)
{
i = i % 360;
Mat transMat = getRotationMatrix2D(Point2f(imgTemplate.cols / 2.0, imgTemplate.rows / 2.0), j, 1.0);
Mat dst;
warpAffine(imgTemplate, dst, transMat, imgTemplate.size());
Mat dstRoi = dst(rect);
templates[i] = dstRoi;
}
vector<vector<float>> candiateAngleRange;
candiateAngleRange.resize(candidatePoints.size());
int nOffSet = 0;
for (int x = 0; x < candidatePoints.size(); ++x)
{
float startIndex = candidatePoints[x] - templates[0].cols / 2.0 - nOffSet;
startIndex = luffy_math::mod(startIndex, paramIn.nMaxAngle);
float holeStartAngle = startIndex / paramIn.nMaxAngle * 360;
float endIndex = candidatePoints[x] + templates[0].cols + nOffSet;
float holeEndAngle = 0.0;
if (endIndex > paramIn.nMaxAngle)
{
holeEndAngle = fmod(endIndex, paramIn.nMaxAngle) / paramIn.nMaxAngle * 360;
}
else
{
holeEndAngle = endIndex / paramIn.nMaxAngle * 360;
}
candiateAngleRange[x].push_back(holeStartAngle);
candiateAngleRange[x].push_back(holeEndAngle);
}
float fvalveWidth = paramIn.fValveWidth;
float fvalveDis = paramIn.fValveDis;
Point wheelCenter = paramIn.ptCenter;
int offset = 30;
Mat srcImg = imgSrc.clone();
int outterRadius = fvalveDis + offset;
int innerRadius = fvalveDis - offset;
Mat wheelRoi = srcImg(Rect(wheelCenter.x - outterRadius, wheelCenter.y - outterRadius, outterRadius * 2, outterRadius * 2));
Mat wheelRoiMask(wheelRoi.size(), wheelRoi.type(), Scalar::all(0));
cv::circle(wheelRoiMask, Point2f(wheelRoi.cols / 2.0, wheelRoi.rows / 2.0), outterRadius, Scalar::all(255), -1);
cv::circle(wheelRoiMask, Point2f(wheelRoi.cols / 2.0, wheelRoi.rows / 2.0), innerRadius, Scalar::all(0), -1);
Mat selectRoi = (wheelRoiMask / 255).mul(wheelRoi);
/*vector<Mat> imgs;
Mat img1 = selectRoi.clone();
Mat img2 = selectRoi.clone();
imgs.push_back(selectRoi);
imgs.push_back(img2);
imgs.push_back(img1);
Mat showImage;
showImage.setTo(0);
merge(imgs, showImage);*/
/*std::map<float, Point> valToLoc;*/
////qDebug() << "start";
//float sumVal = 0;
Point p = Point(0, 0);
float maxVal = _I32_MIN;
float m_Index = 0.0;
Mat roi;
roi.setTo(0);
for (int k = 0; k < selectRoi.rows; ++k)
{
//uchar *ptr = selectRoi.row(k).data;
for (int m = 0; m < selectRoi.cols; ++m)
{
//qDebug() << "k:" << k << "m :" << m ;
float dis = luffy_math::disofPoints(Point2f(m, k), Point2f(wheelRoi.cols / 2.0, wheelRoi.rows / 2.0));
if (dis > outterRadius || dis < innerRadius)
{
continue;
}
float nIndex = luffy_math::caculAngle(Point2f(wheelRoi.cols / 2.0, wheelRoi.rows / 2.0), Point2f(m, k));
int flag = false;
for (int y = 0; y < candiateAngleRange.size(); ++y)
{
if (candiateAngleRange[y][0] > candiateAngleRange[y][1])
{
if ((nIndex >= candiateAngleRange[y][0] && nIndex < 360) || (nIndex >=0 && nIndex <=candiateAngleRange[y][1]))
{
const Mat& templ = templates[nIndex];
int nwidth = templ.cols;
int nheight = templ.rows;
if ((m + nwidth >= outterRadius * 2) || (k + nheight > outterRadius * 2))
{
continue;
}
Mat matchRoi = selectRoi(Rect(m, k, nwidth, nheight));
Mat val;
cv::matchTemplate(matchRoi, templ, val, CV_TM_CCOEFF_NORMED);
//float val = norm(matchRoi, templ, NORM_L2);
if (val.at<float>(0, 0) > maxVal)
{
maxVal = val.at<float>(0, 0);
p = Point(m, k);
m_Index = nIndex;
roi = matchRoi;
}
}
}
if (nIndex >= candiateAngleRange[y][0] && nIndex <= candiateAngleRange[y][1])
{
//selectRoi.at<uchar>(k, m) = 0;
const Mat& templ = templates[nIndex];
int nwidth = templ.cols;
int nheight = templ.rows;
if ((m + nwidth >= outterRadius * 2) || (k + nheight > outterRadius * 2))
{
continue;
}
Mat matchRoi = selectRoi(Rect(m, k, nwidth, nheight));
Mat val;
cv::matchTemplate(matchRoi, templ, val, CV_TM_CCOEFF_NORMED);
//float val = norm(matchRoi, templ, NORM_L2);
if (val.at<float>(0, 0) > maxVal)
{
maxVal = val.at<float>(0, 0);
p = Point(m, k);
m_Index = nIndex;
roi = matchRoi;
}
}
}
}
}
Point2f pLoc = Point2f(p.x + templates.front().cols / 2.0, p.y + templates.front().rows / 2.0);
paramOut.rstPoint = paramIn.ptCenter + pLoc - Point2f(wheelRoi.cols / 2.0, wheelRoi.rows / 2.0);
paramOut.dAngleRes = m_Index;
paramOut.dScore = maxVal;
paramIn.fValveWidth = templates.front().cols / 2.0;
//cv::rectangle(showImage, p, Point(p.x + templates[0].cols, p.y + templates[0].rows), Scalar(0, 0, 255), 2, 8, 0);
double disVal = tempScoreShoot(roi, templates[55], detectMode::shootTargetMatch);
return true;
}
bool ValveDetector::detect(Mat & imgSrc, InputParam &paramIn, OutputParam &paramOut, Mat &imgDst /*= Mat()*/)
{
int rtWidth = 100;
if (paramIn.ptCenter.x - rtWidth < 0 || paramIn.ptCenter.y - rtWidth < 0)
return false;
if (paramIn.ptCenter.x + 2 * rtWidth > imgSrc.cols)
return false;
if (paramIn.ptCenter.y + 2 * rtWidth>imgSrc.rows)
return false;
if (paramIn.barNum <= 0)
return false;
cv::Mat imgCenter = imgSrc(Rect(paramIn.ptCenter.x - rtWidth, paramIn.ptCenter.y - rtWidth, 2 * rtWidth, 2 * rtWidth));
Scalar scMean = cv::mean(imgCenter);
if (scMean[0] < 20) {
paramOut.dAngle = 3610;
paramOut.dScore = 0;
}
else {
float fValveWidth = paramIn.fValveWidth;
float fValveDis = paramIn.fValveDis;
int offset = 10;
int nImgHeight = fValveWidth * 2 + 2 * offset;
Mat img2Rect;
paramIn.ptCenter = Point(paramIn.ptCenter.x , paramIn.ptCenter.y);
luffy_math::polar2rect(imgSrc, img2Rect, paramIn.ptCenter,
fValveDis - nImgHeight / 2, fValveDis + nImgHeight / 2, paramIn.nMaxAngle);
Mat imgMatch, barCompare;
if (paramIn.flagCircle == 1 )
{
luffy_match::LoopMatMatch(img2Rect, paramIn.barTemplate, luffy_match::emLoopMatX, barCompare);
double score = 0;
int tarPos;
getTargetPosAndVal(barCompare, paramIn, score, tarPos);
paramOut.dAngle = tarPos;
paramOut.dScore = score;
}
else
{
luffy_match::LoopMatMatch(img2Rect, paramIn.barTemplate, luffy_match::emLoopMatX, barCompare);
vector<Point> candidatePoints;
findCandidateValsInMat(barCompare, candidatePoints, paramIn);
int bIsNotStatisfy = 0;
Mat imgRect = img2Rect.clone();
for (int i = 0; i < candidatePoints.size(); i++)
{
int rectW = paramIn.barTemplate.cols;
int rectH = img2Rect.rows;
if ((candidatePoints[i].x + rectW) > img2Rect.cols)
{
rectW = img2Rect.cols - candidatePoints[i].x;
int leftOffset = candidatePoints[i].x + paramIn.barTemplate.cols - img2Rect.cols;
img2Rect(Rect(0, 0, leftOffset, rectH)).setTo(0);
}
Rect rToBeErease(candidatePoints[i].x, 0, rectW, rectH);
img2Rect(rToBeErease).setTo(0);
Mat barRoi = LoopRoi(barCompare, candidatePoints[i].x, paramIn.barTemplate.cols);
double dx = luffy_math::getMinMaxData(barRoi, luffy_math::emDataMax);
if (dx < paramIn.nBarScore / 100.0) {
bIsNotStatisfy++;
}
}
if (bIsNotStatisfy < 2) {
vector<double> detectedOffset;
findOffsets(paramIn, candidatePoints, detectedOffset);
//Mat iMask(img2Rect.size(), img2Rect.type(), Scalar::all(0));
//creatMask(img2Rect, detectedOffset, paramIn, iMask);
vector<Mat> vecImg;
int nOffset = 10;
for (int i = 0; i < detectedOffset.size(); i++) {
int nStart = detectedOffset.at(i) - paramIn.imgTemplate.cols / 2.0 - nOffset;
nStart = luffy_math::mod(nStart, paramIn.nMaxAngle);
Mat roi = LoopRoi(imgRect, nStart, paramIn.imgTemplate.cols + 2 * nOffset);
Mat roi2 = roi(Rect(0, 0, roi.cols, roi.rows *3.0 / 5));
// Mat roi3;
// float m = 128; float d = 70.0;
// luffy_imageProc::meanvarnorm(roi2, roi3, m, d);
if (paramIn.wheelType == 0)
{
vecImg.push_back(roi2);
}
else
{
vecImg.push_back(roi);
}
}
// FOR MOTORCIRCLE PROGRAM START
Mat ret(vecImg.size(), vecImg.size(), CV_32FC1, Scalar(0));
for (int i = 0; i < vecImg.size(); i++) {
for (int j = 0; j < vecImg.size(); j++) {
Mat imgMatch2;
Point pt;
Mat templ;
luffy_match::LoopMatMatch(vecImg.at(i), vecImg.at(j), luffy_match::emLoopMatY, imgMatch2);
double v = luffy_math::getMinMaxData(imgMatch2, luffy_math::emDataMax, &pt);
ret.at<float>(i, j) = v;
}
}
float fMin = 1000;
int nIndex = 0;
std::map<float, int> scoreMapIndex;
for (int i = 0; i < ret.cols; i++) {
float fSum = sum(ret.col(i))[0];
scoreMapIndex[fSum] = i;
if (fSum < fMin) {
fMin = fSum;
nIndex = i;
}
}
std::map<float, int>::iterator it = scoreMapIndex.begin();
int candidateIndex = 0;
int ni = 0;
for (; it != scoreMapIndex.end(); ++it, ++ni)
{
if (ni == 1)
{
candidateIndex = it->second;
}
}
//FOR MOTORCIRCLE END
double mcutOffset = 1.0;
float ss = 0.0;
if (paramIn.wheelType == 0)
{
mcutOffset = 2.0;
// FOR MOTORCIRCLE PROGRAM START
Mat imgTemplate = paramIn.imgTemplate(Rect(0, 0, paramIn.imgTemplate.cols, paramIn.imgTemplate.rows / mcutOffset));
Mat ret0;
matchTemplate(vecImg[nIndex], imgTemplate, ret0, CV_TM_CCORR_NORMED);
Point p0;
double v0 = luffy_math::getMinMaxData(ret0, luffy_math::emDataMax, &p0);
Mat ret1;
matchTemplate(vecImg[candidateIndex], imgTemplate, ret1, CV_TM_CCORR_NORMED);
Point p1;
double v1 = luffy_math::getMinMaxData(ret1, luffy_math::emDataMax, &p1);
nIndex = v1 > v0 ? candidateIndex : nIndex;
Mat identicalImg = vecImg[nIndex](Rect(10, 0, imgTemplate.cols, imgTemplate.rows));
double disVal = tempScoreShoot(identicalImg, imgTemplate, detectMode::shootTargetMatch);
std::vector<Mat> vecMat;
auto imgCrop = [&](Mat srcMat, std::vector<Mat>& vecMat){
int rightTopX = srcMat.cols - imgTemplate.cols;
int leftDownY = srcMat.rows - imgTemplate.rows;
Mat rightTopMat = srcMat(Rect(rightTopX, 0, imgTemplate.cols, imgTemplate.rows));
Mat leftDownMat = srcMat(Rect(0, leftDownY, imgTemplate.cols, imgTemplate.rows));
Mat rightDownMat = srcMat(Rect(rightTopX, leftDownY, imgTemplate.cols, imgTemplate.rows));
vecMat.push_back(rightTopMat);
vecMat.push_back(leftDownMat);
vecMat.push_back(rightDownMat);
};
imgCrop(vecImg[nIndex], vecMat);
for each (Mat vMat in vecMat)
{
double s = tempScoreShoot(vMat, imgTemplate, detectMode::shootTargetMatch);
if (s > disVal)
{
disVal = s;
}
}
int targetIndex = nIndex;
float maxVal = disVal;
if (disVal < 0.85)
{
float vMax = FLT_MIN;
for (int k = 0; k < vecImg.size(); k++)
{
if (k == nIndex)
{
continue;
}
else
{
Mat imgRet;
matchTemplate(vecImg[k], imgTemplate, imgRet, CV_TM_CCORR_NORMED);
Point pnt;
double v3 = luffy_math::getMinMaxData(imgRet, luffy_math::emDataMax, &pnt);
if (v3 > vMax)
{
targetIndex = k;
vMax = v3;
}
}
}
/*identicalImg = vecImg[targetIndex](Rect(10, 0, imgTemplate.cols, imgTemplate.rows));
vector<Mat> localMatVec;
imgCrop(vecImg[targetIndex], localMatVec);
for each (Mat mat in localMatVec)
{
double s = tempScoreShoot(mat, imgTemplate, detectMode::shootTargetMatch);
if (s > disVal)
{
disVal = s;
}
}
*/
/*disVal = tempScoreShoot(identicalImg, imgTemplate, detectMode::shootTargetMatch);
if (disVal > maxVal)
{
maxVal = disVal;
targetIndex = k;
}*/
}
nIndex = targetIndex;
Mat imgMatchRet;
matchTemplate(vecImg[nIndex], imgTemplate, imgMatchRet, CV_TM_CCORR_NORMED);
Point pt3;
double v3 = luffy_math::getMinMaxData(imgMatchRet, luffy_math::emDataMax, &pt3);
float nPos = pt3.x + detectedOffset.at(nIndex) - nOffset;
paramOut.dAngle = fmod(nPos, (double)paramIn.nMaxAngle);
paramOut.dScore = v3;
}
else
{
Rect ret = Rect(0, 0, paramIn.imgTemplate.cols, paramIn.imgTemplate.rows / mcutOffset);
if (paramIn.imgTemplate.cols <= 0 || paramIn.imgTemplate.rows / mcutOffset <= 0 || paramIn.imgTemplate.rows / mcutOffset > paramIn.imgTemplate.rows)
return false;
Mat imgTemplate = paramIn.imgTemplate(ret);
PatternDetector m_detect;
m_detect.train(imgTemplate);
Vec4f t_vec;
int m_posIndex = 0;
float maxVal = 0;
int m_index = 0;
for (int k = 0; k < vecImg.size(); k++)
{
Mat roiMat = vecImg[k];
float score = m_detect.detectBest(roiMat, t_vec);
if (score > maxVal)
{
maxVal = score;
m_posIndex = t_vec[0];
m_index = k;
}
}
//Mat imgMatchRet;
//int m_index = roiCandidateMatch(vecImg, imgTemplate);
//matchTemplate(vecImg[nIndex], imgTemplate, imgMatchRet, CV_TM_CCORR_NORMED);
//Point pt3;
// double v3 = luffy_math::getMinMaxData(imgMatchRet, luffy_math::emDataMax, &pt3);
float nPos = m_posIndex + detectedOffset.at(m_index) - nOffset - imgTemplate.cols / 2.0;
paramOut.dAngle = fmod(nPos, (double)paramIn.nMaxAngle);
//paramOut.dScore = disVal;
paramOut.dScore = maxVal / 100.0;
}
//}
}
else {
qDebug() << "bar check is failed";
paramOut.dAngle = 3610;
paramOut.dScore = 0;
}
}
}
if (paramOut.dScore < paramIn.dScoreThres / 100.0 )
{
paramOut.nErrorType += 8;
}
paramOut.bIsFind = true;
return true;
}
void ValveDetector::drawResult(Mat &img, InputParam &paramIn, OutputParam &paramOut)
{
if (img.empty()) {
return;
}
QString strObj = paramIn.strObj;
QString str = "type: " + (strObj.isEmpty() ? "no type" : strObj);
putText(img, str.toLatin1().data(), Point(10, 100), 3, 3, LP_COLOR_RED, 3);
QString strAngle;
if (!paramOut.bIsFind) {
strAngle = "result: can not find valve";
}
else {
strAngle = "result: " + QString::number(paramOut.dAngleRes, 'f', 2);
}
putText(img, strAngle.toLatin1().data(), Point(10, 200), 3, 3, LP_COLOR_RED, 3);
QString strScore;
QString strComp = ">";
if ((paramOut.nErrorType & 0x08) || (paramOut.nErrorType & 0x16)) {
strComp = "<";
}
strScore = "score=" + QString::number((paramOut.dScore)*100.0, 'f', 2) + "%" + strComp + QString::number(paramIn.dScoreThres, 'f', 2) + "%";
putText(img, strScore.toLatin1().data(), Point(10, 400), 3, 3, LP_COLOR_RED, 3);
str = "time: " + QString::number((int)paramOut.dTime) + "ms";
putText(img, str.toLatin1().data(), Point(10, 300), 3, 3, LP_COLOR_RED, 3);
str = "errorType: " + QString::number(paramOut.nErrorType);
putText(img, str.toLatin1().data(), Point(10, 500), 3, 3, LP_COLOR_RED, 3);
if (paramOut.flag == 1)
{
str = "Attention: center need to be ccalibrated";
putText(img, str.toLatin1().data(), Point(10, 600), 3, 3, LP_COLOR_RED, 3);
}
if (paramOut.nErrorType & 0x16) {
strComp = ">";
}
else
{
strComp = "<";
}
if (paramOut.showMatchScore >= 0)
{
str = "model judge score = " + QString::number(paramOut.showMatchScore, 'f', 4) + strComp + QString::number(paramIn.cMatchScore, 'f', 4);
putText(img, str.toLatin1().data(), Point(10, 700), 3, 3, LP_COLOR_RED, 3);
}
if (paramOut.bIsFind) {
//<! base line
luffy_base::luffy_triangle::createNewTrigValue(paramIn.nMaxAngle);
int tmpX2 = paramIn.ptCenter.x + paramIn.fValveDis * luffy_base::luffy_triangle::getCos(paramIn.nMaxAngle, paramIn.nValveOffset);
int tmpY2 = paramIn.ptCenter.y - paramIn.fValveDis * luffy_base::luffy_triangle::getSin(paramIn.nMaxAngle, paramIn.nValveOffset);
qDebug() << "x, y : " << tmpX2 << tmpY2;
Point ptValveBase(tmpX2, tmpY2);
cv::line(img, paramIn.ptCenter, ptValveBase, LP_COLOR_GREEN, 2);
//cv::circle(img, paramIn.ptCenter, paramIn.fValveDis, LP_COLOR_GREEN, 2);
//cv::circle(img, ptValveBase, paramIn.fValveWidth, LP_COLOR_GREEN, 2);
cv::circle(img, ptValveBase, 3, LP_COLOR_GREEN, 3);
//<! result line
int angle = paramOut.dAngle >= paramIn.nMaxAngle ? 0 : paramOut.dAngle;
int tmpX = paramIn.ptCenter.x + paramIn.fValveDis * luffy_base::luffy_triangle::getCos(paramIn.nMaxAngle, angle);
int tmpY = paramIn.ptCenter.y - paramIn.fValveDis * luffy_base::luffy_triangle::getSin(paramIn.nMaxAngle, angle);
Point ptValve(tmpX, tmpY);
cv::line(img, paramIn.ptCenter, ptValve, LP_COLOR_RED, 2);
cv::circle(img, ptValve, paramIn.fValveWidth, LP_COLOR_RED, 2);
cv::circle(img, ptValve, 3, LP_COLOR_BLUE, 3);
}
cv::circle(img, paramIn.ptCenter, 3, LP_COLOR_BLUE, 2);
if (paramIn.nCenterAlg == 1)
{
cv::circle(img, paramIn.originalPoint, 3, LP_COLOR_GREEN, 2);
}
//imwrite("C:\\Users\\Administrator\\Desktop\\1\\1.bmp", img);
}
double ValveDetector::ruleData(double dAngle, int nType)
{
if (0 != nType) {
dAngle = 361;
}
if (dAngle < 0) {
dAngle += 360.0;
}
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
int r = rand() % 100;
double dr = r / 4000.0;
dAngle += dr;
if (dAngle >= 359.99 && dAngle < 360.0)
{
dAngle += 0.01;
}
if (dAngle < 361.0 && dAngle >= 360.0)
{
dAngle -= 360;
}
return dAngle;
}
QString ValveDetector::genResultTip(QString str, int nType)
{
if (nType & 0x0001) {
// no image
str += "no image; ";
}
if (nType & 0x0002) {
// no obj
str += "no obj; ";
}
if (nType & 0x0004) {
// lost calibrate info
str += "no cali info; ";
}
if (nType & 0x0008) {
// less than score th
str += "less than scoreTh; ";
}
if (nType &0x0010)
{
str += "model is not matched; ";
}
return str;
}
cv::Point2f ValveDetector::getCenter(Mat & imgSrc, Point2f pt, InputParam &paramIn)
{
if (0 == paramIn.nCenterAlg) {
return pt;
}
Mat imgBinary;
int nOffset = 80; //need
Mat imgRoi;
imgSrc(Rect(pt.x - nOffset, pt.y - nOffset, 2 * nOffset, 2 * nOffset)).copyTo(imgRoi);
cv::threshold(imgRoi, imgBinary, 40, 255.0, THRESH_BINARY_INV);
vector<vector<Point>> con;
Rect rect = Rect(0, 0, imgBinary.cols, imgBinary.rows);
if (rect.width > imgBinary.cols || rect.height > imgBinary.rows)
return pt;
cv::rectangle(imgBinary, rect, Scalar(255), 1);
cv::findContours(imgBinary.clone(), con, RETR_EXTERNAL, CHAIN_APPROX_NONE);
bool bFind = false;
Point2f ptNew;
for (int i = 0; i < con.size(); i++) {
const vector<Point>& c = con.at(i);
if (c.size() < 20) {
continue;
}
Rect rt = boundingRect(c);
if (abs(rt.width - rt.height) > 5) {
continue;
}
int nArea = luffy_blob::getArea(imgBinary.size(), c);
double r = (rt.width + rt.height) / 4.0;
double d = nArea / r /r;
if (d < 2.5) {
continue;
}
bFind = true;
ptNew.x = rt.x + rt.width / 2.0 + pt.x - nOffset;
ptNew.y = rt.y + rt.height / 2.0 + pt.y - nOffset;
}
if (bFind) {
return ptNew;
}
return pt;
}
bool ValveDetector::saveResult(Mat &img, InputParam &paramIn, OutputParam &paramOut, QString modelStr)
{
if (0 == paramOut.nErrorType) {
return true;
}
QString strName = "";
strName += "time" + QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss-zzz") + "error=" + QString::number(paramOut.nErrorType);
strName += ".bmp";
QString strPath = qApp->applicationDirPath() + "//errorImage//";
QString str = strPath + modelStr + "\\";
QDir fileInfo(strPath);
if (fileInfo.exists())
{
QDir errorFile(str);
if (!errorFile.exists())
{
fileInfo.mkdir(str);
}
}
strName = str + strName;
bool bSave = cv::imwrite(strName.toLocal8Bit().data(), img);
qDebug() << "save error image:" << bSave;
return true;
}
void ValveDetector::drawToImage(Mat &img, InputParam &paramIn, OutputParam &paramOut)
{
if (img.empty())
{
return;
}
QString strObj = paramIn.strObj;
QString str = "type: " + (strObj.isEmpty() ? "no type" : strObj);
putText(img, str.toLatin1().data(), Point(10, 100), 3, 3, LP_COLOR_RED, 3);
QString strAngle;
if (!paramOut.bIsFind) {
strAngle = "result: can not find valve";
}
else {
strAngle = "result: " + QString::number(paramOut.dAngleRes, 'f', 2);
}
putText(img, strAngle.toLatin1().data(), Point(10, 200), 3, 3, LP_COLOR_RED, 3);
QString strScore;
QString strComp = ">";
if (paramOut.nErrorType & 0x08) {
strComp = "<";
}
strScore = "score=" + QString::number((paramOut.dScore)*100.0, 'f', 2) + "%" + strComp + QString::number(paramIn.dScoreThres, 'f', 2) + "%";
putText(img, strScore.toLatin1().data(), Point(10, 400), 3, 3, LP_COLOR_RED, 3);
str = "time: " + QString::number((int)paramOut.dTime) + "ms";
putText(img, str.toLatin1().data(), Point(10, 300), 3, 3, LP_COLOR_RED, 3);
str = "errorType: " + QString::number(paramOut.nErrorType);
putText(img, str.toLatin1().data(), Point(10, 500), 3, 3, LP_COLOR_RED, 3);
if (paramOut.bIsFind) {
//<! base line
luffy_base::luffy_triangle::createNewTrigValue(paramIn.nMaxAngle);
int tmpX2 = paramIn.ptCenter.x + paramIn.fValveDis * luffy_base::luffy_triangle::getCos(paramIn.nMaxAngle, paramIn.nValveOffset);
int tmpY2 = paramIn.ptCenter.y - paramIn.fValveDis * luffy_base::luffy_triangle::getSin(paramIn.nMaxAngle, paramIn.nValveOffset);
Point ptValveBase(tmpX2, tmpY2);
cv::line(img, paramIn.ptCenter, ptValveBase, LP_COLOR_GREEN, 2);
//cv::circle(img, paramIn.ptCenter, paramIn.fValveDis, LP_COLOR_GREEN, 2);
//cv::circle(img, ptValveBase, paramIn.fValveWidth, LP_COLOR_GREEN, 2);
cv::circle(img, ptValveBase, 3, LP_COLOR_GREEN, 3);
//<! result line
cv::line(img, paramIn.ptCenter, paramOut.rstPoint, LP_COLOR_RED, 2);
cv::circle(img, paramOut.rstPoint, paramIn.fValveWidth, LP_COLOR_RED, 2);
cv::circle(img, paramOut.rstPoint, 3, LP_COLOR_BLUE, 3);
}
cv::circle(img, paramIn.ptCenter, 3, LP_COLOR_BLUE, 2);
}