Commit 6c7e636f 张士柳

1 个父辈 c7efc275
...@@ -1227,34 +1227,6 @@ namespace eyemLib_Sharp ...@@ -1227,34 +1227,6 @@ namespace eyemLib_Sharp
Stopwatch sw = new Stopwatch(); Stopwatch sw = new Stopwatch();
sw.Restart(); sw.Restart();
string file = fileName.Split(new string[] { "\\" }, StringSplitOptions.RemoveEmptyEntries)[2]; string file = fileName.Split(new string[] { "\\" }, StringSplitOptions.RemoveEmptyEntries)[2];
//string[] fileNames = Directory.GetFiles(@"C:\Users\nzslw\PycharmProjects\pythonProject\venv\data\AntBee\test\ants", "*.jpg", SearchOption.AllDirectories);
//return;
//foreach (var item in fileNames)
//{
// eyemBuildTrainFile(item, "D:\\标签识别\\" + item.Split(new string[] { "\\" }, StringSplitOptions.RemoveEmptyEntries)[4]);
//}
//return;
//for (int i = 0; i < fileNames.Length; i++)
//{
// string item = fileNames[i];
// string[] items = item.Split(new string[] { "\\" }, StringSplitOptions.RemoveEmptyEntries);
// FileInfo fi = new FileInfo(item);
// fi.MoveTo(@"D:\日志\" + (i+83).ToString() + ".png");
//}
//return;
//StreamWriter swr = new StreamWriter("D:\\val.txt", true);
//foreach (var item in random_shuffle)
//{
// string[] items = item.Split(new string[] { "\\" }, StringSplitOptions.RemoveEmptyEntries);
// swr.WriteLine("data/val_images/" + items[items.Length - 1]);
// swr.Flush();
//}
//return;
//eyemRenameFile(@"D:\训练数据集\20211021");
//return;
//flag = eyemInitNNDetector(".\\darknet\\cifar_resnet50.cfg", ".\\darknet\\cifar_resnet50.weights"); //flag = eyemInitNNDetector(".\\darknet\\cifar_resnet50.cfg", ".\\darknet\\cifar_resnet50.weights");
//if (flag == 0) //if (flag == 0)
...@@ -1388,8 +1360,6 @@ namespace eyemLib_Sharp ...@@ -1388,8 +1360,6 @@ namespace eyemLib_Sharp
//eyemImageFree(ref search); //eyemImageFree(ref search);
//return; //return;
//flag = eyemNormalize(ref image);
//EyemImage image1 = new EyemImage(); EyemImage image2 = new EyemImage(); EyemImage image3 = new EyemImage(); //EyemImage image1 = new EyemImage(); EyemImage image2 = new EyemImage(); EyemImage image3 = new EyemImage();
//eyemDecompose(image, out image1, out image2, out image3); //eyemDecompose(image, out image1, out image2, out image3);
...@@ -1655,12 +1625,12 @@ namespace eyemLib_Sharp ...@@ -1655,12 +1625,12 @@ namespace eyemLib_Sharp
int[] ipReelNum = new int[4]; int[] ipReelNum = new int[4];
//"IP_SMALL_PARTS","IP_LARGE_PARTS","IP_LONG_PARTS","IP_SQUARE_PARTS","IP_DYNAMIC_PARTS","","IP_DYNAMIC_SP1","IP_DYNAMIC_SP2" //"IP_SMALL_PARTS","IP_LARGE_PARTS","IP_LONG_PARTS","IP_SQUARE_PARTS","IP_DYNAMIC_PARTS","","IP_DYNAMIC_SP1","IP_DYNAMIC_SP2"
//eyemCountObject(image, tpRoi, file.Replace(".png", ""), ipReelNum, out tpDstImg); //eyemCountObject(image, tpRoi, file.Replace(".png", ""), ipReelNum, out tpDstImg);
//eyemCountObjectIrregularParts(image, tpRoi, file.Replace(".png", ""), "IP_LARGE_PARTS", ipReelNum, out tpDstImg); //eyemCountObjectIrregularParts(image, tpRoi, file.Replace(".png", ""), "IP_LONG_PARTS", ipReelNum, out tpDstImg);
eyemCountObjectE(image, tpRoi, file.Replace(".png", ""), ipReelNum, out tpDstImg); //eyemCountObjectE(image, tpRoi, file.Replace(".png", ""), ipReelNum, out tpDstImg);
//eyemCountObjectIrregularPartsE(image, tpRoi, file.Replace(".png", ""), "D:\\模板文件\\" + "20210825095751-1.tpl", hModelID, ipReelNum, out tpDstImg); //eyemCountObjectIrregularPartsE(image, tpRoi, file.Replace(".png", ""), "D:\\模板文件\\" + "20210825095751-1.tpl", hModelID, ipReelNum, out tpDstImg);
//算法选项 //算法选项
//std::string sOptions[8] = { "IP_DEFAULT_PARTS","IP_SMALL_PARTS","IP_LARGE_PARTS","IP_LONG_PARTS","IP_SQUARE_PARTS","","IP_DYNAMIC_SP1","IP_DYNAMIC_SP2" }; //std::string sOptions[8] = { "IP_DEFAULT_PARTS","IP_SMALL_PARTS","IP_LARGE_PARTS","IP_LONG_PARTS","IP_SQUARE_PARTS","","IP_DYNAMIC_SP1","IP_DYNAMIC_SP2" };
//eyemCountObjectIrregularPartsMultiopt(image, tpRoi, new int[] { 2, 2, 2, 2 }, ipReelNum, out tpDstImg); eyemCountObjectIrregularPartsMultiopt(image, tpRoi, new int[] { 0, 0, 0, 0 }, ipReelNum, out tpDstImg);
//移除模板 //移除模板
//flag = eyemRemoveModelByName(hModelID, "D:\\模板文件及图像\\df871193-6632-48f9-abfe-540c3fc49c3f.tpl"); //flag = eyemRemoveModelByName(hModelID, "D:\\模板文件及图像\\df871193-6632-48f9-abfe-540c3fc49c3f.tpl");
......
...@@ -28,7 +28,7 @@ namespace eyemLib_Sharp ...@@ -28,7 +28,7 @@ namespace eyemLib_Sharp
eyemImageRead(fileName, -1, out image); eyemImageRead(fileName, -1, out image);
} }
/// <summary> /// <summary>
/// 从Bitmap初始化Unmanaged新实例(GDI不支持除8位以外深度的图像;若要加载不同深度图像请使用从文件名加载 /// 从Bitmap初始化Unmanaged新实例(GDI不支持除8位以外深度的图像;若要加载不同深度图像请从文件名初始化
/// </summary> /// </summary>
/// <param name="bitmap"></param> /// <param name="bitmap"></param>
public UnmanagedBitmap(Bitmap bitmap) public UnmanagedBitmap(Bitmap bitmap)
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
#include <opencv.hpp> #include <opencv.hpp>
#ifndef FILEVERSION #ifndef FILEVERSION
#define FILEVERSION "2.4.8.2" #define FILEVERSION "2.4.8.4"
#endif #endif
#ifndef COPYRIGHT #ifndef COPYRIGHT
......
此文件类型无法预览
...@@ -1791,7 +1791,8 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -1791,7 +1791,8 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
int backThresh = 15 * cvRound((double)maxIdx[0] - processLevel); int backThresh = 15 * cvRound((double)maxIdx[0] - processLevel);
//去掉背景 //去掉背景
cv::parallel_for_(cv::Range(0, Y), [&](const cv::Range range)->void { cv::parallel_for_(cv::Range(0, Y), [&](const cv::Range range)->void {
for (int y = range.start; y < range.end; y++) { for (int y = range.start; y < range.end; y++)
{
for (int x = 0; x < X; x++) { for (int x = 0; x < X; x++) {
if ((src8U.data)[(x)+(y)*X] >= backThresh) { if ((src8U.data)[(x)+(y)*X] >= backThresh) {
(src8U.data)[(x)+(y)*X] = backThresh; (src8U.data)[(x)+(y)*X] = backThresh;
...@@ -1801,6 +1802,7 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -1801,6 +1802,7 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
}); });
//增强到目标亮度方便显示 //增强到目标亮度方便显示
cc += cv::Scalar((162 - backThresh), (162 - backThresh), (162 - backThresh)); cc += cv::Scalar((162 - backThresh), (162 - backThresh), (162 - backThresh));
//cv::imwrite("cc.png",cc);
//料盘中心 //料盘中心
cv::Point reelPt; cv::Point reelPt;
//去掉干扰 //去掉干扰
...@@ -2182,7 +2184,7 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -2182,7 +2184,7 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
image = cv::Scalar(0); image = cv::Scalar(0);
//当仅剩一圈的情况 //当仅剩一圈的情况
cv::Mat srcPrevEx1; cv::Mat srcPrevEx1;
cv::morphologyEx(binary, srcPrevEx1, cv::MORPH_DILATE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(15, 15))); cv::morphologyEx(binary, srcPrevEx1, cv::MORPH_DILATE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(31, 31)));
cv::findContours(srcPrevEx1, contoursFilter, cv::RETR_TREE, cv::CHAIN_APPROX_NONE); cv::findContours(srcPrevEx1, contoursFilter, cv::RETR_TREE, cv::CHAIN_APPROX_NONE);
//闭合轮廓 //闭合轮廓
...@@ -2198,10 +2200,10 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -2198,10 +2200,10 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
cv::findContours(image, contoursFilter, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE); cv::findContours(image, contoursFilter, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
if (contoursFilter.empty()) if (contoursFilter.empty())
{ {
//当不足一圈,中心定位是不对的无法应用追踪算法 //当不足一圈,中心定位是不对的无法应用追踪算法
return FUNC_CANNOT_CALC; return FUNC_CANNOT_CALC;
} }
} }
//过滤轮廓 //过滤轮廓
std::vector<cv::Point> contourMax = contoursFilter[0]; std::vector<cv::Point> contourMax = contoursFilter[0];
...@@ -2215,6 +2217,9 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -2215,6 +2217,9 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
//计算最大外接圆半径 //计算最大外接圆半径
float tFRadius = 0; float tFRadius = 0;
cv::minEnclosingCircle(contourMax, cv::Point2f(), tFRadius); cv::minEnclosingCircle(contourMax, cv::Point2f(), tFRadius);
//
tFRadius = tFRadius < 300 ? 300 : tFRadius;
cv::Moments mu = cv::moments(contourMax); cv::Moments mu = cv::moments(contourMax);
cv::Point2f reelCenter(float(mu.m10 / mu.m00), float(mu.m01 / mu.m00)); cv::Point2f reelCenter(float(mu.m10 / mu.m00), float(mu.m01 / mu.m00));
//画中心 //画中心
...@@ -2297,6 +2302,36 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -2297,6 +2302,36 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
return dMatchDeg < te.dMatchDeg; return dMatchDeg < te.dMatchDeg;
} }
}; };
#ifdef _DEBUG
/** 链码节点(理想情况是一盘料首尾相接,对于追踪条件较好的料盘有用,但是对于存在乱七八糟的起点则难以追踪)
bJunction 是否是节点
iDirect 追踪方向(1 顺时针 -1 逆时针)
iStartOrEnd 起点或终点(0 起点 1 终点 2 中间节点)
iLinkID (每颗料都有的唯一编号)
iChainID 批次编号
iContPrev、iContCt、iContNxt 链接节点(指的是两个不同追踪流程连接处,用iLinkID表示,默认0)
vInfo 位置信息
ptCenter 元件中心坐标
*/
struct Link
{
//是否是接口处
bool bJunction = false;
//方向(1 顺时针 -1 逆时针),起点或终点(0 起点 1 终点 2 中间),编号(总编号),批次编号
int iDirect, iStartOrEnd, iLinkID, iChainID;
//连接节点
int iContPrev, iContCt, iContNxt;//iContPrev 上一个编号,iContCt 当前编号,iContNxt下一个编号
//位置信息
std::vector<cv::Point> vInfo;
//中心
cv::Point ptCenter;
Link() {};
Link(bool bJunction, int iDirect, int iStartOrEnd, int iLinkID, int iChainID, int iContPrev, int iContCt, int iContNxt, cv::Point ptCenter, std::vector<cv::Point> vInfo) :
bJunction(bJunction), iDirect(iDirect), iStartOrEnd(iStartOrEnd), iLinkID(iLinkID), iChainID(iChainID), iContPrev(iContPrev), iContCt(iContCt), iContNxt(iContNxt), ptCenter(ptCenter), vInfo(vInfo) {};
};
#endif
//缩放比例 //缩放比例
float coeff = 1.0f; float coeff = 1.0f;
//填充值 //填充值
...@@ -2310,6 +2345,11 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -2310,6 +2345,11 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
cv::Mat trackMat(Y, X, CV_8UC1, ucpTrackLabel); cv::Mat trackMat(Y, X, CV_8UC1, ucpTrackLabel);
//计数图像 //计数图像
cv::Mat lbMat(Y, X, CV_8UC1, cv::Scalar(0)); cv::Mat lbMat(Y, X, CV_8UC1, cv::Scalar(0));
#ifdef _DEBUG //<编号图像(2022034:新增测试用)
int tracingID = 0;
std::vector<Link> Links;
cv::Mat tracingChainMap(Y, X, CV_16SC3, cv::Scalar(-32768, -32768, -32768));
#endif
//定位图像 //定位图像
cv::Mat srcPrevS, tplMat;//模板文件 cv::Mat srcPrevS, tplMat;//模板文件
srcPrev.convertTo(srcPrevS, CV_32F); srcPrev.convertTo(srcPrevS, CV_32F);
...@@ -2322,6 +2362,8 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -2322,6 +2362,8 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
logger.t("eyemCountObjectIrregularParts 点料阶段被跳过执行..."); logger.t("eyemCountObjectIrregularParts 点料阶段被跳过执行...");
break; break;
} }
//20220314:新增测试用,起始编号等信息
auto chainID = (int)std::distance(tracingAnchors.begin(), itvx) + 1;
//起始位置信息 //起始位置信息
TracingAnchor ta = (*itvx); TracingAnchor ta = (*itvx);
//起始位置坐标 //起始位置坐标
...@@ -2428,9 +2470,15 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -2428,9 +2470,15 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
//最大值 //最大值
cv::minMaxLoc(tplMat, NULL, &taMaxGray); 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]) }; 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::fillConvexPoly(trackMat, vT, cv::Scalar(255));
#ifdef _DEBUG //<20220314:新增测试用
tracingID++;
Links.push_back(Link(false, 1, 0, 0, chainID, -1, 0, tracingID, startCenter, vT));
cv::fillConvexPoly(tracingChainMap, vT, cv::Scalar(0, chainID, Links.back().iContCt));
#endif
//标记计数 //标记计数
lbMat.ptr<uint8_t>(cvRound(startCenter.y))[cvRound(startCenter.x)] = 255; lbMat.ptr<uint8_t>(cvRound(startCenter.y))[cvRound(startCenter.x)] = 255;
//标记当前位置 //标记当前位置
...@@ -2489,8 +2537,6 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -2489,8 +2537,6 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
if (dChordL <= 2.1) { if (dChordL <= 2.1) {
continue; continue;
} }
//20220307测试用:对每次追踪进行编号?然后呢。。。
//顺时针(是否并行取决于在windows下运行还是树莓派上) //顺时针(是否并行取决于在windows下运行还是树莓派上)
{ {
//追踪中心 //追踪中心
...@@ -2506,7 +2552,7 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -2506,7 +2552,7 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
do do
{ {
bool found = true; bool trayEnd = false; bool found = true; bool trayEnd = false;
std::vector<Track> vParts; std::vector<Track> vParts; cv::Point2f predictCenter;//20220316新增测试用
for (double t = trackAngle + (trackOffset + partDist - trackOffset / 12.0); t < trackAngle + (trackOffset + partDist - trackOffset / 12.0) + trackOffset / 6.0; t += dMinorStep) for (double t = trackAngle + (trackOffset + partDist - trackOffset / 12.0); t < trackAngle + (trackOffset + partDist - trackOffset / 12.0) + trackOffset / 6.0; t += dMinorStep)
{ {
cv::Point2f predicPos; cv::Point2f predicPos;
...@@ -2517,6 +2563,8 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -2517,6 +2563,8 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
trayEnd = true; trayEnd = true;
break; break;
} }
//20220316新增测试用
predictCenter = cv::Point2f(predicPos.x, predicPos.y);
//感兴趣区域(向外扩展了一个元件,防止中心定位出现偏差或者料盘本身变形导致的偏差) //感兴趣区域(向外扩展了一个元件,防止中心定位出现偏差或者料盘本身变形导致的偏差)
cv::Point2f predictBox[4]; cv::Point2f predictBox[4];
calcRotateRect(predicPos, (float)(trackAngle + (trackOffset + partDist)), (float)trackLength + (float)trackLength, (float)trackWidth + (float)trackWidth, predictBox); calcRotateRect(predicPos, (float)(trackAngle + (trackOffset + partDist)), (float)trackLength + (float)trackLength, (float)trackWidth + (float)trackWidth, predictBox);
...@@ -2791,6 +2839,10 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -2791,6 +2839,10 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
} }
//追踪终止,选取下一个起点 //追踪终止,选取下一个起点
if (trayEnd) { if (trayEnd) {
#ifdef _DEBUG
Links.back().iStartOrEnd = 1;
cv::drawMarker(cc, predictCenter, cv::Scalar(0, 0, 255, 255), cv::MARKER_TILTED_CROSS, 10, 1);
#endif
break; break;
} }
//更新位置 //更新位置
...@@ -2803,10 +2855,60 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -2803,10 +2855,60 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
trackOffset = (2 * asin(2 * trackLength / (2 * trackRadius))) * 180.0 / PI; trackOffset = (2 * asin(2 * trackLength / (2 * trackRadius))) * 180.0 / PI;
//更新元件间角度 //更新元件间角度
partDist = (2 * asin(dChordL / (2 * trackRadius))) * 180.0 / PI; partDist = (2 * asin(dChordL / (2 * trackRadius))) * 180.0 / PI;
//追踪到了重复的元件 //追踪到了已经标记的元件
if ((trackCenter.x<0 || trackCenter.x>X - 1 || if ((trackCenter.x<0 || trackCenter.x>X - 1 ||
trackCenter.y<0 || trackCenter.y>Y - 1) || trackMat.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] == 255) { trackCenter.y<0 || trackCenter.y>Y - 1) || trackMat.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] == 255) {
found = false; found = false;
#ifdef _DEBUG //<20220314:测试用,获取连接节点junction,大量偏离如何处理
auto linkInfo = tracingChainMap.ptr<cv::Vec3s>(cvRound(trackCenter.y))[cvRound(trackCenter.x)];
//如果是反方向判断是junction,如果是同方向并且批次一样只能是偏离
if (linkInfo[0] == -1) {
//修改编号
Links.back().iContNxt = linkInfo[2]; Links.back().bJunction = true;
}
else {
//同批次且方向相同,判断是偏离
if (chainID == linkInfo[1]) {
//修改结束标志
found = true;
//判断不是junction而是追踪偏离,后续可以在这里增加偏离处理
Links.back().iStartOrEnd = 1;
//判断为偏离,采用理论位置代替
trackCenter = cv::Point2f(predictCenter.x, predictCenter.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;
//计算元件位置
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));
#ifdef _DEBUG //<20220314:测试用
tracingID++;
Links.push_back(Link(false, -1, 2, Links.back().iContNxt, chainID, Links.back().iContCt, Links.back().iContNxt, tracingID, trackCenter, vT));
cv::fillConvexPoly(tracingChainMap, vT, cv::Scalar(-1, chainID, Links.back().iContCt));
#endif
//用于显示
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);
}
#endif
}
}
#endif
} }
else { else {
//计算元件位置 //计算元件位置
...@@ -2817,6 +2919,12 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -2817,6 +2919,12 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
//标记为已追踪过 //标记为已追踪过
std::vector<cv::Point> vT = { cv::Point(pts[0]),cv::Point(pts[1]) ,cv::Point(pts[2]) ,cv::Point(pts[3]) }; 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::fillConvexPoly(trackMat, vT, cv::Scalar(255));
#ifdef _DEBUG //<20220314:测试用 标记编号
tracingID++;
Links.push_back(Link(false, 1, 2, Links.back().iContNxt, chainID, Links.back().iContCt, Links.back().iContNxt, tracingID, trackCenter, vT));
cv::fillConvexPoly(tracingChainMap, vT, cv::Scalar(1, chainID, Links.back().iContCt));
#endif
//用于显示 //用于显示
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
...@@ -2836,7 +2944,15 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -2836,7 +2944,15 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
trackEnd = (!found); trackEnd = (!found);
} while (!trackEnd); } while (!trackEnd);
} }
#ifdef _DEBUG //<调转方向
for (auto&lk : Links)
{
if (lk.iChainID == chainID) {
lk.iContPrev = tracingID;
break;
}
}
#endif
//逆时针 //逆时针
{ {
//追踪起点 //追踪起点
...@@ -2853,7 +2969,7 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -2853,7 +2969,7 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
do do
{ {
bool found = true; bool trayEnd = false; bool found = true; bool trayEnd = false;
std::vector<Track> vParts; std::vector<Track> vParts; cv::Point2f predictCenter;//20220316新增测试用
for (double t = trackAngle - (trackOffset + partDist - trackOffset / 12.0); t > trackAngle - (trackOffset + partDist - trackOffset / 12.0) - trackOffset / 6.0; t -= dMinorStep) for (double t = trackAngle - (trackOffset + partDist - trackOffset / 12.0); t > trackAngle - (trackOffset + partDist - trackOffset / 12.0) - trackOffset / 6.0; t -= dMinorStep)
{ {
cv::Point2f predicPos; cv::Point2f predicPos;
...@@ -2864,6 +2980,8 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -2864,6 +2980,8 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
trayEnd = true; trayEnd = true;
break; break;
} }
//20220316新增测试用
predictCenter = cv::Point2f(predicPos.x, predicPos.y);
//感兴趣区域(向外扩展了一个元件,防止中心定位出现偏差或者料盘本身变形导致的偏差) //感兴趣区域(向外扩展了一个元件,防止中心定位出现偏差或者料盘本身变形导致的偏差)
cv::Point2f predicBox[4]; cv::Point2f predicBox[4];
calcRotateRect(predicPos, (float)(trackAngle - (trackOffset + partDist)), (float)trackLength*2.0f, (float)trackWidth*2.0f, predicBox); calcRotateRect(predicPos, (float)(trackAngle - (trackOffset + partDist)), (float)trackLength*2.0f, (float)trackWidth*2.0f, predicBox);
...@@ -3128,6 +3246,10 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -3128,6 +3246,10 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
} }
//接着下一个起点 //接着下一个起点
if (trayEnd) { if (trayEnd) {
#ifdef _DEBUG //<修改结束标志
Links.back().iStartOrEnd = 1;
cv::drawMarker(cc, predictCenter, cv::Scalar(0, 0, 255, 255), cv::MARKER_TILTED_CROSS, 10, 1);
#endif
break; break;
} }
//更新位置 //更新位置
...@@ -3144,6 +3266,59 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -3144,6 +3266,59 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
if ((trackCenter.x<0 || trackCenter.x>X - 1 || if ((trackCenter.x<0 || trackCenter.x>X - 1 ||
trackCenter.y<0 || trackCenter.y>Y - 1) || trackMat.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] == 255) { trackCenter.y<0 || trackCenter.y>Y - 1) || trackMat.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] == 255) {
found = false; found = false;
#ifdef _DEBUG //<20220315:增加测试用
auto linkInfo = tracingChainMap.ptr<cv::Vec3s>(cvRound(trackCenter.y))[cvRound(trackCenter.x)];
//如果是反方向判断是junction,如果是同方向并且是同一批次只能是偏离,如果不同批次表明中间漏了许多但不能做处理
if (linkInfo[0] == 1) {
//判断为junction
auto lk = Links[linkInfo[2]]; auto bk = Links.back();
Links.back().iContNxt = linkInfo[2]; Links.back().bJunction = true;
}
else {
//满足同方向并且是同批次的,说明一定是偏离
if (chainID == linkInfo[1])
{
//修改结束标志
found = true;
//判断不是junction而是追踪偏离,后续可以在这里增加偏离处理
Links.back().iStartOrEnd = 1;
//判断为偏离,采用理论位置代替
trackCenter = cv::Point2f(predictCenter.x, predictCenter.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;
//计算元件位置
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));
#ifdef _DEBUG //<20220314:测试用
tracingID++;
Links.push_back(Link(false, -1, 2, Links.back().iContNxt, chainID, Links.back().iContCt, Links.back().iContNxt, tracingID, trackCenter, vT));
cv::fillConvexPoly(tracingChainMap, vT, cv::Scalar(-1, chainID, Links.back().iContCt));
#endif
//用于显示
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);
}
#endif
}
}
#endif
} }
else { else {
//计算元件位置 //计算元件位置
...@@ -3154,6 +3329,12 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -3154,6 +3329,12 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
//标记为已追踪过 //标记为已追踪过
std::vector<cv::Point> vT = { cv::Point(pts[0]),cv::Point(pts[1]) ,cv::Point(pts[2]) ,cv::Point(pts[3]) }; 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::fillConvexPoly(trackMat, vT, cv::Scalar(255));
#ifdef _DEBUG //<20220314:测试用
tracingID++;
Links.push_back(Link(false, -1, 2, Links.back().iContNxt, chainID, Links.back().iContCt, Links.back().iContNxt, tracingID, trackCenter, vT));
cv::fillConvexPoly(tracingChainMap, vT, cv::Scalar(-1, chainID, Links.back().iContCt));
#endif
//用于显示 //用于显示
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
...@@ -3174,6 +3355,70 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -3174,6 +3355,70 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
} while (!trackEnd); } while (!trackEnd);
} }
} }
#ifdef _DEBUG //<按顺序整理Links
std::vector<Link> srtLink;
std::vector<std::vector<Link>> srtLinks;
bool found = false; int nxt = -1;
for (auto&lk : Links)
{
//第一步,确定终点(如果有多个终点如何处理)
if (lk.iStartOrEnd == 1 && found == false && lk.iDirect == 1) {
found = true; nxt = lk.iContPrev;
srtLink.push_back(lk);
//第二步,从终点开始向起点排序
bool trackEnd = false;
do
{
auto lks = Links[nxt];
if (lks.iStartOrEnd == 0) {
//到达起点位置
cv::Point st = srtLink.back().ptCenter;
srtLink.push_back(lks);
cv::Point ed = lks.ptCenter;
//获取下一个位置
nxt = lks.iContPrev;
//画图
cv::arrowedLine(cc, st, ed, cv::Scalar(30, 105, 210, 255), 1);
}
else if (lks.iStartOrEnd == 1) {
//画图
cv::Point st = srtLink.back().ptCenter;
srtLink.push_back(lks);
cv::Point ed = lks.ptCenter;
//获取下一个位置
nxt = lks.iContPrev;
//画图
cv::arrowedLine(cc, st, ed, cv::Scalar(30, 105, 210, 255), 1);
//追踪结束
found = false; trackEnd = true;
}
if (lks.iStartOrEnd == 2 && lks.iDirect == 1) {
//到另一个终点,理论情况下到这里已经完全结束
cv::Point st = srtLink.back().ptCenter;
srtLink.push_back(lks);
cv::Point ed = lks.ptCenter;
//获取下一个位置
nxt = lks.iContPrev;
//画图
cv::arrowedLine(cc, st, ed, cv::Scalar(30, 105, 210, 255), 1);
}
if (lks.iStartOrEnd == 2 && lks.iDirect == -1)
{
cv::Point st = srtLink.back().ptCenter;
srtLink.push_back(lks);
cv::Point ed = lks.ptCenter;
//获取下一个位置
nxt = lks.iContNxt;
//画图
cv::arrowedLine(cc, st, ed, cv::Scalar(30, 105, 210, 255), 1);
}
} while (!trackEnd);
break;
}
if (!srtLink.empty()) srtLinks.push_back(srtLink);
}
//如果仅有一条链,判断零星的料距离起点和终点的理论位置是否相近,相近的话判断为料;如果有多条链,判断相邻链之间的位置(多条链生成顺序是不一定的。)
#endif
//计数 //计数
binary = lbMat.clone(); binary = lbMat.clone();
//释放资源 //释放资源
...@@ -3301,14 +3546,14 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -3301,14 +3546,14 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
//获取最大轮廓 //获取最大轮廓
cv::findContours(image, contoursFilter, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE); cv::findContours(image, contoursFilter, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
//定位内圈失败一般是仅剩一圈或者不足一圈的情况 //定位内圈失败一般是仅剩一圈或者不足一圈的情况
if (contoursFilter.size() <= 0) if (contoursFilter.empty())
{ {
image = cv::Scalar(0); image = cv::Scalar(0);
//当仅剩一圈的情况 //当仅剩一圈的情况
cv::Mat srcPrevEx1; cv::Mat srcPrevEx1;
cv::morphologyEx(binary, srcPrevEx1, cv::MORPH_DILATE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(15, 15))); cv::morphologyEx(binary, srcPrevEx1, cv::MORPH_DILATE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(31, 31)));
cv::findContours(srcPrevEx1, contoursFilter, cv::RETR_TREE, cv::CHAIN_APPROX_NONE); cv::findContours(srcPrevEx1, contoursFilter, cv::RETR_TREE, cv::CHAIN_APPROX_NONE);
//闭合轮廓 //闭合轮廓
...@@ -3329,7 +3574,7 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -3329,7 +3574,7 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
return FUNC_CANNOT_CALC; return FUNC_CANNOT_CALC;
} }
} }
std::vector<cv::Point> contourMax = contoursFilter[0]; std::vector<cv::Point> contourMax = contoursFilter[0];
for (int i = 1; i < contoursFilter.size(); i++) for (int i = 1; i < contoursFilter.size(); i++)
{ {
...@@ -3341,6 +3586,9 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -3341,6 +3586,9 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
//计算最大外接圆半径 //计算最大外接圆半径
float tFRadius = 0; float tFRadius = 0;
cv::minEnclosingCircle(contourMax, cv::Point2f(), tFRadius); cv::minEnclosingCircle(contourMax, cv::Point2f(), tFRadius);
//
tFRadius = tFRadius < 300 ? 300 : tFRadius;
cv::Moments mu = cv::moments(contourMax); cv::Moments mu = cv::moments(contourMax);
cv::Point2f reelCenter(float(mu.m10 / mu.m00), float(mu.m01 / mu.m00)); cv::Point2f reelCenter(float(mu.m10 / mu.m00), float(mu.m01 / mu.m00));
//画中心 //画中心
...@@ -5923,61 +6171,128 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -5923,61 +6171,128 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
} }
//最大值 //最大值
cv::minMaxLoc(tplMat, NULL, &taMaxGray); cv::minMaxLoc(tplMat, NULL, &taMaxGray);
//20220302修改测试用,使用模板匹配增加追踪起点
const float icvDirections[4] = { 0 , 90 , 180 , -90 }; //20220302修改测试用,使用模板匹配增加追踪起点,20220310,增加至八个方向
//用以计算元件中心 //正常四个方向
const int icvDirectionDeltas[4][2] = { { tplMat.cols / 2,tplMat.rows / 2 },{ tplMat.rows / 2,tplMat.cols / 2 },{ tplMat.cols / 2,tplMat.rows / 2 },\
{ tplMat.rows / 2, tplMat.cols / 2 } };
//cv::parallel_for_(cv::Range(0, 4), [&](const cv::Range& range)->void {
for (int tpl = 0/*range.start*/; tpl < 4 /*range.end*/; tpl++)
{ {
//模板匹配(仅处理料盘区域以提高速度) const float icvDirections[4] = { 0 , 90 , 180 , -90 };
cv::Mat tplResult0; //用以计算元件中心
cv::matchTemplate(srcPrev(mainZone).clone(), getTplMat(tplMat, icvDirections[tpl], fillVal), tplResult0, cv::TM_CCOEFF_NORMED); const int icvDirectionDeltas[4][2] = { { tplMat.cols / 2,tplMat.rows / 2 },{ tplMat.rows / 2,tplMat.cols / 2 },{ tplMat.cols / 2,tplMat.rows / 2 },\
{ tplMat.rows / 2, tplMat.cols / 2 } };
cv::Mat ki = getTplMat(tplMat, icvDirections[tpl], fillVal); for (int tpl = 0; tpl < 4; tpl++)
{
//模板匹配(仅处理料盘区域以提高速度)
cv::Mat tplResult0;
cv::matchTemplate(srcPrev(mainZone).clone(), getTplMat(tplMat, icvDirections[tpl], fillVal), tplResult0, cv::TM_CCOEFF_NORMED);
//分数大于一定分数才当作元件处理 cv::Mat ki = getTplMat(tplMat, icvDirections[tpl], fillVal);
tplResult0 = cv::Mat(tplResult0 > 0.56);
cv::Point quard[4]{ cv::Point(tplResult0.cols,0),cv::Point(0,0),cv::Point(0,tplResult0.rows),cv::Point(tplResult0.cols,tplResult0.rows) }; //分数大于一定分数才当作元件处理
tplResult0 = cv::Mat(tplResult0 > 0.6);
std::vector<cv::Point> pt = { cv::Point(tplResult0.cols / 2,tplResult0.rows / 2),quard[tpl], quard[(tpl + 1) % 4] }; cv::Point quard[4]{ cv::Point(tplResult0.cols,0),cv::Point(0,0),cv::Point(0,tplResult0.rows),cv::Point(tplResult0.cols,tplResult0.rows) };
std::vector<std::vector<cv::Point>> pts; std::vector<cv::Point> pt = { cv::Point(tplResult0.cols / 2,tplResult0.rows / 2),quard[tpl], quard[(tpl + 1) % 4] };
pts.push_back(pt);
cv::Mat dirMask(tplResult0.size(), CV_8UC1, cv::Scalar(0)); std::vector<std::vector<cv::Point>> pts;
pts.push_back(pt);
cv::drawContours(dirMask, pts, 0, cv::Scalar(255), -1); cv::Mat dirMask(tplResult0.size(), CV_8UC1, cv::Scalar(0));
//除去非必要部分 cv::drawContours(dirMask, pts, 0, cv::Scalar(255), -1);
cv::bitwise_and(tplResult0, dirMask, tplResult0);
//连通域分析 //除去非必要部分
cv::Mat labels, stats, centroids; cv::bitwise_and(tplResult0, dirMask, tplResult0);
int nccomps = cv::connectedComponentsWithStats(tplResult0, labels, stats, centroids);
for (int i = 1; i < nccomps; i++) { //连通域分析
cv::Point matchPt(cvRound(centroids.ptr<double>(i)[0]) + icvDirectionDeltas[tpl][0] + mainZone.x, \ cv::Mat labels, stats, centroids;
cvRound(centroids.ptr<double>(i)[1]) + icvDirectionDeltas[tpl][1] + mainZone.y); int nccomps = cv::connectedComponentsWithStats(tplResult0, labels, stats, centroids);
//判断是否位于有效区域
if (srcPrevEx0.ptr<uint8_t>(matchPt.y)[matchPt.x] == 255) for (int i = 1; i < nccomps; i++) {
{ cv::Point matchPt(cvRound(centroids.ptr<double>(i)[0]) + icvDirectionDeltas[tpl][0] + mainZone.x, \
//计算初始角度 cvRound(centroids.ptr<double>(i)[1]) + icvDirectionDeltas[tpl][1] + mainZone.y);
double _trackAngle_ = atan2((double)matchPt.y - (double)reelCenter.y, (double)matchPt.x - (double)reelCenter.x) * 180.0 / PI; //判断是否位于有效区域
cv::Point2f pts_t[4]; if (srcPrevEx0.ptr<uint8_t>(matchPt.y)[matchPt.x] == 255)
calcRotateRect(cv::Point2f((float)matchPt.x, (float)matchPt.y), (float)_trackAngle_, (float)tplMat.cols / 2.0f, (float)tplMat.rows / 4.0f, pts_t); {
//for (int j = 0; j < 4; j++) //计算初始角度
//{ double _trackAngle_ = atan2((double)matchPt.y - (double)reelCenter.y, (double)matchPt.x - (double)reelCenter.x) * 180.0 / PI;
// cv::line(cc, pts_t[j], pts_t[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1); cv::Point2f pts_t[4];
//} calcRotateRect(cv::Point2f((float)matchPt.x, (float)matchPt.y), (float)_trackAngle_, (float)tplMat.cols / 2.0f, (float)tplMat.rows / 4.0f, pts_t);
cv::RotatedRect _rbox_(pts_t[0], pts_t[1], pts_t[2]); //for (int j = 0; j < 4; j++)
tracingAnchors.push_back(TracingAnchor(cv::Point2f((float)matchPt.x, (float)matchPt.y), (float)tplMat.cols, (float)tplMat.rows, _rbox_.size.area(), _rbox_)); //{
// cv::line(cc, pts_t[j], pts_t[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1);
//}
cv::RotatedRect _rbox_(pts_t[0], pts_t[1], pts_t[2]);
tracingAnchors.push_back(TracingAnchor(cv::Point2f((float)matchPt.x, (float)matchPt.y), (float)tplMat.cols, (float)tplMat.rows, _rbox_.size.area(), _rbox_));
}
} }
} }
} }
//}); //图像旋转后的四个方向
{
const float icvDirections[4] = { 0 , 90 , 180 , -90 };
//用以计算元件中心
const int icvDirectionDeltas[4][2] = { { tplMat.cols / 2,tplMat.rows / 2 },{ tplMat.rows / 2,tplMat.cols / 2 },{ tplMat.cols / 2,tplMat.rows / 2 },\
{ tplMat.rows / 2, tplMat.cols / 2 } };
float matxv[4];
cv::Mat ttmp = getTrackMat(srcPrev(mainZone).clone(), 45.0, 0, matxv);
for (int tpl = 0; tpl < 4; tpl++)
{
//模板匹配(仅处理料盘区域以提高速度)
cv::Mat tplResult0;
cv::matchTemplate(ttmp, getTplMat(tplMat, icvDirections[tpl], fillVal), tplResult0, cv::TM_CCOEFF_NORMED);
cv::Mat ki = getTplMat(tplMat, icvDirections[tpl], fillVal);
//分数大于一定分数才当作元件处理
tplResult0 = cv::Mat(tplResult0 > 0.6);
cv::Point quard[4]{ cv::Point(tplResult0.cols,0),cv::Point(0,0),cv::Point(0,tplResult0.rows),cv::Point(tplResult0.cols,tplResult0.rows) };
std::vector<cv::Point> pt = { cv::Point(tplResult0.cols / 2,tplResult0.rows / 2),quard[tpl], quard[(tpl + 1) % 4] };
std::vector<std::vector<cv::Point>> pts;
pts.push_back(pt);
cv::Mat dirMask(tplResult0.size(), CV_8UC1, cv::Scalar(0));
cv::drawContours(dirMask, pts, 0, cv::Scalar(255), -1);
//除去非必要部分
cv::bitwise_and(tplResult0, dirMask, tplResult0);
//连通域分析
cv::Mat labels, stats, centroids;
int nccomps = cv::connectedComponentsWithStats(tplResult0, labels, stats, centroids);
for (int i = 1; i < nccomps; i++) {
cv::Point matchPt(cvRound(centroids.ptr<double>(i)[0]) + icvDirectionDeltas[tpl][0], \
cvRound(centroids.ptr<double>(i)[1]) + icvDirectionDeltas[tpl][1]);
//计算旋转前的位置
float realX1 = 0.0f, realY1 = 0.0f;
realX1 = (float)mainZone.tl().x + ((matchPt.x - matxv[2])*matxv[4] - (matchPt.y - matxv[5])*matxv[1]) / (matxv[0] * matxv[4] - matxv[3] * matxv[1]);
realY1 = (float)mainZone.tl().y + ((matchPt.x - matxv[2])*matxv[3] - (matchPt.y - matxv[5])*matxv[0]) / (matxv[1] * matxv[3] - matxv[4] * matxv[0]);
//判断是否位于有效区域
if (srcPrevEx0.ptr<uint8_t>(cvRound(realY1))[cvRound(realX1)] == 255)
{
//计算初始角度
double _trackAngle_ = atan2((double)realY1 - (double)reelCenter.y, (double)realX1 - (double)reelCenter.x) * 180.0 / PI;
cv::Point2f pts_t[4];
calcRotateRect(cv::Point2f((float)realX1, (float)realY1), (float)_trackAngle_, (float)tplMat.cols / 2.0f, (float)tplMat.rows / 4.0f, pts_t);
//for (int j = 0; j < 4; j++)
//{
// cv::line(cc, pts_t[j], pts_t[(j + 1) % 4], cv::Scalar(0, 0, 255, 255), 1);
//}
cv::RotatedRect _rbox_(pts_t[0], pts_t[1], pts_t[2]);
tracingAnchors.push_back(TracingAnchor(cv::Point2f((float)realX1, (float)realY1), (float)tplMat.cols, (float)tplMat.rows, _rbox_.size.area(), _rbox_));
}
}
}
}
} }
//标记为已追踪过 //标记为已追踪过
std::vector<cv::Point> vT = { cv::Point(_pts[0]),cv::Point(_pts[1]) ,cv::Point(_pts[2]) ,cv::Point(_pts[3]) }; std::vector<cv::Point> vT = { cv::Point(_pts[0]),cv::Point(_pts[1]) ,cv::Point(_pts[2]) ,cv::Point(_pts[3]) };
...@@ -7099,7 +7414,7 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, in ...@@ -7099,7 +7414,7 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, in
trays.push_back(TrayPos(reelCenter, tray, false, backThresh)); trays.push_back(TrayPos(reelCenter, tray, false, backThresh));
} }
//判断可能无料,不能100%判断 //判断可能无料,不能100%判断
if (trays.empty()) { if (trays.empty()) {//在这里empty的话只能 是单盘,没事,除非四盘都不满一圈。。。
//在这里增加继续判断是否是因为不满一圈的料,可能无法避免空料盘与空点问题,佳世达特供(无法用于多料盘而且佳世达一般多为小料没有那么多种类) //在这里增加继续判断是否是因为不满一圈的料,可能无法避免空料盘与空点问题,佳世达特供(无法用于多料盘而且佳世达一般多为小料没有那么多种类)
{ {
cv::Mat image8U; cv::Mat image8U;
...@@ -7378,7 +7693,7 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, in ...@@ -7378,7 +7693,7 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, in
//判断适用哪种算法 //判断适用哪种算法
if (!useTrackMethod) if (!useTrackMethod)
{ {
const int filterSize = 12; const int filterSize = 15;
//去掉料盘深色部分干扰 //去掉料盘深色部分干扰
const int winSize = sinPartSize > 15 ? 5 : 3;//对于部分器件过小的窗口会漏料 const int winSize = sinPartSize > 15 ? 5 : 3;//对于部分器件过小的窗口会漏料
cv::Mat srcPrevEx; cv::Mat srcPrevEx;
...@@ -7424,8 +7739,10 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, in ...@@ -7424,8 +7739,10 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, in
// continue; // continue;
//} //}
//计算轮廓矩
cv::Moments mu = cv::moments(contourMax); cv::Moments mu = cv::moments(contourMax);
cv::Point2f reelCenter(float(mu.m10 / mu.m00), float(mu.m01 / mu.m00)); cv::Point2f reelCenter(float(mu.m10 / mu.m00), float(mu.m01 / mu.m00));
//计算最大外接圆半径 //计算最大外接圆半径
float tFRadius = 0; float tFRadius = 0;
cv::minEnclosingCircle(contourMax, cv::Point2f(), tFRadius); cv::minEnclosingCircle(contourMax, cv::Point2f(), tFRadius);
...@@ -7611,7 +7928,7 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, in ...@@ -7611,7 +7928,7 @@ int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, in
image = cv::Scalar(0); image = cv::Scalar(0);
//当仅剩一圈的情况 //当仅剩一圈的情况
cv::Mat srcPrevEx1; cv::Mat srcPrevEx1;
cv::morphologyEx(binary, srcPrevEx1, cv::MORPH_DILATE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(15, 15))); cv::morphologyEx(binary, srcPrevEx1, cv::MORPH_DILATE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(31, 31)));
cv::findContours(srcPrevEx1, contoursFilter, cv::RETR_TREE, cv::CHAIN_APPROX_NONE); cv::findContours(srcPrevEx1, contoursFilter, cv::RETR_TREE, cv::CHAIN_APPROX_NONE);
//闭合轮廓 //闭合轮廓
...@@ -9593,7 +9910,6 @@ int eyemCountObjectIrregularPartsMultiopt(EyemImage tpImage, EyemRect tpRoi, int ...@@ -9593,7 +9910,6 @@ int eyemCountObjectIrregularPartsMultiopt(EyemImage tpImage, EyemRect tpRoi, int
cv::minMaxIdx(hist, NULL, NULL, NULL, maxIdx); cv::minMaxIdx(hist, NULL, NULL, NULL, maxIdx);
//背景阈值 //背景阈值
int backThresh = (maxIdx[0] - 1) * (65536 / histSize); int backThresh = (maxIdx[0] - 1) * (65536 / histSize);
//制作掩膜 //制作掩膜
cv::Mat mask(Y, X, CV_8UC1, cv::Scalar(0)); cv::Mat mask(Y, X, CV_8UC1, cv::Scalar(0));
cv::parallel_for_(cv::Range(0, Y), [&](const cv::Range range)->void { cv::parallel_for_(cv::Range(0, Y), [&](const cv::Range range)->void {
...@@ -9605,20 +9921,40 @@ int eyemCountObjectIrregularPartsMultiopt(EyemImage tpImage, EyemRect tpRoi, int ...@@ -9605,20 +9921,40 @@ int eyemCountObjectIrregularPartsMultiopt(EyemImage tpImage, EyemRect tpRoi, int
} }
} }
}); });
//去掉干扰(可有可无)
cv::morphologyEx(mask, mask, cv::MORPH_OPEN, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(9, 9)));
//制作背景 //像素重新排列
cv::Mat mean, stddev; std::vector<uint16_t> data;
cv::meanStdDev(src, mean, stddev, mask); for (int y = 0; y < Y; y++)
{
for (int x = 0; x < X; x++) {
if (mask.ptr<uint8_t>(y)[x] == 255) {
data.push_back(src.ptr<uint16_t>(y)[x]);
}
}
}
//随机打乱(让背景尽量显得自然一点)
std::random_shuffle(data.begin(), data.end());
cv::Mat rnd(Y, X, CV_16UC1); //拷贝指定部分
cv::randn(rnd, mean, stddev); const int dataSize = cvFloor(sqrt((int)data.size()));
std::vector<uint16_t> pixVal(dataSize*dataSize);
memcpy(&pixVal[0], &data[0], dataSize*dataSize*sizeof(uint16_t));
//制作背景
cv::Mat rnd;
rnd = cv::Mat(dataSize, dataSize, CV_16UC1, &pixVal[0]);
//扩充到原尺寸
cv::resize(rnd, rnd, cv::Size(X, Y));
//算法选项 //算法选项
std::string sOptions[8] = { "IP_DEFAULT_PARTS","IP_SMALL_PARTS","IP_LARGE_PARTS","IP_LONG_PARTS","IP_SQUARE_PARTS","","IP_DYNAMIC_SP1","IP_DYNAMIC_SP2" }; std::string sOptions[8] = { "IP_DEFAULT_PARTS","IP_SMALL_PARTS","IP_LARGE_PARTS","IP_LONG_PARTS","IP_SQUARE_PARTS","","IP_DYNAMIC_SP1","IP_DYNAMIC_SP2" };
//将各个料盘分别拷贝到背景里 //将各个料盘分别拷贝到背景里
std::vector<cv::Rect> q = { cv::Rect(0, 0, X / 2, Y / 2),cv::Rect(X / 2, 0, X / 2, Y / 2) std::vector<cv::Rect> q = { cv::Rect(0, 0, X / 2, Y / 2),cv::Rect(0, Y / 2, X / 2, Y / 2)
,cv::Rect(0, Y / 2, X / 2, Y / 2),cv::Rect(X / 2, Y / 2, X / 2, Y / 2) }; ,cv::Rect(X / 2, Y / 2, X / 2, Y / 2),cv::Rect(X / 2, 0, X / 2, Y / 2) };
std::vector<EyemImage> inputs; std::vector<EyemImage> inputs;
for (auto&rect : q) for (auto&rect : q)
...@@ -9641,7 +9977,7 @@ int eyemCountObjectIrregularPartsMultiopt(EyemImage tpImage, EyemRect tpRoi, int ...@@ -9641,7 +9977,7 @@ int eyemCountObjectIrregularPartsMultiopt(EyemImage tpImage, EyemRect tpRoi, int
} }
//用于显示 //用于显示
cv::Mat cc(Y + 1, X + 1, CV_8UC4, cv::Scalar(127, 116, 102, 255)); cv::Mat cc(Y + 1, X + 1, CV_8UC4, cv::Scalar(127, 116, 102, 255));
//点料(左上、右上、左下、右下) //点料(左上、左下、右下、右上)
#define OPTIMIZE true #define OPTIMIZE true
#if OPTIMIZE #if OPTIMIZE
cv::parallel_for_(cv::Range(0, 4), [&](const cv::Range range)->void { cv::parallel_for_(cv::Range(0, 4), [&](const cv::Range range)->void {
...@@ -9664,6 +10000,7 @@ int eyemCountObjectIrregularPartsMultiopt(EyemImage tpImage, EyemRect tpRoi, int ...@@ -9664,6 +10000,7 @@ int eyemCountObjectIrregularPartsMultiopt(EyemImage tpImage, EyemRect tpRoi, int
if (ipReelNum_[j] != 0) if (ipReelNum_[j] != 0)
{ {
ipReelNum[i] = ipReelNum_[j]; ipReelNum[i] = ipReelNum_[j];
break;
} }
} }
//拼接图像 //拼接图像
...@@ -9756,10 +10093,10 @@ int eyemCountObjectIrregularPartsMultiopt(EyemImage tpImage, EyemRect tpRoi, int ...@@ -9756,10 +10093,10 @@ int eyemCountObjectIrregularPartsMultiopt(EyemImage tpImage, EyemRect tpRoi, int
int baseLine; int baseLine;
cv::Size labelSize = cv::getTextSize("No Reel", cv::FONT_HERSHEY_SIMPLEX, 2.5, 2, &baseLine); cv::Size labelSize = cv::getTextSize("No Reel", cv::FONT_HERSHEY_SIMPLEX, 2.5, 2, &baseLine);
cv::putText(cc, "No Reel", cv::Point(reelPt.x - labelSize.width / 2, reelPt.y - labelSize.height), cv::FONT_HERSHEY_SIMPLEX, 2.5, cv::Scalar(0, 0, 238, 255), 2); cv::putText(cc, "No Reel", cv::Point(reelPt.x - labelSize.width / 2, reelPt.y - labelSize.height), cv::FONT_HERSHEY_SIMPLEX, 2.5, cv::Scalar(0, 0, 238, 255), 2);
} }
//画网格 //画网格
cv::rectangle(cc, cv::Rect(q[i].x, q[i].y, q[i].width, q[i].height), cv::Scalar(0, 0, 255, 255), 4); cv::rectangle(cc, cv::Rect(q[i].x, q[i].y, q[i].width, q[i].height), cv::Scalar(0, 0, 255, 255), 4);
} }
#endif #endif
//释放图像 //释放图像
for (auto&input : inputs) for (auto&input : inputs)
...@@ -9778,7 +10115,7 @@ int eyemCountObjectIrregularPartsMultiopt(EyemImage tpImage, EyemRect tpRoi, int ...@@ -9778,7 +10115,7 @@ int eyemCountObjectIrregularPartsMultiopt(EyemImage tpImage, EyemRect tpRoi, int
//拷贝数据 //拷贝数据
memcpy(tpDstImg->vpImage, cc.data, _Size); memcpy(tpDstImg->vpImage, cc.data, _Size);
return FUNC_OK; return FUNC_OK;
} }
int eyemAchvMatchMat(EyemImage tpImage, EyemRect tpRoi, EyemImage *tpDstImg) int eyemAchvMatchMat(EyemImage tpImage, EyemRect tpRoi, EyemImage *tpDstImg)
{ {
...@@ -12932,7 +13269,7 @@ int eyemLibImpl(EyemImage tpImage, EyemImage *tpDstImg) ...@@ -12932,7 +13269,7 @@ int eyemLibImpl(EyemImage tpImage, EyemImage *tpDstImg)
#pragma endregion #pragma endregion
sw.Stop(); sw.Stop();
std::cout << "TimeSpan:" << sw.ElapsedMilliseconds() << std::endl; std::cout << "时间花费:" << sw.ElapsedMilliseconds() << std::endl;
////<输出结果图像 ////<输出结果图像
//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();
////内存尺寸 ////内存尺寸
......
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!