895 lines
29 KiB
C++
895 lines
29 KiB
C++
#include <algorithmThread.h>
|
||
#include <ReadBarcode.h>
|
||
#include "camera_thread.h"
|
||
#include "myiothread.h"
|
||
#include "FrontendBackendBridge.h"
|
||
#include <myTools.h>
|
||
|
||
#include <QtConcurrent/QtConcurrent>
|
||
#include <future>
|
||
#include <iostream>
|
||
#include <halconAlgo/Correction.h>
|
||
#include <halconAlgo/Inspection.h>
|
||
bool showOk = true;//显示ok缺陷的框
|
||
std::string fileSavePath("D://CCD//");
|
||
//////////////////////
|
||
std::vector<cv::Point2f> rotateRect(const cv::Rect& rect, const cv::Point2f& center, double angle) {
|
||
// 构建矩形的四个角点
|
||
std::vector<cv::Point2f> corners(4);
|
||
corners[0] = cv::Point2f(rect.x, rect.y);
|
||
corners[1] = cv::Point2f(rect.x + rect.width, rect.y);
|
||
corners[2] = cv::Point2f(rect.x + rect.width, rect.y + rect.height);
|
||
corners[3] = cv::Point2f(rect.x, rect.y + rect.height);
|
||
|
||
// 创建旋转矩阵
|
||
cv::Mat rotationMatrix = cv::getRotationMatrix2D(center, angle, 1.0);
|
||
|
||
// 对每个角点应用旋转变换
|
||
std::vector<cv::Point2f> rotatedCorners(4);
|
||
for (int i = 0; i < 4; ++i) {
|
||
cv::Mat pointMat = (cv::Mat_<double>(3, 1) << corners[i].x, corners[i].y, 1);
|
||
cv::Mat rotatedPoint = rotationMatrix * pointMat;
|
||
rotatedCorners[i] = cv::Point2f(rotatedPoint.at<double>(0, 0), rotatedPoint.at<double>(1, 0));
|
||
}
|
||
|
||
return rotatedCorners;
|
||
}
|
||
double calculateAngleWithXAxis(const cv::Point& p1, const cv::Point& p2) {
|
||
// 计算两点的坐标差异
|
||
double dx = p2.x - p1.x;
|
||
double dy = p2.y - p1.y;
|
||
|
||
// 使用反正切函数计算角度
|
||
double angle = std::atan2(dy, dx) * 180 / CV_PI;
|
||
|
||
// 确保角度在 0 到 360 度之间
|
||
if (angle < 0) {
|
||
angle += 360;
|
||
}
|
||
|
||
return angle;
|
||
}
|
||
void rotateImage(const cv::Mat& src, double angle, cv::Mat& dst) {
|
||
// 图像中心作为旋转中心
|
||
cv::Point2f center(static_cast<float>(src.cols / 2), static_cast<float>(src.rows / 2));
|
||
|
||
// 计算旋转矩阵
|
||
cv::Mat rot = cv::getRotationMatrix2D(center, angle, 1.0);
|
||
|
||
// 应用旋转
|
||
cv::warpAffine(src, dst, rot, src.size());
|
||
}
|
||
double calculateDistance(const cv::Point& p1, const cv::Point& p2) {
|
||
// 计算距离
|
||
double distance = std::sqrt(std::pow(p2.x - p1.x, 2) + std::pow(p2.y - p1.y, 2));
|
||
return distance;
|
||
}
|
||
//std::vector<std::pair<cv::Point, cv::Point>> fitLines(const std::vector<cv::Point>& points, double length) {
|
||
// // 进行多边形拟合
|
||
// std::vector<cv::Point> approxCurve;
|
||
// cv::approxPolyDP(points, approxCurve, length, true);
|
||
//
|
||
// std::vector<std::pair<cv::Point, cv::Point>> lines;
|
||
//
|
||
// // 从拟合后的多边形中提取直线段
|
||
// for (size_t i = 0; i < approxCurve.size(); ++i) {
|
||
// cv::Point p1 = approxCurve[i];
|
||
// cv::Point p2 = approxCurve[(i + 1) % approxCurve.size()];
|
||
//
|
||
// lines.push_back(std::make_pair(p1, p2));
|
||
// }
|
||
//
|
||
// return lines;
|
||
//}
|
||
|
||
std::vector<std::pair<cv::Point, cv::Point>> fitLines(const std::vector<cv::Point>& points, double length) {
|
||
// 进行多边形拟合
|
||
std::vector<cv::Point> approxCurve;
|
||
cv::approxPolyDP(points, approxCurve, length, true);
|
||
|
||
std::vector<std::pair<cv::Point, cv::Point>> lines;
|
||
|
||
// 构建凸包
|
||
std::vector<cv::Point> convexHull;
|
||
cv::convexHull(approxCurve, convexHull);
|
||
|
||
// 计算凸包的几何中心
|
||
cv::Point2f center(0, 0);
|
||
for (const auto& point : convexHull) {
|
||
center.x += point.x;
|
||
center.y += point.y;
|
||
}
|
||
center *= (1.0 / convexHull.size());
|
||
|
||
// 从拟合后的多边形中提取直线段,并排除方向向内的线段
|
||
for (size_t i = 0; i < approxCurve.size(); ++i) {
|
||
cv::Point p1 = approxCurve[i];
|
||
cv::Point p2 = approxCurve[(i + 1) % approxCurve.size()];
|
||
|
||
// 计算线段的中点
|
||
cv::Point midPoint = (p1 + p2) * 0.5;
|
||
|
||
// 计算线段中点到多边形几何中心的向量
|
||
cv::Point2f centerToMid = cv::Point2f(midPoint) - center;
|
||
|
||
// 计算线段方向向量
|
||
cv::Point2f lineDirection = cv::Point2f(p2) - cv::Point2f(p1);
|
||
|
||
// 计算凸包法线
|
||
cv::Point2f normal = cv::Point2f(-centerToMid.y, centerToMid.x);
|
||
|
||
// 检查线段方向是否朝向凸包内部(与凸包法线方向相反)
|
||
if (lineDirection.dot(normal) < 0) {
|
||
lines.push_back(std::make_pair(p1, p2));
|
||
}
|
||
}
|
||
|
||
return lines;
|
||
}
|
||
void writeToData_xxxCsvOkNgNew(detData* rdata, QString OKNG, ngNoteCls* note)
|
||
{
|
||
QDateTime currentDateTime = QDateTime::currentDateTime();
|
||
std::string ymd = currentDateTime.toString("yyyy-MM-dd").toStdString();
|
||
QString filePath = QString::fromStdString(fileSavePath + "//result//" + ymd + "//Data_" + ymd + ".csv");
|
||
/* QString searchString = QString::fromStdString(rdata->getSN() + "_" + to_string(rdata->snCountIndex));*/
|
||
QString searchString = QString::fromStdString(rdata->SNcode);
|
||
QFile file(filePath);
|
||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||
qDebug() << "Error opening file.";
|
||
}
|
||
|
||
QStringList headers;
|
||
QList<QStringList> data;
|
||
|
||
QTextStream in(&file);
|
||
while (!in.atEnd()) {
|
||
QString line = in.readLine();
|
||
QStringList fields = line.split(',');
|
||
|
||
if (headers.isEmpty()) {
|
||
// 如果headers为空,则当前行为标题行
|
||
headers = fields;
|
||
}
|
||
else {
|
||
data.append(fields);
|
||
}
|
||
}
|
||
|
||
file.close();
|
||
|
||
// 在data中进行字符串检索并修改匹配的行
|
||
int modifiedRowCount = 0;
|
||
for (int i = data.size() - 1; i > 0; --i) {
|
||
QStringList& row = data[i];
|
||
//if (row.size()<3||row.isEmpty())
|
||
//{
|
||
// break;
|
||
//}
|
||
// 在当前行中检索字符串
|
||
try
|
||
{
|
||
if (row.size() >= 6)
|
||
if (row[1].contains(searchString, Qt::CaseInsensitive)) {
|
||
// 匹配到字符串,进行修改
|
||
row[3] = OKNG;
|
||
row[4] += note->getNgSummaryStr();
|
||
row[5] += note->getOkSummaryStr();
|
||
modifiedRowCount++;
|
||
}
|
||
}
|
||
catch (...)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 将修改后的数据写回文件
|
||
QFile writeFile(filePath);
|
||
if (!writeFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||
qDebug() << "Error opening file for writing.";
|
||
}
|
||
|
||
QTextStream out(&writeFile);
|
||
// 写入标题行
|
||
out << headers.join(",") << "\n";
|
||
|
||
// 写入修改后的数据行
|
||
for (const auto& row : data) {
|
||
out << row.join(",") << "\n";
|
||
}
|
||
|
||
writeFile.close();
|
||
|
||
qDebug() << "Modified rows:" << modifiedRowCount;
|
||
qDebug() << "Data modified and saved to data_modified.csv";
|
||
|
||
//return 0;
|
||
}
|
||
void writeToData_xxxCSVNew(detData* resData, string OKNG, ngNoteCls* note)
|
||
{
|
||
QDateTime currentDateTime = QDateTime::currentDateTime();
|
||
std::string ymd = currentDateTime.toString("yyyy-MM-dd").toStdString();
|
||
int hour = currentDateTime.time().hour();
|
||
|
||
QString filePath = QString::fromStdString(fileSavePath + "//result//" + ymd + "//Data_" + ymd + ".csv");
|
||
//string sn(resData->SNcode + "-" + to_string(resData->snCountIndex));
|
||
string sn(resData->SNcode);
|
||
/*std::string str(to_string(hour) + "H//" + sn + "-" + to_string(resData->snCountIndex) + "//" + ymd
|
||
+ "-" + to_string(hour) + "_" + resData->getSN() + "-" + to_string(resData->snCountIndex));*/
|
||
std::string str(to_string(hour) + "H//" + sn + "//" + ymd
|
||
+ "-" + to_string(hour) + "_" + sn);
|
||
bool fileExist = false;
|
||
QStringList dataList;
|
||
if (hour < 10)
|
||
dataList.append("0" + QString::number(hour) + "H");
|
||
else
|
||
dataList.append(QString::number(hour) + "H");
|
||
dataList.append(QString::fromStdString(sn));
|
||
dataList.append(QString::fromStdString(str));
|
||
dataList.append(QString::fromStdString(OKNG));
|
||
dataList.append(note->getNgSummaryStr());
|
||
dataList.append(note->getOkSummaryStr());
|
||
// 创建CSV文件
|
||
QFile file(filePath);
|
||
if (!file.exists())
|
||
{
|
||
// 创建目录(如果不存在)
|
||
QDir dir;
|
||
if (!dir.mkpath(QFileInfo(filePath).absolutePath()))
|
||
{
|
||
//qWarning() << "无法创建目录:" << QFileInfo(filePath).absolutePath();
|
||
return;
|
||
}
|
||
fileExist = true;
|
||
}
|
||
// 打开CSV文件并写入数据
|
||
if (file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) {
|
||
QTextStream stream(&file);
|
||
if (fileExist == true)
|
||
{
|
||
stream << "Time,";
|
||
stream << "SN,";
|
||
stream << "Path,";
|
||
stream << "Result,";
|
||
stream << "summuryResult,";
|
||
stream << "\n";
|
||
}
|
||
// 将数据写入CSV文件
|
||
for (const QString& data : dataList) {
|
||
stream << data << ",";
|
||
}
|
||
stream << "\n";
|
||
|
||
file.close();
|
||
qDebug() << "CSV文件写入成功";
|
||
}
|
||
//else
|
||
// qWarning() << "无法打开CSV文件:" << filePath;
|
||
|
||
}
|
||
void algoThread::getAllFiles(string path, vector<string>& files, string format)
|
||
{
|
||
intptr_t hFile = 0;//恅璃曆梟
|
||
struct _finddata_t fileinfo;//恅璃陓洘
|
||
string p;
|
||
if ((hFile = _findfirst(p.assign(path).append("\\*" + format).c_str(), &fileinfo)) != -1) //恅璃湔婓
|
||
{
|
||
do
|
||
{
|
||
if ((fileinfo.attrib & _A_SUBDIR))//瓚剿岆瘁峈恅璃標
|
||
{
|
||
if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)//恅璃標靡笢祥漪"."睿".."
|
||
{
|
||
files.push_back(p.assign(path).append("\\").append(fileinfo.name)); //悵湔恅璃標靡
|
||
getAllFiles(p.assign(path).append("\\").append(fileinfo.name), files, format); //菰寥梢盪恅璃標
|
||
}
|
||
}
|
||
else
|
||
{
|
||
files.push_back(p.assign(path).append("\\").append(fileinfo.name));//彆祥岆恅璃標ㄛ揣湔恅璃靡
|
||
}
|
||
} while (_findnext(hFile, &fileinfo) == 0);
|
||
_findclose(hFile);
|
||
}
|
||
}
|
||
|
||
inline string getFileName(string path)
|
||
{
|
||
return path.substr(path.find_last_of("\\") + 1, path.find_last_of(".") - path.find_last_of("\\") - 1);
|
||
}
|
||
void drawContoursOverlap(cv::Mat& image, const std::vector<std::vector<cv::Point>>& contours) {
|
||
cv::Mat mask = cv::Mat::zeros(image.size(), CV_8U);
|
||
|
||
// 绘制轮廓在掩码上
|
||
cv::drawContours(mask, contours, -1, cv::Scalar(255), cv::FILLED);
|
||
|
||
// 将图像中与掩码不重叠的区域涂黑
|
||
cv::Mat result;
|
||
image.copyTo(result, mask);
|
||
image.setTo(cv::Scalar(0, 0, 0), ~mask);
|
||
}
|
||
void drawContourOnImage(Mat seg, cv::Mat& imgInput, Size offset = Size(0, 0)) {
|
||
if (seg.empty() || imgInput.empty()) {
|
||
std::cerr << "Empty contour or input image." << std::endl;
|
||
return;
|
||
}
|
||
cv::Mat imgWithAlpha;
|
||
cv::cvtColor(imgInput, imgWithAlpha, cv::COLOR_BGR2BGRA);
|
||
std::vector<std::vector<cv::Point>>contours;
|
||
if (offset.width != 0 && offset.height != 0)
|
||
{
|
||
Mat offsetImg(offset.width + seg.rows, offset.height + seg.cols, CV_8UC1, Scalar(0));
|
||
seg.copyTo(offsetImg(Rect(offset.width, offset.height, seg.rows, seg.cols)));
|
||
offsetImg.copyTo(seg);
|
||
}
|
||
cv::findContours(seg, contours, cv::noArray(), cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
|
||
for (auto& contour : contours)
|
||
{
|
||
cv::Scalar color(0, 255, 0, 128);
|
||
cv::polylines(imgWithAlpha, contour, true, color);
|
||
cv::cvtColor(imgWithAlpha, imgInput, cv::COLOR_BGRA2BGR);
|
||
}
|
||
}
|
||
/////Specified function////////////////
|
||
void writeSpecificStatement(Mat& Paint, const wchar_t* Text, rectAndData& data, int amount, int limit, Scalar& color)
|
||
{
|
||
wstring MM(to_wstring(max(data.defectHeight, data.defectWidth)));
|
||
MM = MM.substr(0, MM.find_first_of(L".") + 2);
|
||
putTextHusky(Paint, (WString2String(Text + to_wstring(amount)
|
||
+ L"/" + to_wstring(limit) + L"|" +
|
||
MM + L"mm")).c_str(),
|
||
cv::Point(data.rect.x, data.rect.y - 20), color, 20);
|
||
}
|
||
int getMaxAreaIndex(std::vector<std::vector<cv::Point>>& pts)
|
||
{
|
||
int maxVal = 0, maxI = -1;
|
||
for (int i =0;i<pts.size();i++)
|
||
{
|
||
int areaSize = cv::contourArea(pts[i]);
|
||
if (areaSize > maxVal)
|
||
{
|
||
maxI = i;
|
||
maxVal = areaSize;
|
||
}
|
||
}
|
||
return maxI;
|
||
}
|
||
std::vector < std::vector<std::pair<cv::Point, cv::Point>>> splitLinesByCenterAndAngle(const std::vector<std::pair<cv::Point, cv::Point>>& lines, const cv::Point& center) {
|
||
std::vector<std::pair<cv::Point, cv::Point>> topLines, bottomLines, leftLines, rightLines;
|
||
|
||
for (const auto& line : lines) {
|
||
const cv::Point& p1 = line.first;
|
||
const cv::Point& p2 = line.second;
|
||
|
||
// 计算线段的方向向量
|
||
cv::Point2f lineDirection = cv::Point2f(p2) - cv::Point2f(p1);
|
||
|
||
// 计算线段与 x 轴和 y 轴的夹角
|
||
double angleWithX = std::atan2(lineDirection.y, lineDirection.x) * 180 / CV_PI;
|
||
double angleWithY = std::atan2(lineDirection.x, lineDirection.y) * 180 / CV_PI;
|
||
angleWithX = (angleWithX < 0) ? 180 + angleWithX : angleWithX;
|
||
angleWithY = (angleWithY < 0) ? 180 + angleWithY : angleWithY;
|
||
// 根据线段方向和中心点位置将线段分组
|
||
if (p1.y <= center.y && p2.y <= center.y && (angleWithX < 10 || angleWithX > 170)) {
|
||
std::cout << "A" << to_string(angleWithX) << "A" << to_string(angleWithY) << std::endl;
|
||
topLines.push_back(line);
|
||
}
|
||
else if (p1.y >= center.y && p2.y >= center.y && (angleWithX < 10 || angleWithX > 170)) {
|
||
bottomLines.push_back(line);
|
||
}
|
||
|
||
else if (p1.x <= center.x && p2.x <= center.x && (angleWithY < 10 || angleWithY > 170)) {
|
||
leftLines.push_back(line);
|
||
}
|
||
else if (p1.x >= center.x && p2.x >= center.x && (angleWithY < 10 || angleWithY > 170)) {
|
||
rightLines.push_back(line);
|
||
}
|
||
}
|
||
|
||
// 返回四个方向的线段结果
|
||
return { topLines, bottomLines, leftLines, rightLines };
|
||
}
|
||
|
||
std::vector<std::pair<cv::Point, cv::Point>> filterLinesByAngle(const std::vector<std::pair<cv::Point, cv::Point>>& lines) {
|
||
std::vector<std::pair<cv::Point, cv::Point>> filteredLines;
|
||
|
||
for (const auto& line : lines) {
|
||
const cv::Point& p1 = line.first;
|
||
const cv::Point& p2 = line.second;
|
||
|
||
// 计算线段的方向向量
|
||
cv::Point2f lineDirection = cv::Point2f(p2) - cv::Point2f(p1);
|
||
|
||
// 计算线段与 x 轴和 y 轴的夹角
|
||
double angleWithX = std::abs(std::atan2(lineDirection.y, lineDirection.x) * 180 / CV_PI);
|
||
double angleWithY = std::abs(std::atan2(lineDirection.x, lineDirection.y) * 180 / CV_PI);
|
||
|
||
// 如果与 x 轴或 y 轴的夹角在正负30度内,则保留该线段
|
||
if ((angleWithX < 10 || angleWithX > 170) || (angleWithY < 10 || angleWithY > 170)) {
|
||
filteredLines.push_back(line);
|
||
}
|
||
}
|
||
|
||
return filteredLines;
|
||
}
|
||
|
||
double pointLineSegmentDistance(const cv::Point& p, const cv::Point& q, const cv::Point& a, const cv::Point& b) {
|
||
cv::Point pq = q - p;
|
||
cv::Point ab = b - a;
|
||
cv::Point pa = a - p;
|
||
|
||
double t = static_cast<double>(pq.dot(ab)) / pq.dot(pq);
|
||
|
||
if (t >= 0 && t <= 1) {
|
||
cv::Point pt = p + pq * t;
|
||
return cv::norm(pt - a);
|
||
}
|
||
else {
|
||
double dist1 = cv::norm(p - a);
|
||
double dist2 = cv::norm(q - b);
|
||
return std::min(dist1, dist2);
|
||
}
|
||
}
|
||
|
||
double calculateLineSegmentDistance(const std::pair<cv::Point, cv::Point>& line1, const std::pair<cv::Point, cv::Point>& line2) {
|
||
cv::Point p1 = line1.first;
|
||
cv::Point p2 = line1.second;
|
||
cv::Point p3 = line2.first;
|
||
cv::Point p4 = line2.second;
|
||
|
||
double distance1 = pointLineSegmentDistance(p1, p2, p3, p4);
|
||
double distance2 = pointLineSegmentDistance(p2, p1, p3, p4);
|
||
double distance3 = pointLineSegmentDistance(p3, p4, p1, p2);
|
||
double distance4 = pointLineSegmentDistance(p4, p3, p1, p2);
|
||
|
||
//return std::min({distance1, distance2, distance3, distance4 });
|
||
return (distance1 + distance2 + distance3 + distance4) / 4;
|
||
}
|
||
|
||
void calculateLineSegmentDistances(const std::vector<std::pair<cv::Point, cv::Point>>& lines1, const std::vector<std::pair<cv::Point, cv::Point>>& lines2) {
|
||
double minDistance = std::numeric_limits<double>::max();
|
||
double maxDistance = std::numeric_limits<double>::min();
|
||
double sumDistance = 0.0;
|
||
|
||
size_t count = 0;
|
||
for (const auto& line1 : lines1) {
|
||
for (const auto& line2 : lines2) {
|
||
double distance = calculateLineSegmentDistance(line1, line2);
|
||
if (distance >= 0) {
|
||
sumDistance += distance;
|
||
std::cout << "Minimum distansssdce: " << distance * 0.014744 << std::endl;
|
||
if (distance < minDistance) {
|
||
minDistance = distance;
|
||
}
|
||
|
||
if (distance > maxDistance) {
|
||
maxDistance = distance;
|
||
}
|
||
|
||
++count;
|
||
}
|
||
}
|
||
}
|
||
|
||
std::cout << "Minimum distance: " << minDistance* 0.014744 << std::endl;
|
||
std::cout << "Maximum distance: " << maxDistance* 0.014744 << std::endl;
|
||
std::cout << "Average distance: " << (sumDistance / count)* 0.014744 << std::endl;
|
||
}
|
||
|
||
|
||
/////////////////////ALGOTHREAD/////////////////////////
|
||
bool algoThread::addDetTask(detData* data)
|
||
{
|
||
detQueueMutex.lock();
|
||
detQueue.append(data);
|
||
detQueueMutex.unlock();
|
||
this->start();
|
||
return false;
|
||
}
|
||
bool algoThread::waitForImg(detData* data,int timeOutSet=10000)
|
||
{
|
||
int timeOut = 0;
|
||
int sleepMs = 100;
|
||
while (1)
|
||
{
|
||
int imgSize = data->imgs.size();
|
||
int imgAmountMin = data->imgAmountMin;
|
||
if (imgSize >= imgAmountMin)
|
||
return true;
|
||
timeOut+= sleepMs;
|
||
if (timeOut > timeOutSet)
|
||
return false;
|
||
QThread::msleep(sleepMs);
|
||
}
|
||
}
|
||
void algoThread::run()
|
||
{
|
||
while (m_runFlag == true)
|
||
{
|
||
while (detQueue.size() > 0)
|
||
{
|
||
|
||
detQueueMutex.lock();
|
||
detData* data = detQueue.dequeue();//取出数据
|
||
detQueueMutex.unlock();
|
||
int threadId = data->algoThreadIndex;//获取线程id
|
||
|
||
if (threadId == 0)
|
||
{
|
||
int timeOut = 0;
|
||
int sleepMs = 100;
|
||
while (data->correctionData==nullptr)
|
||
{
|
||
if (timeOut > 10000)break;
|
||
timeOut += sleepMs;
|
||
QThread::msleep(sleepMs);
|
||
}
|
||
ALGO_Correction(data);
|
||
}
|
||
else
|
||
{
|
||
|
||
if (waitForImg(data) == false)
|
||
{
|
||
qDebug() << "取图失败";
|
||
cout << "get img err" << endl;
|
||
break;
|
||
}
|
||
bridge.front.showImg("Camera", data->imgs[0], threadId);//显示原图
|
||
|
||
auto start = std::chrono::high_resolution_clock::now();
|
||
switch (threadId)
|
||
{
|
||
case 0:
|
||
Camera1_Algo(data);
|
||
break;
|
||
case 1:
|
||
Camera1_Algo(data);
|
||
break;
|
||
}
|
||
oriSaveThread->saveOriImg(data);//保存原图
|
||
|
||
auto end = std::chrono::high_resolution_clock::now();
|
||
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
|
||
std::cout << "Time taken by function: " << duration.count() << " milliseconds" << std::endl;
|
||
|
||
//if (!data->SNcode.compare(snDatas->snErrorsnError))//无sn阻塞
|
||
// data->SNcode = snDatas->waitForSn(data->timeCode);
|
||
if (data->resultImgs.size() > 0)
|
||
{
|
||
resSaveThread->saveResImg(data);//保存结果图
|
||
bridge.front.showImg("Algorithm", data->resultImgs[0], threadId);//显示原图
|
||
//cout << "algoEnd" << data->algoThreadIndex;
|
||
}
|
||
|
||
std::vector<sqlData> sqlDatas;//定义sql数据
|
||
for (auto sqlData : data->sqlVec)//将算法中的数据导入到数据结构中
|
||
sqlDatas.push_back({ sqlData.first, std::to_string(sqlData.second) });
|
||
sql->addData(data->SNcode, sqlDatas);//将数据插入数据库
|
||
|
||
std::vector<QString>strVec({ QString::fromStdString(data->SNcode),QString::number(data->camera1Width) + "x" + QString::number(data->camera1Height) });
|
||
bridge.front.tableViewPtr->addRowDataValue(strVec);//将数据插入界面表格
|
||
|
||
detDataController* dController = data->dController;
|
||
data->dController->deleteDetData(data->timeCode);
|
||
}
|
||
}
|
||
QThread::msleep(10);
|
||
}
|
||
}
|
||
void matsToMat(cv::Mat& mat1, cv::Mat& mat2, cv::Mat* Paint)
|
||
{
|
||
auto start_time = std::chrono::high_resolution_clock::now();
|
||
*Paint = cv::Mat(mat1.rows + mat2.rows, mat1.cols, CV_8UC1);
|
||
memcpy(Paint->data, mat1.data, mat1.rows * mat1.cols);
|
||
memcpy(mat1.rows * mat1.cols + Paint->data, mat2.data, mat2.rows * mat2.cols);
|
||
if (Paint->channels() == 1)
|
||
cv::cvtColor(*Paint, *Paint, cv::COLOR_GRAY2BGR);
|
||
auto end_time = std::chrono::high_resolution_clock::now();
|
||
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time);
|
||
std::cout << "matsToMat: " << duration.count() << " microseconds" << std::endl;
|
||
}
|
||
void algoThread::ALGO_Correction(detData* data)
|
||
{
|
||
ALGO_Inspection(data);
|
||
int pValueBounus = 100;
|
||
if (data->correctionData == nullptr)
|
||
return;
|
||
#pragma region XOY_DEFINE
|
||
HTuple hv_in_X_X0Y;
|
||
for (auto rangeData : data->correctionData->in_X_X0Y)
|
||
hv_in_X_X0Y.Append(rangeData);
|
||
|
||
HTuple hv_in_Y_X0Y;
|
||
for (auto rangeData : data->correctionData->in_Y_X0Y)
|
||
hv_in_Y_X0Y.Append(rangeData);
|
||
|
||
HTuple hv_in_Z_X0Y;
|
||
for (auto rangeData : data->correctionData->in_Z_X0Y)
|
||
hv_in_Z_X0Y.Append(rangeData);
|
||
|
||
HTuple hv_in_Z_X0Y_Value;
|
||
for (auto rangeData : data->correctionData->in_Z_X0Y_Value)
|
||
hv_in_Z_X0Y_Value.Append(rangeData);
|
||
#pragma endregion
|
||
|
||
#pragma region XOZ_DEFINE
|
||
HTuple hv_in_X_X0Z;
|
||
for (auto rangeData : data->correctionData->in_X_X0Z)
|
||
hv_in_X_X0Z.Append(rangeData);
|
||
|
||
HTuple hv_in_Y_X0Z;
|
||
for (auto rangeData : data->correctionData->in_Y_X0Z)
|
||
hv_in_Y_X0Z.Append(rangeData);
|
||
|
||
HTuple hv_in_Z_X0Z;
|
||
for (auto rangeData : data->correctionData->in_Z_X0Z)
|
||
hv_in_Z_X0Z.Append(rangeData);
|
||
|
||
HTuple hv_in_Y_X0Z_Value;
|
||
for (auto rangeData : data->correctionData->in_Y_X0Z_Value)
|
||
hv_in_Y_X0Z_Value.Append(rangeData);
|
||
#pragma endregion
|
||
|
||
#pragma region YOZ_DEFINE
|
||
HTuple hv_in_X_Y0Z;
|
||
for (auto rangeData : data->correctionData->in_X_Y0Z)
|
||
hv_in_X_Y0Z.Append(rangeData);
|
||
|
||
HTuple hv_in_Y_Y0Z;
|
||
for (auto rangeData : data->correctionData->in_Y_Y0Z)
|
||
hv_in_Y_Y0Z.Append(rangeData);
|
||
|
||
HTuple hv_in_Z_Y0Z;
|
||
for (auto rangeData : data->correctionData->in_Z_Y0Z)
|
||
hv_in_Z_Y0Z.Append(rangeData);
|
||
|
||
HTuple hv_in_X_Y0Z_Value;
|
||
for (auto rangeData : data->correctionData->in_X_Y0Z_Value)
|
||
hv_in_X_Y0Z_Value.Append(rangeData);
|
||
#pragma endregion
|
||
|
||
HTuple hv_out_Origin;
|
||
HTuple hv_out_Result_X;
|
||
HTuple hv_out_Result_Y;
|
||
HTuple hv_out_Result_Z;
|
||
HTuple hv_out_AngleZX;
|
||
HTuple hv_out_AngleYZ;
|
||
HTuple hv_out_AngleXY;
|
||
HTuple hv_out_Flag;
|
||
halcon_Correction(
|
||
hv_in_X_X0Y, hv_in_Y_X0Y, hv_in_Z_X0Y, hv_in_Z_X0Y_Value,
|
||
hv_in_X_X0Z, hv_in_Y_X0Z, hv_in_Z_X0Z, hv_in_Y_X0Z_Value,
|
||
hv_in_X_Y0Z, hv_in_Y_Y0Z, hv_in_Z_Y0Z, hv_in_X_Y0Z_Value,
|
||
&hv_out_Origin,&hv_out_Result_X,&hv_out_Result_Y,&hv_out_Result_Z,
|
||
&hv_out_AngleZX,&hv_out_AngleYZ,&hv_out_AngleXY,&hv_out_Flag);
|
||
|
||
int ok_Flag = 0;
|
||
vector<double>out_Origin;
|
||
vector<double>out_Result_X;
|
||
vector<double>out_Result_Y;
|
||
vector<double>out_Result_Z;
|
||
double out_AngleZX;
|
||
double out_AngleYZ;
|
||
double out_AngleXY;
|
||
|
||
if(hv_out_Flag.Length()==1)
|
||
if (hv_out_Flag[0].D()== 1)
|
||
{
|
||
if (hv_out_Origin.Length() == 3)
|
||
{
|
||
out_Origin = { hv_out_Origin[0].D(),hv_out_Origin[1].D(), hv_out_Origin[2].D() };
|
||
ok_Flag++;
|
||
}
|
||
if (hv_out_Result_X.Length() == 3)
|
||
{
|
||
out_Result_X = { hv_out_Result_X[0].D(),hv_out_Result_X[1].D(), hv_out_Result_X[2].D() };
|
||
ok_Flag++;
|
||
}
|
||
if (hv_out_Result_Y.Length() == 3)
|
||
{
|
||
out_Result_Y = { hv_out_Result_Y[0].D(),hv_out_Result_Y[1].D(), hv_out_Result_Y[2].D() };
|
||
ok_Flag++;
|
||
}
|
||
if (hv_out_Result_Z.Length() == 3)
|
||
{
|
||
out_Result_Z = { hv_out_Result_Z[0].D(),hv_out_Result_Z[1].D(), hv_out_Result_Z[2].D() };
|
||
ok_Flag++;
|
||
}
|
||
if (hv_out_AngleZX.Length() == 1)
|
||
{
|
||
out_AngleZX = hv_out_AngleZX[0].D();
|
||
ok_Flag++;
|
||
}
|
||
if (hv_out_AngleYZ.Length() == 1)
|
||
{
|
||
out_AngleYZ = hv_out_AngleYZ[0].D();
|
||
ok_Flag++;
|
||
}
|
||
if (hv_out_AngleXY.Length() == 1)
|
||
{
|
||
out_AngleXY = hv_out_AngleXY[0].D();
|
||
ok_Flag++;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
std::cout << "error";
|
||
}
|
||
|
||
if (ok_Flag != 7)
|
||
{
|
||
//qDebug()
|
||
return;
|
||
}
|
||
//originX
|
||
bridge.back.sendFinsMsg("write_short_310_" + QString::number(out_Origin[0] < 0 ? 2 : 1));
|
||
bridge.back.sendFinsMsg("write_short_311_" + QString::number(abs(static_cast<int>(out_Origin[0]))));
|
||
double pvalue = out_Origin[0] - static_cast<int>(out_Origin[0]);
|
||
bridge.back.sendFinsMsg("write_short_312_" + QString::number(abs(pvalue* pValueBounus)));
|
||
|
||
//originY
|
||
bridge.back.sendFinsMsg("write_short_313_" + QString::number(out_Origin[1] < 0 ? 2 : 1));
|
||
bridge.back.sendFinsMsg("write_short_314_" + QString::number(abs(static_cast<int>(out_Origin[1]))));
|
||
pvalue = out_Origin[1] - static_cast<int>(out_Origin[1]);
|
||
bridge.back.sendFinsMsg("write_short_315_" + QString::number(abs(pvalue * pValueBounus)));
|
||
|
||
//originZ
|
||
bridge.back.sendFinsMsg("write_short_316_" + QString::number(out_Origin[2] < 0 ? 2 : 1));
|
||
bridge.back.sendFinsMsg("write_short_317_" + QString::number(abs(static_cast<int>(out_Origin[2]))));
|
||
pvalue = out_Origin[2] - static_cast<int>(out_Origin[2]);
|
||
bridge.back.sendFinsMsg("write_short_318_" + QString::number(abs(pvalue * pValueBounus)));
|
||
|
||
//ResultX1
|
||
bridge.back.sendFinsMsg("write_short_319_" + QString::number(out_Result_X[0] < 0 ? 2 : 1));
|
||
bridge.back.sendFinsMsg("write_short_320_" + QString::number(abs(static_cast<int>(out_Result_X[0]))));
|
||
pvalue = out_Result_X[0] - static_cast<int>(out_Result_X[0]);
|
||
bridge.back.sendFinsMsg("write_short_321_" + QString::number(abs(pvalue * pValueBounus)));
|
||
|
||
//ResultX2
|
||
bridge.back.sendFinsMsg("write_short_322_" + QString::number(out_Result_X[1] < 0 ? 2 : 1));
|
||
bridge.back.sendFinsMsg("write_short_323_" + QString::number(abs(static_cast<int>(out_Result_X[1]))));
|
||
pvalue = out_Result_X[1] - static_cast<int>(out_Result_X[1]);
|
||
bridge.back.sendFinsMsg("write_short_324_" + QString::number(abs(pvalue * pValueBounus)));
|
||
|
||
//ResultX3
|
||
bridge.back.sendFinsMsg("write_short_325_" + QString::number(out_Result_X[2] < 0 ? 2 : 1));
|
||
bridge.back.sendFinsMsg("write_short_326_" + QString::number(abs(static_cast<int>(out_Result_X[2]))));
|
||
pvalue = out_Result_X[2] - static_cast<int>(out_Result_X[2]);
|
||
bridge.back.sendFinsMsg("write_short_327_" + QString::number(abs(pvalue * pValueBounus)));
|
||
|
||
//ResultY1
|
||
bridge.back.sendFinsMsg("write_short_328_" + QString::number(out_Result_Y[0] < 0 ? 2 : 1));
|
||
bridge.back.sendFinsMsg("write_short_329_" + QString::number(abs(static_cast<int>(out_Result_Y[0]))));
|
||
pvalue = out_Result_Y[0] - static_cast<int>(out_Result_Y[0]);
|
||
bridge.back.sendFinsMsg("write_short_330_" + QString::number(abs(pvalue * pValueBounus)));
|
||
|
||
//ResultY2
|
||
bridge.back.sendFinsMsg("write_short_331_" + QString::number(out_Result_Y[1] < 0 ? 2 : 1));
|
||
bridge.back.sendFinsMsg("write_short_332_" + QString::number(abs(static_cast<int>(out_Result_Y[1]))));
|
||
pvalue = out_Result_Y[1] - static_cast<int>(out_Result_Y[1]);
|
||
bridge.back.sendFinsMsg("write_short_333_" + QString::number(abs(pvalue * pValueBounus)));
|
||
|
||
//ResultY3
|
||
bridge.back.sendFinsMsg("write_short_334_" + QString::number(out_Result_Y[2] < 0 ? 2 : 1));
|
||
bridge.back.sendFinsMsg("write_short_335_" + QString::number(abs(static_cast<int>(out_Result_Y[2]))));
|
||
pvalue = out_Result_Y[2] - static_cast<int>(out_Result_Y[2]);
|
||
bridge.back.sendFinsMsg("write_short_336_" + QString::number(abs(pvalue * pValueBounus)));
|
||
}
|
||
void algoThread::ALGO_Inspection(detData* data)
|
||
{
|
||
if (data->imgs.size() < 1)
|
||
{
|
||
qDebug() << __FUNCDNAME__ << __LINE__ << "camera Mat size is Error!";
|
||
return;
|
||
}
|
||
//hv_in_Parameter
|
||
//[0]-产品种类; 1A正面 2A反面 3B正面 4C正面
|
||
//[1]-图像序号第一位;
|
||
//[2]-图像序号第二位;
|
||
//[3]-3d相机精度(mm);
|
||
//[4]-ping针偏移判NG阈值(mm);
|
||
//[5]-切图存图开关
|
||
#pragma region halcon变量定义
|
||
//测量
|
||
HObject ho_in_Image;
|
||
HTuple hv_in_ShapePath;
|
||
HTuple hv_in_Parameter;
|
||
HTuple hv_out_Pings_X;
|
||
HTuple hv_out_Pings_Y;
|
||
HTuple hv_out_NG_Pings_X;
|
||
HTuple hv_out_NG_Pings_Y;
|
||
HTuple hv_out_Pings_Num;
|
||
HTuple hv_out_NG_Pings_Num;
|
||
HTuple hv_out_Flag_INS;
|
||
|
||
//ROI
|
||
HTuple hv_out_ROI_Value;
|
||
HTuple hv_out_Flag_ROI;
|
||
#pragma endregion
|
||
|
||
cv::Mat mat = cv::imread("C://NHMJDHNN78474-5_1-ASR1006X20240320-150822.BMP", -1);
|
||
ho_in_Image=simpleAlgo::MatToHObject(mat);
|
||
|
||
hv_in_Parameter.Append(3);
|
||
hv_in_Parameter.Append(5);
|
||
hv_in_Parameter.Append(1);
|
||
hv_in_Parameter.Append(0.0135);
|
||
hv_in_Parameter.Append(0.2);
|
||
hv_in_Parameter.Append(2);
|
||
|
||
hv_in_ShapePath = "./halconModel";
|
||
|
||
|
||
Pings_Inspection(ho_in_Image, hv_in_ShapePath, hv_in_Parameter, &hv_out_Pings_X,
|
||
&hv_out_Pings_Y, &hv_out_NG_Pings_X, &hv_out_NG_Pings_Y, &hv_out_Pings_Num,
|
||
&hv_out_NG_Pings_Num, &hv_out_Flag_INS);
|
||
|
||
Pings_ROI(ho_in_Image, hv_in_ShapePath, hv_in_Parameter, &hv_out_ROI_Value, &hv_out_Flag_ROI);
|
||
vector<Rect>Result;
|
||
for (int i = 0; i < hv_out_ROI_Value.Length()/4;i++)
|
||
{
|
||
Result.push_back(
|
||
cv::Rect(
|
||
hv_out_ROI_Value[i * 4 +1].D(),
|
||
hv_out_ROI_Value[i * 4].D(),
|
||
hv_out_ROI_Value[i * 4 +3].D() - hv_out_ROI_Value[i * 4 + 1].D(),
|
||
hv_out_ROI_Value[i * 4 +2].D() - hv_out_ROI_Value[i * 4].D()
|
||
));
|
||
}
|
||
cv::Mat Paint;
|
||
cvtColor(mat, Paint, COLOR_GRAY2BGR);
|
||
rectangle(Paint, Result[0], cv::Scalar(0, 0, 255), 4);
|
||
_sleep(100);
|
||
}
|
||
void algoThread::Camera1_Algo(detData* data)
|
||
{
|
||
auto start_time = std::chrono::high_resolution_clock::now();
|
||
if (data->imgs.size() < 1)
|
||
{
|
||
qDebug() << __FUNCDNAME__ << __LINE__ << "camera Mat size is Error!";
|
||
return;
|
||
}
|
||
///////////////////取图///声明/////////////////////
|
||
ngNoteCls Note;
|
||
cv::Mat src;
|
||
cv::Mat Paint;
|
||
int CCD1OK = 1;
|
||
double CCD1height = -1;
|
||
double dmCodeWidth = 0, dmCodeHeight = 0;
|
||
double pixAccX = 0.013502052, pixAccY = 0.014005423575;
|
||
double camera1Width = 1, camera1Height = 2;
|
||
QFuture<void> future1;
|
||
if (data->imgs.size() == 1)
|
||
{
|
||
src = data->imgs[0];
|
||
if (Paint.channels() == 1)
|
||
cv::cvtColor(src, Paint, cv::COLOR_GRAY2BGR);
|
||
else
|
||
src.copyTo(Paint);
|
||
}
|
||
|
||
|
||
//}
|
||
if (CCD1OK == 2)
|
||
cv::putText(Paint, "NG", cv::Point(150, 600), 1, 10, cv::Scalar(0, 0, 255), 30);
|
||
else
|
||
cv::putText(Paint, "OK", cv::Point(150, 600), 1, 10, cv::Scalar(0, 255, 0), 30);
|
||
|
||
///////////////////无SN阻塞///////////////////////
|
||
//if (!data->SNcode.compare(snDatas->snErrorsnError))
|
||
// data->SNcode = snDatas->waitForSn(data->timeCode);
|
||
cv::putText(Paint, data->SNcode, cv::Point(150, 800), 1, 10, cv::Scalar(0, 255, 0), 10);
|
||
/////////////////////SQL////////////////////////
|
||
data->sqlVec.push_back({ "Camera1Result", CCD1OK });
|
||
data->sqlVec.push_back({ "Camera1_Width", camera1Width });
|
||
data->sqlVec.push_back({ "Camera1_Height", camera1Height });
|
||
////////////////////结果保存//////////////////
|
||
cv::resize(Paint, Paint, cv::Size(Paint.cols / 2, Paint.rows / 2));
|
||
data->resultImgs.push_back(Paint);
|
||
//////////////CSV/////////////////////////////
|
||
string OKNG("OK");
|
||
if (CCD1OK == 2)OKNG = "NG";
|
||
qDebug() << "[Debug]algo1 end:" << QString::fromStdString(data->SNcode);
|
||
std::cout << "algo1 end:" << QString::fromStdString(data->SNcode).toStdString() << endl;
|
||
} |