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.
wheeldetect/src/algorithm/AlgorithmFluorescence.cpp

432 lines
12 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 "AlgorithmFluorescence.h"
#include "ImageProcess.h"
#include <QVariant>
#include <QImage>
#include <QDebug>
#include <QPixmap>
#include "CVUtils.h"
#include "qtcvutils.h"
#include "Result2Ui.h"
#include "ICompareModel.h"
#include "IWheelModel.h"
#pragma execution_character_set("utf-8")
#define MAX_CIRCLE_RADII 110
#define MIN_INSIDE_RATIO 0.038
#define MAX_INSIDE_RATIO 0.072
#define INSIDE_NUM_DIS_THRE 1.5
using namespace cv;
using namespace lp;
class CLocalWheel{
public:
CLocalWheel() {
useHeight = true;
useDiameter = true;
}
cv::Mat img;
int height;
int diameter;
bool useHeight;
bool useDiameter;
QStringList defectList;
double dRatioVal{0};
int ratioType{ 0 };
};
CAlgorithmFluorescence::CAlgorithmFluorescence(void)
{
}
CAlgorithmFluorescence::~CAlgorithmFluorescence(void)
{
}
//检测算法入口函数 由corctl框架回调
int CAlgorithmFluorescence::IImageAnalysis(class IImageObject* pImgObj, TP_ALGORITHM_OPTION* pOpt, class IDetectorEngine* pDE)
{
try {
qDebug() << "start alg";
QMutexLocker locker(&mutex);
CircleParam cParam;
double dStart = cv::getTickCount();
Mat matSrc = getImage(pImgObj).clone();//获取相机原始图像
QVariantMap vMap = pImgObj->IVarFromUI().toMap();//获取由UI传递过来的算法参数
//解析出模板库指针 这里获取的是整个模块库
long long modelMapPtr = vMap.value("modelMap").toLongLong();
QMap<QString, IWheelModel*> *ptr = (QMap<QString, IWheelModel*>*)modelMapPtr;
//获取需要检测的列表 型号名
long long defectListPtr = vMap.value("defectList").toLongLong();
QStringList* strModelListptr = (QStringList*)defectListPtr;
QStringList strModelList;
if(strModelListptr)
strModelList = *(strModelListptr);
int IsCutedImg = vMap.value("IsCutImg", 0).toInt();//裁剪后的轮毂图 检测模式 小图
int th = vMap.value("thickness", -1).toInt();//轮毂厚度 轮毂高度数据
bool useThickness = vMap.value("useThickness", 0).toBool();//是否使用厚度检测判断 匹配时过滤不符合范围的模板
bool useDiameter = vMap.value("useDiameter", 0).toBool();//是否使用直径参数检测判断
double dD2H = vMap.value("d2h", -1).toDouble();
int nthreshold = vMap.value("Threshold", 15).toInt();//图像阈值参数 使用背景图抠图算法时使用
bool bUseBackground = vMap.value("useBackground",false).toBool();//true 使用背景图抠图 false 不使用背景
int ratioType = vMap.value("RatioType").toInt();//偏距检测模式 启用方式
double ratioVal = vMap.value("Ratio").toDouble();//偏距系数
bool bEqual = vMap.value("bEqual").toBool();//是否使用图像增强
int filterSize = vMap.value("filterSize").toInt();//过滤圆大小
cParam.CirclePolarity = vMap.value("Circle_Polarity",0).toInt();
cParam.CircleACThres = vMap.value("Circle_ACThres",3).toInt();
cParam.CircleEdgeWidth = vMap.value("Circle_EdgeWidth",3).toInt();
cParam.filterSize = filterSize;
if (nthreshold <= 0)
nthreshold = 15;
QVariantMap rltMap;//算法检测结果值 输出到UI用
rltMap.insert("ratioVal", ratioVal);
luffy_base::luffyCircle lCircle;
static bool bReload = false;//背景图加载判断
Mat matBack = getBackGroundImage(pImgObj, bReload);//获取背景图
Mat matMatch;//抠图后的图像 目标图像
if (IsCutedImg == 0) //使用的是原始图像 需要执行圆查找算法找出 轮毂
{
//原始图像的size和背景图size不匹配 直接返回错误提示
if (bUseBackground == true && (matSrc.size().height != matBack.size().height || matSrc.size().width != matBack.size().width))
{
rltMap.insert("error", 0);
pImgObj->IVariantMapToUI(rltMap);
bReload = true;
return 0;
}
else{
bReload = false;
}
if (bUseBackground == true)//使用背景图 做减法找圆
{
Point2f centerPoint;
double radius = 0;
matMatch = ImageProcess::findCircleByBackground(matSrc, matBack, centerPoint, radius, bEqual, filterSize, cParam);
lCircle.ptCenter = centerPoint;
lCircle.fRadius = radius;
}
else {
//不需要 背景图找圆算法
Point2f centerPoint;
double radius = 0;
matMatch = ImageProcess::findCircle(matSrc, centerPoint, radius, bEqual,filterSize,cParam);
lCircle.ptCenter = centerPoint;
lCircle.fRadius = radius;
}
if (matMatch.cols >= 1800 || matMatch.rows >= 1800)//控制检测图像大小不能超过这个范围
{
cv::resize(matMatch, matMatch, cv::Size(matMatch.cols / 2, matMatch.rows / 2));
lCircle.fRadius = lCircle.fRadius / 2;
}
}
else{
matMatch = matSrc;
}
Result2Ui *pResult = new Result2Ui;
pResult->m_pixSrc = QtCVUtils::cvMatToQPixmap(matSrc);//!>原图像发送值UI 用于保存备份和调试
if (matMatch.empty())//抠图为空,表示抠图失败,直接返回错误
{
rltMap.insert("noCircle", 0);
long long varRlt = (long long)pResult;
rltMap.insert("result", varRlt);
pImgObj->IVariantMapToUI(rltMap);
return 0;
}
double dDiameter = dD2H * lCircle.fRadius * 2;//计算轮毂直径
//打包相关数据
CLocalWheel wheelLocal;
wheelLocal.defectList = strModelList;
wheelLocal.img = matMatch.clone();
wheelLocal.height = th;
wheelLocal.diameter = dDiameter;
wheelLocal.useHeight = useThickness;
wheelLocal.useDiameter = useDiameter;
wheelLocal.ratioType = ratioType;
wheelLocal.dRatioVal = ratioVal;
//开始匹配
if (!matMatch.empty() && ptr && ptr->size() > 0) {
vector<double> minDisVec(ptr->size());//初始化模板匹配分数值
QString str = bestMatch(ptr, &wheelLocal, &(minDisVec[0]), minDisVec.size());
pResult->m_strModel = str;
pResult->m_dMinDis = minDisVec[0];
if (ptr->contains(str) && ptr->value(str)->getImageComModel()) {
ICompareModel *pModel = ptr->value(str)->getImageComModel();
double d = pModel->getDisThre();
double dValue = (d - minDisVec[0]) / d * 0.4 + 0.6;
pResult->m_dScore = dValue;
}
}
qDebug() << "pull result";
QImage img = QtCVUtils::cvMatToQImage(matMatch);
pResult->m_pixResult = QtCVUtils::cvMatToQPixmap(matMatch);// .scaled(125, 125);
pResult->m_dDiameter = dDiameter;
pResult->m_dThickness = th;
//!>传递检测结果到UI
//pImgObj->IDrawImage(img.scaled(300, 300));//!>显示结果图片到UI的第二个窗口上
double dTime = (cv::getTickCount() - dStart) / cv::getTickFrequency();
pResult->m_dRunTime = dTime;
long long varRlt = (long long)pResult;
rltMap.insert("result", varRlt);
pImgObj->IVariantMapToUI(rltMap);
qDebug() << "finish alg";
return 1;
}
catch (...) {
qDebug() << "algo run Error " << __FUNCTION__;
return 1;
}
}
//模板匹配流程
QString CAlgorithmFluorescence::bestMatch(const QMap<QString, IWheelModel*>* modelMap, CLocalWheel* pLocal, double* pMinDis /*= NULL*/, int minDisNum /*= -1*/) const
{
double minDis = DBL_MAX;
QString bestName;
vector<double> disVec(modelMap->size());
int nIndex = 0;
if (!modelMap)
return bestName;
QStringList strDetectModels = pLocal->defectList;
int similarNum = 0;
const QString hubName1("DH151079");
const QString hubName2("DK151050");
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;
if (pLocal->useDiameter) {
if (abs(pLocal->diameter - pWheel->getDiameter()) >= 15) {
nIndex++;
continue;
}
}
if (pLocal->useHeight) {
if (abs(pLocal->height - pWheel->getThickness()) >= 15) {
nIndex++;
continue;
}
}
if (pLocal->ratioType == 1) {//开启使用偏距过滤检测模板的功能
//必须三个数值不为0才进行 否则可能导致不明问题
double curRatioVal = pLocal->dRatioVal;
double minRatio = pWheel->getMinRotia();
double maxRatio = pWheel->getMaxRotia();
if (curRatioVal != 0)
{
if ((curRatioVal < minRatio || curRatioVal > maxRatio) && maxRatio > minRatio)
{
nIndex++;
continue;
}
}
}
QString name = strModelName;
ICompareModel* pModel = pWheel->getImageComModel();
if (pModel->getBaseImg().data == NULL)
{
nIndex++;
continue;
}
pModel->setIsEnableCache(false);
double dis = pModel->compare(pLocal->img, NULL, true, 1);
double disThre = pModel->getDisThre();
double innerCircleNum = pModel->getInnerCircleNum();
if (dis < disThre)
{
similarNum++;
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);
}
if (similarNum < 1)
{
return bestName;
}
const cv::Mat originalMat = pLocal->img;
float startX = originalMat.cols / 2.0 - MAX_CIRCLE_RADII;//找最大圆外径,固定直径
float startY = originalMat.rows / 2.0 - MAX_CIRCLE_RADII;
Rect rect(startX, startY, MAX_CIRCLE_RADII * 2, MAX_CIRCLE_RADII * 2);
cv::Mat centerMat = originalMat(rect).clone();
EDCircles edCircles(centerMat);
std::vector<mCircle> circles = edCircles.getCircles();
const int nSize = circles.size();
float rMax = 0;
for (int i = 0; i < nSize; ++i)
{
float radius = circles[i].r;
if (radius > rMax)
{
rMax = radius;
}
}
double innerCircleNumSum = 0;
double rMaxUp = rMax * MAX_INSIDE_RATIO;
double rMaxLow = rMax * MIN_INSIDE_RATIO;
for (int i = 0; i < nSize; ++i)
{
double radius = circles[i].r;
if (radius < rMaxUp && radius > rMaxLow * MIN_INSIDE_RATIO)
{
innerCircleNumSum++;
}
}
if (bestName.toUpper() == hubName1)
{
if (innerCircleNumSum > 1)
{
QStringList modelList = pLocal->defectList;
bool bFind = false;
while (modelList.size())
{
QString modelName = modelList.takeFirst();
if (modelName == hubName2)
{
bestName = hubName2;
bFind = true;
break;
}
}
if (!bFind)
{
// bestName = QString();
}
}
}
else if (bestName.toUpper() == hubName2)
{
if (innerCircleNumSum < 2)
{
QStringList modelList = pLocal->defectList;
bool bFind = false;
while (modelList.size())
{
QString modelName = modelList.takeFirst();
if (modelName == hubName1)
{
bestName = hubName1;
bFind = true;
break;
}
}
if (!bFind)
{
// bestName = QString();
}
}
}
return bestName;
}
cv::Mat CAlgorithmFluorescence::getImage(class IImageObject *pImgObj)
{
emTpColorFormat colorFormat = pImgObj->IColorFormat();
int nImageW;
int nImageH;
int nBitsPerPixel;
int nBytesPerLine;
BYTE* pImageData = pImgObj->IImageData(nImageW, nImageH, nBitsPerPixel, nBytesPerLine);
Mat matSrc;
if (TP_COLOR_Y800 != colorFormat)
{
Mat colorMat = Mat(nImageH, nImageW, CV_8UC4, pImageData, nBytesPerLine);
matSrc = getFirstChannel(colorMat);
}
else
{
matSrc = Mat(nImageH, nImageW, CV_8UC1, pImageData, nBytesPerLine);
}
return matSrc;
}
cv::Mat CAlgorithmFluorescence::getBackGroundImage(class IImageObject *pObj, bool bReLoad)
{
static Mat matback;
if (matback.empty()) {
QString filepath = ".\\user\\background.png";
matback = cv::imread(string((const char *)filepath.toLocal8Bit()), 0);
if (matback.empty()) {
QString filepath = getPath(pObj) + "\\user\\background_r.png";
matback = cv::imread(string((const char *)filepath.toLocal8Bit()), 0);
cv::flip(matback, matback, 1);
}
}
else {
if (bReLoad) {
QString filepath = getPath(pObj) + "\\user\\background.png";
matback = cv::imread(string((const char *)filepath.toLocal8Bit()), 0);
if (matback.empty()) {
QString filepath = getPath(pObj) + "\\user\\background_r.png";
matback = cv::imread(string((const char *)filepath.toLocal8Bit()), 0);
cv::flip(matback, matback, 1);
}
}
}
return matback;
}
QString CAlgorithmFluorescence::getPath(class IImageObject *pObj)
{
IAlgorithmShared* pShare = pObj->IGetShared();
if (!pShare)
return QString();
QStringList mlist = pObj->IGetShared()->IGetStringList("filepath");
if (mlist.empty()) {
return QString();
}
return mlist.first();
}