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++

#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")
5 years ago
5 years ago
#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;
5 years ago
5 years ago
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 && minRatio > 0 && maxRatio > 0)
{
if (curRatioVal < minRatio || curRatioVal > maxRatio)
{
nIndex++;
continue;
}
}
}
QString name = strModelName;
ICompareModel* pModel = pWheel->getImageComModel();
if (pModel->getBaseImg().data == NULL)
{
nIndex++;
continue;
}
pModel->setIsEnableCache(false);
5 years ago
double dis = pModel->compare(pLocal->img, NULL, true, 1);
5 years ago
double disThre = pModel->getDisThre();
double innerCircleNum = pModel->getInnerCircleNum();
if (dis < disThre)
{
similarNum++;
simularModelMap[name] = innerCircleNum;
}
disVec[nIndex] = dis;
5 years ago
if (dis < minDis && dis != -1)
{
minDis = dis;
bestName = name;
}
nIndex++;
}
5 years ago
if (pMinDis)
{
*pMinDis = minDis;
}
if (minDisNum > 1)
{
sort(disVec.begin(), disVec.end());
std::copy_n(disVec.begin(), minDisNum, pMinDis);
}
5 years ago
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();
}
5 years ago
}
}
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();
}
5 years ago
}
}
5 years ago
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();
}