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.

331 lines
8.7 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "QAlgDetect.h"
#include "ED.h"
#include "EDLines.h"
#include "EDCircles.h"
#include <QDebug>
#include <vector>
#include "CircleDetector.h"
#include "ICompareModel.h"
#include "QFunctionTransfer.h"
using namespace std;
static QImage cvMat2QImage(const cv::Mat& mat) {
if (mat.type() == CV_8UC1) {
QImage image(mat.cols, mat.rows, QImage::Format_Indexed8);
image.setColorCount(256);
for (int i = 0; i < 256; i++) {
image.setColor(i, qRgb(i, i, i));
}
uchar *pSrc = mat.data;
for (int row = 0; row < mat.rows; row++) {
uchar *pDest = image.scanLine(row);
memcpy(pDest, pSrc, mat.cols);
pSrc += mat.step;
}
return image;
}
else if (mat.type() == CV_8UC3) {
const uchar *pSrc = (const uchar*)mat.data;
QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
if (image.isNull())
return QImage();
return image.rgbSwapped();
}
else if (mat.type() == CV_8UC4) {
const uchar *pSrc = (const uchar*)mat.data;
QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
return image.copy();
}
else {
qDebug() << "ERROR: Mat could not be converted to QImage.";
return QImage();
}
}
static cv::Mat QImageToMat(QImage image) {
cv::Mat mat;
QImage::Format f = image.format();
switch (image.format())
{
case QImage::Format_ARGB32:
case QImage::Format_RGB32:
case QImage::Format_ARGB32_Premultiplied:
mat = cv::Mat(image.height(), image.width(), CV_8UC4, (void*)image.constBits(), image.bytesPerLine());
break;
case QImage::Format_RGB888:
mat = cv::Mat(image.height(), image.width(), CV_8UC3, (void*)image.constBits(), image.bytesPerLine());
cv::cvtColor(mat, mat, CV_BGR2RGB);
break;
case QImage::Format_Indexed8:
case QImage::Format_Grayscale8:
mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void*)image.constBits(), image.bytesPerLine());
break;
}
return mat;
}
Mat _EnhanImg_sharpen(const Mat &img) {
int mGainValue = 3;
float amount = mGainValue * 0.5f;
Mat blurred;
int mSmoothValue = 3;
GaussianBlur(img, blurred, Size(), mSmoothValue);
Mat lowContrastMask = abs(img - blurred) < 5;
Mat orResult = img * (1 + amount) + blurred * (-amount);
img.copyTo(orResult, lowContrastMask);
Mat openMat = orResult.clone();
return openMat;
}
Mat findEdge2(const Mat &Src)
{
Mat ret = Src.clone();
Mat kernel = (Mat_<float>(5, 5) <<
-1, -1, -1, -1, -1,
-1, -1, -1, -1, -1,
-1, -1, 24, -1, -1,
-1, -1, -1, -1, -1,
-1, -1, -1, -1, -1);
filter2D(Src, ret, CV_8UC1, kernel);
return ret;
}
QAlgDetect::QAlgDetect(QObject *parent)
: QObject(parent)
{
QFunctionTransfer::Instance();
m_pThreadPool = std::make_shared<ThreadPool>(3);
m_pThreadPool->init();
}
QAlgDetect::~QAlgDetect()
{
m_pThreadPool->stop();
m_pThreadPool->wait();
}
#define REAIZE 2
cv::Mat QAlgDetect::findCircle(cv::Mat srcImg, QVariantMap param)
{
bool bEqual = param.value("equal").toBool();
//Mat srcImg = QImageToMat(img);
if(srcImg.channels()!=1)
cv::cvtColor(srcImg, srcImg, CV_RGB2GRAY);
Mat detectImg;
Mat src = srcImg;
cv::resize(src, detectImg, cv::Size(src.cols / REAIZE, src.rows / REAIZE));
int bBaseX = detectImg.cols;
int bBaseY = detectImg.rows;
if(bEqual == true)
equalizeHist(detectImg, detectImg);//<2F><><EFBFBD><EFBFBD>ͼ<EFBFBD><CDBC><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9> ͼ<><CDBC><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><E3B2BB>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ
detectImg = _EnhanImg_sharpen(detectImg);
EDCircles edcircles(detectImg);
vector<mCircle> EDCircle = edcircles.getCircles();
double maxR = 0;
int nIndex = -1;
for (int i = 0; i < EDCircle.size(); i++)
{
int startX = EDCircle[i].center.x - EDCircle[i].r;
int startY = EDCircle[i].center.y - EDCircle[i].r;
if (startX < 0 || startY < 0)
continue;
if (EDCircle[i].center.x + EDCircle[i].r > bBaseX || EDCircle[i].center.y + EDCircle[i].r > bBaseY)
continue;
if(EDCircle[i].r< 50 )
continue;
if (EDCircle[i].r > maxR)
{
maxR = EDCircle[i].r;
nIndex = i;
}
}
if (nIndex != -1)
{
int startX = EDCircle[nIndex].center.x * REAIZE - EDCircle[nIndex].r * REAIZE;
int startY = EDCircle[nIndex].center.y * REAIZE - EDCircle[nIndex].r* REAIZE;
double radius = EDCircle[nIndex].r;
int hight = 2 * radius * REAIZE;
QPointF centerP;
centerP.setX(EDCircle[nIndex].center.x * REAIZE);
centerP.setY(EDCircle[nIndex].center.y * REAIZE);
double r = radius * REAIZE;
Mat aa = DetectCircle(srcImg, centerP, r, bEqual);
return aa;
}
else {
QPointF centerP;
centerP.setX(srcImg.cols/2);
centerP.setY(srcImg.rows/2);
double r = 0;
Mat aa = DetectCircle(srcImg, centerP, r, bEqual);
return aa;
}
}
bool QAlgDetect::detect(QImage img, QVariantMap param, AlgResultCallBack func)
{
Mat srcImg = QImageToMat(img);
if (srcImg.channels() != 1)
cv::cvtColor(srcImg, srcImg, CV_RGB2GRAY);
Task task = std::bind(&QAlgDetect::taskFunc, this, srcImg.clone(), param, func);
m_pThreadPool->AddNewTask(task);
return true;
}
Mat QAlgDetect::DetectCircle(Mat img, QPointF center, double radius,bool bEqual)
{
Mat detectImg;
if(bEqual == true)
equalizeHist(img, detectImg);
else
detectImg = img;
CircleDetector cd;
cd.setAlgoType(CircleDetector::PeakCircle);
cd.setEdgeWidth(3);
cd.setPolarity(Polarity::White2Black);
cd.setFindBy(FindBy::Best);
double difRadiusMin = radius - 100;
double difRadiusMax = radius + 150;
if (difRadiusMin < 0)
{
difRadiusMin = 0;
if (radius > 0)
{
difRadiusMax = abs(center.y() - (img.cols / 2)) - 50;
}
else
{
int minV = (img.rows / 2) > (img.cols / 2) ? (img.cols / 2) : (img.rows / 2);
difRadiusMax = minV - 50;
center.setX(img.cols / 2);
center.setY(img.rows / 2);
}
}
cd.setRadii(difRadiusMin, difRadiusMax);
cd.setACThres(3);
vector<float> allScores;
Vec3f bestCircle;
float bestScore = cd.detectBest(detectImg, Point2f(center.x(), center.y()), bestCircle, &allScores);
if (abs(bestScore) <= FLT_EPSILON || bestCircle == Vec3f::zeros()) {
return Mat();
}
QPointF cen(bestCircle[0], bestCircle[1]);
double r = bestCircle[2];
Rect rect;
rect.x = cen.x() - r;
rect.y = cen.y() - r;
if (rect.x < 0)
rect.x = 0;
if (rect.y < 0)
rect.y = 0;
rect.width = 2 * r;
rect.height = 2 * r;
Mat s = img(rect);
return s;
}
QString QAlgDetect::matchTemplate(const QMap<QString, IWheelModel*>* modelMap, cv::Mat detectImg, double* pMinDis /*= NULL*/, int minDisNum /*= -1*/) const
{
double minDis = DBL_MAX;
QString bestName = "NG";
vector<double> disVec(modelMap->size());
int nIndex = 0;
if (!modelMap)
return bestName;
QStringList strDetectModels = modelMap->keys();
QMap<QString, double> simularModelMap;
while (strDetectModels.size())
{
QString strModelName = strDetectModels.takeFirst();
if (!modelMap->contains(strModelName))
continue;
QMap<QString, IWheelModel*>::const_iterator itsModel = modelMap->find(strModelName);
disVec[nIndex] = DBL_MAX;
IWheelModel *pWheel = itsModel.value();
if (!pWheel)
break;
QString name = strModelName;
ICompareModel* pModel = pWheel->getImageComModel();
if (pModel->getBaseImg().data == NULL)
{
nIndex++;
continue;
}
pModel->setIsEnableCache(false);
double dis = pModel->compare(detectImg, NULL, true, 1);
double disThre = pModel->getDisThre();
double innerCircleNum = pModel->getInnerCircleNum();
if (dis < disThre) {
simularModelMap[name] = innerCircleNum;
}
disVec[nIndex] = dis;
if (dis < minDis && dis != -1) {
minDis = dis;
bestName = name;
}
nIndex++;
}
if (pMinDis) {
*pMinDis = minDis;
}
if (minDisNum > 1) {
sort(disVec.begin(), disVec.end());
std::copy_n(disVec.begin(), minDisNum, pMinDis);
}
return bestName;
}
void QAlgDetect::taskFunc(cv::Mat srcImg, QVariantMap param, AlgResultCallBack func)
{
double dStart = cv::getTickCount();
QVariantMap rltMap;
cv::Mat circleMat = findCircle(srcImg, param);
long long modelMapPtr = param.value("modelMap").toLongLong();
QMap<QString, IWheelModel*> *ptr = (QMap<QString, IWheelModel*>*)modelMapPtr;
if (!circleMat.empty()&&ptr&&ptr->size()>0)
{
vector<double> minDisVec(ptr->size());
QString strName = matchTemplate(ptr, circleMat, &(minDisVec[0]), minDisVec.size());
rltMap.insert("modeName", strName);
rltMap.insert("minDis", minDisVec[0]);
if (ptr->contains(strName) && ptr->value(strName)->getImageComModel()) {
ICompareModel *pModel = ptr->value(strName)->getImageComModel();
double d = pModel->getDisThre();
double dValue = (d - minDisVec[0]) / d * 0.4 + 0.6;
rltMap.insert("score", dValue);
}
}
QImage srcImage = cvMat2QImage(srcImg);
QImage resultImage = cvMat2QImage(circleMat);
rltMap.insert("SrcImage", srcImage);
rltMap.insert("ResImage", resultImage);
double dTime = (cv::getTickCount() - dStart) / cv::getTickFrequency();
rltMap.insert("runTime", dTime);
if (func) {
QFunctionTransfer::Instance()->execInMain([this, rltMap, func]() {
if (func)
func(rltMap);
});
}
}