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.

330 lines
8.6 KiB
C++

#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()
{
}
#define REAIZE 4
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);
});
}
}