Commit c28b0fea 张士柳

1 个父辈 87a1305d
......@@ -1021,18 +1021,18 @@ namespace eyemLib_Sharp
#endregion
#region 项目
//普通器件
//普通器件(仍采用旧的算法)
[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)]
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)]
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)]
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)]
private static extern int eyemCreateTemplateModel(EyemImage tpImage, EyemRect tpRoi, double dMinScore, string ccTplName);
......@@ -1129,6 +1129,7 @@ namespace eyemLib_Sharp
//记录日志
private static void EyemLib_OnNewLogCallback(string msg)
{
//算法里输出的一切日志都会在这里
logcpp.WriteLog("[" + Thread.CurrentThread.ManagedThreadId.ToString("X16") + "]" + msg);
}
......@@ -1363,14 +1364,13 @@ namespace eyemLib_Sharp
//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];
//获取用于制作模板的图像
//flag = eyemAchvTemplateImage(image, tpRoi, out tpDstImg);
//Bitmap bitmap = eyemCvtToBitmap(tpDstImg);
//if (bitmap != null)
//{
// bitmap.Save(System.Windows.Forms.Application.StartupPath + "\\ResOut\\" + file);
......@@ -1423,10 +1423,10 @@ namespace eyemLib_Sharp
//eyemImageFree(ref tpDstImg);
//"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);
//eyemCountObjectIrregularParts(image, tpRoi, file.Replace(".png", ""), "IP_LONG_PARTS", ref pNumObj, out tpDstImg);
eyemCountObjectE(image, tpRoi, fileName, ref pNumObj, out tpDstImg);
//eyemCountObjectIrregularPartsE(image, tpRoi, file.Replace(".png", ""), tpModels[0], hModelID, ref pNumObj, out tpDstImg);
//eyemCountObject(image, tpRoi, file.Replace(".png", ""), ipReelNum, out tpDstImg);
eyemCountObjectIrregularParts(image, tpRoi, file.Replace(".png", ""), "IP_LARGE_PARTS", ipReelNum, out tpDstImg);
//eyemCountObjectE(image, tpRoi, fileName, ipReelNum, 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);
//移除模板
......@@ -1435,8 +1435,8 @@ namespace eyemLib_Sharp
Bitmap bitmap = eyemCvtToBitmap(tpDstImg);
if (bitmap != null)
{
bitmap.Save("D:\\ResOut\\" + file);
//bitmap.Save(System.Windows.Forms.Application.StartupPath + "\\ResOut\\" + file);
//bitmap.Save("D:\\ResOut\\" + file);
bitmap.Save(System.Windows.Forms.Application.StartupPath + "\\ResOut\\" + file);
}
//< 解码测试
......@@ -1449,16 +1449,19 @@ namespace eyemLib_Sharp
// Marshal.FreeCoTaskMem(tpResults[i].hText); Marshal.FreeCoTaskMem(tpResults[i].hType);
//}
//hObject.Dispose();
//flag = eyemDetectAndDecodeUseNN(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();
Console.WriteLine(file + "--->" + "耗时:" + sw.ElapsedMilliseconds.ToString() + "毫秒" + ",结果:" + pNumObj);
Console.WriteLine(file + "--->" + "耗时:" + sw.ElapsedMilliseconds.ToString() + "ms" + ",结果:" + strReelNum);
//Bitmap bitmap = eyemCvtToBitmap(tpDstImg);
//if (bitmap != null)
//{
// bitmap.Save("D:\\ResOut\\" + file);
......@@ -1498,7 +1501,7 @@ namespace eyemLib_Sharp
tpRoi.iHeight = image.iHeight - 100;
//
string pNumObj = "";
int[] pNumObj = new int[4];
string file = fileName.Split(new string[] { "\\" }, StringSplitOptions.RemoveEmptyEntries)[2];
//获取用于制作模板的图像
......@@ -1537,7 +1540,7 @@ namespace eyemLib_Sharp
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");
......
using Microsoft.Win32.SafeHandles;
using System;
using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Linq;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
......@@ -323,8 +319,41 @@ namespace eyemLib_Sharp
//释放图像资源
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
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
// 日志
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)
{
......@@ -355,7 +384,6 @@ namespace eyemLib_Sharp
#endregion
}
#region EyemImageBitmap相互转换
public static Bitmap eyemCvtToBitmap(EyemImage tpImage)
{
......
......@@ -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();
if (image.empty()) {
logger.t("__eyemDetectAndDecodeUseNN__:图像文件不存在");
return FUNC_IMAGE_NOT_EXIST;
}
logger.t("__eyemDetectAndDecodeUseNN__:开始识别并解码二维码");
//识别并解码
std::vector<cv::Rect> points; std::vector<cv::Rect> __points;
auto results = detector->detectAndDecode(image, points, __points);
......@@ -569,6 +571,7 @@ int eyemDetectAndDecodeUseNN(EyemImage tpImage, EyemRect tpRoi, IntPtr *hObject,
//}
#pragma endregion
logger.t("__eyemDetectAndDecodeUseNN__:输出结果");
//解码结果
std::vector<EyemBarCode> *tpResults = new std::vector<EyemBarCode>();
for (int n = 0; n < results.size(); n++) {
......
......@@ -5,6 +5,13 @@
#ifndef __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 "nnDetector.h"
......@@ -12,6 +19,8 @@ std::mutex mtx;
cv::Ptr<NNDetector> detector;
extern Logger logger;
//预处理区域
struct WaitArea
{
......
......@@ -5,7 +5,6 @@
#ifndef __EYEM_LIB_H
#define __EYEM_LIB_H
#include <Windows.h>
#include <opencv.hpp>
......@@ -662,7 +661,7 @@ extern "C" {
// 函数接口
EXPORTS int eyemEdgesPixel(EyemImage tpImage, double dThresh);
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 eyemAutoCanny(EyemImage tpImage, float dSigma = 0.33);
......@@ -799,8 +798,8 @@ typedef struct {
double dAngle; // 角度
int iCenterX; // y坐标
int iCenterY; // y坐标
LPSTR lpszType; // 码类型
LPSTR lpszText; // 码内容
char* lpszType; // 码类型
char* lpszText; // 码内容
} EyemBarCode;
typedef struct {
......@@ -810,7 +809,7 @@ typedef struct {
int iWidth; // 图像内存X方向大小
int iHeight; // 图像内存Y方向大小
double dMatchDeg; // 匹配度
LPSTR lpszName; // 名称
char* lpszName; // 名称
} EyemModelID;
......@@ -822,13 +821,13 @@ extern "C" {
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 bool eyemDetectAndDecodeFree(IntPtr hObject);
EXPORTS int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LPSTR *lpszNumObj, EyemImage *tpDstImg);
EXPORTS int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LPSTR *lpszReelNum, EyemImage *tpDstImg);
EXPORTS int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char *fileName, const char * ccSubType, LPSTR *lpszNumObj, EyemImage *tpDstImg);
EXPORTS int eyemCountObjectIrregularPartsE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, const char *ccTplName, IntPtr hModelID, LPSTR *lpszReelNum, 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, int *ipReelNum, 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, int *ipReelNum, 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 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 eyemAchvModelByName(const char *ccTplName, IntPtr hModelID, EyemModelID &tpModelID);
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"
#pragma region 一些参数计算公式
......@@ -655,7 +663,7 @@ static bool checkSize(cv::Mat &srcPrev, cv::Mat &mask, int &partSize)
#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();
if (src.empty()) {
......@@ -781,10 +789,8 @@ int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LPS
if (trays.size() < 1)
{
std::string strTrayNum = "无料,";
*lpszNumObj = (char *)CoTaskMemAlloc(strTrayNum.size());
if (NULL != *lpszNumObj)
{
strcpy(*lpszNumObj, strTrayNum.c_str());
for (int i = 0; i < 4; i++) {
ipReelNum[i] = 0;
}
return FUNC_CANNOT_CALC;
}
......@@ -1107,220 +1113,107 @@ int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LPS
});
//去掉中心1/3区域
cv::circle(image, reelCenter, cvRound(tFRadius / 3), cv::Scalar(0), -1);
struct TracingAnchor
{
float Size;
float Length, Height;
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;
//追踪直至没有单个元件存在
bool bExistSingle = true;
//用于计数
cv::Mat lb4Count(Y, X, CV_8UC1, cv::Scalar(0));
//标签图
unsigned char *ucpTrackLabel = new unsigned char[Y*X]();
cv::Mat trackMat(Y, X, CV_8UC1, ucpTrackLabel);
//计数图像
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) {
do
{
//跳过执行
if (killProcessID == 0) {
logger.t("eyemCountObjectIrregularParts 点料阶段被跳过执行...");
logger.t("eyemCountObjectIrregularPartsE 点料阶段被跳过执行...");
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) {};
};
auto _dir_l = std::vector<DIR>(); auto _dir_r = std::vector<DIR>();
for (int j = 0; j < 4; j++)
//不随机挑选起点(考虑换成面积最小的那个)
std::vector<cv::Point> contourMin;
cv::findContours(image, contoursFilter, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
//终止追踪
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) {
_dir_l.push_back(DIR(j, __pts[j]));
}
else {
_dir_r.push_back(DIR(j, __pts[j]));
if (cv::contourArea(contoursFilter[fc]) > 0.4*sinPartSize)
{
if (cv::contourArea(contoursFilter[fc]) < cv::contourArea(contourMin))
{
contourMin = contoursFilter[fc];
}
}
}
//重新选点计算模板
if (_dir_l.size() != _dir_r.size()) {
continue;
}
//确定顶点方向
cv::Point2f p0, p1, p2, p3;
if (_dir_l[0].pt.y < _dir_l[1].pt.y) {
p0 = _pts[_dir_l[0].i];
p1 = _pts[_dir_l[1].i];
}
else {
p0 = _pts[_dir_l[1].i];
p1 = _pts[_dir_l[0].i];
}
}
else if (contoursFilter.size() == 1)
{
contourMin = contoursFilter[0];
}
//去掉起始位置
std::vector<std::vector<cv::Point>> vTempRect;
vTempRect.push_back(contourMin);
cv::drawContours(image, vTempRect, 0, cv::Scalar(0), -1);
//最小外包矩形
cv::RotatedRect rect = cv::minAreaRect(contourMin);
cv::Point2f points[4];
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) {
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);
Track() {};
double realT = atan2((double)p23.y - (double)p01.y, (double)p23.x - (double)p01.x) * 180.0 / PI;
cv::Mat realTplMat = getTrackMat(traceMat, realT, 0, matx);
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::Point2f __mpts[4];
for (int j = 0; j < 4; j++)
bool operator >(const Track &te)const
{
__mpts[j].x = matx[0] * (_pts[j].x - (float)_rLimits.x) + matx[1] * (_pts[j].y - (float)_rLimits.y) + matx[2];
__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;
return dMatchDeg > te.dMatchDeg;
}
//最大值
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 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 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 / PI;
//起始扫描半径
const double startRadius = cv::norm(startCenter - reelCenter);
//偏移角度(元件尺寸)
const double dOffset = (2.0 * asin(2.0 * trackLength / (2.0 * startRadius))) * 180.0 / PI;
//扫描角度(默认15度范围内存在元件
const double dScanRange = 15.0;
const double dOffset = (2 * asin(2 * trackLength / (2 * startRadius))) * 180 / PI;
//偏移角度(元件间距
const double dScanRange = 15;
//追踪元件间距(弦长,可以尽量避免因个别器件偏离导致的追踪中断)
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 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);
......@@ -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)),
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);
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);
break;
}
}
if (dChordL > 2.1)
if (dChordL > 0)
break;
}
//没确定出元件间距一般为结尾或单个元件,继续从下一个起点计算弦长并开始追踪
if (dChordL <= 2.1) {
continue;
}
//顺时针(是否并行取决于在windows下运行还是树莓派上)
//并行处理
//#pragma omp parallel sections
{
//追踪中心
cv::Point2f trackCenter = cv::Point2f(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
//(顺时针)
//#pragma omp section
{
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 trackCenter = cv::Point2f(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
{
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;
bool found = true;
std::vector<Track> vParts;
for (double t = trackAngle + (trackOffset / 2.0 + partDist); t < trackAngle + (trackOffset / 2.0 + partDist) + trackOffset; t += dMinorStep)
{
trackCenter.x = reelCenter.x + (float)trackRadius*(float)cos(t*c);
trackCenter.y = reelCenter.y + (float)trackRadius*(float)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)
{
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);
}
//感兴趣区域(向外扩展了一个元件,防止中心定位出现偏差或者料盘本身变形导致的偏差)
cv::Point2f predictBox[4];
calcRotateRect(predicPos, (float)(trackAngle + (trackOffset + partDist)), (float)trackLength + (float)trackLength, (float)trackWidth + (float)trackWidth, predictBox);
cv::RotatedRect r(predictBox[0], predictBox[1], predictBox[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++)
if (vParts.size() == 0) continue;
//
trackEndPos = vParts[vParts.size() / 2];
//灰度极值认为是元件
std::sort(vParts.begin(), vParts.end(), std::greater<Track>());
//更新位置
trackCenter = cv::Point(vParts[0].Pos.x, vParts[0].Pos.y);
//更新扫描角度
trackAngle = atan2((double)trackCenter.y - reelCenter.y, (double)trackCenter.x - reelCenter.x) * 180 / PI;
//纵向扫描
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)
{
predictBoxR[j].x = matx[0] * (predictBox[j].x - (float)rLimits.x) + matx[1] * (predictBox[j].y - (float)rLimits.y) + matx[2];
predictBoxR[j].y = matx[3] * (predictBox[j].x - (float)rLimits.x) + matx[4] * (predictBox[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::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++)
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)
{
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 {
//存在多个峰值,先判断分数最高是否位于理论位置
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));
if (vParts.size() == 0) continue;
//方案二每个点以当前半径画圆,看下个点偏离圆多少
//灰度极值认为是元件(最多问题出现在这里,加个条件判断矩形内是否存在已标记像素)
std::sort(vParts.begin(), vParts.end(), std::greater<Track>());
//更新当前元件位置(必须不与已有元件重合)
Track mac = vParts[0];
if (mac.iLimit != 0)
{
for (int cc = 1; cc < vParts.size(); cc++)
{
if (vParts[cc].iLimit < mac.iLimit)
mac = vParts[cc];
if (mac.iLimit == 0)
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);
}
}
}
if (!vParts.empty()) {
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)),
cv::Size(cvRound(trackLength*2.0) + 2, cvRound(trackWidth*4.0) + 2))
&cv::Rect(0, 0, traceMat.cols, traceMat.rows);
//当作一种辅助手段,无需设置太严格
double dmax;
cv::minMaxLoc(traceMat(tRec_).clone(), NULL, &dmax);
if (dmax < 0.7*taMaxGray) {
trayEnd = true;
}
trackCenter = mac.Pos;
//更新扫描半径
trackRadius = cv::norm(trackCenter - reelCenter);
//更新扫描角度
trackAngle = atan2((double)trackCenter.y - reelCenter.y, (double)trackCenter.x - reelCenter.x) * 180 / PI;
//更新偏移量(元件大小)
trackOffset = (2 * asin(2 * trackLength / (2 * trackRadius))) * 180 / PI;
//更新元件间角度
partDist = (2 * asin(dChordL / (2 * trackRadius))) * 180 / PI;
//判断是否结束
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;
}
//追踪终止,选取下一个起点
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++)
else
{
cv::line(cc, pts[j], pts[(j + 1) % 4], cv::Scalar(14, 173, 238, 255), 1);
}
//#endif
}
//清空下一个
vParts.resize(0);
//跳过执行
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));
//画出最终位置
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);
}
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::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)
{
cv::line(cc, predicBox[j], predicBox[(j + 1) % 4], cv::Scalar(0, 0, 238, 255), 1);
}
}
}
else {
//存在定位出错的可能性,先判断分数最高是否位于理论位置
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]);
int label = labels.at<int>(vTemp[p]);
if (label != 0)
{
labeled[label] = 255;
break;
}
}
}
}
//外包矩形顶点
cv::Point2f pts[4];
calcRotateRect(cv::Point2f(realX, realY), (float)(trackAngle - (trackOffset + partDist)), (float)trackLength*2.0f, (float)trackWidth*2.0f, pts);
//跳过执行
if (killProcessID == 0) {
logger.t("eyemCountObjectIrregularPartsE 追踪阶段被跳过执行...");
found = false;
}
//
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
trackEnd = (!found);
} while (!trackEnd);
}
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()) {
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)),
cv::Size(cvRound(trackLength*2.0) + 2, cvRound(trackWidth*4.0) + 2))
&cv::Rect(0, 0, traceMat.cols, traceMat.rows);
//当作一种辅助手段,无需设置太严格
double dmax;
cv::minMaxLoc(traceMat(tRec_).clone(), NULL, &dmax);
if (dmax < 0.7*taMaxGray) {
trayEnd = true;
if (vParts.size() == 0) continue;
//
trackEndPos = vParts[vParts.size() / 2];
//灰度极值认为是元件
std::sort(vParts.begin(), vParts.end(), std::greater<Track>());
//更新位置
trackCenter = cv::Point(vParts[0].Pos.x, vParts[0].Pos.y);
//更新扫描角度
trackAngle = atan2((double)trackCenter.y - reelCenter.y, (double)trackCenter.x - reelCenter.x) * 180 / PI;
//纵向扫描
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 (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.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++)
if (vParts.size() == 0) continue;
//灰度极值认为是元件
std::sort(vParts.begin(), vParts.end(), std::greater<Track>());
//更新当前元件位置
Track mac = vParts[0];
if (mac.iLimit != 0)
{
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
}
//继续下一个起点
vParts.resize(0);
//跳过执行
if (killProcessID == 0) {
logger.t("eyemCountObjectIrregularParts 追踪阶段被跳过执行...");
found = false;
}
trackEnd = (!found);
} while (!trackEnd);
trackCenter = mac.Pos;
//更新扫描半径
trackRadius = cv::norm(trackCenter - reelCenter);
//更新扫描角度
trackAngle = atan2((double)trackCenter.y - reelCenter.y, (double)trackCenter.x - reelCenter.x) * 180 / PI;
//更新偏移量
trackOffset = (2 * asin(2 * trackLength / (2 * trackRadius))) * 180 / PI;
//更新追踪角度
partDist = (2 * asin(dChordL / (2 * trackRadius))) * 180 / PI;
//绕完一周后更新料盘中心试试?
//判断是否结束
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);
//计数
int reelNum = cv::countNonZero(lbMat);
int numObj = cv::countNonZero(lb4Count);
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);
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;
ucpTrackLabel = NULL;
}
}
//输出结果
const int bufSize = 64;
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);
}
const int SizeConst = 4;
//<输出计数结果标记图像
{
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();
//内存尺寸
......@@ -2066,7 +1656,7 @@ int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LPS
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();
if (src.empty()) {
......@@ -2781,9 +2371,9 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
cv::Point p2 = cv::Point(cvRound(x + trackWidth * cos(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);
//#endif
#endif
cv::LineIterator it(binary, p1, p2, 4);
for (int n = 0; n < it.count; n++, ++it)
{
......@@ -3001,11 +2591,12 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
//
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
#ifdef _DEBUG
for (int j = 0; j < 4; j++)
{
cv::line(cc, predictBox[j], predictBox[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1);
}
#endif
}
}
else {
......@@ -3071,11 +2662,12 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
//
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
#ifdef _DEBUG
for (int j = 0; j < 4; j++)
{
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
cv::fillConvexPoly(trackMat, vT, cv::Scalar(255));
//用于显示
cv::circle(cc, trackCenter, 2, cv::Scalar(0, 255, 0, 255), 1);
//#ifdef _DEBUG
#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);
}
//#endif
#endif
}
//清空下一个
vParts.resize(0);
......@@ -3334,11 +2926,12 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
//
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
#ifdef _DEBUG
for (int j = 0; j < 4; j++)
{
cv::line(cc, predicBox[j], predicBox[(j + 1) % 4], cv::Scalar(0, 0, 238, 255), 1);
}
#endif
}
}
else {
......@@ -3402,23 +2995,15 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
//
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
#ifdef _DEBUG
for (int j = 0; j < 4; j++)
{
cv::line(cc, predicBox[j], predicBox[(j + 1) % 4], cv::Scalar(0, 0, 238, 255), 1);
}
#endif
}
}
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),
cvFloor((((float)maxLox.y)*2.0f - (float)trackWidth*4.0f) / 2.0f)),
cv::Size(cvRound(trackLength*2.0) + 2, cvRound(trackWidth*4.0) + 2))
......@@ -3461,12 +3046,12 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
cv::fillConvexPoly(trackMat, vT, cv::Scalar(255));
//用于显示
cv::circle(cc, trackCenter, 2, cv::Scalar(0, 255, 0, 255), 1);
//#ifdef _DEBUG
#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);
}
//#endif
#endif
}
//继续下一个起点
vParts.resize(0);
......@@ -3820,9 +3405,9 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
cv::Point p2 = cv::Point(cvRound(x + trackWidth * cos(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);
//#endif
#endif
cv::LineIterator it(binary, p1, p2, 4);
for (int n = 0; n < it.count; n++, ++it)
{
......@@ -4040,11 +3625,12 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
//
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
#ifdef _DEBUG
for (int j = 0; j < 4; j++)
{
cv::line(cc, predictBox[j], predictBox[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1);
}
#endif
}
}
else {
......@@ -4110,11 +3696,12 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
//
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
#ifdef _DEBUG
for (int j = 0; j < 4; j++)
{
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
//
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
#ifdef _DEBUG
for (int j = 0; j < 4; j++)
{
cv::line(cc, predicBox[j], predicBox[(j + 1) % 4], cv::Scalar(0, 0, 238, 255), 1);
}
#endif
}
}
else {
......@@ -4441,11 +4029,12 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
//
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
#ifdef _DEBUG
for (int j = 0; j < 4; j++)
{
cv::line(cc, predicBox[j], predicBox[(j + 1) % 4], cv::Scalar(0, 0, 238, 255), 1);
}
#endif
}
}
if (!vParts.empty()) {
......@@ -4646,47 +4235,15 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
else
{
//先用自动算法点,如果不行判断为散料
LPSTR trayNum = "";
int iRet = eyemCountObjectE(tpImage, tpRoi, "", &trayNum, tpDstImg);
int trayNum[4];
int iRet = eyemCountObjectE(tpImage, tpRoi, "", trayNum, tpDstImg);
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++)
{
if (trayNums[i] != "0")
{
//输出结果
tTrayNum = trayNums[i];
break;
}
}
*lpszReelNum = (char *)CoTaskMemAlloc(tTrayNum.size() + 1);
if (NULL != lpszReelNum)
{
strcpy(*lpszReelNum, tTrayNum.c_str());
for (int i = 0; i < 4; i++) {
//输出结果
ipReelNum[i] = trayNum[i];
break;
}
//获取当前运行目录
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;
}
else {
......@@ -4755,17 +4312,13 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
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);
//<输出结果
const int bufSize = 16;
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);
}
const int SizeConst = 4;
//<输出计数结果标记图像
{
memset(ipReelNum, 0, SizeConst);
ipReelNum[0] = trayNum;
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
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();
if (src.empty()) {
......@@ -4903,13 +4456,9 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP
trays.push_back(TrayPos(reelCenter, tray, false, backThresh));
}
//判断可能无料,不能100%判断
if (trays.size() < 1)
{
std::string strTrayNum = "无料,";
*lpszNumObj = (char *)CoTaskMemAlloc(strTrayNum.size());
if (NULL != *lpszNumObj)
{
strcpy(*lpszNumObj, strTrayNum.c_str());
if (trays.size() < 1) {
for (int i = 0; i < 4; i++) {
ipReelNum[i] = 0;
}
return FUNC_CANNOT_CALC;
}
......@@ -4975,8 +4524,10 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP
//分料盘计数
for (int i = 0; i < sortedTrays.size(); i++)
{
cv::Mat srcPrev;
cv::Mat srcPrev, srcPrevB;
cv::bitwise_not(sortedTrays[i].Tray, srcPrev);
//备份
srcPrevB = srcPrev.clone();
//二值化可以分别放在两个算法里
cv::Mat sinParts;
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
cv::Mat lbMat(Y, X, CV_8UC1, cv::Scalar(0));
//定位图像
cv::Mat srcPrevS, tplMat;//模板文件
srcPrev.convertTo(srcPrevS, CV_32F);
srcPrevB.convertTo(srcPrevS, CV_32F);
//随机打乱顺序(降低计算错误dChordL的可能性,也为了测试在起点信息不同时的稳定性)
std::random_shuffle(tracingAnchors.begin(), tracingAnchors.end());
//开始确定起点(现在是用圆轨迹来追踪,不排除用螺旋线轨迹来追踪)
......@@ -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;
//计算旋转角度
cv::Mat traceMat = srcPrev(_rLimits);
cv::Mat traceMat = srcPrevB(_rLimits);
//这里计算得出的模板不是很对
float matx[6];
tplMat = getTrackMat(traceMat, t + 90.0, 0, matx);
......@@ -5422,7 +4973,7 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP
const double dMinorStep = 0.1;
//追踪长宽
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 startRadius = cv::norm(startCenter - reelCenter);
......@@ -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)),
cvRound(y + trackWidth * sin(angle + CV_PI)));
//#ifdef _DEBUG
#ifdef _DEBUG
cv::line(cc, p1, p2, cv::Scalar(0, 215, 255, 255), 1);
//#endif
#endif
cv::LineIterator it(sinParts, p1, p2, 4);
for (int n = 0; n < it.count; n++, ++it)
{
......@@ -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));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
#ifdef _DEBUG
for (int j = 0; j < 4; j++)
{
cv::line(cc, predictBox[j], predictBox[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1);
}
#endif
}
}
else {
......@@ -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));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
#ifdef _DEBUG
for (int j = 0; j < 4; j++)
{
cv::line(cc, predictBox[j], predictBox[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1);
}
#endif
}
}
if (!vParts.empty()) {
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)),
......@@ -5793,12 +5345,12 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP
cv::fillConvexPoly(trackMat, vT, cv::Scalar(255));
//用于显示
cv::circle(cc, trackCenter, 2, cv::Scalar(0, 255, 0, 255), 1);
//#ifdef _DEBUG
#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);
}
//#endif
#endif
}
//清空下一个
vParts.resize(0);
......@@ -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));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
#ifdef _DEBUG
for (int j = 0; j < 4; j++)
{
cv::line(cc, predicBox[j], predicBox[(j + 1) % 4], cv::Scalar(0, 0, 238, 255), 1);
}
#endif
}
}
else {
......@@ -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));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
#ifdef _DEBUG
for (int j = 0; j < 4; j++)
{
cv::line(cc, predicBox[j], predicBox[(j + 1) % 4], cv::Scalar(0, 0, 238, 255), 1);
}
#endif
}
}
if (!vParts.empty()) {
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)),
......@@ -6123,12 +5678,12 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP
cv::fillConvexPoly(trackMat, vT, cv::Scalar(255));
//用于显示
cv::circle(cc, trackCenter, 2, cv::Scalar(0, 255, 0, 255), 1);
//#ifdef _DEBUG
#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);
}
//#endif
#endif
}
//继续下一个起点
vParts.resize(0);
......@@ -6157,21 +5712,13 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP
}
}
//输出结果
const int bufSize = 64;
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);
}
const int SizeConst = 4;
//<输出计数结果标记图像
{
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();
//内存尺寸
......@@ -6189,7 +5736,7 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LP
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();
......@@ -7097,22 +6644,14 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, EyemRect tpRoi, const char
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);
///<输出结果
const int bufSize = 16;
char cReelNum[bufSize] = { 0 };
sprintf_s(cReelNum, bufSize, "%d,", reelNum);
//拷贝std::string拼接的字符串会莫名的报错??
*lpszReelNum = (char *)CoTaskMemAlloc(bufSize);
memset(*lpszReelNum, 0, bufSize);
if (NULL != *lpszReelNum)
//<输出结果
const int SizeConst = 4;
//<输出计数结果标记图像
{
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();
//内存尺寸
......@@ -7502,7 +7041,13 @@ int eyemRemoveModelByName(IntPtr hModelID, const char *ccTplName)
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();
......@@ -7617,93 +7162,6 @@ int eyemMatchTemplateModel(EyemImage tpImage, IntPtr hModelID, LPSTR *lpszTplNam
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)
{
if (NULL == hModelID)
......@@ -7803,7 +7261,6 @@ int eyemTrackFeature(EyemImage tpRefImg, EyemImage tpNextImg, EyemRect3 *tpRois,
int eyemAOIForTSAV(EyemImage tpRefImg, EyemImage tpNextImg, EyemRect3 *tpRois, int iRoiNum)
{
return FUNC_OK;
}
......
......@@ -5,17 +5,12 @@
#ifndef __EYEM_MISC_H
#define __EYEM_MISC_H
#include <io.h>
#include <fstream>
#include <direct.h>
#include "eyemLib.h"
#include <tbb\tbb.h>
extern Logger logger;
constexpr double c = PI / 180.;
extern Logger logger;
extern int killProcessID;
#endif/* __EYEM_MISC_H */
......@@ -48,6 +48,7 @@ std::vector<std::string> NNDetector::detectAndDecode(cv::InputArray img, std::ve
if (img.cols() <= 20 || img.rows() <= 20) {
return std::vector<std::string>();
}
logger.t("__eyemDetectAndDecodeUseNN__detectAndDecode__:开始图像格式转换");
cv::Mat input;
int incn = img.channels();
if (incn == 4) {
......@@ -59,14 +60,20 @@ std::vector<std::string> NNDetector::detectAndDecode(cv::InputArray img, std::ve
else {
input = img.getMat();
}
logger.t("__eyemDetectAndDecodeUseNN__detectAndDecode__:图像格式转换完成");
_mtx.lock();
//识别
logger.t("__eyemDetectAndDecodeUseNN__detectAndDecode__:开始识别二维码");
std::vector<cv::Rect> bboxes = p->detect(input);
for (auto&bbox : bboxes) {
__points.push_back(bbox);
}
logger.t("__eyemDetectAndDecodeUseNN__detectAndDecode__:识别二维码结束");
logger.t("__eyemDetectAndDecodeUseNN__detectAndDecode__:开始解码");
//解码
std::vector<std::string> results = p->decode(input, bboxes, points);
logger.t("__eyemDetectAndDecodeUseNN__detectAndDecode__:解码完成");
_mtx.unlock();
return results;
}
......@@ -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) {
if (bboxes.size() == 0) {
logger.t("__eyemDetectAndDecodeUseNN__detectAndDecode__decode__:未识别到二维码");
return std::vector<std::string>();
}
std::vector<std::string> decode_results;
//限定框,防止越界
for (auto& bbox : bboxes) {
if (bbox.height > 1000 || bbox.width > 1000) {
logger.t("__eyemDetectAndDecodeUseNN__detectAndDecode__decode__:识别尺寸太大,判断不是二维码");
continue;
}
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
int end_x = cv::min(bbox.br().x + padx, img.cols - 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::Mat cropped_img = img(crop_roi);
//转单通道
cv::cvtColor(cropped_img, cropped_img, cv::COLOR_BGR2GRAY);
logger.t("__eyemDetectAndDecodeUseNN__detectAndDecode__decode__:获取多尺度信息");
auto scale_list = getScaleList(cropped_img.cols, cropped_img.rows);
for (auto cur_scale : scale_list) {
cv::Mat scaled_img =
......@@ -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);
if (ret != -1) {
//恢复真实尺度
logger.t("__eyemDetectAndDecodeUseNN__detectAndDecode__decode__:恢复真实尺度");
for (auto& _point : _points) {
_point.x = cvRound((float)_point.x / cur_scale);
_point.x += crop_roi.tl().x;
_point.y = cvRound((float)_point.y / cur_scale);
_point.y += crop_roi.tl().y;
}
logger.t("__eyemDetectAndDecodeUseNN__detectAndDecode__decode__:解码成功");
cv::Rect br = cv::boundingRect(_points);
points.push_back(br);
decode_results.push_back(result);
......
......@@ -7,6 +7,9 @@
#include "opencv2/core.hpp"
#include "libdecode.h"
#include "eyemLib.h"
extern Logger logger;
class NNDetector {
public:
......
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!