|
|
#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 ¢erTempl, 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 ¶mIn)
|
|
|
{
|
|
|
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 ¶mIn, OutputParam ¶mOut, 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 ¶mIn, OutputParam ¶mOut, 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 ¶mIn, OutputParam ¶mOut)
|
|
|
{
|
|
|
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 ¶mIn)
|
|
|
{
|
|
|
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 ¶mIn, OutputParam ¶mOut, 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 ¶mIn, OutputParam ¶mOut)
|
|
|
{
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
|
|
}
|