Commit c28b0fea 张士柳

1 个父辈 87a1305d
...@@ -1021,18 +1021,18 @@ namespace eyemLib_Sharp ...@@ -1021,18 +1021,18 @@ namespace eyemLib_Sharp
#endregion #endregion
#region 项目 #region 项目
//普通器件 //普通器件(仍采用旧的算法)
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)] [DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, string fileName, double dOffset, int iMinArea, int iMaxArea, int iWinSize, ref string pNumObj, out EyemImage tpDstImg); private static extern int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, string fileName, [MarshalAs(UnmanagedType.LPArray)]int[] ipReelNum, out EyemImage tpDstImg);
//异型器件 //异型器件(新版本新算法)
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)] [DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, string fileName, string strType, ref string pNumObj, out EyemImage tpDstImg); private static extern int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, string fileName, string strType, [MarshalAs(UnmanagedType.LPArray)]int[] ipReelNum, out EyemImage tpDstImg);
//普通器件(新版本) //普通器件(新版本新算法)
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)] [DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, string fileName, ref string pNumObj, out EyemImage tpDstImg); private static extern int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, string fileName, [MarshalAs(UnmanagedType.LPArray)]int[] ipReelNum, out EyemImage tpDstImg);
//异型器件(新版本) //异型器件(新版本模板匹配)
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)] [DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemCountObjectIrregularPartsE(EyemImage tpImage, EyemRect tpRoi, string fileName, string ccTplName, IntPtr hModelID, ref string pNumObj, out EyemImage tpDstImg); private static extern int eyemCountObjectIrregularPartsE(EyemImage tpImage, EyemRect tpRoi, string fileName, string ccTplName, IntPtr hModelID, [MarshalAs(UnmanagedType.LPArray)]int[] ipReelNum, out EyemImage tpDstImg);
//创建模板匹配模型 //创建模板匹配模型
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)] [DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemCreateTemplateModel(EyemImage tpImage, EyemRect tpRoi, double dMinScore, string ccTplName); private static extern int eyemCreateTemplateModel(EyemImage tpImage, EyemRect tpRoi, double dMinScore, string ccTplName);
...@@ -1129,6 +1129,7 @@ namespace eyemLib_Sharp ...@@ -1129,6 +1129,7 @@ namespace eyemLib_Sharp
//记录日志 //记录日志
private static void EyemLib_OnNewLogCallback(string msg) private static void EyemLib_OnNewLogCallback(string msg)
{ {
//算法里输出的一切日志都会在这里
logcpp.WriteLog("[" + Thread.CurrentThread.ManagedThreadId.ToString("X16") + "]" + msg); logcpp.WriteLog("[" + Thread.CurrentThread.ManagedThreadId.ToString("X16") + "]" + msg);
} }
...@@ -1363,14 +1364,13 @@ namespace eyemLib_Sharp ...@@ -1363,14 +1364,13 @@ namespace eyemLib_Sharp
//flag = eyemMulFuncTool(image, tpRoi, "__func1", 65, 75, ref tpCircle, out tpDstImg); //flag = eyemMulFuncTool(image, tpRoi, "__func1", 65, 75, ref tpCircle, out tpDstImg);
string pNumObj = ""; int[] ipReelNum = new int[4];
string file = fileName.Split(new string[] { "\\" }, StringSplitOptions.RemoveEmptyEntries)[2]; string file = fileName.Split(new string[] { "\\" }, StringSplitOptions.RemoveEmptyEntries)[2];
//获取用于制作模板的图像 //获取用于制作模板的图像
//flag = eyemAchvTemplateImage(image, tpRoi, out tpDstImg); //flag = eyemAchvTemplateImage(image, tpRoi, out tpDstImg);
//Bitmap bitmap = eyemCvtToBitmap(tpDstImg); //Bitmap bitmap = eyemCvtToBitmap(tpDstImg);
//if (bitmap != null) //if (bitmap != null)
//{ //{
// bitmap.Save(System.Windows.Forms.Application.StartupPath + "\\ResOut\\" + file); // bitmap.Save(System.Windows.Forms.Application.StartupPath + "\\ResOut\\" + file);
...@@ -1423,10 +1423,10 @@ namespace eyemLib_Sharp ...@@ -1423,10 +1423,10 @@ namespace eyemLib_Sharp
//eyemImageFree(ref tpDstImg); //eyemImageFree(ref tpDstImg);
//"IP_SMALL_PARTS","IP_LARGE_PARTS","IP_LONG_PARTS","IP_LOWCONTRAST_PARTS" //"IP_SMALL_PARTS","IP_LARGE_PARTS","IP_LONG_PARTS","IP_LOWCONTRAST_PARTS"
//eyemCountObject(image, tpRoi, file.Replace(".png", ""), 35, 0, 100, 5, ref pNumObj, out tpDstImg); //eyemCountObject(image, tpRoi, file.Replace(".png", ""), ipReelNum, out tpDstImg);
//eyemCountObjectIrregularParts(image, tpRoi, file.Replace(".png", ""), "IP_LONG_PARTS", ref pNumObj, out tpDstImg); eyemCountObjectIrregularParts(image, tpRoi, file.Replace(".png", ""), "IP_LARGE_PARTS", ipReelNum, out tpDstImg);
eyemCountObjectE(image, tpRoi, fileName, ref pNumObj, out tpDstImg); //eyemCountObjectE(image, tpRoi, fileName, ipReelNum, out tpDstImg);
//eyemCountObjectIrregularPartsE(image, tpRoi, file.Replace(".png", ""), tpModels[0], hModelID, ref pNumObj, out tpDstImg); //eyemCountObjectIrregularPartsE(image, tpRoi, file.Replace(".png", ""), tpModels[0], hModelID, ipReelNum, out tpDstImg);
//eyemCountObjectIrregularPartsE(image, tpRoi, file.Replace(".png", ""), "D:\\模板文件\\" + /*file.Replace(".png", ".tpl")*/"74d571ed-9fd4-4959-85dd-3195261e4b48.tpl", ref pNumObj, out tpDstImg); //eyemCountObjectIrregularPartsE(image, tpRoi, file.Replace(".png", ""), "D:\\模板文件\\" + /*file.Replace(".png", ".tpl")*/"74d571ed-9fd4-4959-85dd-3195261e4b48.tpl", ref pNumObj, out tpDstImg);
//移除模板 //移除模板
...@@ -1435,8 +1435,8 @@ namespace eyemLib_Sharp ...@@ -1435,8 +1435,8 @@ namespace eyemLib_Sharp
Bitmap bitmap = eyemCvtToBitmap(tpDstImg); Bitmap bitmap = eyemCvtToBitmap(tpDstImg);
if (bitmap != null) if (bitmap != null)
{ {
bitmap.Save("D:\\ResOut\\" + file); //bitmap.Save("D:\\ResOut\\" + file);
//bitmap.Save(System.Windows.Forms.Application.StartupPath + "\\ResOut\\" + file); bitmap.Save(System.Windows.Forms.Application.StartupPath + "\\ResOut\\" + file);
} }
//< 解码测试 //< 解码测试
...@@ -1449,16 +1449,19 @@ namespace eyemLib_Sharp ...@@ -1449,16 +1449,19 @@ namespace eyemLib_Sharp
// Marshal.FreeCoTaskMem(tpResults[i].hText); Marshal.FreeCoTaskMem(tpResults[i].hType); // Marshal.FreeCoTaskMem(tpResults[i].hText); Marshal.FreeCoTaskMem(tpResults[i].hType);
//} //}
//hObject.Dispose(); //hObject.Dispose();
//flag = eyemDetectAndDecodeUseNN(image, tpRoi, out hObject, out tpResults, out ipNum, out tpDstImg); //flag = eyemDetectAndDecodeUseNN(image, tpRoi, out hObject, out tpResults, out ipNum, out tpDstImg);
//flag = eyemDetectAndDecodeBarcodeUseNN(image, tpRoi, out hObject, out tpResults, out ipNum, out tpDstImg); //flag = eyemDetectAndDecodeBarcodeUseNN(image, tpRoi, out hObject, out tpResults, out ipNum, out tpDstImg);
string strReelNum = "";
for (int i = 0; i < 4; i++)
{
strReelNum += ipReelNum[i].ToString() + ",";
}
sw.Stop(); sw.Stop();
Console.WriteLine(file + "--->" + "耗时:" + sw.ElapsedMilliseconds.ToString() + "毫秒" + ",结果:" + pNumObj); Console.WriteLine(file + "--->" + "耗时:" + sw.ElapsedMilliseconds.ToString() + "ms" + ",结果:" + strReelNum);
//Bitmap bitmap = eyemCvtToBitmap(tpDstImg); //Bitmap bitmap = eyemCvtToBitmap(tpDstImg);
//if (bitmap != null) //if (bitmap != null)
//{ //{
// bitmap.Save("D:\\ResOut\\" + file); // bitmap.Save("D:\\ResOut\\" + file);
...@@ -1498,7 +1501,7 @@ namespace eyemLib_Sharp ...@@ -1498,7 +1501,7 @@ namespace eyemLib_Sharp
tpRoi.iHeight = image.iHeight - 100; tpRoi.iHeight = image.iHeight - 100;
// //
string pNumObj = ""; int[] pNumObj = new int[4];
string file = fileName.Split(new string[] { "\\" }, StringSplitOptions.RemoveEmptyEntries)[2]; string file = fileName.Split(new string[] { "\\" }, StringSplitOptions.RemoveEmptyEntries)[2];
//获取用于制作模板的图像 //获取用于制作模板的图像
...@@ -1537,7 +1540,7 @@ namespace eyemLib_Sharp ...@@ -1537,7 +1540,7 @@ namespace eyemLib_Sharp
eyemImageFree(ref tpDstImg); eyemImageFree(ref tpDstImg);
//点料 //点料
eyemCountObjectIrregularPartsE(image, tpRoi, file.Replace(".png", ""), selectModel.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)[0], hModelID, ref pNumObj, out tpDstImg); eyemCountObjectIrregularPartsE(image, tpRoi, file.Replace(".png", ""), selectModel.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)[0], hModelID, pNumObj, out tpDstImg);
//测试移除模板 //测试移除模板
//eyemRemoveModelByName(hModelID, "D:\\模板文件及图像\\df871193-6632-48f9-abfe-540c3fc49c3f.tpl"); //eyemRemoveModelByName(hModelID, "D:\\模板文件及图像\\df871193-6632-48f9-abfe-540c3fc49c3f.tpl");
......
using Microsoft.Win32.SafeHandles; using System;
using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Linq;
using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Drawing.Imaging; using System.Drawing.Imaging;
...@@ -323,8 +319,41 @@ namespace eyemLib_Sharp ...@@ -323,8 +319,41 @@ namespace eyemLib_Sharp
//释放图像资源 //释放图像资源
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)] [DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern void eyemImageFree(ref EyemImage tpImage); private static extern void eyemImageFree(ref EyemImage tpImage);
// 设定日志回调
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern void setLogCallback(TCallBack cb);
#endregion #endregion
// 日志
public delegate void TCallBack(string msg);
public static TCallBack sld = new TCallBack(TLogCallback);
public static event TCallBack OnNewLogCallback;
public static void TLogCallback(string msg)
{
OnNewLogCallback?.Invoke(msg);
}
//程序启动时初始化一次
public static void Init()
{
setLogCallback(sld);
OnNewLogCallback += new TCallBack(EyemLib_OnNewLogCallback);
}
//程序结束时释放
public static void Free()
{
setLogCallback(null); sld = null;
}
//记录算法日志
private static void EyemLib_OnNewLogCallback(string msg)
{
//算法里输出的一切日志都会在这里
}
//例程 //例程
public static void eyeyTestTemplateModelMethod(string fileName) public static void eyeyTestTemplateModelMethod(string fileName)
{ {
...@@ -355,7 +384,6 @@ namespace eyemLib_Sharp ...@@ -355,7 +384,6 @@ namespace eyemLib_Sharp
#endregion #endregion
} }
#region EyemImageBitmap相互转换 #region EyemImageBitmap相互转换
public static Bitmap eyemCvtToBitmap(EyemImage tpImage) public static Bitmap eyemCvtToBitmap(EyemImage tpImage)
{ {
......
...@@ -516,8 +516,10 @@ int eyemDetectAndDecodeUseNN(EyemImage tpImage, EyemRect tpRoi, IntPtr *hObject, ...@@ -516,8 +516,10 @@ int eyemDetectAndDecodeUseNN(EyemImage tpImage, EyemRect tpRoi, IntPtr *hObject,
{ {
cv::Mat image = cv::Mat(tpImage.iHeight, tpImage.iWidth, MAKETYPE(tpImage.iDepth, tpImage.iChannels), tpImage.vpImage).clone(); cv::Mat image = cv::Mat(tpImage.iHeight, tpImage.iWidth, MAKETYPE(tpImage.iDepth, tpImage.iChannels), tpImage.vpImage).clone();
if (image.empty()) { if (image.empty()) {
logger.t("__eyemDetectAndDecodeUseNN__:图像文件不存在");
return FUNC_IMAGE_NOT_EXIST; return FUNC_IMAGE_NOT_EXIST;
} }
logger.t("__eyemDetectAndDecodeUseNN__:开始识别并解码二维码");
//识别并解码 //识别并解码
std::vector<cv::Rect> points; std::vector<cv::Rect> __points; std::vector<cv::Rect> points; std::vector<cv::Rect> __points;
auto results = detector->detectAndDecode(image, points, __points); auto results = detector->detectAndDecode(image, points, __points);
...@@ -569,6 +571,7 @@ int eyemDetectAndDecodeUseNN(EyemImage tpImage, EyemRect tpRoi, IntPtr *hObject, ...@@ -569,6 +571,7 @@ int eyemDetectAndDecodeUseNN(EyemImage tpImage, EyemRect tpRoi, IntPtr *hObject,
//} //}
#pragma endregion #pragma endregion
logger.t("__eyemDetectAndDecodeUseNN__:输出结果");
//解码结果 //解码结果
std::vector<EyemBarCode> *tpResults = new std::vector<EyemBarCode>(); std::vector<EyemBarCode> *tpResults = new std::vector<EyemBarCode>();
for (int n = 0; n < results.size(); n++) { for (int n = 0; n < results.size(); n++) {
......
...@@ -5,6 +5,13 @@ ...@@ -5,6 +5,13 @@
#ifndef __EYEM_DATACODE_H #ifndef __EYEM_DATACODE_H
#define __EYEM_DATACODE_H #define __EYEM_DATACODE_H
#ifdef _WIN32
#include <io.h>
#include <Windows.h>
#elif __linux__
#include <sys/stat.h>
#endif
#include "eyemLib.h" #include "eyemLib.h"
#include "nnDetector.h" #include "nnDetector.h"
...@@ -12,6 +19,8 @@ std::mutex mtx; ...@@ -12,6 +19,8 @@ std::mutex mtx;
cv::Ptr<NNDetector> detector; cv::Ptr<NNDetector> detector;
extern Logger logger;
//预处理区域 //预处理区域
struct WaitArea struct WaitArea
{ {
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
#ifndef __EYEM_LIB_H #ifndef __EYEM_LIB_H
#define __EYEM_LIB_H #define __EYEM_LIB_H
#include <Windows.h>
#include <opencv.hpp> #include <opencv.hpp>
...@@ -662,7 +661,7 @@ extern "C" { ...@@ -662,7 +661,7 @@ extern "C" {
// 函数接口 // 函数接口
EXPORTS int eyemEdgesPixel(EyemImage tpImage, double dThresh); EXPORTS int eyemEdgesPixel(EyemImage tpImage, double dThresh);
EXPORTS int eyemEdgesSubpixel(EyemImage tpImage, IntPtr *hObject, EyemOcsDXY **tpEdges, int iFilter, int iLow, int iHigh); EXPORTS int eyemEdgesSubpixel(EyemImage tpImage, IntPtr *hObject, EyemOcsDXY **tpEdges, int iFilter, int iLow, int iHigh);
EXPORTS int eyemSkeleton(EyemImage tpImage, cv::Mat &skeleton); EXPORTS int eyemSkeleton(EyemImage tpImage, EyemImage &skeleton);
EXPORTS int eyemSobelAmp(EyemImage tpImage, EyemImage &ImaAmp); EXPORTS int eyemSobelAmp(EyemImage tpImage, EyemImage &ImaAmp);
EXPORTS int eyemAutoCanny(EyemImage tpImage, float dSigma = 0.33); EXPORTS int eyemAutoCanny(EyemImage tpImage, float dSigma = 0.33);
...@@ -799,8 +798,8 @@ typedef struct { ...@@ -799,8 +798,8 @@ typedef struct {
double dAngle; // 角度 double dAngle; // 角度
int iCenterX; // y坐标 int iCenterX; // y坐标
int iCenterY; // y坐标 int iCenterY; // y坐标
LPSTR lpszType; // 码类型 char* lpszType; // 码类型
LPSTR lpszText; // 码内容 char* lpszText; // 码内容
} EyemBarCode; } EyemBarCode;
typedef struct { typedef struct {
...@@ -810,7 +809,7 @@ typedef struct { ...@@ -810,7 +809,7 @@ typedef struct {
int iWidth; // 图像内存X方向大小 int iWidth; // 图像内存X方向大小
int iHeight; // 图像内存Y方向大小 int iHeight; // 图像内存Y方向大小
double dMatchDeg; // 匹配度 double dMatchDeg; // 匹配度
LPSTR lpszName; // 名称 char* lpszName; // 名称
} EyemModelID; } EyemModelID;
...@@ -822,13 +821,13 @@ extern "C" { ...@@ -822,13 +821,13 @@ extern "C" {
EXPORTS int eyemInitNNDataCodeModel(const char *detectorConfigPath, const char *detectorModelPath, const char *superResolutionConfigPath, const char *superResolutionModelPath); EXPORTS int eyemInitNNDataCodeModel(const char *detectorConfigPath, const char *detectorModelPath, const char *superResolutionConfigPath, const char *superResolutionModelPath);
EXPORTS int eyemDetectAndDecodeBarcodeUseNN(EyemImage tpImage, EyemRect tpRoi, IntPtr *hObject, EyemBarCode **hResults, int *ipNum, EyemImage *tpDstImg); EXPORTS int eyemDetectAndDecodeBarcodeUseNN(EyemImage tpImage, EyemRect tpRoi, IntPtr *hObject, EyemBarCode **hResults, int *ipNum, EyemImage *tpDstImg);
EXPORTS bool eyemDetectAndDecodeFree(IntPtr hObject); EXPORTS bool eyemDetectAndDecodeFree(IntPtr hObject);
EXPORTS int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LPSTR *lpszNumObj, EyemImage *tpDstImg); EXPORTS int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, int *ipReelNum, EyemImage *tpDstImg);
EXPORTS int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LPSTR *lpszReelNum, EyemImage *tpDstImg); EXPORTS int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, int *ipReelNum, EyemImage *tpDstImg);
EXPORTS int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char *fileName, const char * ccSubType, LPSTR *lpszNumObj, EyemImage *tpDstImg); EXPORTS int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char *fileName, const char * ccSubType, int *ipReelNum, EyemImage *tpDstImg);
EXPORTS int eyemCountObjectIrregularPartsE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, const char *ccTplName, IntPtr hModelID, LPSTR *lpszReelNum, EyemImage *tpDstImg); EXPORTS int eyemCountObjectIrregularPartsE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, const char *ccTplName, IntPtr hModelID, int *ipReelNum, EyemImage *tpDstImg);
EXPORTS int eyemAchvTemplateImage(EyemImage tpImage, EyemRect tpRoi, EyemImage *tpDstImg); EXPORTS int eyemAchvTemplateImage(EyemImage tpImage, EyemRect tpRoi, EyemImage *tpDstImg);
EXPORTS int eyemCreateTemplateModel(EyemImage tpImage, EyemRect tpRoi, double dMinScore, const char *ccTplName); EXPORTS int eyemCreateTemplateModel(EyemImage tpImage, EyemRect tpRoi, double dMinScore, const char *ccTplName);
EXPORTS int eyemMatchTemplateModel(EyemImage tpImage, IntPtr hModelID, LPSTR *lpszTplName); EXPORTS int eyemMatchTemplateModel(EyemImage tpImage, IntPtr hModelID, char **lpszTplName);
EXPORTS int eyemInitModel(const char *ccTplName, IntPtr *hModelID); EXPORTS int eyemInitModel(const char *ccTplName, IntPtr *hModelID);
EXPORTS int eyemAchvModelByName(const char *ccTplName, IntPtr hModelID, EyemModelID &tpModelID); EXPORTS int eyemAchvModelByName(const char *ccTplName, IntPtr hModelID, EyemModelID &tpModelID);
EXPORTS int eyemInsertModel(IntPtr hModelID, const char *ccTplName); EXPORTS int eyemInsertModel(IntPtr hModelID, const char *ccTplName);
......
此文件类型无法预览
#ifdef _WIN32
#include <io.h>
#include <Windows.h>
#elif __linux__
#include <sys/stat.h>
#endif
#include <fstream>
#include "eyemMisc.h" #include "eyemMisc.h"
#pragma region 一些参数计算公式 #pragma region 一些参数计算公式
...@@ -655,7 +663,7 @@ static bool checkSize(cv::Mat &srcPrev, cv::Mat &mask, int &partSize) ...@@ -655,7 +663,7 @@ static bool checkSize(cv::Mat &srcPrev, cv::Mat &mask, int &partSize)
#pragma endregion #pragma endregion
int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LPSTR *lpszNumObj, EyemImage *tpDstImg) int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, int *ipReelNum, EyemImage *tpDstImg)
{ {
cv::Mat src = cv::Mat(tpImage.iHeight, tpImage.iWidth, MAKETYPE(tpImage.iDepth, tpImage.iChannels), tpImage.vpImage).clone(); cv::Mat src = cv::Mat(tpImage.iHeight, tpImage.iWidth, MAKETYPE(tpImage.iDepth, tpImage.iChannels), tpImage.vpImage).clone();
if (src.empty()) { if (src.empty()) {
...@@ -781,10 +789,8 @@ int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LPS ...@@ -781,10 +789,8 @@ int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LPS
if (trays.size() < 1) if (trays.size() < 1)
{ {
std::string strTrayNum = "无料,"; std::string strTrayNum = "无料,";
*lpszNumObj = (char *)CoTaskMemAlloc(strTrayNum.size()); for (int i = 0; i < 4; i++) {
if (NULL != *lpszNumObj) ipReelNum[i] = 0;
{
strcpy(*lpszNumObj, strTrayNum.c_str());
} }
return FUNC_CANNOT_CALC; return FUNC_CANNOT_CALC;
} }
...@@ -1107,220 +1113,107 @@ int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LPS ...@@ -1107,220 +1113,107 @@ int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LPS
}); });
//去掉中心1/3区域 //去掉中心1/3区域
cv::circle(image, reelCenter, cvRound(tFRadius / 3), cv::Scalar(0), -1); cv::circle(image, reelCenter, cvRound(tFRadius / 3), cv::Scalar(0), -1);
struct TracingAnchor //追踪直至没有单个元件存在
{ bool bExistSingle = true;
float Size; //用于计数
float Length, Height; cv::Mat lb4Count(Y, X, CV_8UC1, cv::Scalar(0));
cv::Point2f Anchor;
cv::RotatedRect RBox;
TracingAnchor(cv::Point2f Anchor, float Length, float Height, float Size, cv::RotatedRect RBox) :Anchor(Anchor), Length(Length), Height(Height), Size(Size), RBox(RBox) {}
bool operator >(const TracingAnchor &te)const
{
return Size > te.Size;
}
bool operator <(const TracingAnchor &te)const
{
return Size < te.Size;
}
};
std::vector<std::vector<cv::Point>> contourTracing;
cv::findContours(image, contourTracing, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
//所有追踪锚点
std::vector<TracingAnchor> tracingAnchors;
for (auto&contour : contourTracing) {
cv::RotatedRect rbox = cv::minAreaRect(contour);
if (cv::min(rbox.size.width, rbox.size.height) > 2.0f) {
tracingAnchors.push_back(TracingAnchor(rbox.center, cv::max(rbox.size.width, rbox.size.height), cv::min(rbox.size.width, rbox.size.height), rbox.size.area(), rbox));
}
}
//不存在独立元件
if (tracingAnchors.empty()) {
return FUNC_CANNOT_CALC;
}
//尺寸只计算一次
std::sort(tracingAnchors.begin(), tracingAnchors.end(), std::greater<TracingAnchor>());
//
struct Track {
int iLimit, iPartSize;
double dMatchDeg = 0.0;
cv::Point2f Pos;
std::vector<cv::Point2f> Rect;
Track() {};
Track(int iLimit, int iPartSize, double dMatchDeg, cv::Point2f Pos, std::vector<cv::Point2f> Rect) :iLimit(iLimit), iPartSize(iPartSize), dMatchDeg(dMatchDeg), Pos(Pos), Rect(Rect) {};
bool operator >(const Track &te)const
{
return dMatchDeg > te.dMatchDeg;
}
bool operator <(const Track &te)const
{
return dMatchDeg < te.dMatchDeg;
}
};
//缩放比例
float coeff = 1.0f;
//填充值
const int fillVal = 255 - backThresh;
//元件尺寸
const double taLength = tracingAnchors[tracingAnchors.size() / 2].Length; const double taHeight = tracingAnchors[tracingAnchors.size() / 2].Height;
//元件灰度值
double taMaxGray = 0.0;
//标签图 //标签图
unsigned char *ucpTrackLabel = new unsigned char[Y*X](); unsigned char *ucpTrackLabel = new unsigned char[Y*X]();
cv::Mat trackMat(Y, X, CV_8UC1, ucpTrackLabel); cv::Mat trackMat(Y, X, CV_8UC1, ucpTrackLabel);
//计数图像 do
cv::Mat lbMat(Y, X, CV_8UC1, cv::Scalar(0)); {
//定位图像
cv::Mat srcPrevS, tplMat;//模板文件
srcPrev.convertTo(srcPrevS, CV_32F);
//随机打乱顺序(降低计算错误dChordL的可能性,也为了测试在起点信息不同时的稳定性)
std::random_shuffle(tracingAnchors.begin(), tracingAnchors.end());
//开始确定起点(现在是用圆轨迹来追踪,不排除用螺旋线轨迹来追踪)
for (std::vector<TracingAnchor>::iterator itvx = tracingAnchors.begin(); itvx != tracingAnchors.end(); ++itvx) {
//跳过执行 //跳过执行
if (killProcessID == 0) { if (killProcessID == 0) {
logger.t("eyemCountObjectIrregularParts 点料阶段被跳过执行..."); logger.t("eyemCountObjectIrregularPartsE 点料阶段被跳过执行...");
break; break;
} }
//起始位置信息
TracingAnchor ta = (*itvx);
//起始位置坐标
cv::Point2f startCenter(ta.Anchor.x, ta.Anchor.y);
//最小外包矩形
cv::Point2f _pts[4];
ta.RBox.points(_pts);
//已做标记(TODO:考虑增加判断哪些是起点哪些不是)
if (trackMat.ptr<uint8_t>(cvRound(startCenter.y))[cvRound(startCenter.x)] == 255) {
continue;
}
//获取模板图像(是否每次起点都计算模板,如果元件变形过大是否还会有用?)
if (tplMat.empty())
{
float tDist = ta.Height / 2.0f;
//理论范围扩展
cv::Rect _rLimits = cv::Rect(cv::Point2i(cvRound((float)ta.RBox.boundingRect2f().tl().x - tDist),
cvRound((float)ta.RBox.boundingRect2f().tl().y - tDist)), cv::Point2i(cvRound((float)ta.RBox.boundingRect2f().br().x + tDist),
cvRound((float)ta.RBox.boundingRect2f().br().y + tDist))
)&cv::Rect(0, 0, X, Y);
//确定元件位置根据旋转后的位置确定(前提是料盘中心定位的准确)
double t = atan2((double)startCenter.y - reelCenter.y, (double)startCenter.x - reelCenter.x) * 180.0 / PI;
//计算旋转角度
cv::Mat traceMat = srcPrev(_rLimits);
//这里计算得出的模板不是很对
float matx[6];
tplMat = getTrackMat(traceMat, t + 90.0, 0, matx);
//变换后的坐标
cv::Point2f __pts[4];
for (int j = 0; j < 4; j++)
{
__pts[j].x = matx[0] * (_pts[j].x - (float)_rLimits.x) + matx[1] * (_pts[j].y - (float)_rLimits.y) + matx[2];
__pts[j].y = matx[3] * (_pts[j].x - (float)_rLimits.x) + matx[4] * (_pts[j].y - (float)_rLimits.y) + matx[5];
}
cv::Point2f __ptsc((__pts[0].x + __pts[1].x + __pts[2].x + __pts[3].x) / 4.0f, (__pts[0].y + __pts[1].y + __pts[2].y + __pts[3].y) / 4.0f);
//确定各顶点方位
struct DIR {
int i = -1;
cv::Point2f pt;
DIR() {};
DIR(int i, cv::Point2f pt) :i(i), pt(pt) {}; //不随机挑选起点(考虑换成面积最小的那个)
}; std::vector<cv::Point> contourMin;
auto _dir_l = std::vector<DIR>(); auto _dir_r = std::vector<DIR>(); cv::findContours(image, contoursFilter, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
for (int j = 0; j < 4; j++) //终止追踪
if (contoursFilter.size() <= 0) break;
//大于等于1个随机挑选
if (contoursFilter.size() > 1)
{
//随机数生成
srand((unsigned)time(NULL));
contourMin = contoursFilter[rand() % (contoursFilter.size() - 1)];
for (int fc = 0; fc < contoursFilter.size(); fc++)
{ {
if (__pts[j].x < __ptsc.x) { if (cv::contourArea(contoursFilter[fc]) > 0.4*sinPartSize)
_dir_l.push_back(DIR(j, __pts[j])); {
} if (cv::contourArea(contoursFilter[fc]) < cv::contourArea(contourMin))
else { {
_dir_r.push_back(DIR(j, __pts[j])); contourMin = contoursFilter[fc];
}
} }
} }
//重新选点计算模板 }
if (_dir_l.size() != _dir_r.size()) { else if (contoursFilter.size() == 1)
continue; {
} contourMin = contoursFilter[0];
//确定顶点方向 }
cv::Point2f p0, p1, p2, p3; //去掉起始位置
if (_dir_l[0].pt.y < _dir_l[1].pt.y) { std::vector<std::vector<cv::Point>> vTempRect;
p0 = _pts[_dir_l[0].i]; vTempRect.push_back(contourMin);
p1 = _pts[_dir_l[1].i]; cv::drawContours(image, vTempRect, 0, cv::Scalar(0), -1);
} //最小外包矩形
else { cv::RotatedRect rect = cv::minAreaRect(contourMin);
p0 = _pts[_dir_l[1].i]; cv::Point2f points[4];
p1 = _pts[_dir_l[0].i]; rect.points(points);
} //画图
//for (int j = 0; j < 4; j++)
//{
// cv::line(cc, points[j], points[(j + 1) % 4], cv::Scalar(0, 165, 255, 255), 1);
//}
//追踪起点
cv::Point2f startCenter((points[0].x + points[1].x + points[2].x + points[3].x) / 4.f, (points[0].y + points[1].y + points[2].y + points[3].y) / 4.f);
//打标签
cv::Mat labels;
nccomps = cv::connectedComponents(image, labels);
//去掉已处理的分离器件
std::vector<uchar> labeled(nccomps + 1, 0);
//标记为已追踪过
std::vector<cv::Point> vT = { cv::Point(points[0]),cv::Point(points[1]) ,cv::Point(points[2]) ,cv::Point(points[3]) };
cv::fillConvexPoly(trackMat, vT, cv::Scalar(255));
//起点加入计数
cv::circle(lb4Count, cv::Point(startCenter), 0, cv::Scalar(255), 1);
cv::circle(cc, cv::Point(startCenter), 2, cv::Scalar(0, 255, 0, 255), 1);
///<追踪元件算法
struct Track {
int iLimit, iPartSize;
double dMatchDeg;
cv::Point Pos;
std::vector<cv::Point2f> Rect;
if (_dir_r[0].pt.y > _dir_r[1].pt.y) { Track() {};
p2 = _pts[_dir_r[0].i];
p3 = _pts[_dir_r[1].i];
}
else {
p2 = _pts[_dir_r[1].i];
p3 = _pts[_dir_r[0].i];
}
//计算精确角度
cv::Point2f p01((p0.x + p1.x) / 2.0f, (p0.y + p1.y) / 2.0f), p23((p2.x + p3.x) / 2.0f, (p2.y + p3.y) / 2.0f);
double realT = atan2((double)p23.y - (double)p01.y, (double)p23.x - (double)p01.x) * 180.0 / PI; Track(int iLimit, int iPartSize, double dMatchDeg, cv::Point Pos, std::vector<cv::Point2f> Rect) :iLimit(iLimit), iPartSize(iPartSize), dMatchDeg(dMatchDeg), Pos(Pos), Rect(Rect) {};
cv::Mat realTplMat = getTrackMat(traceMat, realT, 0, matx);
cv::Point2f __mpts[4]; bool operator >(const Track &te)const
for (int j = 0; j < 4; j++)
{ {
__mpts[j].x = matx[0] * (_pts[j].x - (float)_rLimits.x) + matx[1] * (_pts[j].y - (float)_rLimits.y) + matx[2]; return dMatchDeg > te.dMatchDeg;
__mpts[j].y = matx[3] * (_pts[j].x - (float)_rLimits.x) + matx[4] * (_pts[j].y - (float)_rLimits.y) + matx[5];
}
cv::Rect _rr(cvFloor(std::min(std::min(std::min(__mpts[0].x, __mpts[1].x), __mpts[2].x), __mpts[3].x)),
cvFloor(std::min(std::min(std::min(__mpts[0].y, __mpts[1].y), __mpts[2].y), __mpts[3].y)),
cvCeil(std::max(std::max(std::max(__mpts[0].x, __mpts[1].x), __mpts[2].x), __mpts[3].x)),
cvCeil(std::max(std::max(std::max(__mpts[0].y, __mpts[1].y), __mpts[2].y), __mpts[3].y))); _rr.width -= _rr.x - 1; _rr.height -= _rr.y - 1;
//最终模板
tplMat = realTplMat(_rr).clone();
//缩放比例
if (MIN(tplMat.size().width, tplMat.size().height) < 12.0) {
coeff = 2.0f;
} }
//最大值 };
cv::minMaxLoc(tplMat, NULL, &taMaxGray);
}
//标记为已追踪过
std::vector<cv::Point> vT = { cv::Point(_pts[0]),cv::Point(_pts[1]) ,cv::Point(_pts[2]) ,cv::Point(_pts[3]) };
cv::fillConvexPoly(trackMat, vT, cv::Scalar(255));
//标记计数
lbMat.ptr<uint8_t>(cvRound(startCenter.y))[cvRound(startCenter.x)] = 255;
//标记当前位置
cv::drawMarker(cc, cv::Point(startCenter), cv::Scalar(0, 255, 0, 255), cv::MARKER_DIAMOND, 5);
//扫描步长 //扫描步长
const double dMinorStep = 0.1; const double dMinorStep = 0.1;
//追踪长宽 //追踪长宽
const double trackLength = taLength / 2.0, trackWidth = taHeight / 4.0;//是否用较小尺寸的窗口 const double trackLength = std::max(rect.size.width / 2, rect.size.height / 2), trackWidth = std::min(rect.size.width / 4, rect.size.height / 4);
//起始扫描角度 //起始扫描角度
const double startAngle = atan2((double)startCenter.y - reelCenter.y, (double)startCenter.x - reelCenter.x) * 180.0 / PI; const double startAngle = atan2((double)startCenter.y - reelCenter.y, (double)startCenter.x - reelCenter.x) * 180 / PI;
//起始扫描半径 //起始扫描半径
const double startRadius = cv::norm(startCenter - reelCenter); const double startRadius = cv::norm(startCenter - reelCenter);
//偏移角度(元件尺寸) //偏移角度(元件尺寸)
const double dOffset = (2.0 * asin(2.0 * trackLength / (2.0 * startRadius))) * 180.0 / PI; const double dOffset = (2 * asin(2 * trackLength / (2 * startRadius))) * 180 / PI;
//扫描角度(默认15度范围内存在元件 //偏移角度(元件间距
const double dScanRange = 15.0; const double dScanRange = 15;
//追踪元件间距(弦长,可以尽量避免因个别器件偏离导致的追踪中断) //追踪元件间距(弦长,可以尽量避免因个别器件偏离导致的追踪中断)
double dChordL = .0; double dChordL = .0;
for (double t = startAngle + dOffset / 1.5; t < startAngle + dScanRange; t += dMinorStep) for (double t = startAngle + dOffset / 1.5; t < startAngle + dOffset / 1.5 + dScanRange; t += dMinorStep)
{ {
float x = float(reelCenter.x + startRadius*cos(t*c)); float x = float(reelCenter.x + startRadius*cos(t*c));
float y = float(reelCenter.y + startRadius*sin(t*c)); float y = float(reelCenter.y + startRadius*sin(t*c));
//防止超出图像范围
if (cvRound(x) < 0 || (cvRound(x) > X - 1) || cvRound(y) < 0 || (cvRound(y) > Y - 1)) {
break;
}
//确定是否是下一个元件
if (trackMat.ptr<uint8_t>(cvRound(y))[cvRound(x)] == 255) {
continue;
}
//初次确定元件间距 //初次确定元件间距
const double angle = atan2((double)reelCenter.y - y, (double)reelCenter.x - x); const double angle = atan2((double)reelCenter.y - y, (double)reelCenter.x - x);
...@@ -1329,726 +1222,423 @@ int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LPS ...@@ -1329,726 +1222,423 @@ int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LPS
cv::Point p2 = cv::Point(cvRound(x + trackWidth * cos(angle + CV_PI)), cv::Point p2 = cv::Point(cvRound(x + trackWidth * cos(angle + CV_PI)),
cvRound(y + trackWidth * sin(angle + CV_PI))); cvRound(y + trackWidth * sin(angle + CV_PI)));
//#ifdef _DEBUG
cv::line(cc, p1, p2, cv::Scalar(0, 215, 255, 255), 1);
//#endif
cv::LineIterator it(sinParts, p1, p2, 4); cv::LineIterator it(sinParts, p1, p2, 4);
for (int n = 0; n < it.count; n++, ++it) for (int n = 0; n < it.count; n++, ++it)
{ {
if (sinParts.ptr<uint8_t>(it.pos().y)[it.pos().x] == 255) if ((sinParts.data)[(it.pos().x) + (it.pos().y)*X] == 255)
{ {
//计算元件间距(弦长) //计算元件间距(弦长)
dChordL = 2.0 * startRadius*sin(((2.0 * asin((cv::norm(startCenter - cv::Point2f(x, y))) / (2.0 * startRadius))) * 180.0 / PI - dOffset / 2.0)*PI / 180.0 / 2.0); dChordL = 2.0 * startRadius*sin(((2.0 * asin((cv::norm(startCenter - cv::Point2f(x, y))) / (2.0 * startRadius))) * 180.0 / PI - dOffset / 2.0)*PI / 180.0 / 2.0);
break; break;
} }
} }
if (dChordL > 2.1) if (dChordL > 0)
break; break;
} }
//没确定出元件间距一般为结尾或单个元件,继续从下一个起点计算弦长并开始追踪 //并行处理
if (dChordL <= 2.1) { //#pragma omp parallel sections
continue;
}
//顺时针(是否并行取决于在windows下运行还是树莓派上)
{ {
//追踪中心 //(顺时针)
cv::Point2f trackCenter = cv::Point2f(startCenter.x, startCenter.y); //#pragma omp section
//追踪角度、半径
double trackAngle = startAngle, trackRadius = startRadius;
//元件本身所占角度
double trackOffset = dOffset;
//元件间间距
double partDist = (2.0 * asin(dChordL / (2.0 * trackRadius))) * 180.0 / PI;
//开始追踪
bool trackEnd = true;
do
{ {
bool found = true; bool trayEnd = false; //追踪中心
std::vector<Track> vParts; cv::Point2f trackCenter = cv::Point2f(startCenter.x, startCenter.y);
for (double t = trackAngle + (trackOffset + partDist - trackOffset / 12.0); t < trackAngle + (trackOffset + partDist - trackOffset / 12.0) + trackOffset / 6.0; t += dMinorStep) //追踪角度、半径
double trackAngle = startAngle, trackRadius = startRadius;
//元件本身角度
double trackOffset = dOffset;
//元件间间距
double partDist = (2 * asin(dChordL / (2 * trackRadius))) * 180 / PI;
//外包矩形顶点
cv::Point2f pts[4];
//结束位置
Track trackEndPos;
//开始追踪
bool trackEnd = true;
do
{ {
cv::Point2f predicPos; bool found = true;
predicPos.x = reelCenter.x + (float)trackRadius*(float)cos((trackAngle + (trackOffset + partDist))*c); std::vector<Track> vParts;
predicPos.y = reelCenter.y + (float)trackRadius*(float)sin((trackAngle + (trackOffset + partDist))*c); for (double t = trackAngle + (trackOffset / 2.0 + partDist); t < trackAngle + (trackOffset / 2.0 + partDist) + trackOffset; t += dMinorStep)
//如果追踪到图像外则追踪终止 {
if (cvRound(predicPos.x) < 0 || (cvRound(predicPos.x) > X - 1) || cvRound(predicPos.y) < 0 || (cvRound(predicPos.y) > Y - 1)) { trackCenter.x = reelCenter.x + (float)trackRadius*(float)cos(t*c);
trayEnd = true; trackCenter.y = reelCenter.y + (float)trackRadius*(float)sin(t*c);
break;
float b = (float)cos(t*c)*0.5f;
float a = (float)sin(t*c)*0.5f;
pts[0].x = float(trackCenter.x - a*trackLength * 2 - b*trackWidth * 4);
pts[0].y = float(trackCenter.y + b*trackLength * 2 - a*trackWidth * 4);
pts[1].x = float(trackCenter.x + a*trackLength * 2 - b*trackWidth * 4);
pts[1].y = float(trackCenter.y - b*trackLength * 2 - a*trackWidth * 4);
pts[2].x = float(2 * trackCenter.x - pts[0].x);
pts[2].y = float(2 * trackCenter.y - pts[0].y);
pts[3].x = float(2 * trackCenter.x - pts[1].x);
pts[3].y = float(2 * trackCenter.y - pts[1].y);
std::vector<cv::Point> vPoints;
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
//获取内部坐标
calcRotateRect(vRect, vPoints);
//计算灰度值
double dMatch = 0;
for (int v = 0; v < vPoints.size(); v++)
{
if (vPoints[v].x >= 0 && vPoints[v].x <= X&&vPoints[v].y >= 0 && vPoints[v].y <= Y)
{
dMatch += (srcPrev.data)[(vPoints[v].x) + (vPoints[v].y)*X];
}
}
dMatch /= (double)vPoints.size();
//仅扫描一个元件的角度
vParts.push_back(Track(0, 0, dMatch, cv::Point(cvRound(trackCenter.x), cvRound(trackCenter.y)), vRect));
//cv::circle(cc, cv::Point(cvRound(trackCenter.x), cvRound(trackCenter.y)), 0, cv::Scalar(0, 255, 255, 255), 1);
} }
//感兴趣区域(向外扩展了一个元件,防止中心定位出现偏差或者料盘本身变形导致的偏差) if (vParts.size() == 0) continue;
cv::Point2f predictBox[4]; //
calcRotateRect(predicPos, (float)(trackAngle + (trackOffset + partDist)), (float)trackLength + (float)trackLength, (float)trackWidth + (float)trackWidth, predictBox); trackEndPos = vParts[vParts.size() / 2];
//灰度极值认为是元件
cv::RotatedRect r(predictBox[0], predictBox[1], predictBox[2]); std::sort(vParts.begin(), vParts.end(), std::greater<Track>());
cv::Rect rLimits = r.boundingRect()&cv::Rect(0, 0, X, Y); //更新位置
trackCenter = cv::Point(vParts[0].Pos.x, vParts[0].Pos.y);
//获取感兴趣区域 //更新扫描角度
float matx[6]; trackAngle = atan2((double)trackCenter.y - reelCenter.y, (double)trackCenter.x - reelCenter.x) * 180 / PI;
cv::Mat traceMat = getTrackMat(srcPrevS(rLimits).clone() //纵向扫描
, (trackAngle + (trackOffset + partDist)) + 90.0, fillVal, matx); vParts.clear();
std::vector<cv::Point> trackLine;
//计算原图中的点在旋转后的位置(即在traceMat中的精确位置) drawLine(cc, reelCenter, trackCenter, cv::Scalar(0, 255, 255, 255), 1, trackLength, trackWidth * 2, trackLine);
cv::Point2f predictBoxR[4]; //更改纵向扫描方向,分两个方向?
for (int j = 0; j < 4; j++) cv::LineIterator it(sinParts, trackLine[0], trackLine[1], 4);
for (int n = 0; n < it.count; n++, ++it)
{ {
predictBoxR[j].x = matx[0] * (predictBox[j].x - (float)rLimits.x) + matx[1] * (predictBox[j].y - (float)rLimits.y) + matx[2]; float b = (float)cos(trackAngle*PI / 180.)*0.5f;
predictBoxR[j].y = matx[3] * (predictBox[j].x - (float)rLimits.x) + matx[4] * (predictBox[j].y - (float)rLimits.y) + matx[5]; float a = (float)sin(trackAngle*PI / 180.)*0.5f;
} pts[0].x = (float)(it.pos().x - a*trackLength * 2 - b*trackWidth * 4);
//中点 pts[0].y = (float)(it.pos().y + b*trackLength * 2 - a*trackWidth * 4);
cv::Point2f predicPosR((predictBoxR[0].x + predictBoxR[1].x + predictBoxR[2].x + predictBoxR[3].x) / 4.0f, pts[1].x = (float)(it.pos().x + a*trackLength * 2 - b*trackWidth * 4);
(predictBoxR[0].y + predictBoxR[1].y + predictBoxR[2].y + predictBoxR[3].y) / 4.0f); pts[1].y = (float)(it.pos().y - b*trackLength * 2 - a*trackWidth * 4);
pts[2].x = (float)(2 * it.pos().x - pts[0].x);
//理论区域 pts[2].y = (float)(2 * it.pos().y - pts[0].y);
cv::Rect tRec = cv::Rect(cv::Point(cvRound((predicPosR.x*2.0f - (float)trackLength*2.0f) / 2.0f), pts[3].x = (float)(2 * it.pos().x - pts[1].x);
cvRound((predicPosR.y*2.0f - (float)trackWidth*4.0f) / 2.0f)), pts[3].y = (float)(2 * it.pos().y - pts[1].y);
cv::Size(cvRound(trackLength*2.0), cvRound(trackWidth*4.0)))
&cv::Rect(0, 0, traceMat.cols, traceMat.rows); std::vector<cv::Point> vPoints;
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
//高精度理论区域 //获取内部坐标
cv::Rect_<float> tRecF = cv::Rect_<float>(cv::Point2f((predicPosR.x*2.0f - (float)trackLength*2.0f) / 2.0f, calcRotateRect(vRect, vPoints);
(predicPosR.y*2.0f - (float)trackWidth*4.0f) / 2.0f), //计算灰度值
cv::Size2f((float)trackLength*2.0f, (float)trackWidth*4.0f)) int iLimit = 0, iPartSize = 0;
&cv::Rect_<float>(0.0f, 0.0f, (float)traceMat.cols, (float)traceMat.rows); double dMatch = 0;
for (int v = 0; v < vPoints.size(); v++)
//理论区域向外扩展(即predictBox范围) {
cv::Rect rr = cv::Rect(cv::Point(cvRound((double)predicPosR.x - trackLength*2.0), if (vPoints[v].x >= 0 && vPoints[v].x <= X&&vPoints[v].y >= 0 && vPoints[v].y <= Y)
cvRound((double)predicPosR.y - trackWidth*4.0)), cv::Size(cvRound(trackLength*2.0*2.0),
cvRound(trackWidth*4.0*2.0)))&cv::Rect(0, 0, traceMat.cols, traceMat.rows);
cv::Rect_<float> rrf = cv::Rect2f(cv::Point2f((predicPosR.x*2.0f - (float)trackLength*4.0f) / 2.0f,
(predicPosR.y*2.0f - (float)trackWidth*8.0f) / 2.0f), cv::Size2f((float)trackLength*4.0f, (float)trackWidth*8.0f))
&cv::Rect2f(0.0f, 0.0f, (float)traceMat.cols, (float)traceMat.rows);
//元件尺寸太小放大N倍处理,这样坐标会精细些,考虑元件的80%尺寸作为kernel,防止元件尺寸变化太大
cv::Mat kernel = cv::Mat::ones(cv::Size(cv::max(cvRound((float)(trackLength*2.0) * coeff),
cvRound((float)(trackWidth*4.0) * coeff)), cv::min(cvRound((float)(trackLength*2.0) * coeff),
cvRound((float)(trackWidth*4.0) * coeff))), CV_32FC1);
cv::Mat _traceMat = traceMat.clone();
//放大
if (coeff > 1.0f) {
cv::resize(_traceMat, _traceMat, cv::Size(cvRound(traceMat.size().width * coeff), cvRound(traceMat.size().height * coeff)));
}
//计算最大值(当_traceMat尺寸小于kernel会报错)
cv::Mat dst;
cv::filter2D(_traceMat, dst, CV_32F, kernel);
//归一化
cv::Mat mmRescaling;
cv::normalize(dst, mmRescaling, 1.0, 0.0, cv::NORM_MINMAX);
//模板匹配做辅助判断,为了尽量避免定位出错
cv::Mat _tplMat;
tplMat.convertTo(_tplMat, CV_32FC1);
if (coeff > 1.0f) {
cv::resize(_tplMat, _tplMat, cv::Size(), coeff, coeff);
}
//考虑并行计算两个模板结果
cv::Mat tplResult0;
cv::matchTemplate(_traceMat, _tplMat, tplResult0, cv::TM_SQDIFF_NORMED);
int modx = _tplMat.cols % 2, mody = _tplMat.rows % 2;
cv::Mat tplResultMap;
cv::copyMakeBorder(tplResult0, tplResultMap, (_tplMat.rows - mody) / 2, _traceMat.rows - tplResult0.rows - (_tplMat.rows - mody) / 2,
(_tplMat.cols - modx) / 2, _traceMat.cols - tplResult0.cols - (_tplMat.cols - modx) / 2, cv::BORDER_REPLICATE);
//减去模板匹配的结果
mmRescaling -= tplResultMap;
//非极大值抑制
cv::Mat mask;
cv::dilate(mmRescaling, mask, cv::Mat());
cv::compare(mmRescaling, mask, mask, cv::CMP_GE);
cv::Mat non_plateau_mask;
cv::erode(mmRescaling, non_plateau_mask, cv::Mat());
cv::compare(mmRescaling, non_plateau_mask, non_plateau_mask, cv::CMP_GT);
cv::bitwise_and(mask, non_plateau_mask, mask);
//去掉分数过低的
mask &= cv::Mat(mmRescaling > 0.36);
//限定区域(mmRescaling范围内)
cv::Rect _rr = cv::Rect(cvRound(rr.x*coeff), cvRound(rr.y*coeff), cvRound(rr.width*coeff), cvRound(rr.height*coeff));
//候选元件位置
std::vector<cv::Point> candidates;
cv::findNonZero(mask(_rr), candidates);
//过滤
std::vector<Track> _vParts;
for (auto&candidate : candidates) {
cv::Point pt(candidate.x + _rr.x, candidate.y + _rr.y);
float confidence = mmRescaling.ptr<float>(pt.y)[pt.x];
if (confidence > 0.5f) {
_vParts.push_back(Track(0, 0, confidence, cv::Point2f((float)pt.x, (float)pt.y), std::vector<cv::Point2f>()));
}
}
//目标元件在小图中的位置
cv::Point2f maxLox;
//元件位置判断
if (_vParts.size() <= 0) {
//大概率终止
trayEnd = true;
}
else if (_vParts.size() == 1) {
//有可能会出错
maxLox = cv::Point2f(_vParts[0].Pos.x / coeff, _vParts[0].Pos.y / coeff);
if (tRecF.contains(maxLox)) {
//计算旋转前的坐标(即匹配的最终坐标)
float realX = 0.0f, realY = 0.0f;
realX = (float)rLimits.tl().x + ((maxLox.x - matx[2])*matx[4] - (maxLox.y - matx[5])*matx[1]) / (matx[0] * matx[4] - matx[3] * matx[1]);
realY = (float)rLimits.tl().y + ((maxLox.x - matx[2])*matx[3] - (maxLox.y - matx[5])*matx[0]) / (matx[1] * matx[3] - matx[4] * matx[0]);
//外包矩形顶点
cv::Point2f pts[4];
calcRotateRect(cv::Point2f(realX, realY), (float)(trackAngle + (trackOffset + partDist)), (float)trackLength*2.0f, (float)trackWidth*2.0f, pts);
//
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
}
else {
//这里负责处理意外情况(极大可能是元件偏离过多或者料盘中心定位不准确导致的),
//采用距离理论位置最近的点(两种方式都失效的概率比较低,如果真的失效那就听天由命吧)
cv::Mat _mmRescaling, _tplResultMap;
_mmRescaling = mmRescaling.clone(); _tplResultMap = tplResultMap.clone();
//累加的方式
double maxVal; cv::Point maxLoc;
cv::minMaxLoc(_mmRescaling(_rr), NULL, &maxVal, NULL, &maxLoc);
maxLoc += _rr.tl();
//模板匹配的方式
double minVal; cv::Point minLoc;
cv::minMaxLoc(_tplResultMap(_rr), &minVal, NULL, &minLoc, NULL);
minLoc += _rr.tl();
std::vector<Track> __vParts;
__vParts.push_back(Track(0, 0, cv::norm(cv::Point2f((float)maxLoc.x, (float)maxLoc.y) - cv::Point2f(floorf((float)_traceMat.cols / 2.0f), floorf((float)_traceMat.rows / 2.0f))),
cv::Point2f((float)maxLoc.x, (float)maxLoc.y), std::vector<cv::Point2f>()));
__vParts.push_back(Track(0, 0, cv::norm(cv::Point2f((float)minLoc.x, (float)minLoc.y) - cv::Point2f(floorf((float)_traceMat.cols / 2.0f), floorf((float)_traceMat.rows / 2.0f))),
cv::Point2f((float)minLoc.x, (float)minLoc.y), std::vector<cv::Point2f>()));
//排序
std::sort(__vParts.begin(), __vParts.end(), std::less<Track>());
//在小图中的位置
maxLox = cv::Point2f(__vParts[0].Pos.x / coeff, __vParts[0].Pos.y / coeff);
//计算旋转前的坐标(即匹配的最终坐标)
float realX = 0.0f, realY = 0.0f;
realX = (float)rLimits.tl().x + ((maxLox.x - matx[2])*matx[4] - (maxLox.y - matx[5])*matx[1]) / (matx[0] * matx[4] - matx[3] * matx[1]);
realY = (float)rLimits.tl().y + ((maxLox.x - matx[2])*matx[3] - (maxLox.y - matx[5])*matx[0]) / (matx[1] * matx[3] - matx[4] * matx[0]);
//外包矩形顶点
cv::Point2f pts[4];
calcRotateRect(cv::Point2f(realX, realY), (float)(trackAngle + (trackOffset + partDist)), (float)trackLength*2.0f, (float)trackWidth*2.0f, pts);
//
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
for (int j = 0; j < 4; j++)
{ {
cv::line(cc, predictBox[j], predictBox[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1); iLimit += ucpTrackLabel[(vPoints[v].x) + (vPoints[v].y)*X];
dMatch += (srcPrev.data)[(vPoints[v].x) + (vPoints[v].y)*X];
if ((sinParts.data)[(vPoints[v].x) + (vPoints[v].y)*X] == 255)
iPartSize++;
} }
} }
vParts.push_back(Track(iLimit, iPartSize, dMatch, it.pos(), vRect));
//cv::circle(cc, it.pos(), 0, cv::Scalar(255, 0, 0, 255), 1);
} }
else { if (vParts.size() == 0) continue;
//存在多个峰值,先判断分数最高是否位于理论位置 //方案二每个点以当前半径画圆,看下个点偏离圆多少
std::sort(_vParts.begin(), _vParts.end(), std::greater<Track>()); //灰度极值认为是元件(最多问题出现在这里,加个条件判断矩形内是否存在已标记像素)
for (auto&_vPart : _vParts) { std::sort(vParts.begin(), vParts.end(), std::greater<Track>());
maxLox = cv::Point2f(_vPart.Pos.x / coeff, _vPart.Pos.y / coeff); //更新当前元件位置(必须不与已有元件重合)
if (tRecF.contains(maxLox)) { Track mac = vParts[0];
//计算旋转前的坐标(即匹配的最终坐标) if (mac.iLimit != 0)
float realX = 0.0f, realY = 0.0f; {
realX = (float)rLimits.tl().x + ((maxLox.x - matx[2])*matx[4] - (maxLox.y - matx[5])*matx[1]) / (matx[0] * matx[4] - matx[3] * matx[1]); for (int cc = 1; cc < vParts.size(); cc++)
realY = (float)rLimits.tl().y + ((maxLox.x - matx[2])*matx[3] - (maxLox.y - matx[5])*matx[0]) / (matx[1] * matx[3] - matx[4] * matx[0]); {
if (vParts[cc].iLimit < mac.iLimit)
//外包矩形顶点 mac = vParts[cc];
cv::Point2f pts[4]; if (mac.iLimit == 0)
calcRotateRect(cv::Point2f(realX, realY), (float)(trackAngle + (trackOffset + partDist)), (float)trackLength*2.0f, (float)trackWidth*2.0f, pts);
//
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
break; break;
}
}
//如果不在则选取距离理论位置最近的
if (vParts.empty()) {
//这里负责处理意外情况(极大可能是元件偏离过多或者中心定位不准确)
//,采用距离理论位置最近的点(两种方式都失效的概率比较低)
cv::Mat _mmRescaling, _tplResultMap;
_mmRescaling = mmRescaling.clone(); _tplResultMap = tplResultMap.clone();
//累加的方式
double maxVal; cv::Point maxLoc;
cv::minMaxLoc(_mmRescaling(_rr), NULL, &maxVal, NULL, &maxLoc);
maxLoc += _rr.tl();
//模板匹配的方式
double minVal; cv::Point minLoc;
cv::minMaxLoc(_tplResultMap(_rr), &minVal, NULL, &minLoc, NULL);
minLoc += _rr.tl();
std::vector<Track> __vParts;
__vParts.push_back(Track(0, 0, cv::norm(cv::Point2f((float)maxLoc.x, (float)maxLoc.y) - cv::Point2f(floorf((float)_traceMat.cols / 2.0f), floorf((float)_traceMat.rows / 2.0f))),
cv::Point2f((float)maxLoc.x, (float)maxLoc.y), std::vector<cv::Point2f>()));
__vParts.push_back(Track(0, 0, cv::norm(cv::Point2f((float)minLoc.x, (float)minLoc.y) - cv::Point2f(floorf((float)_traceMat.cols / 2.0f), floorf((float)_traceMat.rows / 2.0f))),
cv::Point2f((float)minLoc.x, (float)minLoc.y), std::vector<cv::Point2f>()));
//排序
std::sort(__vParts.begin(), __vParts.end(), std::less<Track>());
//在小图中的位置
maxLox = cv::Point2f(__vParts[0].Pos.x / coeff, __vParts[0].Pos.y / coeff);
//计算旋转前的坐标(即匹配的最终坐标)
float realX = 0.0f, realY = 0.0f;
realX = (float)rLimits.tl().x + ((maxLox.x - matx[2])*matx[4] - (maxLox.y - matx[5])*matx[1]) / (matx[0] * matx[4] - matx[3] * matx[1]);
realY = (float)rLimits.tl().y + ((maxLox.x - matx[2])*matx[3] - (maxLox.y - matx[5])*matx[0]) / (matx[1] * matx[3] - matx[4] * matx[0]);
//外包矩形顶点
cv::Point2f pts[4];
calcRotateRect(cv::Point2f(realX, realY), (float)(trackAngle + (trackOffset + partDist)), (float)trackLength*2.0f, (float)trackWidth*2.0f, pts);
//
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
for (int j = 0; j < 4; j++)
{
cv::line(cc, predictBox[j], predictBox[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1);
}
} }
} }
trackCenter = mac.Pos;
if (!vParts.empty()) { //更新扫描半径
cv::Rect tRec_ = cv::Rect(cv::Point(cvFloor((((float)maxLox.x)*2.0f - (float)trackLength*2.0f) / 2.0f), trackRadius = cv::norm(trackCenter - reelCenter);
cvFloor((((float)maxLox.y)*2.0f - (float)trackWidth*4.0f) / 2.0f)), //更新扫描角度
cv::Size(cvRound(trackLength*2.0) + 2, cvRound(trackWidth*4.0) + 2)) trackAngle = atan2((double)trackCenter.y - reelCenter.y, (double)trackCenter.x - reelCenter.x) * 180 / PI;
&cv::Rect(0, 0, traceMat.cols, traceMat.rows); //更新偏移量(元件大小)
//当作一种辅助手段,无需设置太严格 trackOffset = (2 * asin(2 * trackLength / (2 * trackRadius))) * 180 / PI;
double dmax; //更新元件间角度
cv::minMaxLoc(traceMat(tRec_).clone(), NULL, &dmax); partDist = (2 * asin(dChordL / (2 * trackRadius))) * 180 / PI;
if (dmax < 0.7*taMaxGray) { //判断是否结束
trayEnd = true; if ((mac.iPartSize < sinPartSize / 4) || (trackMat.at<uchar>((cvRound(trackCenter.y)), (cvRound(trackCenter.x))) == 255) || (mac.iLimit / 255) > (rect.size.area() / 4) || (sinParts.at<uchar>((cvRound(trackCenter.y)), (cvRound(trackCenter.x))) == 0))
} {
found = false;
//for (int j = 0; j < 4; j++)
//{
// cv::line(cc, trackEndPos.Rect[j], trackEndPos.Rect[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1);
//}
//cv::circle(cc, trackCenter, 1, cv::Scalar(0, 255, 0, 255), 1);
} }
break; else
}
//追踪终止,选取下一个起点
if (trayEnd) {
break;
}
//更新位置
trackCenter = cv::Point2f(vParts[0].Pos.x, vParts[0].Pos.y);
//更新扫描半径
trackRadius = cv::norm(trackCenter - reelCenter);
//更新扫描角度
trackAngle = atan2((double)trackCenter.y - (double)reelCenter.y, (double)trackCenter.x - (double)reelCenter.x) * 180.0 / PI;
//更新偏移量(元件角度大小)
trackOffset = (2 * asin(2 * trackLength / (2 * trackRadius))) * 180.0 / PI;
//更新元件间角度
partDist = (2 * asin(dChordL / (2 * trackRadius))) * 180.0 / PI;
//追踪到了重复的元件
if (trackMat.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] == 255) {
found = false;
}
else {
//计算元件位置
cv::Point2f pts[4];
calcRotateRect(trackCenter, (float)trackAngle, (float)trackLength, (float)trackWidth, pts);
//标记计数
lbMat.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] = 255;
//标记为已追踪过
std::vector<cv::Point> vT = { cv::Point(pts[0]),cv::Point(pts[1]) ,cv::Point(pts[2]) ,cv::Point(pts[3]) };
cv::fillConvexPoly(trackMat, vT, cv::Scalar(255));
//用于显示
cv::circle(cc, trackCenter, 2, cv::Scalar(0, 255, 0, 255), 1);
//#ifdef _DEBUG
for (int j = 0; j < 4; j++)
{ {
cv::line(cc, pts[j], pts[(j + 1) % 4], cv::Scalar(14, 173, 238, 255), 1); //画出最终位置
} std::vector<cv::Point> ptPoly;
//#endif for (int j = 0; j < 4; j++)
} {
//清空下一个 ptPoly.push_back(cv::Point(cvRound(mac.Rect[j].x), cvRound(mac.Rect[j].y)));
vParts.resize(0); //cv::line(cc, mac.Rect[j], mac.Rect[(j + 1) % 4], cv::Scalar(0, 255, 0, 255), 1);
//跳过执行
if (killProcessID == 0) {
logger.t("eyemCountObjectIrregularPartsE 追踪阶段被跳过执行...");
found = false;
}
trackEnd = (!found);
} while (!trackEnd);
}
//逆时针
{
//追踪起点
cv::Point2f trackCenter(startCenter.x, startCenter.y);
//追踪角度、半径
double trackAngle = startAngle, trackRadius = startRadius;
//元件本身角度
double trackOffset = dOffset;
//元件间间距
double partDist = (2.0 * asin(dChordL / (2.0 * trackRadius))) * 180.0 / PI;
//开始追踪
bool trackEnd = true;
//
do
{
bool found = true; bool trayEnd = false;
std::vector<Track> vParts;
for (double t = trackAngle - (trackOffset + partDist - trackOffset / 12.0); t > trackAngle - (trackOffset + partDist - trackOffset / 12.0) - trackOffset / 6.0; t -= dMinorStep)
{
cv::Point2f predicPos;
predicPos.x = reelCenter.x + (float)trackRadius*(float)cos((trackAngle - (trackOffset + partDist))*c);
predicPos.y = reelCenter.y + (float)trackRadius*(float)sin((trackAngle - (trackOffset + partDist))*c);
//如果追踪到图像外追踪终止
if (cvRound(predicPos.x) < 0 || (cvRound(predicPos.x) > X - 1) || cvRound(predicPos.y) < 0 || (cvRound(predicPos.y) > Y - 1)) {
trayEnd = true;
break;
}
//感兴趣区域(向外扩展了一个元件,防止中心定位出现偏差或者料盘本身变形导致的偏差)
cv::Point2f predicBox[4];
calcRotateRect(predicPos, (float)(trackAngle - (trackOffset + partDist)), (float)trackLength*2.0f, (float)trackWidth*2.0f, predicBox);
cv::RotatedRect r(predicBox[0], predicBox[1], predicBox[2]);
cv::Rect rLimits = r.boundingRect()&cv::Rect(0, 0, X, Y);
//获取感兴趣区域
float matx[6];
cv::Mat traceMat = getTrackMat(srcPrevS(rLimits).clone()
, (trackAngle - (trackOffset + partDist)) + 90.0, fillVal, matx);
//计算原图中的点在旋转后的位置(即在traceMat中的精确位置)
cv::Point2f predictBoxR[4];
for (int j = 0; j < 4; j++)
{
predictBoxR[j].x = matx[0] * (predicBox[j].x - (float)rLimits.x) + matx[1] * (predicBox[j].y - (float)rLimits.y) + matx[2];
predictBoxR[j].y = matx[3] * (predicBox[j].x - (float)rLimits.x) + matx[4] * (predicBox[j].y - (float)rLimits.y) + matx[5];
}
//中点
cv::Point2f predicPosR((predictBoxR[0].x + predictBoxR[1].x + predictBoxR[2].x + predictBoxR[3].x) / 4.0f,
(predictBoxR[0].y + predictBoxR[1].y + predictBoxR[2].y + predictBoxR[3].y) / 4.0f);
//理论区域
cv::Rect tRec = cv::Rect(cv::Point(cvRound((predicPosR.x*2.0f - (float)trackLength*2.0f) / 2.0f),
cvRound((predicPosR.y*2.0f - (float)trackWidth*4.0f) / 2.0f)),
cv::Size(cvRound(trackLength*2.0), cvRound(trackWidth*4.0)))
&cv::Rect(0, 0, traceMat.cols, traceMat.rows);
//高精度理论区域
cv::Rect_<float> tRecF = cv::Rect_<float>(cv::Point2f((predicPosR.x*2.0f - (float)trackLength*2.0f) / 2.0f,
(predicPosR.y*2.0f - (float)trackWidth*4.0f) / 2.0f),
cv::Size2f((float)trackLength*2.0f, (float)trackWidth*4.0f))
&cv::Rect_<float>(0.0f, 0.0f, (float)traceMat.cols, (float)traceMat.rows);
//理论区域向外扩展(即predictBox范围)
cv::Rect rr = cv::Rect(cv::Point(cvRound((double)predicPosR.x - trackLength*2.0),
cvRound((double)predicPosR.y - trackWidth*4.0)), cv::Size(cvRound(trackLength*2.0*2.0),
cvRound(trackWidth*4.0*2.0)))&cv::Rect(0, 0, traceMat.cols, traceMat.rows);
cv::Rect_<float> rrf = cv::Rect2f(cv::Point2f((predicPosR.x*2.0f - (float)trackLength*4.0f) / 2.0f,
(predicPosR.y*2.0f - (float)trackWidth*8.0f) / 2.0f), cv::Size2f((float)trackLength*4.0f, (float)trackWidth*8.0f))
&cv::Rect2f(0.0f, 0.0f, (float)traceMat.cols, (float)traceMat.rows);
//元件尺寸太小放大N倍处理,这样坐标会精细些,元件的80%尺寸作为kernel,防止元件尺寸变化太大
cv::Mat kernel = cv::Mat::ones(cv::Size(cv::max(cvRound((float)(trackLength*2.0) * coeff),
cvRound((float)(trackWidth*4.0) * coeff)), cv::min(cvRound((float)(trackLength*2.0) * coeff),
cvRound((float)(trackWidth*4.0) * coeff))), CV_32FC1);
cv::Mat _traceMat = traceMat.clone();
//放大
if (coeff > 1.0f) {
cv::resize(_traceMat, _traceMat, cv::Size(cvRound(traceMat.size().width * coeff), cvRound(traceMat.size().height * coeff)));
}
//计算最大值(当_traceMat尺寸小于kernel会报错)
cv::Mat dst;
cv::filter2D(_traceMat, dst, CV_32F, kernel);
//归一化
cv::Mat mmRescaling;
cv::normalize(dst, mmRescaling, 1.0, 0.0, cv::NORM_MINMAX);
//模板匹配,为了尽量避免定位出错
cv::Mat _tplMat;
tplMat.convertTo(_tplMat, CV_32FC1);
if (coeff > 1.0f) {
cv::resize(_tplMat, _tplMat, cv::Size(), coeff, coeff);
}
//考虑并行计算两个模板结果
cv::Mat tplResult0;
cv::matchTemplate(_traceMat, _tplMat, tplResult0, cv::TM_SQDIFF_NORMED);
int modx = _tplMat.cols % 2, mody = _tplMat.rows % 2;
cv::Mat tplResultMap;
cv::copyMakeBorder(tplResult0, tplResultMap, (_tplMat.rows - mody) / 2, _traceMat.rows - tplResult0.rows - (_tplMat.rows - mody) / 2,
(_tplMat.cols - modx) / 2, _traceMat.cols - tplResult0.cols - (_tplMat.cols - modx) / 2, cv::BORDER_REPLICATE);
//减去模板匹配的结果
mmRescaling -= tplResultMap;
//非极大值抑制
cv::Mat mask;
cv::dilate(mmRescaling, mask, cv::Mat());
cv::compare(mmRescaling, mask, mask, cv::CMP_GE);
cv::Mat non_plateau_mask;
cv::erode(mmRescaling, non_plateau_mask, cv::Mat());
cv::compare(mmRescaling, non_plateau_mask, non_plateau_mask, cv::CMP_GT);
cv::bitwise_and(mask, non_plateau_mask, mask);
//去掉分数过低的
mask &= cv::Mat(mmRescaling > 0.36);
//限定区域(mmRescaling范围内)
cv::Rect _rr = cv::Rect(cvRound(rr.x*coeff), cvRound(rr.y*coeff), cvRound(rr.width*coeff), cvRound(rr.height*coeff));
//候选元件位置
std::vector<cv::Point> candidates;
cv::findNonZero(mask(_rr), candidates);
//过滤
std::vector<Track> _vParts;
for (auto&candidate : candidates) {
cv::Point pt(candidate.x + _rr.x, candidate.y + _rr.y);
float confidence = mmRescaling.ptr<float>(pt.y)[pt.x];
if (confidence > 0.5f) {
_vParts.push_back(Track(0, 0, confidence, cv::Point2f((float)pt.x, (float)pt.y), std::vector<cv::Point2f>()));
}
}
//目标元件在小图中的位置
cv::Point2f maxLox;
//元件位置判断
if (_vParts.size() <= 0) {
//大概率终止
trayEnd = true;
}
else if (_vParts.size() == 1) {
maxLox = cv::Point2f(_vParts[0].Pos.x / coeff, _vParts[0].Pos.y / coeff);
//有可能会出错,当靠的太近可能只存在一个峰值
if (tRecF.contains(maxLox)) {
//计算旋转前的坐标(即匹配的最终坐标)
float realX = 0.0f, realY = 0.0f;
realX = (float)rLimits.tl().x + ((maxLox.x - matx[2])*matx[4] - (maxLox.y - matx[5])*matx[1]) / (matx[0] * matx[4] - matx[3] * matx[1]);
realY = (float)rLimits.tl().y + ((maxLox.x - matx[2])*matx[3] - (maxLox.y - matx[5])*matx[0]) / (matx[1] * matx[3] - matx[4] * matx[0]);
//外包矩形顶点
cv::Point2f pts[4];
calcRotateRect(cv::Point2f(realX, realY), (float)(trackAngle + (trackOffset + partDist)), (float)trackLength*2.0f, (float)trackWidth*2.0f, pts);
//
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
} }
else { cv::circle(cc, trackCenter, 2, cv::Scalar(0, 255, 0, 255), 1);
//这里负责处理意外情况(极大可能是元件偏离过多或者中心定位不准确),采用距离理论位置最近的点(两种方式都失效的概率比较低) cv::circle(lb4Count, trackCenter, 0, cv::Scalar(255), 1);
cv::Mat _mmRescaling, _tplResultMap; //标记Label
_mmRescaling = mmRescaling.clone(); _tplResultMap = tplResultMap.clone(); cv::fillConvexPoly(trackMat, ptPoly, cv::Scalar(255));
//获得已处理标签
//累加的方式 std::vector<cv::Point> vTemp;
double maxVal; cv::Point maxLoc; calcRotateRect(mac.Rect, vTemp);
cv::minMaxLoc(_mmRescaling(_rr), NULL, &maxVal, NULL, &maxLoc); for (int p = 0; p < vTemp.size(); p++)
maxLoc += _rr.tl(); {
if (vTemp[p].x >= 0 && vTemp[p].x <= X&&vTemp[p].y >= 0 && vTemp[p].y <= Y)
//模板匹配的方式
double minVal; cv::Point minLoc;
cv::minMaxLoc(_tplResultMap(_rr), &minVal, NULL, &minLoc, NULL);
minLoc += _rr.tl();
std::vector<Track> __vParts;
__vParts.push_back(Track(0, 0, cv::norm(cv::Point2f((float)maxLoc.x, (float)maxLoc.y) - cv::Point2f(floorf((float)_traceMat.cols / 2.0f), floorf((float)_traceMat.rows / 2.0f))),
cv::Point2f((float)maxLoc.x, (float)maxLoc.y), std::vector<cv::Point2f>()));
__vParts.push_back(Track(0, 0, cv::norm(cv::Point2f((float)minLoc.x, (float)minLoc.y) - cv::Point2f(floorf((float)_traceMat.cols / 2.0f), floorf((float)_traceMat.rows / 2.0f))),
cv::Point2f((float)minLoc.x, (float)minLoc.y), std::vector<cv::Point2f>()));
//排序
std::sort(__vParts.begin(), __vParts.end(), std::less<Track>());
//小图中的定位坐标
maxLox = cv::Point2f(__vParts[0].Pos.x / coeff, __vParts[0].Pos.y / coeff);
//计算旋转前的坐标(即匹配的最终坐标)
float realX = 0.0f, realY = 0.0f;
realX = (float)rLimits.tl().x + ((maxLox.x - matx[2])*matx[4] - (maxLox.y - matx[5])*matx[1]) / (matx[0] * matx[4] - matx[3] * matx[1]);
realY = (float)rLimits.tl().y + ((maxLox.x - matx[2])*matx[3] - (maxLox.y - matx[5])*matx[0]) / (matx[1] * matx[3] - matx[4] * matx[0]);
//外包矩形顶点
cv::Point2f pts[4];
calcRotateRect(cv::Point2f(realX, realY), (float)(trackAngle - (trackOffset + partDist)), (float)trackLength*2.0f, (float)trackWidth*2.0f, pts);
//
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
for (int j = 0; j < 4; j++)
{ {
cv::line(cc, predicBox[j], predicBox[(j + 1) % 4], cv::Scalar(0, 0, 238, 255), 1); int label = labels.at<int>(vTemp[p]);
} if (label != 0)
} {
} labeled[label] = 255;
else { break;
//存在定位出错的可能性,先判断分数最高是否位于理论位置 }
std::sort(_vParts.begin(), _vParts.end(), std::greater<Track>()); }
for (auto&_vPart : _vParts) { }
maxLox = cv::Point2f(_vPart.Pos.x / coeff, _vPart.Pos.y / coeff); }
if (tRecF.contains(maxLox)) {
//计算旋转前的坐标(即匹配的最终坐标)
float realX = 0.0f, realY = 0.0f;
realX = (float)rLimits.tl().x + ((maxLox.x - matx[2])*matx[4] - (maxLox.y - matx[5])*matx[1]) / (matx[0] * matx[4] - matx[3] * matx[1]);
realY = (float)rLimits.tl().y + ((maxLox.x - matx[2])*matx[3] - (maxLox.y - matx[5])*matx[0]) / (matx[1] * matx[3] - matx[4] * matx[0]);
//外包矩形顶点
cv::Point2f pts[4];
calcRotateRect(cv::Point2f(realX, realY), (float)(trackAngle - (trackOffset + partDist)), (float)trackLength*2.0f, (float)trackWidth*2.0f, pts);
//
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
break;
}
}
//如果不在则选取距离理论位置最近的
if (vParts.empty()) {
//这里负责处理意外情况(极大可能是元件偏离过多或者中心定位不准确),采用距离理论位置最近的点(两种方式都失效的概率比较低)
cv::Mat _mmRescaling, _tplResultMap;
_mmRescaling = mmRescaling.clone(); _tplResultMap = tplResultMap.clone();
//累加的方式
double maxVal; cv::Point maxLoc;
cv::minMaxLoc(_mmRescaling(_rr), NULL, &maxVal, NULL, &maxLoc);
maxLoc += _rr.tl();
//模板匹配的方式
double minVal; cv::Point minLoc;
cv::minMaxLoc(_tplResultMap(_rr), &minVal, NULL, &minLoc, NULL);
minLoc += _rr.tl();
std::vector<Track> __vParts;
__vParts.push_back(Track(0, 0, cv::norm(cv::Point2f((float)maxLoc.x, (float)maxLoc.y) - cv::Point2f(floorf((float)_traceMat.cols / 2.0f), floorf((float)_traceMat.rows / 2.0f))),
cv::Point2f((float)maxLoc.x, (float)maxLoc.y), std::vector<cv::Point2f>()));
__vParts.push_back(Track(0, 0, cv::norm(cv::Point2f((float)minLoc.x, (float)minLoc.y) - cv::Point2f(floorf((float)_traceMat.cols / 2.0f), floorf((float)_traceMat.rows / 2.0f))),
cv::Point2f((float)minLoc.x, (float)minLoc.y), std::vector<cv::Point2f>()));
//排序
std::sort(__vParts.begin(), __vParts.end(), std::less<Track>());
//小图中的位置
maxLox = cv::Point2f(__vParts[0].Pos.x / coeff, __vParts[0].Pos.y / coeff);
//计算旋转前的坐标(即匹配的最终坐标)
float realX = 0.0f, realY = 0.0f;
realX = (float)rLimits.tl().x + ((maxLox.x - matx[2])*matx[4] - (maxLox.y - matx[5])*matx[1]) / (matx[0] * matx[4] - matx[3] * matx[1]);
realY = (float)rLimits.tl().y + ((maxLox.x - matx[2])*matx[3] - (maxLox.y - matx[5])*matx[0]) / (matx[1] * matx[3] - matx[4] * matx[0]);
//外包矩形顶点 //跳过执行
cv::Point2f pts[4]; if (killProcessID == 0) {
calcRotateRect(cv::Point2f(realX, realY), (float)(trackAngle - (trackOffset + partDist)), (float)trackLength*2.0f, (float)trackWidth*2.0f, pts); logger.t("eyemCountObjectIrregularPartsE 追踪阶段被跳过执行...");
found = false;
}
// trackEnd = (!found);
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f)); } while (!trackEnd);
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect)); }
for (int j = 0; j < 4; j++) //#pragma omp section
//逆时针追踪
{
//追踪起点
cv::Point2f trackCenter(startCenter.x, startCenter.y);
//起始扫描角度、半径
double trackAngle = startAngle, trackRadius = startRadius;
//元件本身角度
double trackOffset = dOffset;
//元件间间距
double partDist = (2 * asin(dChordL / (2 * trackRadius))) * 180 / PI;
//当扫描一圈后修正中心位置(待测试)
cv::Point2f pts[4];
//结束位置
Track trackEndPos;
//开始追踪
bool trackEnd = true;
//
do
{
bool found = true;
std::vector<Track> vParts;
for (double t = trackAngle - (partDist + trackOffset / 2.0); t > trackAngle - (partDist + trackOffset / 2.0) - trackOffset; t -= dMinorStep)
{
trackCenter.x = float(reelCenter.x + trackRadius*cos(t*c));
trackCenter.y = float(reelCenter.y + trackRadius*sin(t*c));
float b = (float)cos(t*c)*0.5f;
float a = (float)sin(t*c)*0.5f;
pts[0].x = (float)(trackCenter.x - a*trackLength * 2 - b*trackWidth * 4);
pts[0].y = (float)(trackCenter.y + b*trackLength * 2 - a*trackWidth * 4);
pts[1].x = (float)(trackCenter.x + a*trackLength * 2 - b*trackWidth * 4);
pts[1].y = (float)(trackCenter.y - b*trackLength * 2 - a*trackWidth * 4);
pts[2].x = (float)(2 * trackCenter.x - pts[0].x);
pts[2].y = (float)(2 * trackCenter.y - pts[0].y);
pts[3].x = (float)(2 * trackCenter.x - pts[1].x);
pts[3].y = (float)(2 * trackCenter.y - pts[1].y);
std::vector<cv::Point> vPoints;
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
//获取内部坐标
calcRotateRect(vRect, vPoints);
//计算灰度值
double dMatch = 0;
for (int v = 0; v < vPoints.size(); v++)
{
if (vPoints[v].x >= 0 && vPoints[v].x <= X&&vPoints[v].y >= 0 && vPoints[v].y <= Y)
{ {
cv::line(cc, predicBox[j], predicBox[(j + 1) % 4], cv::Scalar(0, 0, 238, 255), 1); dMatch += (srcPrev.data)[(vPoints[v].x) + (vPoints[v].y)*X];
} }
} }
dMatch /= (double)vPoints.size();
//仅扫描一个元件的角度
vParts.push_back(Track(0, 0, dMatch, cv::Point(cvRound(trackCenter.x), cvRound(trackCenter.y)), vRect));
//cv::circle(cc, trackCenter, 0, cv::Scalar(0, 255, 255, 255), 1);
} }
if (!vParts.empty()) { if (vParts.size() == 0) continue;
cv::Rect tRec_ = cv::Rect(cv::Point(cvFloor((((float)maxLox.x)*2.0f - (float)trackLength*2.0f) / 2.0f), //
cvFloor((((float)maxLox.y)*2.0f - (float)trackWidth*4.0f) / 2.0f)), trackEndPos = vParts[vParts.size() / 2];
cv::Size(cvRound(trackLength*2.0) + 2, cvRound(trackWidth*4.0) + 2)) //灰度极值认为是元件
&cv::Rect(0, 0, traceMat.cols, traceMat.rows); std::sort(vParts.begin(), vParts.end(), std::greater<Track>());
//当作一种辅助手段,无需设置太严格 //更新位置
double dmax; trackCenter = cv::Point(vParts[0].Pos.x, vParts[0].Pos.y);
cv::minMaxLoc(traceMat(tRec_).clone(), NULL, &dmax); //更新扫描角度
if (dmax < 0.7*taMaxGray) { trackAngle = atan2((double)trackCenter.y - reelCenter.y, (double)trackCenter.x - reelCenter.x) * 180 / PI;
trayEnd = true; //纵向扫描
vParts.clear();
std::vector<cv::Point> trackLine;
drawLine(cc, reelCenter, trackCenter, cv::Scalar(0, 255, 255, 255), 1, trackLength, trackWidth * 2, trackLine);
//更改纵向扫描方向,分两个方向
cv::LineIterator it(sinParts, trackLine[0], trackLine[1], 4);
for (int n = 0; n < it.count; n++, ++it)
{
float b = (float)cos(trackAngle*PI / 180.)*0.5f;
float a = (float)sin(trackAngle*PI / 180.)*0.5f;
pts[0].x = (float)(it.pos().x - a*trackLength * 2 - b*trackWidth * 4);
pts[0].y = (float)(it.pos().y + b*trackLength * 2 - a*trackWidth * 4);
pts[1].x = (float)(it.pos().x + a*trackLength * 2 - b*trackWidth * 4);
pts[1].y = (float)(it.pos().y - b*trackLength * 2 - a*trackWidth * 4);
pts[2].x = (float)(2 * it.pos().x - pts[0].x);
pts[2].y = (float)(2 * it.pos().y - pts[0].y);
pts[3].x = (float)(2 * it.pos().x - pts[1].x);
pts[3].y = (float)(2 * it.pos().y - pts[1].y);
std::vector<cv::Point> vPoints;
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
//获取内部坐标
calcRotateRect(vRect, vPoints);
//计算灰度值
int iLimit = 0, iPartSize = 0;
double dMatch = 0;
for (int v = 0; v < vPoints.size(); v++)
{
if (vPoints[v].x >= 0 && vPoints[v].x <= X&&vPoints[v].y >= 0 && vPoints[v].y <= Y)
{
iLimit += ucpTrackLabel[(vPoints[v].x) + (vPoints[v].y)*X];
dMatch += (srcPrev.data)[(vPoints[v].x) + (vPoints[v].y)*X];
if ((sinParts.data)[(vPoints[v].x) + (vPoints[v].y)*X] == 255)
iPartSize++;
}
} }
vParts.push_back(Track(iLimit, iPartSize, dMatch, it.pos(), vRect));
//cv::circle(cc, it.pos(), 0, cv::Scalar(255, 0, 0, 255), 1);
} }
break; if (vParts.size() == 0) continue;
} //灰度极值认为是元件
//接着下一个起点 std::sort(vParts.begin(), vParts.end(), std::greater<Track>());
if (trayEnd) { //更新当前元件位置
break; Track mac = vParts[0];
} if (mac.iLimit != 0)
//更新位置
trackCenter = cv::Point2f(vParts[0].Pos.x, vParts[0].Pos.y);
//更新扫描半径
trackRadius = cv::norm(trackCenter - reelCenter);
//更新扫描角度
trackAngle = atan2((double)trackCenter.y - (double)reelCenter.y, (double)trackCenter.x - (double)reelCenter.x) * 180.0 / PI;
//更新偏移量(元件角度大小)
trackOffset = (2.0 * asin(2.0 * trackLength / (2.0 * trackRadius))) * 180.0 / PI;
//更新元件间角度
partDist = (2.0 * asin(dChordL / (2.0 * trackRadius))) * 180.0 / PI;
//追踪到了重复的元件
if (trackMat.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] == 255) {
found = false;
}
else {
//计算元件位置
cv::Point2f pts[4];
calcRotateRect(trackCenter, (float)trackAngle, (float)trackLength, (float)trackWidth, pts);
//标记计数
lbMat.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] = 255;
//标记为已追踪过
std::vector<cv::Point> vT = { cv::Point(pts[0]),cv::Point(pts[1]) ,cv::Point(pts[2]) ,cv::Point(pts[3]) };
cv::fillConvexPoly(trackMat, vT, cv::Scalar(255));
//用于显示
cv::circle(cc, trackCenter, 2, cv::Scalar(0, 255, 0, 255), 1);
//#ifdef _DEBUG
for (int j = 0; j < 4; j++)
{ {
cv::line(cc, pts[j], pts[(j + 1) % 4], cv::Scalar(102, 205, 0, 255), 1); for (int cc = 1; cc < vParts.size(); cc++)
{
if (vParts[cc].iLimit < mac.iLimit)
mac = vParts[cc];
if (mac.iLimit == 0)
break;
}
} }
//#endif trackCenter = mac.Pos;
} //更新扫描半径
//继续下一个起点 trackRadius = cv::norm(trackCenter - reelCenter);
vParts.resize(0); //更新扫描角度
//跳过执行 trackAngle = atan2((double)trackCenter.y - reelCenter.y, (double)trackCenter.x - reelCenter.x) * 180 / PI;
if (killProcessID == 0) { //更新偏移量
logger.t("eyemCountObjectIrregularParts 追踪阶段被跳过执行..."); trackOffset = (2 * asin(2 * trackLength / (2 * trackRadius))) * 180 / PI;
found = false; //更新追踪角度
} partDist = (2 * asin(dChordL / (2 * trackRadius))) * 180 / PI;
trackEnd = (!found); //绕完一周后更新料盘中心试试?
} while (!trackEnd); //判断是否结束
if (mac.iPartSize < sinPartSize / 4 || (trackMat.at<uchar>((cvRound(trackCenter.y)), (cvRound(trackCenter.x))) == 255) || (mac.iLimit / 255) >(rect.size.area() / 4) || (sinParts.at<uchar>((cvRound(trackCenter.y)), (cvRound(trackCenter.x))) == 0))
{
found = false;
//for (int j = 0; j < 4; j++)
//{
// cv::line(cc, trackEndPos.Rect[j], trackEndPos.Rect[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1);
//}
//cv::circle(cc, trackCenter, 1, cv::Scalar(0, 255, 0, 255), 1);
}
else
{
//画出最终位置
std::vector<cv::Point> ptPoly;
for (int j = 0; j < 4; j++)
{
ptPoly.push_back(cv::Point(cvRound(mac.Rect[j].x), cvRound(mac.Rect[j].y)));
//cv::line(cc, mac.Rect[j], mac.Rect[(j + 1) % 4], cv::Scalar(0, 255, 0, 255), 1);
}
//
cv::circle(cc, trackCenter, 2, cv::Scalar(0, 255, 0, 255), 1);
cv::circle(lb4Count, trackCenter, 0, cv::Scalar(255), 1);
//标记Label
cv::fillConvexPoly(trackMat, ptPoly, cv::Scalar(255));
//获得已处理标签
std::vector<cv::Point> vTemp;
calcRotateRect(mac.Rect, vTemp);
for (int p = 0; p < vTemp.size(); p++)
{
if (vTemp[p].x >= 0 && vTemp[p].x <= X&&vTemp[p].y >= 0 && vTemp[p].y <= Y)
{
int label = labels.at<int>(vTemp[p]);
if (label != 0)
{
labeled[label] = 255;
break;
}
}
}
}
//跳过执行
if (killProcessID == 0) {
logger.t("eyemCountObjectIrregularPartsE 追踪阶段被跳过执行...");
found = false;
}
trackEnd = (!found);
} while (!trackEnd);
}
} }
} //去掉已标记处理的
cv::parallel_for_(cv::Range(0, Y), [&](const cv::Range& range)->void {
for (int y = range.start; y < range.end; y++)
{
for (int x = 0; x < X; x++)
{
int label = ((int *)labels.data)[(x)+(y)*labels.cols];
CV_Assert(0 <= label && label <= nccomps);
if (labeled[label])
{
((int *)(labels.data))[(x)+(y)*X] = 0;
}
}
}
});
image = labels > 0;
//判断是否存在未追踪单个料
bExistSingle = (cv::countNonZero(image) == 0);
} while (!bExistSingle);
//标记料盘编号 //标记料盘编号
//cv::putText(cc, std::to_string(sortedTrays[i].iDir), cv::Point(cvRound(reelCenter.x), cvRound(reelCenter.y) - 50), 0, 1.0, cv::Scalar(0, 140, 255, 255), 2); //cv::putText(cc, std::to_string(sortedTrays[i].iDir), cv::Point(cvRound(reelCenter.x), cvRound(reelCenter.y) - 50), 0, 1.0, cv::Scalar(0, 140, 255, 255), 2);
//计数 //计数
int reelNum = cv::countNonZero(lbMat); int numObj = cv::countNonZero(lb4Count);
std::string text = std::to_string(i + 1) + ": Reel Number = "; std::string text = std::to_string(i + 1) + ": Reel Number = ";
text += std::to_string(reelNum); text += std::to_string(numObj);
text += " ; PartSize = " + std::to_string(sinPartSize); text += " ; PartSize = " + std::to_string(sinPartSize);
cv::putText(cc, text, cv::Point(35, 35 + i * 35), 0, 1.0, cv::Scalar(0, 140, 255, 255), 2); cv::putText(cc, text, cv::Point(35, 35 + i * 35), 0, 1.0, cv::Scalar(0, 140, 255, 255), 2);
//输出 //输出
trayNum[sortedTrays[i].iDir] = reelNum; trayNum[sortedTrays[i].iDir] = numObj;
//释放资源 //释放资源
delete[] ucpTrackLabel; delete[] ucpTrackLabel;
ucpTrackLabel = NULL; ucpTrackLabel = NULL;
} }
} }
//输出结果 //输出结果
const int bufSize = 64; const int SizeConst = 4;
char cTrayNum[bufSize * 4] = { 0 };
for (int i = 0; i < trayNum.size(); i++) {
char cTemp[bufSize] = { 0 };
sprintf_s(cTemp, bufSize, "%d,", trayNum[i]);
strcat(cTrayNum, cTemp);
}
//拷贝std::string拼接的字符串会莫名的报错??
*lpszNumObj = (char *)CoTaskMemAlloc(bufSize * 4);
memset(*lpszNumObj, 0, bufSize * 4);
if (NULL != *lpszNumObj) {
strcpy(*lpszNumObj, cTrayNum);
}
//<输出计数结果标记图像 //<输出计数结果标记图像
{ {
for (int i = 0; i < SizeConst; i++) {
ipReelNum[i] = trayNum[i];
}
tpDstImg->iWidth = cc.cols; tpDstImg->iHeight = cc.rows; tpDstImg->iDepth = cc.depth(); tpDstImg->iChannels = cc.channels(); tpDstImg->iWidth = cc.cols; tpDstImg->iHeight = cc.rows; tpDstImg->iDepth = cc.depth(); tpDstImg->iChannels = cc.channels();
//内存尺寸 //内存尺寸
...@@ -2066,7 +1656,7 @@ int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LPS ...@@ -2066,7 +1656,7 @@ int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LPS
return FUNC_OK; return FUNC_OK;
} }
int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char *fileName, const char * ccSubType, LPSTR *lpszReelNum, EyemImage *tpDstImg) int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char *fileName, const char * ccSubType, int *ipReelNum, EyemImage *tpDstImg)
{ {
cv::Mat src = cv::Mat(tpImage.iHeight, tpImage.iWidth, MAKETYPE(tpImage.iDepth, tpImage.iChannels), tpImage.vpImage).clone(); cv::Mat src = cv::Mat(tpImage.iHeight, tpImage.iWidth, MAKETYPE(tpImage.iDepth, tpImage.iChannels), tpImage.vpImage).clone();
if (src.empty()) { if (src.empty()) {
...@@ -2781,9 +2371,9 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -2781,9 +2371,9 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
cv::Point p2 = cv::Point(cvRound(x + trackWidth * cos(angle + CV_PI)), cv::Point p2 = cv::Point(cvRound(x + trackWidth * cos(angle + CV_PI)),
cvRound(y + trackWidth * sin(angle + CV_PI))); cvRound(y + trackWidth * sin(angle + CV_PI)));
//#ifdef _DEBUG #ifdef _DEBUG
cv::line(cc, p1, p2, cv::Scalar(0, 215, 255, 255), 1); cv::line(cc, p1, p2, cv::Scalar(0, 215, 255, 255), 1);
//#endif #endif
cv::LineIterator it(binary, p1, p2, 4); cv::LineIterator it(binary, p1, p2, 4);
for (int n = 0; n < it.count; n++, ++it) for (int n = 0; n < it.count; n++, ++it)
{ {
...@@ -3001,11 +2591,12 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -3001,11 +2591,12 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
// //
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f)); std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect)); vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
#ifdef _DEBUG
for (int j = 0; j < 4; j++) for (int j = 0; j < 4; j++)
{ {
cv::line(cc, predictBox[j], predictBox[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1); cv::line(cc, predictBox[j], predictBox[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1);
} }
#endif
} }
} }
else { else {
...@@ -3071,11 +2662,12 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -3071,11 +2662,12 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
// //
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f)); std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect)); vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
#ifdef _DEBUG
for (int j = 0; j < 4; j++) for (int j = 0; j < 4; j++)
{ {
cv::line(cc, predictBox[j], predictBox[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1); cv::line(cc, predictBox[j], predictBox[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1);
} }
#endif
} }
} }
...@@ -3122,12 +2714,12 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -3122,12 +2714,12 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
cv::fillConvexPoly(trackMat, vT, cv::Scalar(255)); cv::fillConvexPoly(trackMat, vT, cv::Scalar(255));
//用于显示 //用于显示
cv::circle(cc, trackCenter, 2, cv::Scalar(0, 255, 0, 255), 1); cv::circle(cc, trackCenter, 2, cv::Scalar(0, 255, 0, 255), 1);
//#ifdef _DEBUG #ifdef _DEBUG
for (int j = 0; j < 4; j++) for (int j = 0; j < 4; j++)
{ {
cv::line(cc, pts[j], pts[(j + 1) % 4], cv::Scalar(14, 173, 238, 255), 1); cv::line(cc, pts[j], pts[(j + 1) % 4], cv::Scalar(14, 173, 238, 255), 1);
} }
//#endif #endif
} }
//清空下一个 //清空下一个
vParts.resize(0); vParts.resize(0);
...@@ -3334,11 +2926,12 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -3334,11 +2926,12 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
// //
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f)); std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect)); vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
#ifdef _DEBUG
for (int j = 0; j < 4; j++) for (int j = 0; j < 4; j++)
{ {
cv::line(cc, predicBox[j], predicBox[(j + 1) % 4], cv::Scalar(0, 0, 238, 255), 1); cv::line(cc, predicBox[j], predicBox[(j + 1) % 4], cv::Scalar(0, 0, 238, 255), 1);
} }
#endif
} }
} }
else { else {
...@@ -3402,23 +2995,15 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -3402,23 +2995,15 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
// //
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f)); std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect)); vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
#ifdef _DEBUG
for (int j = 0; j < 4; j++) for (int j = 0; j < 4; j++)
{ {
cv::line(cc, predicBox[j], predicBox[(j + 1) % 4], cv::Scalar(0, 0, 238, 255), 1); cv::line(cc, predicBox[j], predicBox[(j + 1) % 4], cv::Scalar(0, 0, 238, 255), 1);
} }
#endif
} }
} }
if (!vParts.empty()) { if (!vParts.empty()) {
#pragma region 测试用
////显示用
//cv::Mat traceMat4, traceMat5;
//_traceMat.convertTo(traceMat4, CV_8U);
//traceMat.convertTo(traceMat5, CV_8U);
//cv::rectangle(traceMat5, rr, cv::Scalar(0));
//cv::rectangle(traceMat4, _rr, cv::Scalar(0));
#pragma endregion
cv::Rect tRec_ = cv::Rect(cv::Point(cvFloor((((float)maxLox.x)*2.0f - (float)trackLength*2.0f) / 2.0f), cv::Rect tRec_ = cv::Rect(cv::Point(cvFloor((((float)maxLox.x)*2.0f - (float)trackLength*2.0f) / 2.0f),
cvFloor((((float)maxLox.y)*2.0f - (float)trackWidth*4.0f) / 2.0f)), cvFloor((((float)maxLox.y)*2.0f - (float)trackWidth*4.0f) / 2.0f)),
cv::Size(cvRound(trackLength*2.0) + 2, cvRound(trackWidth*4.0) + 2)) cv::Size(cvRound(trackLength*2.0) + 2, cvRound(trackWidth*4.0) + 2))
...@@ -3461,12 +3046,12 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -3461,12 +3046,12 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
cv::fillConvexPoly(trackMat, vT, cv::Scalar(255)); cv::fillConvexPoly(trackMat, vT, cv::Scalar(255));
//用于显示 //用于显示
cv::circle(cc, trackCenter, 2, cv::Scalar(0, 255, 0, 255), 1); cv::circle(cc, trackCenter, 2, cv::Scalar(0, 255, 0, 255), 1);
//#ifdef _DEBUG #ifdef _DEBUG
for (int j = 0; j < 4; j++) for (int j = 0; j < 4; j++)
{ {
cv::line(cc, pts[j], pts[(j + 1) % 4], cv::Scalar(102, 205, 0, 255), 1); cv::line(cc, pts[j], pts[(j + 1) % 4], cv::Scalar(102, 205, 0, 255), 1);
} }
//#endif #endif
} }
//继续下一个起点 //继续下一个起点
vParts.resize(0); vParts.resize(0);
...@@ -3820,9 +3405,9 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -3820,9 +3405,9 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
cv::Point p2 = cv::Point(cvRound(x + trackWidth * cos(angle + CV_PI)), cv::Point p2 = cv::Point(cvRound(x + trackWidth * cos(angle + CV_PI)),
cvRound(y + trackWidth * sin(angle + CV_PI))); cvRound(y + trackWidth * sin(angle + CV_PI)));
//#ifdef _DEBUG #ifdef _DEBUG
cv::line(cc, p1, p2, cv::Scalar(0, 215, 255, 255), 1); cv::line(cc, p1, p2, cv::Scalar(0, 215, 255, 255), 1);
//#endif #endif
cv::LineIterator it(binary, p1, p2, 4); cv::LineIterator it(binary, p1, p2, 4);
for (int n = 0; n < it.count; n++, ++it) for (int n = 0; n < it.count; n++, ++it)
{ {
...@@ -4040,11 +3625,12 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -4040,11 +3625,12 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
// //
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f)); std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect)); vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
#ifdef _DEBUG
for (int j = 0; j < 4; j++) for (int j = 0; j < 4; j++)
{ {
cv::line(cc, predictBox[j], predictBox[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1); cv::line(cc, predictBox[j], predictBox[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1);
} }
#endif
} }
} }
else { else {
...@@ -4110,11 +3696,12 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -4110,11 +3696,12 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
// //
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f)); std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect)); vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
#ifdef _DEBUG
for (int j = 0; j < 4; j++) for (int j = 0; j < 4; j++)
{ {
cv::line(cc, predictBox[j], predictBox[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1); cv::line(cc, predictBox[j], predictBox[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1);
} }
#endif
} }
} }
...@@ -4373,11 +3960,12 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -4373,11 +3960,12 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
// //
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f)); std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect)); vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
#ifdef _DEBUG
for (int j = 0; j < 4; j++) for (int j = 0; j < 4; j++)
{ {
cv::line(cc, predicBox[j], predicBox[(j + 1) % 4], cv::Scalar(0, 0, 238, 255), 1); cv::line(cc, predicBox[j], predicBox[(j + 1) % 4], cv::Scalar(0, 0, 238, 255), 1);
} }
#endif
} }
} }
else { else {
...@@ -4441,11 +4029,12 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -4441,11 +4029,12 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
// //
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f)); std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect)); vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
#ifdef _DEBUG
for (int j = 0; j < 4; j++) for (int j = 0; j < 4; j++)
{ {
cv::line(cc, predicBox[j], predicBox[(j + 1) % 4], cv::Scalar(0, 0, 238, 255), 1); cv::line(cc, predicBox[j], predicBox[(j + 1) % 4], cv::Scalar(0, 0, 238, 255), 1);
} }
#endif
} }
} }
if (!vParts.empty()) { if (!vParts.empty()) {
...@@ -4646,47 +4235,15 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -4646,47 +4235,15 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
else else
{ {
//先用自动算法点,如果不行判断为散料 //先用自动算法点,如果不行判断为散料
LPSTR trayNum = ""; int trayNum[4];
int iRet = eyemCountObjectE(tpImage, tpRoi, "", &trayNum, tpDstImg); int iRet = eyemCountObjectE(tpImage, tpRoi, "", trayNum, tpDstImg);
if (iRet == FUNC_OK) { if (iRet == FUNC_OK) {
cv::Mat showCC = cv::Mat(tpDstImg->iHeight, tpDstImg->iWidth, MAKETYPE(tpDstImg->iDepth, tpDstImg->iChannels), tpDstImg->vpImage);
std::vector<std::string> trayNums;
split(trayNum, ",", trayNums);
//输出结果 //输出结果
std::string tTrayNum = ""; for (int i = 0; i < 4; i++) {
//输出结果
for (int i = 0; i < 4; i++) ipReelNum[i] = trayNum[i];
{ break;
if (trayNums[i] != "0")
{
//输出结果
tTrayNum = trayNums[i];
break;
}
}
*lpszReelNum = (char *)CoTaskMemAlloc(tTrayNum.size() + 1);
if (NULL != lpszReelNum)
{
strcpy(*lpszReelNum, tTrayNum.c_str());
} }
//获取当前运行目录
char buf[128];
_getcwd(buf, sizeof(buf));
////不存在则创建
std::string filePath(buf);
filePath += "\\ResOut";
if (_access(filePath.c_str(), 0) == -1)
_mkdir(filePath.c_str());
//格式化文件名
char file[256];
sprintf_s(file, "%s\\%s-Mark.png", filePath.c_str(), fileName);
cv::imwrite(file, showCC);
return FUNC_OK; return FUNC_OK;
} }
else { else {
...@@ -4755,17 +4312,13 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -4755,17 +4312,13 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
std::string text = "Reel Number = " + std::to_string(trayNum); std::string text = "Reel Number = " + std::to_string(trayNum);
cv::putText(cc, text, cv::Point(35, 35), 0, 1.0, cv::Scalar(0, 140, 255, 255), 2); cv::putText(cc, text, cv::Point(35, 35), 0, 1.0, cv::Scalar(0, 140, 255, 255), 2);
//<输出结果 //<输出结果
const int bufSize = 16; const int SizeConst = 4;
char cReelNum[bufSize] = { 0 };
sprintf_s(cReelNum, bufSize, "%d,", trayNum);
//拷贝std::string拼接的字符串会莫名的报错??
*lpszReelNum = (char *)CoTaskMemAlloc(bufSize);
memset(*lpszReelNum, 0, bufSize);
if (NULL != *lpszReelNum) {
strcpy(*lpszReelNum, cReelNum);
}
//<输出计数结果标记图像 //<输出计数结果标记图像
{ {
memset(ipReelNum, 0, SizeConst);
ipReelNum[0] = trayNum;
tpDstImg->iWidth = cc.cols; tpDstImg->iHeight = cc.rows; tpDstImg->iDepth = cc.depth(); tpDstImg->iChannels = cc.channels(); tpDstImg->iWidth = cc.cols; tpDstImg->iHeight = cc.rows; tpDstImg->iDepth = cc.depth(); tpDstImg->iChannels = cc.channels();
//内存尺寸 //内存尺寸
...@@ -4783,7 +4336,7 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -4783,7 +4336,7 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
return FUNC_OK; return FUNC_OK;
} }
int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LPSTR *lpszNumObj, EyemImage *tpDstImg) int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, int *ipReelNum, EyemImage *tpDstImg)
{ {
cv::Mat src = cv::Mat(tpImage.iHeight, tpImage.iWidth, MAKETYPE(tpImage.iDepth, tpImage.iChannels), tpImage.vpImage).clone(); cv::Mat src = cv::Mat(tpImage.iHeight, tpImage.iWidth, MAKETYPE(tpImage.iDepth, tpImage.iChannels), tpImage.vpImage).clone();
if (src.empty()) { if (src.empty()) {
...@@ -4903,13 +4456,9 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP ...@@ -4903,13 +4456,9 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP
trays.push_back(TrayPos(reelCenter, tray, false, backThresh)); trays.push_back(TrayPos(reelCenter, tray, false, backThresh));
} }
//判断可能无料,不能100%判断 //判断可能无料,不能100%判断
if (trays.size() < 1) if (trays.size() < 1) {
{ for (int i = 0; i < 4; i++) {
std::string strTrayNum = "无料,"; ipReelNum[i] = 0;
*lpszNumObj = (char *)CoTaskMemAlloc(strTrayNum.size());
if (NULL != *lpszNumObj)
{
strcpy(*lpszNumObj, strTrayNum.c_str());
} }
return FUNC_CANNOT_CALC; return FUNC_CANNOT_CALC;
} }
...@@ -4975,8 +4524,10 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP ...@@ -4975,8 +4524,10 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP
//分料盘计数 //分料盘计数
for (int i = 0; i < sortedTrays.size(); i++) for (int i = 0; i < sortedTrays.size(); i++)
{ {
cv::Mat srcPrev; cv::Mat srcPrev, srcPrevB;
cv::bitwise_not(sortedTrays[i].Tray, srcPrev); cv::bitwise_not(sortedTrays[i].Tray, srcPrev);
//备份
srcPrevB = srcPrev.clone();
//二值化可以分别放在两个算法里 //二值化可以分别放在两个算法里
cv::Mat sinParts; cv::Mat sinParts;
cv::threshold(srcPrev, sinParts, (255 - sortedTrays[i].dBackThresh), 255, cv::THRESH_BINARY); cv::threshold(srcPrev, sinParts, (255 - sortedTrays[i].dBackThresh), 255, cv::THRESH_BINARY);
...@@ -5297,7 +4848,7 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP ...@@ -5297,7 +4848,7 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP
cv::Mat lbMat(Y, X, CV_8UC1, cv::Scalar(0)); cv::Mat lbMat(Y, X, CV_8UC1, cv::Scalar(0));
//定位图像 //定位图像
cv::Mat srcPrevS, tplMat;//模板文件 cv::Mat srcPrevS, tplMat;//模板文件
srcPrev.convertTo(srcPrevS, CV_32F); srcPrevB.convertTo(srcPrevS, CV_32F);
//随机打乱顺序(降低计算错误dChordL的可能性,也为了测试在起点信息不同时的稳定性) //随机打乱顺序(降低计算错误dChordL的可能性,也为了测试在起点信息不同时的稳定性)
std::random_shuffle(tracingAnchors.begin(), tracingAnchors.end()); std::random_shuffle(tracingAnchors.begin(), tracingAnchors.end());
//开始确定起点(现在是用圆轨迹来追踪,不排除用螺旋线轨迹来追踪) //开始确定起点(现在是用圆轨迹来追踪,不排除用螺旋线轨迹来追踪)
...@@ -5331,7 +4882,7 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP ...@@ -5331,7 +4882,7 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP
//确定元件位置根据旋转后的位置确定(前提是料盘中心定位的准确) //确定元件位置根据旋转后的位置确定(前提是料盘中心定位的准确)
double t = atan2((double)startCenter.y - reelCenter.y, (double)startCenter.x - reelCenter.x) * 180.0 / PI; double t = atan2((double)startCenter.y - reelCenter.y, (double)startCenter.x - reelCenter.x) * 180.0 / PI;
//计算旋转角度 //计算旋转角度
cv::Mat traceMat = srcPrev(_rLimits); cv::Mat traceMat = srcPrevB(_rLimits);
//这里计算得出的模板不是很对 //这里计算得出的模板不是很对
float matx[6]; float matx[6];
tplMat = getTrackMat(traceMat, t + 90.0, 0, matx); tplMat = getTrackMat(traceMat, t + 90.0, 0, matx);
...@@ -5422,7 +4973,7 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP ...@@ -5422,7 +4973,7 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP
const double dMinorStep = 0.1; const double dMinorStep = 0.1;
//追踪长宽 //追踪长宽
const double trackLength = taLength / 2.0, trackWidth = taHeight / 4.0;//是否用较小尺寸的窗口 const double trackLength = taLength / 2.0, trackWidth = taHeight / 4.0;//是否用较小尺寸的窗口
//起始扫描角度 //起始扫描角度
const double startAngle = atan2((double)startCenter.y - reelCenter.y, (double)startCenter.x - reelCenter.x) * 180.0 / PI; const double startAngle = atan2((double)startCenter.y - reelCenter.y, (double)startCenter.x - reelCenter.x) * 180.0 / PI;
//起始扫描半径 //起始扫描半径
const double startRadius = cv::norm(startCenter - reelCenter); const double startRadius = cv::norm(startCenter - reelCenter);
...@@ -5452,9 +5003,9 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP ...@@ -5452,9 +5003,9 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP
cv::Point p2 = cv::Point(cvRound(x + trackWidth * cos(angle + CV_PI)), cv::Point p2 = cv::Point(cvRound(x + trackWidth * cos(angle + CV_PI)),
cvRound(y + trackWidth * sin(angle + CV_PI))); cvRound(y + trackWidth * sin(angle + CV_PI)));
//#ifdef _DEBUG #ifdef _DEBUG
cv::line(cc, p1, p2, cv::Scalar(0, 215, 255, 255), 1); cv::line(cc, p1, p2, cv::Scalar(0, 215, 255, 255), 1);
//#endif #endif
cv::LineIterator it(sinParts, p1, p2, 4); cv::LineIterator it(sinParts, p1, p2, 4);
for (int n = 0; n < it.count; n++, ++it) for (int n = 0; n < it.count; n++, ++it)
{ {
...@@ -5672,11 +5223,12 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP ...@@ -5672,11 +5223,12 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP
// //
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f)); std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect)); vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
#ifdef _DEBUG
for (int j = 0; j < 4; j++) for (int j = 0; j < 4; j++)
{ {
cv::line(cc, predictBox[j], predictBox[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1); cv::line(cc, predictBox[j], predictBox[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1);
} }
#endif
} }
} }
else { else {
...@@ -5742,14 +5294,14 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP ...@@ -5742,14 +5294,14 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP
// //
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f)); std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect)); vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
#ifdef _DEBUG
for (int j = 0; j < 4; j++) for (int j = 0; j < 4; j++)
{ {
cv::line(cc, predictBox[j], predictBox[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1); cv::line(cc, predictBox[j], predictBox[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1);
} }
#endif
} }
} }
if (!vParts.empty()) { if (!vParts.empty()) {
cv::Rect tRec_ = cv::Rect(cv::Point(cvFloor((((float)maxLox.x)*2.0f - (float)trackLength*2.0f) / 2.0f), cv::Rect tRec_ = cv::Rect(cv::Point(cvFloor((((float)maxLox.x)*2.0f - (float)trackLength*2.0f) / 2.0f),
cvFloor((((float)maxLox.y)*2.0f - (float)trackWidth*4.0f) / 2.0f)), cvFloor((((float)maxLox.y)*2.0f - (float)trackWidth*4.0f) / 2.0f)),
...@@ -5793,12 +5345,12 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP ...@@ -5793,12 +5345,12 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP
cv::fillConvexPoly(trackMat, vT, cv::Scalar(255)); cv::fillConvexPoly(trackMat, vT, cv::Scalar(255));
//用于显示 //用于显示
cv::circle(cc, trackCenter, 2, cv::Scalar(0, 255, 0, 255), 1); cv::circle(cc, trackCenter, 2, cv::Scalar(0, 255, 0, 255), 1);
//#ifdef _DEBUG #ifdef _DEBUG
for (int j = 0; j < 4; j++) for (int j = 0; j < 4; j++)
{ {
cv::line(cc, pts[j], pts[(j + 1) % 4], cv::Scalar(14, 173, 238, 255), 1); cv::line(cc, pts[j], pts[(j + 1) % 4], cv::Scalar(14, 173, 238, 255), 1);
} }
//#endif #endif
} }
//清空下一个 //清空下一个
vParts.resize(0); vParts.resize(0);
...@@ -6005,11 +5557,12 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP ...@@ -6005,11 +5557,12 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP
// //
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f)); std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect)); vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
#ifdef _DEBUG
for (int j = 0; j < 4; j++) for (int j = 0; j < 4; j++)
{ {
cv::line(cc, predicBox[j], predicBox[(j + 1) % 4], cv::Scalar(0, 0, 238, 255), 1); cv::line(cc, predicBox[j], predicBox[(j + 1) % 4], cv::Scalar(0, 0, 238, 255), 1);
} }
#endif
} }
} }
else { else {
...@@ -6073,13 +5626,15 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP ...@@ -6073,13 +5626,15 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP
// //
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f)); std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect)); vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
#ifdef _DEBUG
for (int j = 0; j < 4; j++) for (int j = 0; j < 4; j++)
{ {
cv::line(cc, predicBox[j], predicBox[(j + 1) % 4], cv::Scalar(0, 0, 238, 255), 1); cv::line(cc, predicBox[j], predicBox[(j + 1) % 4], cv::Scalar(0, 0, 238, 255), 1);
} }
#endif
} }
} }
if (!vParts.empty()) { if (!vParts.empty()) {
cv::Rect tRec_ = cv::Rect(cv::Point(cvFloor((((float)maxLox.x)*2.0f - (float)trackLength*2.0f) / 2.0f), cv::Rect tRec_ = cv::Rect(cv::Point(cvFloor((((float)maxLox.x)*2.0f - (float)trackLength*2.0f) / 2.0f),
cvFloor((((float)maxLox.y)*2.0f - (float)trackWidth*4.0f) / 2.0f)), cvFloor((((float)maxLox.y)*2.0f - (float)trackWidth*4.0f) / 2.0f)),
...@@ -6123,12 +5678,12 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP ...@@ -6123,12 +5678,12 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP
cv::fillConvexPoly(trackMat, vT, cv::Scalar(255)); cv::fillConvexPoly(trackMat, vT, cv::Scalar(255));
//用于显示 //用于显示
cv::circle(cc, trackCenter, 2, cv::Scalar(0, 255, 0, 255), 1); cv::circle(cc, trackCenter, 2, cv::Scalar(0, 255, 0, 255), 1);
//#ifdef _DEBUG #ifdef _DEBUG
for (int j = 0; j < 4; j++) for (int j = 0; j < 4; j++)
{ {
cv::line(cc, pts[j], pts[(j + 1) % 4], cv::Scalar(102, 205, 0, 255), 1); cv::line(cc, pts[j], pts[(j + 1) % 4], cv::Scalar(102, 205, 0, 255), 1);
} }
//#endif #endif
} }
//继续下一个起点 //继续下一个起点
vParts.resize(0); vParts.resize(0);
...@@ -6157,21 +5712,13 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP ...@@ -6157,21 +5712,13 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP
} }
} }
//输出结果 //输出结果
const int bufSize = 64; const int SizeConst = 4;
char cTrayNum[bufSize * 4] = { 0 };
for (int i = 0; i < trayNum.size(); i++) {
char cTemp[bufSize] = { 0 };
sprintf_s(cTemp, bufSize, "%d,", trayNum[i]);
strcat(cTrayNum, cTemp);
}
//拷贝std::string拼接的字符串会莫名的报错??
*lpszNumObj = (char *)CoTaskMemAlloc(bufSize * 4);
memset(*lpszNumObj, 0, bufSize * 4);
if (NULL != *lpszNumObj) {
strcpy(*lpszNumObj, cTrayNum);
}
//<输出计数结果标记图像 //<输出计数结果标记图像
{ {
for (int i = 0; i < SizeConst; i++) {
ipReelNum[i] = trayNum[i];
}
tpDstImg->iWidth = cc.cols; tpDstImg->iHeight = cc.rows; tpDstImg->iDepth = cc.depth(); tpDstImg->iChannels = cc.channels(); tpDstImg->iWidth = cc.cols; tpDstImg->iHeight = cc.rows; tpDstImg->iDepth = cc.depth(); tpDstImg->iChannels = cc.channels();
//内存尺寸 //内存尺寸
...@@ -6189,7 +5736,7 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP ...@@ -6189,7 +5736,7 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP
return FUNC_OK; return FUNC_OK;
} }
int eyemCountObjectIrregularPartsE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, const char *ccTplName, IntPtr hModelID, LPSTR *lpszReelNum, EyemImage *tpDstImg) int eyemCountObjectIrregularPartsE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, const char *ccTplName, IntPtr hModelID, int *ipReelNum, EyemImage *tpDstImg)
{ {
cv::Mat src = cv::Mat(tpImage.iHeight, tpImage.iWidth, MAKETYPE(tpImage.iDepth, tpImage.iChannels), tpImage.vpImage).clone(); cv::Mat src = cv::Mat(tpImage.iHeight, tpImage.iWidth, MAKETYPE(tpImage.iDepth, tpImage.iChannels), tpImage.vpImage).clone();
...@@ -7097,22 +6644,14 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -7097,22 +6644,14 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, EyemRect tpRoi, const char
std::string text = "Reel Number = " + std::to_string(reelNum); std::string text = "Reel Number = " + std::to_string(reelNum);
cv::putText(cc, text, cv::Point(35, 35), 0, 1.0, cv::Scalar(0, 140, 255, 255), 2); cv::putText(cc, text, cv::Point(35, 35), 0, 1.0, cv::Scalar(0, 140, 255, 255), 2);
///<输出结果 //<输出结果
const int bufSize = 16; const int SizeConst = 4;
//<输出计数结果标记图像
char cReelNum[bufSize] = { 0 };
sprintf_s(cReelNum, bufSize, "%d,", reelNum);
//拷贝std::string拼接的字符串会莫名的报错??
*lpszReelNum = (char *)CoTaskMemAlloc(bufSize);
memset(*lpszReelNum, 0, bufSize);
if (NULL != *lpszReelNum)
{ {
strcpy(*lpszReelNum, cReelNum); memset(ipReelNum, 0, SizeConst);
}
ipReelNum[0] = reelNum;
///<输出计数结果标记图像
{
tpDstImg->iWidth = cc.cols; tpDstImg->iHeight = cc.rows; tpDstImg->iDepth = cc.depth(); tpDstImg->iChannels = cc.channels(); tpDstImg->iWidth = cc.cols; tpDstImg->iHeight = cc.rows; tpDstImg->iDepth = cc.depth(); tpDstImg->iChannels = cc.channels();
//内存尺寸 //内存尺寸
...@@ -7502,7 +7041,13 @@ int eyemRemoveModelByName(IntPtr hModelID, const char *ccTplName) ...@@ -7502,7 +7041,13 @@ int eyemRemoveModelByName(IntPtr hModelID, const char *ccTplName)
return FUNC_OK; return FUNC_OK;
} }
int eyemMatchTemplateModel(EyemImage tpImage, IntPtr hModelID, LPSTR *lpszTplName) int eyemRemoveModelByID(IntPtr hModelID, const int iTplID)
{
return FUNC_OK;
}
int eyemMatchTemplateModel(EyemImage tpImage, IntPtr hModelID, char **lpszTplName)
{ {
cv::Mat image = cv::Mat(tpImage.iHeight, tpImage.iWidth, MAKETYPE(tpImage.iDepth, tpImage.iChannels), tpImage.vpImage).clone(); cv::Mat image = cv::Mat(tpImage.iHeight, tpImage.iWidth, MAKETYPE(tpImage.iDepth, tpImage.iChannels), tpImage.vpImage).clone();
...@@ -7617,93 +7162,6 @@ int eyemMatchTemplateModel(EyemImage tpImage, IntPtr hModelID, LPSTR *lpszTplNam ...@@ -7617,93 +7162,6 @@ int eyemMatchTemplateModel(EyemImage tpImage, IntPtr hModelID, LPSTR *lpszTplNam
return FUNC_OK; return FUNC_OK;
} }
int eyemUpdateModel(const char *ccTplPath)
{
//获取文件路径
std::vector<std::string> fileNames;
cv::glob(ccTplPath, fileNames);
//判断文件
if (fileNames.size() <= 0)
return FUNC_CANNOT_CALC;
for (std::vector<std::string>::iterator it = fileNames.begin(); it != fileNames.end(); ++it) {
std::string fileName = (*it);
struct stat _Stat;
if (stat(fileName.c_str(), &_Stat) != 0)
return FUNC_CANNOT_CALC;
FILE *fps = NULL;
fopen_s(&fps, fileName.c_str(), "r");
//判断文件是否打开
if (NULL == fps)
return FUNC_CANNOT_CALC;
//获取文件大小
const int _Size = (int)_Stat.st_size;
//分配内存
unsigned char *_Data = (unsigned char *)malloc(_Size);
if (NULL == _Data)
return FUNC_CANNOT_CALC;
//初始化
memset(_Data, 0, _Size);
//读取数据
fread(_Data, sizeof(uint8_t), _Size, fps);
//关闭文件
fclose(fps);
////获取图像数据大小
//unsigned char _SizeData[8];
//memcpy(_SizeData, _Data, 8);
////有效信息长度
//const int valSize = std::atoi((const char *)_SizeData);
////文件信息
//const int tplSize = _Size - valSize - 8;
////拷贝文件信息
//char *tplInfo = new char[tplSize];
//memcpy(tplInfo, _Data + valSize + 8, tplSize);
////获取文件信息
//std::string line(tplInfo);
//std::vector<std::string> hints;
//split(line, ",", hints);
////宽,高,坐标,匹配度
//int X = std::atoi(hints[2].c_str()), Y = std::atoi(hints[3].c_str());
//double dMatchDeg = std::atof(hints[4].substr(0, 4).c_str()); pt = cv::Point(std::atoi(hints[0].c_str()), std::atoi(hints[1].c_str()));
//////创建图像文件
////cv::Mat tplMat= tplMat.create(Y, X, CV_8UC1, -1, true);
//////拷贝数据
////cv::Mat _tplMat = tplMat.getMat();
////memcpy(_tplMat.data, _Data + 8, valSize);
////释放内存
//delete[] tplInfo;
//tplInfo = NULL;
////释放文件内存
//free(_Data);
//_Data = NULL;
}
return FUNC_OK;
}
int eyemReleaseModel(IntPtr &hModelID) int eyemReleaseModel(IntPtr &hModelID)
{ {
if (NULL == hModelID) if (NULL == hModelID)
...@@ -7803,7 +7261,6 @@ int eyemTrackFeature(EyemImage tpRefImg, EyemImage tpNextImg, EyemRect3 *tpRois, ...@@ -7803,7 +7261,6 @@ int eyemTrackFeature(EyemImage tpRefImg, EyemImage tpNextImg, EyemRect3 *tpRois,
int eyemAOIForTSAV(EyemImage tpRefImg, EyemImage tpNextImg, EyemRect3 *tpRois, int iRoiNum) int eyemAOIForTSAV(EyemImage tpRefImg, EyemImage tpNextImg, EyemRect3 *tpRois, int iRoiNum)
{ {
return FUNC_OK; return FUNC_OK;
} }
......
...@@ -5,17 +5,12 @@ ...@@ -5,17 +5,12 @@
#ifndef __EYEM_MISC_H #ifndef __EYEM_MISC_H
#define __EYEM_MISC_H #define __EYEM_MISC_H
#include <io.h>
#include <fstream>
#include <direct.h>
#include "eyemLib.h" #include "eyemLib.h"
#include <tbb\tbb.h> #include <tbb\tbb.h>
extern Logger logger;
constexpr double c = PI / 180.; constexpr double c = PI / 180.;
extern Logger logger;
extern int killProcessID; extern int killProcessID;
#endif/* __EYEM_MISC_H */ #endif/* __EYEM_MISC_H */
...@@ -48,6 +48,7 @@ std::vector<std::string> NNDetector::detectAndDecode(cv::InputArray img, std::ve ...@@ -48,6 +48,7 @@ std::vector<std::string> NNDetector::detectAndDecode(cv::InputArray img, std::ve
if (img.cols() <= 20 || img.rows() <= 20) { if (img.cols() <= 20 || img.rows() <= 20) {
return std::vector<std::string>(); return std::vector<std::string>();
} }
logger.t("__eyemDetectAndDecodeUseNN__detectAndDecode__:开始图像格式转换");
cv::Mat input; cv::Mat input;
int incn = img.channels(); int incn = img.channels();
if (incn == 4) { if (incn == 4) {
...@@ -59,14 +60,20 @@ std::vector<std::string> NNDetector::detectAndDecode(cv::InputArray img, std::ve ...@@ -59,14 +60,20 @@ std::vector<std::string> NNDetector::detectAndDecode(cv::InputArray img, std::ve
else { else {
input = img.getMat(); input = img.getMat();
} }
logger.t("__eyemDetectAndDecodeUseNN__detectAndDecode__:图像格式转换完成");
_mtx.lock(); _mtx.lock();
//识别 //识别
logger.t("__eyemDetectAndDecodeUseNN__detectAndDecode__:开始识别二维码");
std::vector<cv::Rect> bboxes = p->detect(input); std::vector<cv::Rect> bboxes = p->detect(input);
for (auto&bbox : bboxes) { for (auto&bbox : bboxes) {
__points.push_back(bbox); __points.push_back(bbox);
} }
logger.t("__eyemDetectAndDecodeUseNN__detectAndDecode__:识别二维码结束");
logger.t("__eyemDetectAndDecodeUseNN__detectAndDecode__:开始解码");
//解码 //解码
std::vector<std::string> results = p->decode(input, bboxes, points); std::vector<std::string> results = p->decode(input, bboxes, points);
logger.t("__eyemDetectAndDecodeUseNN__detectAndDecode__:解码完成");
_mtx.unlock(); _mtx.unlock();
return results; return results;
} }
...@@ -77,12 +84,14 @@ std::vector<cv::Rect> NNDetector::Impl::detect(const cv::Mat& img) { ...@@ -77,12 +84,14 @@ std::vector<cv::Rect> NNDetector::Impl::detect(const cv::Mat& img) {
std::vector<std::string> NNDetector::Impl::decode(const cv::Mat& img, std::vector<cv::Rect>& bboxes, std::vector<cv::Rect>& points) { std::vector<std::string> NNDetector::Impl::decode(const cv::Mat& img, std::vector<cv::Rect>& bboxes, std::vector<cv::Rect>& points) {
if (bboxes.size() == 0) { if (bboxes.size() == 0) {
logger.t("__eyemDetectAndDecodeUseNN__detectAndDecode__decode__:未识别到二维码");
return std::vector<std::string>(); return std::vector<std::string>();
} }
std::vector<std::string> decode_results; std::vector<std::string> decode_results;
//限定框,防止越界 //限定框,防止越界
for (auto& bbox : bboxes) { for (auto& bbox : bboxes) {
if (bbox.height > 1000 || bbox.width > 1000) { if (bbox.height > 1000 || bbox.width > 1000) {
logger.t("__eyemDetectAndDecodeUseNN__detectAndDecode__decode__:识别尺寸太大,判断不是二维码");
continue; continue;
} }
float padding_w = 0.1f, padding_h = 0.1f; float padding_w = 0.1f, padding_h = 0.1f;
...@@ -95,10 +104,12 @@ std::vector<std::string> NNDetector::Impl::decode(const cv::Mat& img, std::vecto ...@@ -95,10 +104,12 @@ std::vector<std::string> NNDetector::Impl::decode(const cv::Mat& img, std::vecto
int end_x = cv::min(bbox.br().x + padx, img.cols - 1); int end_x = cv::min(bbox.br().x + padx, img.cols - 1);
int end_y = cv::min(bbox.br().y + pady, img.rows - 1); int end_y = cv::min(bbox.br().y + pady, img.rows - 1);
logger.t("__eyemDetectAndDecodeUseNN__detectAndDecode__decode__:裁剪图像");
cv::Rect crop_roi(crop_x_, crop_y_, end_x - crop_x_ + 1, end_y - crop_y_ + 1); cv::Rect crop_roi(crop_x_, crop_y_, end_x - crop_x_ + 1, end_y - crop_y_ + 1);
cv::Mat cropped_img = img(crop_roi); cv::Mat cropped_img = img(crop_roi);
//转单通道 //转单通道
cv::cvtColor(cropped_img, cropped_img, cv::COLOR_BGR2GRAY); cv::cvtColor(cropped_img, cropped_img, cv::COLOR_BGR2GRAY);
logger.t("__eyemDetectAndDecodeUseNN__detectAndDecode__decode__:获取多尺度信息");
auto scale_list = getScaleList(cropped_img.cols, cropped_img.rows); auto scale_list = getScaleList(cropped_img.cols, cropped_img.rows);
for (auto cur_scale : scale_list) { for (auto cur_scale : scale_list) {
cv::Mat scaled_img = cv::Mat scaled_img =
...@@ -109,12 +120,14 @@ std::vector<std::string> NNDetector::Impl::decode(const cv::Mat& img, std::vecto ...@@ -109,12 +120,14 @@ std::vector<std::string> NNDetector::Impl::decode(const cv::Mat& img, std::vecto
auto ret = decodeImage(scaled_img, result, false, 0, _points); auto ret = decodeImage(scaled_img, result, false, 0, _points);
if (ret != -1) { if (ret != -1) {
//恢复真实尺度 //恢复真实尺度
logger.t("__eyemDetectAndDecodeUseNN__detectAndDecode__decode__:恢复真实尺度");
for (auto& _point : _points) { for (auto& _point : _points) {
_point.x = cvRound((float)_point.x / cur_scale); _point.x = cvRound((float)_point.x / cur_scale);
_point.x += crop_roi.tl().x; _point.x += crop_roi.tl().x;
_point.y = cvRound((float)_point.y / cur_scale); _point.y = cvRound((float)_point.y / cur_scale);
_point.y += crop_roi.tl().y; _point.y += crop_roi.tl().y;
} }
logger.t("__eyemDetectAndDecodeUseNN__detectAndDecode__decode__:解码成功");
cv::Rect br = cv::boundingRect(_points); cv::Rect br = cv::boundingRect(_points);
points.push_back(br); points.push_back(br);
decode_results.push_back(result); decode_results.push_back(result);
......
...@@ -7,6 +7,9 @@ ...@@ -7,6 +7,9 @@
#include "opencv2/core.hpp" #include "opencv2/core.hpp"
#include "libdecode.h" #include "libdecode.h"
#include "eyemLib.h"
extern Logger logger;
class NNDetector { class NNDetector {
public: public:
......
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!