Commit 87a1305d 张士柳

1 个父辈 5564312a
......@@ -822,7 +822,7 @@ 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, double dOffset, int iMinArea, int iMaxArea, int iWinSize, LPSTR *lpszNumObj, EyemImage *tpDstImg);
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);
......
......@@ -655,7 +655,7 @@ static bool checkSize(cv::Mat &srcPrev, cv::Mat &mask, int &partSize)
#pragma endregion
int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, double dOffset, int iMinArea, int iMaxArea, int iWinSize, LPSTR *lpszNumObj, EyemImage *tpDstImg)
int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LPSTR *lpszNumObj, EyemImage *tpDstImg)
{
cv::Mat src = cv::Mat(tpImage.iHeight, tpImage.iWidth, MAKETYPE(tpImage.iDepth, tpImage.iChannels), tpImage.vpImage).clone();
if (src.empty()) {
......@@ -1107,107 +1107,220 @@ int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, dou
});
//去掉中心1/3区域
cv::circle(image, reelCenter, cvRound(tFRadius / 3), cv::Scalar(0), -1);
//追踪直至没有单个元件存在
bool bExistSingle = true;
//用于计数
cv::Mat lb4Count(Y, X, CV_8UC1, cv::Scalar(0));
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;
//标签图
unsigned char *ucpTrackLabel = new unsigned char[Y*X]();
cv::Mat trackMat(Y, X, CV_8UC1, ucpTrackLabel);
do
{
//计数图像
cv::Mat lbMat(Y, X, CV_8UC1, cv::Scalar(0));
//定位图像
cv::Mat srcPrevS, tplMat;//模板文件
srcPrev.convertTo(srcPrevS, CV_32F);
//随机打乱顺序(降低计算错误dChordL的可能性,也为了测试在起点信息不同时的稳定性)
std::random_shuffle(tracingAnchors.begin(), tracingAnchors.end());
//开始确定起点(现在是用圆轨迹来追踪,不排除用螺旋线轨迹来追踪)
for (std::vector<TracingAnchor>::iterator itvx = tracingAnchors.begin(); itvx != tracingAnchors.end(); ++itvx) {
//跳过执行
if (killProcessID == 0) {
logger.t("eyemCountObjectIrregularPartsE 点料阶段被跳过执行...");
logger.t("eyemCountObjectIrregularParts 点料阶段被跳过执行...");
break;
}
//不随机挑选起点(考虑换成面积最小的那个)
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)
//起始位置信息
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())
{
//随机数生成
srand((unsigned)time(NULL));
contourMin = contoursFilter[rand() % (contoursFilter.size() - 1)];
for (int fc = 0; fc < contoursFilter.size(); fc++)
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++)
{
if (cv::contourArea(contoursFilter[fc]) > 0.4*sinPartSize)
{
if (cv::contourArea(contoursFilter[fc]) < cv::contourArea(contourMin))
{
contourMin = contoursFilter[fc];
}
__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++)
{
if (__pts[j].x < __ptsc.x) {
_dir_l.push_back(DIR(j, __pts[j]));
}
else {
_dir_r.push_back(DIR(j, __pts[j]));
}
}
}
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_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];
}
Track() {};
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(int iLimit, int iPartSize, double dMatchDeg, cv::Point Pos, std::vector<cv::Point2f> Rect) :iLimit(iLimit), iPartSize(iPartSize), dMatchDeg(dMatchDeg), Pos(Pos), Rect(Rect) {};
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);
bool operator >(const Track &te)const
cv::Point2f __mpts[4];
for (int j = 0; j < 4; j++)
{
return dMatchDeg > te.dMatchDeg;
__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;
}
//最大值
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 = 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 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);
//偏移角度(元件尺寸)
const double dOffset = (2 * asin(2 * trackLength / (2 * startRadius))) * 180 / PI;
//偏移角度(元件间距
const double dScanRange = 15;
const double dOffset = (2.0 * asin(2.0 * trackLength / (2.0 * startRadius))) * 180.0 / PI;
//扫描角度(默认15度范围内存在元件
const double dScanRange = 15.0;
//追踪元件间距(弦长,可以尽量避免因个别器件偏离导致的追踪中断)
double dChordL = .0;
for (double t = startAngle + dOffset / 1.5; t < startAngle + dOffset / 1.5 + dScanRange; t += dMinorStep)
for (double t = startAngle + dOffset / 1.5; t < startAngle + 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);
......@@ -1216,420 +1329,714 @@ int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, dou
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.data)[(it.pos().x) + (it.pos().y)*X] == 255)
if (sinParts.ptr<uint8_t>(it.pos().y)[it.pos().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 > 0)
if (dChordL > 2.1)
break;
}
//并行处理
//#pragma omp parallel sections
//没确定出元件间距一般为结尾或单个元件,继续从下一个起点计算弦长并开始追踪
if (dChordL <= 2.1) {
continue;
}
//顺时针(是否并行取决于在windows下运行还是树莓派上)
{
//(顺时针)
//#pragma omp section
//追踪中心
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
{
//追踪中心
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
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)
{
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);
}
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);
}
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;
}
}
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);
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;
}
else
//感兴趣区域(向外扩展了一个元件,防止中心定位出现偏差或者料盘本身变形导致的偏差)
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++)
{
//画出最终位置
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);
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::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::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++)
{
int label = labels.at<int>(vTemp[p]);
if (label != 0)
{
labeled[label] = 255;
break;
}
cv::line(cc, predictBox[j], predictBox[(j + 1) % 4], cv::Scalar(0, 0, 255, 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]);
//外包矩形顶点
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 (killProcessID == 0) {
logger.t("eyemCountObjectIrregularPartsE 追踪阶段被跳过执行...");
found = false;
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;
}
}
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++)
{
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]);
trackEnd = (!found);
} while (!trackEnd);
}
//外包矩形顶点
cv::Point2f pts[4];
calcRotateRect(cv::Point2f(realX, realY), (float)(trackAngle + (trackOffset + partDist)), (float)trackLength*2.0f, (float)trackWidth*2.0f, pts);
//#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)
{
dMatch += (srcPrev.data)[(vPoints[v].x) + (vPoints[v].y)*X];
}
//
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
vParts.push_back(Track(0, 0, 0, cv::Point2f(realX, realY), vRect));
}
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.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)
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++)
{
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++;
cv::line(cc, predicBox[j], predicBox[(j + 1) % 4], cv::Scalar(0, 0, 238, 255), 1);
}
}
vParts.push_back(Track(iLimit, iPartSize, dMatch, it.pos(), vRect));
//cv::circle(cc, it.pos(), 0, cv::Scalar(255, 0, 0, 255), 1);
}
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)
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;
}
}
}
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)
//如果不在则选取距离理论位置最近的
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++)
{
int label = labels.at<int>(vTemp[p]);
if (label != 0)
{
labeled[label] = 255;
break;
}
cv::line(cc, predicBox[j], predicBox[(j + 1) % 4], cv::Scalar(0, 0, 238, 255), 1);
}
}
}
//跳过执行
if (killProcessID == 0) {
logger.t("eyemCountObjectIrregularPartsE 追踪阶段被跳过执行...");
found = false;
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;
}
}
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])
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++)
{
((int *)(labels.data))[(x)+(y)*X] = 0;
cv::line(cc, pts[j], pts[(j + 1) % 4], cv::Scalar(102, 205, 0, 255), 1);
}
//#endif
}
}
});
image = labels > 0;
//判断是否存在未追踪单个料
bExistSingle = (cv::countNonZero(image) == 0);
} while (!bExistSingle);
//继续下一个起点
vParts.resize(0);
//跳过执行
if (killProcessID == 0) {
logger.t("eyemCountObjectIrregularParts 追踪阶段被跳过执行...");
found = false;
}
trackEnd = (!found);
} while (!trackEnd);
}
}
//标记料盘编号
//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 numObj = cv::countNonZero(lb4Count);
int reelNum = cv::countNonZero(lbMat);
std::string text = std::to_string(i + 1) + ": Reel Number = ";
text += std::to_string(numObj);
text += std::to_string(reelNum);
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] = numObj;
trayNum[sortedTrays[i].iDir] = reelNum;
//释放资源
delete[] ucpTrackLabel;
ucpTrackLabel = NULL;
}
} // 分料盘计数
}
//输出结果
const int bufSize = 64;
char cTrayNum[bufSize * 4] = { 0 };
for (int i = 0; i < trayNum.size(); i++)
{
for (int i = 0; i < trayNum.size(); i++) {
char cTemp[bufSize] = { 0 };
sprintf_s(cTemp, bufSize, "%d,", trayNum[i]);
strcat(cTrayNum, cTemp);
......@@ -1637,22 +2044,25 @@ int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, dou
//拷贝std::string拼接的字符串会莫名的报错??
*lpszNumObj = (char *)CoTaskMemAlloc(bufSize * 4);
memset(*lpszNumObj, 0, bufSize * 4);
if (NULL != *lpszNumObj)
{
if (NULL != *lpszNumObj) {
strcpy(*lpszNumObj, cTrayNum);
}
//获取当前运行目录
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[64 * 4] = { 0 };
sprintf_s(file, "%s\\%s-Mark.png", filePath.c_str(), fileName);
cv::imwrite(file, cc);
//<输出计数结果标记图像
{
tpDstImg->iWidth = cc.cols; tpDstImg->iHeight = cc.rows; tpDstImg->iDepth = cc.depth(); tpDstImg->iChannels = cc.channels();
//内存尺寸
int _Size = tpDstImg->iWidth*tpDstImg->iHeight*tpDstImg->iChannels * sizeof(uint8_t);
//分配内存
tpDstImg->vpImage = (uint8_t *)malloc(_Size);
if (NULL == tpDstImg->vpImage)
return FUNC_NOT_ENOUGH_MEM;
memset(tpDstImg->vpImage, 0, _Size);
//拷贝数据
memcpy(tpDstImg->vpImage, cc.data, _Size);
}
return FUNC_OK;
}
......
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!