Commit 5361861d 张士柳

1 个父辈 37fb9c9a
...@@ -720,6 +720,9 @@ namespace eyemLib_Sharp ...@@ -720,6 +720,9 @@ namespace eyemLib_Sharp
//异型器件(新版本) //异型器件(新版本)
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)] [DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemCountObjectIrregularPartsE(EyemImage tpImage, string fileName, string ccSubType, string ccTplName, double dMinScore, ref string pNumObj, out EyemImage tpDstImg); private static extern int eyemCountObjectIrregularPartsE(EyemImage tpImage, string fileName, string ccSubType, string ccTplName, double dMinScore, ref string pNumObj, out EyemImage tpDstImg);
//创建模板匹配模型
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemCreateTemplateModel(EyemImage tpImage, EyemRect tpRoi, string ccTplName);
//读码程序 //读码程序
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)] [DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, string fileName, string strCodeType, out DataCodeHandle hObject, out EyemBarCode* tpResults, out int ipNum, bool bUseNiBlack, int iBlockSize, int iRangeC, int iSymbolMin, int iSymbolMax, double dScaleUpAndDown = 0.5, double dToleErr = 0.5, double dMinorStep = 1.0); private static extern int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, string fileName, string strCodeType, out DataCodeHandle hObject, out EyemBarCode* tpResults, out int ipNum, bool bUseNiBlack, int iBlockSize, int iRangeC, int iSymbolMin, int iSymbolMax, double dScaleUpAndDown = 0.5, double dToleErr = 0.5, double dMinorStep = 1.0);
...@@ -901,10 +904,19 @@ namespace eyemLib_Sharp ...@@ -901,10 +904,19 @@ namespace eyemLib_Sharp
//eyemEdgesPixel(ucpImage, 15); //eyemEdgesPixel(ucpImage, 15);
#endregion #endregion
////EyemRect tpRoi = new EyemRect();
////tpRoi.iXs = 1231; tpRoi.iYs = 433;
////tpRoi.iWidth = 41;
////tpRoi.iHeight = 14;
EyemRect tpRoi = new EyemRect(); EyemRect tpRoi = new EyemRect();
tpRoi.iXs = tpRoi.iYs = 0; tpRoi.iXs = 0; tpRoi.iYs = 0;
tpRoi.iWidth = image.iWidth; tpRoi.iWidth = image.iWidth;
tpRoi.iHeight = image.iHeight; tpRoi.iHeight = image.iHeight;
//创建模板匹配模型
//flag = eyemCreateTemplateModel(image, tpRoi, "D://批量测试图像2//template.tpl");
// //
string pNumObj = ""; string pNumObj = "";
string file = fileName.Split(new string[] { "\\" }, StringSplitOptions.RemoveEmptyEntries)[2]; string file = fileName.Split(new string[] { "\\" }, StringSplitOptions.RemoveEmptyEntries)[2];
...@@ -912,16 +924,25 @@ namespace eyemLib_Sharp ...@@ -912,16 +924,25 @@ namespace eyemLib_Sharp
//eyemCountObject(image, file.Replace(".png", ""), 35, 0, 100, 5, ref pNumObj, out tpDstImg); //eyemCountObject(image, file.Replace(".png", ""), 35, 0, 100, 5, ref pNumObj, out tpDstImg);
//eyemCountObjectIrregularParts(image, file.Replace(".png", ""), 0.1, "IP_LARGE_PARTS", 100, 7, ref pNumObj, out tpDstImg); //eyemCountObjectIrregularParts(image, file.Replace(".png", ""), 0.1, "IP_LARGE_PARTS", 100, 7, ref pNumObj, out tpDstImg);
//eyemCountObjectE(image, fileName, ref pNumObj, out tpDstImg); //eyemCountObjectE(image, fileName, ref pNumObj, out tpDstImg);
eyemCountObjectIrregularPartsE(image, file.Replace(".png", ""), "IP_LARGE_PARTS", "D://批量测试图像2//template.png", 0.7, ref pNumObj, out tpDstImg); //eyemCountObjectIrregularPartsE(image, file.Replace(".png", ""), "IP_LARGE_PARTS", "D://批量测试图像2//template.png", 0.7, ref pNumObj, out tpDstImg);
//int ipNum; EyemBarCode* tpResults;
//DataCodeHandle hObject; //Bitmap bmp = eyemCvtToBitmap(tpDstImg);
//int iRes = eyemDetectAndDecode(image, tpRoi, file.Replace(".png", ""), "QR_CODE|DATA_MATRIX|CODE_39|CODE_128", out hObject, out tpResults, out ipNum, false, 11, 5, 128, 256, 0.5);
//for (int i = 0; i < ipNum; i++) //bmp.Save("D://ResOut//" + file);
//{
// Console.WriteLine("类型:" + Marshal.PtrToStringAnsi(tpResults[i].hType) + ";坐标" + "[" + tpResults[i].iCenterX.ToString() + "," + tpResults[i].iCenterY.ToString() + "]" + ";角度:" + tpResults[i].dAngle.ToString("F4") + "," + ";内容:" + Marshal.PtrToStringAnsi(tpResults[i].hText) + ""); //<解码测试
// Marshal.FreeCoTaskMem(tpResults[i].hText); Marshal.FreeCoTaskMem(tpResults[i].hType); int ipNum; EyemBarCode* tpResults;
//} DataCodeHandle hObject;
//hObject.Dispose(); int iRes = eyemDetectAndDecode(image, tpRoi, file.Replace(".png", ""), "QR_CODE|DATA_MATRIX|CODE_39|CODE_128", out hObject, out tpResults, out ipNum, false, 7, 5, 128, 256, 1d);
for (int i = 0; i < ipNum; i++)
{
Console.WriteLine("类型:" + Marshal.PtrToStringAnsi(tpResults[i].hType) + ";坐标" + "[" + tpResults[i].iCenterX.ToString() + "," + tpResults[i].iCenterY.ToString() + "]" + ";角度:" + tpResults[i].dAngle.ToString("F4") + "," + ";内容:" + Marshal.PtrToStringAnsi(tpResults[i].hText) + "");
Marshal.FreeCoTaskMem(tpResults[i].hText); Marshal.FreeCoTaskMem(tpResults[i].hType);
}
hObject.Dispose();
sw.Stop(); sw.Stop();
Console.WriteLine("耗时:" + sw.ElapsedMilliseconds.ToString() + ",结果:" + pNumObj); Console.WriteLine("耗时:" + sw.ElapsedMilliseconds.ToString() + ",结果:" + pNumObj);
//free image //free image
......
...@@ -649,6 +649,9 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam ...@@ -649,6 +649,9 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam
if (src.empty()) { if (src.empty()) {
return FUNC_IMAGE_NOT_EXIST; return FUNC_IMAGE_NOT_EXIST;
} }
//转单通道图像
if (src.channels() != 1)
cv::cvtColor(src, src, cv::COLOR_BGR2GRAY);
//提取ROI //提取ROI
src = src(cv::Rect(tpRoi.iXs, tpRoi.iYs, tpRoi.iWidth, tpRoi.iHeight)); src = src(cv::Rect(tpRoi.iXs, tpRoi.iYs, tpRoi.iWidth, tpRoi.iHeight));
//图像原图备份 //图像原图备份
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
#define __EYEM_EDGE_H #define __EYEM_EDGE_H
#include "eyemLib.h" #include "eyemLib.h"
#include "eyemGeneric.h"
......
...@@ -836,6 +836,7 @@ extern "C" { ...@@ -836,6 +836,7 @@ extern "C" {
EXPORTS int eyemCountObjectE(EyemImage tpImage, const char *fileName, LPSTR *lpszNumObj, EyemImage *tpDstImg); EXPORTS int eyemCountObjectE(EyemImage tpImage, const char *fileName, LPSTR *lpszNumObj, EyemImage *tpDstImg);
EXPORTS int eyemCountObjectIrregularParts(EyemImage tpImage, const char *fileName, double dOffset, const char * ccSubType, int iMaxArea, int iWinSize, LPSTR *lpszNumObj, EyemImage *tpDstImg); EXPORTS int eyemCountObjectIrregularParts(EyemImage tpImage, const char *fileName, double dOffset, const char * ccSubType, int iMaxArea, int iWinSize, LPSTR *lpszNumObj, EyemImage *tpDstImg);
EXPORTS int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, const char * ccSubType, const char *ccTplName, double dMinScore, LPSTR *lpszNumObj, EyemImage *tpDstImg); EXPORTS int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, const char * ccSubType, const char *ccTplName, double dMinScore, LPSTR *lpszNumObj, EyemImage *tpDstImg);
EXPORTS int eyemCreateTemplateModel(EyemImage tpImage, EyemRect tpRoi, const char *ccTplName);
EXPORTS int eyemTrackFeature(EyemImage tpPrevImg, EyemImage tpNextImg, EyemRect3 *tpRois, int iRoiNum, int *ipResults); EXPORTS int eyemTrackFeature(EyemImage tpPrevImg, EyemImage tpNextImg, EyemRect3 *tpRois, int iRoiNum, int *ipResults);
EXPORTS int eyemAOIForTSAV(EyemImage tpRefImg, EyemImage tpNextImg, EyemRect3 *tpRois, int iRoiNum); EXPORTS int eyemAOIForTSAV(EyemImage tpRefImg, EyemImage tpNextImg, EyemRect3 *tpRois, int iRoiNum);
......
...@@ -51,6 +51,20 @@ static void calcRotateRect(std::vector<cv::Point2f> &vRect, std::vector<cv::Poin ...@@ -51,6 +51,20 @@ static void calcRotateRect(std::vector<cv::Point2f> &vRect, std::vector<cv::Poin
} }
} }
static void calcRotateRect(cv::Point2f pt, float t, float length, float width, cv::Point2f *pts)
{
float b = (float)cos(t*PI / 180.)*0.5f;
float a = (float)sin(t*PI / 180.)*0.5f;
pts[0].x = (float)(pt.x - a*length * 2 - b*width * 4);
pts[0].y = (float)(pt.y + b*length * 2 - a*width * 4);
pts[1].x = (float)(pt.x + a*length * 2 - b*width * 4);
pts[1].y = (float)(pt.y - b*length * 2 - a*width * 4);
pts[2].x = (float)(2 * pt.x - pts[0].x);
pts[2].y = (float)(2 * pt.y - pts[0].y);
pts[3].x = (float)(2 * pt.x - pts[1].x);
pts[3].y = (float)(2 * pt.y - pts[1].y);
}
static cv::Mat getTplMat(cv::Mat &tplMat, double t) static cv::Mat getTplMat(cv::Mat &tplMat, double t)
{ {
const int tplH = tplMat.rows, tplW = tplMat.cols; const int tplH = tplMat.rows, tplW = tplMat.cols;
...@@ -3824,9 +3838,11 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons ...@@ -3824,9 +3838,11 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons
//转8位灰度图 //转8位灰度图
cv::Mat src8U; cv::Mat src8U;
src.convertTo(src8U, CV_8UC1, 1 / 255.); src.convertTo(src8U, CV_8UC1, 1 / 255.);
//用于显示 //用于显示
cv::Mat cc; cv::Mat cc;
cv::cvtColor(src8U, cc, cv::COLOR_GRAY2BGRA); cv::cvtColor(src8U, cc, cv::COLOR_GRAY2BGRA);
//设定bin数目 //设定bin数目
const int histSize = 17; const int histSize = 17;
//设定取值范围 //设定取值范围
...@@ -3853,11 +3869,14 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons ...@@ -3853,11 +3869,14 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons
} }
} }
}); });
//增强到目标亮度 //增强到目标亮度
cc += cv::Scalar((162 - backThresh), (162 - backThresh), (162 - backThresh)); cc += cv::Scalar((162 - backThresh), (162 - backThresh), (162 - backThresh));
//去掉干扰 //去掉干扰
cv::Mat binary, srcPrev; cv::Mat binary, srcPrev;
cv::bitwise_not(src8U, srcPrev); cv::bitwise_not(src8U, srcPrev);
//使用小料算法 //使用小料算法
if (strcmp(ccSubType, "IP_SMALL_PARTS") == 0) if (strcmp(ccSubType, "IP_SMALL_PARTS") == 0)
{ {
...@@ -3963,7 +3982,7 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons ...@@ -3963,7 +3982,7 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons
//释放资源 //释放资源
free((void *)pLabelImg); free((void *)pLabelImg);
} }
//使用大料算法 //使用大料算法(模板匹配方式)
else if (strcmp(ccSubType, "IP_LARGE_PARTS") == 0) else if (strcmp(ccSubType, "IP_LARGE_PARTS") == 0)
{ {
//二值化 //二值化
...@@ -4113,13 +4132,12 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons ...@@ -4113,13 +4132,12 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons
double sinPartSize = (double)tplWidth*(double)tplHeight; double sinPartSize = (double)tplWidth*(double)tplHeight;
//标签图 //标签图
unsigned char *ucpTrackLabel = new unsigned char[Y*X](); cv::Mat trackMat(Y, X, CV_8UC1, cv::Scalar(0));
cv::Mat trackMat(Y, X, CV_8UC1, ucpTrackLabel);
//开始追踪 //开始追踪
for (std::vector<cv::Point>::iterator itv = matchPts.begin(); itv != matchPts.end(); ++itv) for (std::vector<cv::Point>::iterator itv = matchPts.begin(); itv != matchPts.end(); ++itv)
{ {
//已标记 //已标记
if (trackMat.ptr<uint8_t>((*itv).y)[(*itv).x] == 255) if (trackMat.ptr<uint8_t>((*itv).y)[(*itv).x] == 255)
continue; continue;
...@@ -4131,19 +4149,9 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons ...@@ -4131,19 +4149,9 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons
{ {
double t = atan2((double)(*itv).y - reelCenter.y, (double)(*itv).x - reelCenter.x) * 180 / PI; double t = atan2((double)(*itv).y - reelCenter.y, (double)(*itv).x - reelCenter.x) * 180 / PI;
const double trackLength = tplWidth / 2, trackWidth = tplHeight / 4; const float trackLength = (float)tplWidth / 2.0f, trackWidth = (float)tplHeight / 4.0f;
float b = (float)cos(t*c)*0.5f;
float a = (float)sin(t*c)*0.5f;
points[0].x = float((*itv).x - a*trackLength * 2 - b*trackWidth * 4); calcRotateRect(cv::Point2f((float)(*itv).x, (float)(*itv).y), (float)t, trackLength, trackWidth, points);
points[0].y = float((*itv).y + b*trackLength * 2 - a*trackWidth * 4);
points[1].x = float((*itv).x + a*trackLength * 2 - b*trackWidth * 4);
points[1].y = float((*itv).y - b*trackLength * 2 - a*trackWidth * 4);
points[2].x = float(2 * (*itv).x - points[0].x);
points[2].y = float(2 * (*itv).y - points[0].y);
points[3].x = float(2 * (*itv).x - points[1].x);
points[3].y = float(2 * (*itv).y - points[1].y);
} }
//标记为已追踪过 //标记为已追踪过
...@@ -4229,10 +4237,8 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons ...@@ -4229,10 +4237,8 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons
double trackOffset = dOffset; double trackOffset = dOffset;
//元件间间距 //元件间间距
double partDist = (2 * asin(dChordL / (2 * trackRadius))) * 180 / PI; double partDist = (2 * asin(dChordL / (2 * trackRadius))) * 180 / PI;
//外矩形顶点 //外矩形顶点
cv::Point2f pts[4]; cv::Point2f pts[4];
//结束位置
Track trackEndPos;
//开始追踪 //开始追踪
bool trackEnd = true; bool trackEnd = true;
do do
...@@ -4245,16 +4251,7 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons ...@@ -4245,16 +4251,7 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons
trackCenter.x = reelCenter.x + (float)trackRadius*(float)cos(t*c); trackCenter.x = reelCenter.x + (float)trackRadius*(float)cos(t*c);
trackCenter.y = reelCenter.y + (float)trackRadius*(float)sin(t*c); trackCenter.y = reelCenter.y + (float)trackRadius*(float)sin(t*c);
float b = (float)cos(t*c)*0.5f; calcRotateRect(trackCenter, (float)t, (float)trackLength, (float)trackWidth, pts);
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::Point> vPoints;
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f)); std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
...@@ -4273,74 +4270,29 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons ...@@ -4273,74 +4270,29 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons
//仅扫描一个元件的角度 //仅扫描一个元件的角度
vParts.push_back(Track(0, 0, dMatch, cv::Point(cvRound(trackCenter.x), cvRound(trackCenter.y)), vRect)); vParts.push_back(Track(0, 0, dMatch, cv::Point(cvRound(trackCenter.x), cvRound(trackCenter.y)), vRect));
} }
if (vParts.size() == 0) continue; if (vParts.size() == 0) continue;
//
trackEndPos = vParts[vParts.size() / 2];
//灰度极值认为是元件 //灰度极值认为是元件
std::sort(vParts.begin(), vParts.end(), std::greater<Track>()); std::sort(vParts.begin(), vParts.end(), std::greater<Track>());
//更新位置 //更新位置
trackCenter = cv::Point(vParts[0].Pos.x, vParts[0].Pos.y); 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; trackAngle = atan2((double)trackCenter.y - reelCenter.y, (double)trackCenter.x - reelCenter.x) * 180 / PI;
//测试用
//cv::rectangle(cc, vParts[0].Rect, cv::Scalar(0, 0, 255, 255));
//纵向扫描
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(binary, 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(trackCenter, (float)trackAngle, (float)trackLength, (float)trackWidth, pts);
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 ((binary.data)[(vPoints[v].x) + (vPoints[v].y)*X] == 255)
iPartSize++;
}
}
vParts.push_back(Track(iLimit, iPartSize, dMatch, it.pos(), vRect));
}
//测试用
{
float b = (float)cos(trackAngle*PI / 180.)*0.5f;
float a = (float)sin(trackAngle*PI / 180.)*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);
//
cv::RotatedRect r(pts[0], pts[1], pts[2]); cv::RotatedRect r(pts[0], pts[1], pts[2]);
cv::rectangle(cc, r.boundingRect(), cv::Scalar(0, 255, 0, 255)); //待匹配图像
cv::Rect rr(cv::Point2i(cv::max(r.boundingRect().x - cvRound(trackWidth), 0), \
cv::max(r.boundingRect().y - cvRound(trackWidth), 0)), \
cv::Point2i(cv::min(r.boundingRect().x + r.boundingRect().width + cvRound(trackWidth), X), \
cv::min(r.boundingRect().y + r.boundingRect().height + cvRound(trackWidth), Y)));
// cv::Mat yyuc = srcPrev(rr);
cv::Mat yyuc = srcPrev(cv::Rect(r.boundingRect().x - 27, r.boundingRect().y - 27, r.boundingRect().width + 54, r.boundingRect().height + 54));
//不同方向模板图像 //不同方向模板图像
cv::Mat yyu = getTplMat(tplMat, 90 - (trackAngle + 180)); cv::Mat yyu = getTplMat(tplMat, 90 - (trackAngle + 180));
...@@ -4349,29 +4301,16 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons ...@@ -4349,29 +4301,16 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons
cv::Mat tplResult0; cv::Mat tplResult0;
cv::matchTemplate(yyuc, yyu, tplResult0, cv::TM_CCOEFF_NORMED); cv::matchTemplate(yyuc, yyu, tplResult0, cv::TM_CCOEFF_NORMED);
// //
double minyyu, maxyyu; cv::Point minyyuloc, maxyyuloc; double maxyyu; cv::Point maxyyuloc;
cv::minMaxLoc(tplResult0, &minyyu, &maxyyu, &minyyuloc, &maxyyuloc); cv::minMaxLoc(tplResult0, NULL, &maxyyu, NULL, &maxyyuloc);
cv::circle(cc, cv::Point(maxyyuloc.x + r.boundingRect().x + cvRound(yyu.cols / 2) - 27, maxyyuloc.y + r.boundingRect().y + cvRound(yyu.rows / 2) - 27), 1, cv::Scalar(0, 0, 255, 255), -1); //更新元件精确位置
} trackCenter = cv::Point2f(maxyyuloc.x + rr.x + cvRound((float)yyu.cols / 2.0f), \
maxyyuloc.y + rr.y + cvRound((float)yyu.rows / 2.0f));
//cv::drawMarker(cc, trackCenter, cv::Scalar(0, 0, 255, 255));
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); trackRadius = cv::norm(trackCenter - reelCenter);
//更新扫描角度 //更新扫描角度
...@@ -4380,30 +4319,31 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons ...@@ -4380,30 +4319,31 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons
trackOffset = (2 * asin(2 * trackLength / (2 * trackRadius))) * 180 / PI; trackOffset = (2 * asin(2 * trackLength / (2 * trackRadius))) * 180 / PI;
//更新元件间角度 //更新元件间角度
partDist = (2 * asin(dChordL / (2 * trackRadius))) * 180 / PI; partDist = (2 * asin(dChordL / (2 * trackRadius))) * 180 / PI;
//判断是否结束
if ((mac.iPartSize < sinPartSize / 4) || (trackMat.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] == 255) || \ //更新元件区域
(mac.iLimit / 255) > (sinPartSize / 4) /*|| (binary.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] == 0)*/) calcRotateRect(trackCenter, (float)trackAngle, (float)trackLength, (float)trackWidth, pts);
//判断是否结束(重新考虑终止条件)
if ((trackMat.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] == 255) || (maxyyu < dMinScore*0.7))
{ {
found = false; found = false;
} }
else else
{ {
//画出最终位置 //标记为已追踪过
std::vector<cv::Point> ptPoly; std::vector<cv::Point> ptPoly = { cv::Point(pts[0]),cv::Point(pts[1]) ,cv::Point(pts[2]) ,cv::Point(pts[3]) };
for (int j = 0; j < 4; j++) cv::fillConvexPoly(trackMat, ptPoly, cv::Scalar(255));
{
ptPoly.push_back(cv::Point(cvRound(mac.Rect[j].x), cvRound(mac.Rect[j].y)));
}
//标记当前位置
cv::drawMarker(cc, trackCenter, cv::Scalar(0, 255, 0, 255), cv::MARKER_DIAMOND, 5);
//画出元件区域
//for (int j = 0; j < 4; j++) //for (int j = 0; j < 4; j++)
//{ //{
// cv::line(cc, pts[j], pts[(j + 1) % 4], cv::Scalar(0, 165, 255, 255), 1); // cv::line(cc, pts[j], pts[(j + 1) % 4], cv::Scalar(0, 165, 255, 255), 1);
//} //}
//标记已追踪
cv::fillConvexPoly(trackMat, ptPoly, cv::Scalar(255)); //标记当前位置
cv::drawMarker(cc, trackCenter, cv::Scalar(0, 255, 0, 255), cv::MARKER_DIAMOND, 5);
} }
trackEnd = (!found); trackEnd = (!found);
} while (!trackEnd); } while (!trackEnd);
} }
...@@ -4419,10 +4359,8 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons ...@@ -4419,10 +4359,8 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons
double trackOffset = dOffset; double trackOffset = dOffset;
//元件间间距 //元件间间距
double partDist = (2 * asin(dChordL / (2 * trackRadius))) * 180 / PI; double partDist = (2 * asin(dChordL / (2 * trackRadius))) * 180 / PI;
//当扫描一圈后修正中心位置(待测试) //外接矩形
cv::Point2f pts[4]; cv::Point2f pts[4];
//结束位置
Track trackEndPos;
//开始追踪 //开始追踪
bool trackEnd = true; bool trackEnd = true;
// //
...@@ -4436,16 +4374,7 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons ...@@ -4436,16 +4374,7 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons
trackCenter.x = float(reelCenter.x + trackRadius*cos(t*c)); trackCenter.x = float(reelCenter.x + trackRadius*cos(t*c));
trackCenter.y = float(reelCenter.y + trackRadius*sin(t*c)); trackCenter.y = float(reelCenter.y + trackRadius*sin(t*c));
float b = (float)cos(t*c)*0.5f; calcRotateRect(trackCenter, (float)t, (float)trackLength, (float)trackWidth, pts);
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::Point> vPoints;
std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f)); std::vector<cv::Point2f> vRect(pts, pts + sizeof(pts) / sizeof(cv::Point2f));
...@@ -4465,72 +4394,27 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons ...@@ -4465,72 +4394,27 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons
vParts.push_back(Track(0, 0, dMatch, cv::Point(cvRound(trackCenter.x), cvRound(trackCenter.y)), vRect)); vParts.push_back(Track(0, 0, dMatch, cv::Point(cvRound(trackCenter.x), cvRound(trackCenter.y)), vRect));
} }
if (vParts.size() == 0) continue; if (vParts.size() == 0) continue;
//
trackEndPos = vParts[vParts.size() / 2];
//灰度极值认为是元件 //灰度极值认为是元件
std::sort(vParts.begin(), vParts.end(), std::greater<Track>()); std::sort(vParts.begin(), vParts.end(), std::greater<Track>());
//更新位置 //更新位置
trackCenter = cv::Point(vParts[0].Pos.x, vParts[0].Pos.y); 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; 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(binary, 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(trackCenter, (float)trackAngle, (float)trackLength, (float)trackWidth, pts);
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 ((binary.data)[(vPoints[v].x) + (vPoints[v].y)*X] == 255)
iPartSize++;
}
}
vParts.push_back(Track(iLimit, iPartSize, dMatch, it.pos(), vRect));
}
//测试用
{
float b = (float)cos(trackAngle*PI / 180.)*0.5f;
float a = (float)sin(trackAngle*PI / 180.)*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);
//
cv::RotatedRect r(pts[0], pts[1], pts[2]); cv::RotatedRect r(pts[0], pts[1], pts[2]);
cv::rectangle(cc, r.boundingRect(), cv::Scalar(0, 255, 0, 255)); //待匹配图像
cv::Rect rr(cv::Point2i(cv::max(r.boundingRect().x - cvRound(trackWidth), 0), \
cv::max(r.boundingRect().y - cvRound(trackWidth), 0)), \
cv::Point2i(cv::min(r.boundingRect().x + r.boundingRect().width + cvRound(trackWidth), X), \
cv::min(r.boundingRect().y + r.boundingRect().height + cvRound(trackWidth), Y)));
// cv::Mat yyuc = srcPrev(rr);
cv::Mat yyuc = srcPrev(cv::Rect(r.boundingRect().x - 27, r.boundingRect().y - 27, r.boundingRect().width + 54, r.boundingRect().height + 54));
//不同方向模板图像 //不同方向模板图像
cv::Mat yyu = getTplMat(tplMat, 90 - (trackAngle + 180)); cv::Mat yyu = getTplMat(tplMat, 90 - (trackAngle + 180));
...@@ -4539,66 +4423,54 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons ...@@ -4539,66 +4423,54 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons
cv::Mat tplResult0; cv::Mat tplResult0;
cv::matchTemplate(yyuc, yyu, tplResult0, cv::TM_CCOEFF_NORMED); cv::matchTemplate(yyuc, yyu, tplResult0, cv::TM_CCOEFF_NORMED);
// //
double minyyu, maxyyu; cv::Point minyyuloc, maxyyuloc; double maxyyu; cv::Point maxyyuloc;
cv::minMaxLoc(tplResult0, &minyyu, &maxyyu, &minyyuloc, &maxyyuloc); cv::minMaxLoc(tplResult0, NULL, &maxyyu, NULL, &maxyyuloc);
cv::circle(cc, cv::Point(maxyyuloc.x + r.boundingRect().x + cvRound(yyu.cols / 2) - 27, maxyyuloc.y + r.boundingRect().y + cvRound(yyu.rows / 2) - 27), 1, cv::Scalar(0, 0, 255, 255), -1); //更新元件精确位置
} trackCenter = cv::Point2f(maxyyuloc.x + rr.x + cvRound((float)yyu.cols / 2.0f), \
maxyyuloc.y + rr.y + cvRound((float)yyu.rows / 2.0f));
//cv::drawMarker(cc, trackCenter, cv::Scalar(0, 0, 255, 255));
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); trackRadius = cv::norm(trackCenter - reelCenter);
//更新扫描角度 //更新扫描角度
trackAngle = atan2((double)trackCenter.y - reelCenter.y, (double)trackCenter.x - reelCenter.x) * 180 / PI; trackAngle = atan2((double)trackCenter.y - reelCenter.y, (double)trackCenter.x - reelCenter.x) * 180 / PI;
//更新偏移量 //更新偏移量
trackOffset = (2 * asin(2 * trackLength / (2 * trackRadius))) * 180 / PI; trackOffset = (2 * asin(2 * trackLength / (2 * trackRadius))) * 180 / PI;
//更新追踪角度 //更新元件间角度
partDist = (2 * asin(dChordL / (2 * trackRadius))) * 180 / PI; partDist = (2 * asin(dChordL / (2 * trackRadius))) * 180 / PI;
//绕完一周后更新料盘中心试试?
//更新元件区域
calcRotateRect(trackCenter, (float)trackAngle, (float)trackLength, (float)trackWidth, pts);
//判断是否结束 //判断是否结束
if (mac.iPartSize < sinPartSize / 4 || (trackMat.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] == 255) || \ if ((trackMat.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] == 255) || (maxyyu < dMinScore*0.7))
(mac.iLimit / 255) >(sinPartSize / 4) /*|| (binary.ptr<uint8_t>(cvRound(trackCenter.y))[cvRound(trackCenter.x)] == 0)*/)
{ {
found = false; found = false;
} }
else else
{ {
//画出最终位置 //标记为已追踪过
std::vector<cv::Point> ptPoly; std::vector<cv::Point> ptPoly = { cv::Point(pts[0]),cv::Point(pts[1]) ,cv::Point(pts[2]) ,cv::Point(pts[3]) };
for (int j = 0; j < 4; j++)
{
ptPoly.push_back(cv::Point(cvRound(mac.Rect[j].x), cvRound(mac.Rect[j].y)));
}
//画图显示
cv::circle(cc, trackCenter, 2, cv::Scalar(0, 255, 0, 255), 1);
//标记Label
cv::fillConvexPoly(trackMat, ptPoly, cv::Scalar(255)); cv::fillConvexPoly(trackMat, ptPoly, cv::Scalar(255));
//画出元件区域
//for (int j = 0; j < 4; j++)
//{
// cv::line(cc, pts[j], pts[(j + 1) % 4], cv::Scalar(0, 165, 255, 255), 1);
//}
//标记当前位置
cv::drawMarker(cc, trackCenter, cv::Scalar(0, 255, 0, 255), cv::MARKER_DIAMOND, 5);
} }
trackEnd = (!found); trackEnd = (!found);
} while (!trackEnd); } while (!trackEnd);
} }
} }
} }
//释放资源
delete[] ucpTrackLabel;
ucpTrackLabel = NULL;
} }
//对单个器件间存在断裂使用,及料盘内圈颜色过深 //对单个器件间存在断裂使用,及料盘内圈颜色过深
else if (strcmp(ccSubType, "IP_LONG_PARTS") == 0) else if (strcmp(ccSubType, "IP_LONG_PARTS") == 0)
...@@ -5291,43 +5163,72 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons ...@@ -5291,43 +5163,72 @@ int eyemCountObjectIrregularPartsE(EyemImage tpImage, const char *fileName, cons
} }
} }
//输出图像
//计数 //计数
std::vector<cv::Point> vLocations; int numObj = cv::countNonZero(binary);
cv::findNonZero(binary, vLocations); std::string text = "Reel Number = :" + std::to_string(numObj);
for (int c = 0; c < vLocations.size(); c++) cv::putText(cc, text, cv::Point(35, 35), 0, 1.0, cv::Scalar(0, 140, 255, 255), 2);
{
//cv::circle(cc, vLocations[c], 1, cv::Scalar(0, 255, 0, 255), 1); std::string trayNum = std::to_string(numObj);
}
std::string trayNum = std::to_string(vLocations.size());
//输出结果 //输出结果
*lpszNumObj = (char *)CoTaskMemAlloc(trayNum.size()); *lpszNumObj = (char *)CoTaskMemAlloc(trayNum.size());
if (NULL != lpszNumObj) if (NULL != lpszNumObj)
{ {
strcpy(*lpszNumObj, trayNum.c_str()); strcpy(*lpszNumObj, trayNum.c_str());
} }
//获取当前运行目录
char buf[128]; ///<输出计数结果标记图像
_getcwd(buf, sizeof(buf)); {
//创建路径 tpDstImg->iWidth = cc.cols; tpDstImg->iHeight = cc.rows; tpDstImg->iDepth = cc.depth(); tpDstImg->iChannels = cc.channels();
std::string filePath(buf);
filePath += "\\ResOut"; //内存尺寸
if (_access(filePath.c_str(), 0) == -1) int _Size = tpDstImg->iWidth*tpDstImg->iHeight*tpDstImg->iChannels * sizeof(uint8_t);
_mkdir(filePath.c_str());//不存在则创建
//格式化文件名 //分配内存
char file[256]; tpDstImg->vpImage = (uint8_t *)malloc(_Size);
sprintf_s(file, "%s\\%s-Mark.png", filePath.c_str(), fileName); if (NULL == tpDstImg->vpImage)
cv::imwrite(file, cc); return FUNC_NOT_ENOUGH_MEM;
memset(tpDstImg->vpImage, 0, _Size);
//拷贝数据
memcpy(tpDstImg->vpImage, cc.data, _Size);
}
return FUNC_OK; return FUNC_OK;
} }
int eyemCreateTemplateImage(EyemImage tpImage, EyemRect tpRoi, const char *ccTplName) int eyemCreateTemplateModel(EyemImage tpImage, EyemRect tpRoi, const char *ccTplName)
{ {
cv::Mat src = cv::Mat(tpImage.iHeight, tpImage.iWidth, MAKETYPE(tpImage.iDepth, tpImage.iChannels), tpImage.vpImage)\ cv::Mat tplMat = cv::Mat(tpImage.iHeight, tpImage.iWidth, MAKETYPE(tpImage.iDepth, tpImage.iChannels), tpImage.vpImage)\
(cv::Rect(tpRoi.iXs, tpRoi.iYs, tpRoi.iWidth, tpRoi.iHeight)); (cv::Rect(tpRoi.iXs, tpRoi.iYs, tpRoi.iWidth, tpRoi.iHeight)).clone();
//模板信息
std::string hint = " " + std::to_string(tpRoi.iXs) + "," + std::to_string(tpRoi.iYs) + "," \
+ std::to_string(tpRoi.iWidth) + "," + std::to_string(tpRoi.iHeight);
//内存尺寸(将信息添加到图像后面)
int _Size = tplMat.cols*tplMat.rows*tplMat.channels() * sizeof(uint8_t);
unsigned char *_Dst = new unsigned char[_Size + (int)hint.size()];
//拷贝图像
memcpy(_Dst, tplMat.data, _Size);
//拷贝信息
memcpy(_Dst + _Size, hint.c_str(), (int)hint.size());
//写入本地
std::ofstream fileStream(ccTplName, std::ios::binary);
fileStream.write(reinterpret_cast<const char *>(_Dst), _Size + (int)hint.size());
fileStream.close();
//测试用
//释放资源
delete _Dst;
_Dst = NULL;
return FUNC_OK; return FUNC_OK;
} }
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define __EYEM_MISC_H #define __EYEM_MISC_H
#include <io.h> #include <io.h>
#include <fstream>
#include <direct.h> #include <direct.h>
#include "eyemLib.h" #include "eyemLib.h"
......
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!