feat 添加参数配置pin角方法选择

dev_lsy
liusiyang 2 weeks ago
parent e5cd28f970
commit 211296fc20

@ -40,17 +40,6 @@
using namespace std; using namespace std;
using namespace cv; using namespace cv;
// ============================ Pin 检测方案开关 ============================
// 1 = 新方案(Pin 直接分析, 不做模板对比): 不做仿射变换, 检测图直接按当前外定位结果裁剪;
// 只分析检测Pin: 自动区分两排Pin(考虑图像旋转)并逐排拟合直线,
// 到直线(法线方向)距离超过 pin_y_offset 的判 偏移;
// 相邻两Pin中心连线距离超过 pin_x_offset 的判 两Pin中间缺失一个Pin。
// 0 = 旧方案(模板对比/内定位仿射): 以内定位(无效时回退外定位)仿射变换到模板坐标系后与模板Pin对比。
// 说明: 可通过编译参数 -DPIN_USE_DIRECT_MATCH=0/1 覆盖此处默认值。
#ifndef PIN_USE_DIRECT_MATCH
#define PIN_USE_DIRECT_MATCH 0
#endif
enum AT_THRESHOLD_TYPE_ enum AT_THRESHOLD_TYPE_
{ {
AT_THRESHOLD_TYPE_NULL, AT_THRESHOLD_TYPE_NULL,
@ -207,10 +196,11 @@ private:
// 边缘缺陷检测 // 边缘缺陷检测
int Pin_Qx_Det(const cv::Mat &img); int Pin_Qx_Det(const cv::Mat &img);
#if PIN_USE_DIRECT_MATCH // 当前 Pin 检测方案是否为"直接分析"(参数 pinDet.Det_Method == "line_fitting")
bool IsDirectPinMethod() const;
// 新方案: 不做模板对比, 只分析检测Pin: 自动分两排(考虑旋转) -> 拟合直线判偏移 + 相邻间距判缺失 // 新方案: 不做模板对比, 只分析检测Pin: 自动分两排(考虑旋转) -> 拟合直线判偏移 + 相邻间距判缺失
int Pin_Direct_Check(); int Pin_Direct_Check();
#endif
// 把blob 汇总成 检测结果。 // 把blob 汇总成 检测结果。
int BLobToDetResult(); int BLobToDetResult();

@ -12,6 +12,7 @@
#include <omp.h> #include <omp.h>
#include <map> #include <map>
#include <algorithm> #include <algorithm>
#include <cctype>
#include "AICommonDefine.h" #include "AICommonDefine.h"
#include <cstdlib> #include <cstdlib>
#include <fstream> #include <fstream>
@ -805,65 +806,69 @@ int ImgCheckAnalysisy::CheckRun()
} }
/*投影对齐模板*/ /*投影对齐模板*/
#if PIN_USE_DIRECT_MATCH // Pin 检测方案由参数 Det_Method 运行时选择(替代原 PIN_USE_DIRECT_MATCH 编译宏)
// 新方案(开关 PIN_USE_DIRECT_MATCH = 1): 不做仿射变换, 检测图直接按当前外定位结果裁剪; if (IsDirectPinMethod())
// Pin分析在 Pin_Qx_Det -> Pin_Direct_Check 中完成(只分析检测Pin, 不做模板对比) {
m_pdetlog->AddCheckstr(PrintLevel_0, "2.1、pre detect", "Align mode: Direct Pin Check (no affine)"); // 新方案(Det_Method == "line_fitting"): 不做仿射变换, 检测图直接按当前外定位结果裁剪;
{ // Pin分析在 Pin_Qx_Det -> Pin_Direct_Check 中完成(只分析检测Pin, 不做模板对比)
cv::Rect curOuterBound = m_outer_rroi.boundingRect(); m_pdetlog->AddCheckstr(PrintLevel_0, "2.1、pre detect", "Align mode: Direct Pin Check (no affine)");
cv::Rect curImgBound(0, 0, m_CheckResult_shareP->in_shareImage->img.cols, {
m_CheckResult_shareP->in_shareImage->img.rows); cv::Rect curOuterBound = m_outer_rroi.boundingRect();
curOuterBound &= curImgBound; cv::Rect curImgBound(0, 0, m_CheckResult_shareP->in_shareImage->img.cols,
if (curOuterBound.width <= 0 || curOuterBound.height <= 0) m_CheckResult_shareP->in_shareImage->img.rows);
{ curOuterBound &= curImgBound;
cv::Rect rawBound = m_outer_rroi.boundingRect(); if (curOuterBound.width <= 0 || curOuterBound.height <= 0)
m_pdetlog->AddCheckstr(PrintLevel_0, "Error", "Direct Pin Match: current outer roi invalid [%d %d %d %d]", {
rawBound.x, rawBound.y, rawBound.width, rawBound.height); cv::Rect rawBound = m_outer_rroi.boundingRect();
m_nErrorCode = CHECK_ERROR_Config_cutRoi; m_pdetlog->AddCheckstr(PrintLevel_0, "Error", "Direct Pin Match: current outer roi invalid [%d %d %d %d]",
m_nCheckResultErrorCode = m_nErrorCode; rawBound.x, rawBound.y, rawBound.width, rawBound.height);
return m_nErrorCode; m_nErrorCode = CHECK_ERROR_Config_cutRoi;
m_nCheckResultErrorCode = m_nErrorCode;
return m_nErrorCode;
}
m_outer_roi = curOuterBound;
} }
m_outer_roi = curOuterBound;
}
#else
// 不对原图做 warpAffine, 只计算矩阵, 并把模板 Pin 轮廓反变换到当前图坐标系。
bool bUseInnerAlign = (m_tplInnerRect.size.width > 0 && m_tplInnerRect.size.height > 0 &&
m_inner_rroi.size.width > 0 && m_inner_rroi.size.height > 0);
if (bUseInnerAlign)
{
m_pdetlog->AddCheckstr(PrintLevel_0, "2.1、pre detect",
"Affine align basis: Inner(inner_rroi -> tplInnerRect), template pins warp only, image NOT warped");
CalAffineMats(m_tplInnerRect, m_inner_rroi);
} }
else else
{ {
m_pdetlog->AddCheckstr(PrintLevel_0, "2.1、pre detect", // 旧方案(Det_Method == "BTB_Marix" 或未配置): 不对原图做 warpAffine, 只计算矩阵, 并把模板 Pin 轮廓反变换到当前图坐标系。
"Affine align basis: Outer(outer_rroi -> tplOuterRect), template pins warp only, image NOT warped"); bool bUseInnerAlign = (m_tplInnerRect.size.width > 0 && m_tplInnerRect.size.height > 0 &&
CalAffineMats(m_tplOuterRect, m_outer_rroi); m_inner_rroi.size.width > 0 && m_inner_rroi.size.height > 0);
} if (bUseInnerAlign)
{
m_pdetlog->AddCheckstr(PrintLevel_0, "2.1、pre detect",
"Affine align basis: Inner(inner_rroi -> tplInnerRect), template pins warp only, image NOT warped");
CalAffineMats(m_tplInnerRect, m_inner_rroi);
}
else
{
m_pdetlog->AddCheckstr(PrintLevel_0, "2.1、pre detect",
"Affine align basis: Outer(outer_rroi -> tplOuterRect), template pins warp only, image NOT warped");
CalAffineMats(m_tplOuterRect, m_outer_rroi);
}
// 后续所有检测/裁剪都在当前图坐标系: 裁剪框取当前外定位的包围框(原图不 warp) // 后续所有检测/裁剪都在当前图坐标系: 裁剪框取当前外定位的包围框(原图不 warp)
{
cv::Rect curOuterBound = m_outer_rroi.boundingRect();
cv::Rect curImgBound(0, 0, m_CheckResult_shareP->in_shareImage->img.cols,
m_CheckResult_shareP->in_shareImage->img.rows);
m_outer_roi = curOuterBound & curImgBound;
if (m_outer_roi.width <= 0 || m_outer_roi.height <= 0)
{ {
m_pdetlog->AddCheckstr(PrintLevel_0, "Error", "Affine mode: current outer roi invalid [%d %d %d %d]", cv::Rect curOuterBound = m_outer_rroi.boundingRect();
curOuterBound.x, curOuterBound.y, curOuterBound.width, curOuterBound.height); cv::Rect curImgBound(0, 0, m_CheckResult_shareP->in_shareImage->img.cols,
m_nErrorCode = CHECK_ERROR_Config_cutRoi; m_CheckResult_shareP->in_shareImage->img.rows);
m_nCheckResultErrorCode = m_nErrorCode; m_outer_roi = curOuterBound & curImgBound;
return m_nErrorCode; if (m_outer_roi.width <= 0 || m_outer_roi.height <= 0)
{
m_pdetlog->AddCheckstr(PrintLevel_0, "Error", "Affine mode: current outer roi invalid [%d %d %d %d]",
curOuterBound.x, curOuterBound.y, curOuterBound.width, curOuterBound.height);
m_nErrorCode = CHECK_ERROR_Config_cutRoi;
m_nCheckResultErrorCode = m_nErrorCode;
return m_nErrorCode;
}
} }
}
// 模板 Pin(pinImg 坐标) -> 模板图坐标 -> 当前图坐标 -> detImg 坐标 // 模板 Pin(pinImg 坐标) -> 模板图坐标 -> 当前图坐标 -> detImg 坐标
TransformTplPinContoursToCur(); TransformTplPinContoursToCur();
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "2.1、pre detect", m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "2.1、pre detect",
"tpl pin contours -> current frame: %ld (affineValid %d)", "tpl pin contours -> current frame: %ld (affineValid %d)",
static_cast<long>(m_tplPinContoursCur.size()), static_cast<int>(m_bAffineValid)); static_cast<long>(m_tplPinContoursCur.size()), static_cast<int>(m_bAffineValid));
#endif }
m_Crop_Roi_paramImg = m_outer_roi; m_Crop_Roi_paramImg = m_outer_roi;
m_pImageAllResult->pDetResult->CutRoi = m_outer_roi; m_pImageAllResult->pDetResult->CutRoi = m_outer_roi;
m_pImageAllResult->pDetResult->Param_CropRoi = m_Crop_Roi_paramImg; m_pImageAllResult->pDetResult->Param_CropRoi = m_Crop_Roi_paramImg;
@ -2127,27 +2132,28 @@ int ImgCheckAnalysisy::DrawResult_Step_1()
float fs_resize_y = m_pImageAllResult->resultImg.rows * 1.0f / m_pImageAllResult->detImg.rows; float fs_resize_y = m_pImageAllResult->resultImg.rows * 1.0f / m_pImageAllResult->detImg.rows;
// 绘制模板 pin 轮廓(绿色)与当前 pin 轮廓(红色) // 绘制模板 pin 轮廓(绿色)与当前 pin 轮廓(红色)
#if PIN_USE_DIRECT_MATCH // Pin 绘制内容按当前检测方案选择: 新方案绘制拟合直线/缺失标记, 旧方案绘制反变换后的模板Pin
// 新方案: 模板pin已配准到当前检测图坐标系 std::vector<std::vector<cv::Point>> directDrawPinContours;
// 新方案: 不做模板对比; 将两排Pin拟合直线段与缺失标记组织成 2点"轮廓", 复用下方循环缩放绘制(绿色) const std::vector<std::vector<cv::Point>> *pTplDrawPinContours = &m_tplPinContoursCur;
std::vector<std::vector<cv::Point>> tplDrawPinContours; if (IsDirectPinMethod())
for (const auto &seg : m_pinFitLines)
{
tplDrawPinContours.push_back({cv::Point(cvRound(seg.first.x), cvRound(seg.first.y)),
cv::Point(cvRound(seg.second.x), cvRound(seg.second.y))});
}
for (const auto &mark : m_pinMissMarks)
{ {
// 缺失位置: 十字标记(两条短线) // 新方案: 不做模板对比; 将两排Pin拟合直线段与缺失标记组织成 2点"轮廓", 复用下方循环缩放绘制(绿色)
tplDrawPinContours.push_back({cv::Point(cvRound(mark.x - 6.0f), cvRound(mark.y)), for (const auto &seg : m_pinFitLines)
cv::Point(cvRound(mark.x + 6.0f), cvRound(mark.y))}); {
tplDrawPinContours.push_back({cv::Point(cvRound(mark.x), cvRound(mark.y - 6.0f)), directDrawPinContours.push_back({cv::Point(cvRound(seg.first.x), cvRound(seg.first.y)),
cv::Point(cvRound(mark.x), cvRound(mark.y + 6.0f))}); cv::Point(cvRound(seg.second.x), cvRound(seg.second.y))});
}
for (const auto &mark : m_pinMissMarks)
{
// 缺失位置: 十字标记(两条短线)
directDrawPinContours.push_back({cv::Point(cvRound(mark.x - 6.0f), cvRound(mark.y)),
cv::Point(cvRound(mark.x + 6.0f), cvRound(mark.y))});
directDrawPinContours.push_back({cv::Point(cvRound(mark.x), cvRound(mark.y - 6.0f)),
cv::Point(cvRound(mark.x), cvRound(mark.y + 6.0f))});
}
pTplDrawPinContours = &directDrawPinContours;
} }
#else for (const auto &contour : *pTplDrawPinContours)
const std::vector<std::vector<cv::Point>> &tplDrawPinContours = m_tplPinContoursCur;
#endif
for (const auto &contour : tplDrawPinContours)
{ {
std::vector<cv::Point> draw_pts; std::vector<cv::Point> draw_pts;
draw_pts.reserve(contour.size()); draw_pts.reserve(contour.size());
@ -2240,6 +2246,31 @@ int ImgCheckAnalysisy::UpdateImgageScale()
return 0; return 0;
} }
// 当前 Pin 检测方案是否为"直接分析"(新方案): 由参数 pinDet.Det_Method 在运行时决定
// "line_fitting" -> 新方案(不做模板对比); 其它/未配置 -> 旧方案(模板对比)
bool ImgCheckAnalysisy::IsDirectPinMethod() const
{
if (m_pbaseCheckFunction == NULL)
{
return false;
}
std::string method = m_pbaseCheckFunction->pinDet.Det_Method;
// 去掉首尾空白并转小写, 兼容大小写/带空格的配置值
size_t begin = method.find_first_not_of(" \t\r\n");
if (begin == std::string::npos)
{
return false;
}
size_t end = method.find_last_not_of(" \t\r\n");
method = method.substr(begin, end - begin + 1);
std::transform(method.begin(), method.end(), method.begin(),
[](unsigned char c)
{ return static_cast<char>(std::tolower(c)); });
return (method == "line_fitting");
}
int ImgCheckAnalysisy::Pin_Qx_Det(const cv::Mat &img) int ImgCheckAnalysisy::Pin_Qx_Det(const cv::Mat &img)
{ {
@ -2278,10 +2309,12 @@ int ImgCheckAnalysisy::Pin_Qx_Det(const cv::Mat &img)
m_curPinContours.push_back(mapped); m_curPinContours.push_back(mapped);
} }
#if PIN_USE_DIRECT_MATCH if (IsDirectPinMethod())
// 新方案: 不做模板对比, 只分析检测Pin(自动分两排 -> 逐排拟合直线判偏移 + 相邻间距判缺失) {
Pin_Direct_Check(); // 新方案: 不做模板对比, 只分析检测Pin(自动分两排 -> 逐排拟合直线判偏移 + 相邻间距判缺失)
#else Pin_Direct_Check();
}
else
// 根据模板Pin和当前Pin轮廓进行对比,判断当前有无缺失和偏移 // 根据模板Pin和当前Pin轮廓进行对比,判断当前有无缺失和偏移
{ {
// 计算轮廓中心点(外接矩形中心) // 计算轮廓中心点(外接矩形中心)
@ -2533,7 +2566,6 @@ int ImgCheckAnalysisy::Pin_Qx_Det(const cv::Mat &img)
m_pdetlog->AddCheckstr(PrintLevel_0, "Pin Check", "tpl %d cur %d miss %d offset %d", nTpl, nCur, nMiss, nOffset); m_pdetlog->AddCheckstr(PrintLevel_0, "Pin Check", "tpl %d cur %d miss %d offset %d", nTpl, nCur, nMiss, nOffset);
} }
} }
#endif
if (m_Edge_DetConfig.bSaveResultImg) if (m_Edge_DetConfig.bSaveResultImg)
{ {
@ -2554,29 +2586,31 @@ int ImgCheckAnalysisy::Pin_Qx_Det(const cv::Mat &img)
showimg = img.clone(); showimg = img.clone();
} }
cv::drawContours(showimg, m_curPinContours, -1, CheckUtil::GetDrawColor(showimg, cv::Scalar(0, 0, 255)), 1); cv::drawContours(showimg, m_curPinContours, -1, CheckUtil::GetDrawColor(showimg, cv::Scalar(0, 0, 255)), 1);
#if PIN_USE_DIRECT_MATCH if (IsDirectPinMethod())
// 新方案: 绘制两排Pin的拟合直线(绿); 缺失位置以黄色十字标记
for (const auto &seg : m_pinFitLines)
{ {
cv::line(showimg, cv::Point(cvRound(seg.first.x), cvRound(seg.first.y)), // 新方案: 绘制两排Pin的拟合直线(绿); 缺失位置以黄色十字标记
cv::Point(cvRound(seg.second.x), cvRound(seg.second.y)), for (const auto &seg : m_pinFitLines)
CheckUtil::GetDrawColor(showimg, cv::Scalar(0, 255, 0)), 1); {
cv::line(showimg, cv::Point(cvRound(seg.first.x), cvRound(seg.first.y)),
cv::Point(cvRound(seg.second.x), cvRound(seg.second.y)),
CheckUtil::GetDrawColor(showimg, cv::Scalar(0, 255, 0)), 1);
}
for (const auto &mark : m_pinMissMarks)
{
cv::drawMarker(showimg, cv::Point(cvRound(mark.x), cvRound(mark.y)),
CheckUtil::GetDrawColor(showimg, cv::Scalar(0, 255, 255)), cv::MARKER_CROSS, 16, 1);
}
} }
for (const auto &mark : m_pinMissMarks) else
{ {
cv::drawMarker(showimg, cv::Point(cvRound(mark.x), cvRound(mark.y)), cv::drawContours(showimg, m_tplPinContoursCur, -1, CheckUtil::GetDrawColor(showimg, cv::Scalar(0, 255, 0)), 1);
CheckUtil::GetDrawColor(showimg, cv::Scalar(0, 255, 255)), cv::MARKER_CROSS, 16, 1);
} }
#else
cv::drawContours(showimg, m_tplPinContoursCur, -1, CheckUtil::GetDrawColor(showimg, cv::Scalar(0, 255, 0)), 1);
#endif
imwrite("pin_contours.png", showimg); imwrite("pin_contours.png", showimg);
} }
return 0; return 0;
} }
#if PIN_USE_DIRECT_MATCH
#if 0 // ----- 旧配准匹配方案(Pin_Direct_Match)已停用, 仅保留代码参考; 如需启用需恢复 m_tplPinContoursCur 成员 ----- #if 0 // ----- 旧配准匹配方案(Pin_Direct_Match)已停用, 仅保留代码参考; 如需启用需恢复 m_tplPinContoursCur 成员 -----
// 新方案(开关 PIN_USE_DIRECT_MATCH = 1): 不做仿射变换, 直接对模板Pin与检测Pin做配准后对比 // 新方案(开关 PIN_USE_DIRECT_MATCH = 1): 不做仿射变换, 直接对模板Pin与检测Pin做配准后对比
// 输入: m_tplPinContours(模板裁剪坐标系) / m_curPinContours(当前检测图坐标系) // 输入: m_tplPinContours(模板裁剪坐标系) / m_curPinContours(当前检测图坐标系)
@ -2842,7 +2876,7 @@ int ImgCheckAnalysisy::Pin_Direct_Match()
} }
#endif #endif
// 新方案(开关 PIN_USE_DIRECT_MATCH = 1): 不做模板对比, 只针对检测Pin分析 // 新方案(Det_Method == "line_fitting"): 不做模板对比, 只针对检测Pin分析
// 1) 方向扫描(0~180°, 步长1°): 取 "两排Pin沿法线投影组内方差之和" 最小的角度作为Pin排方向(对图像旋转不敏感), // 1) 方向扫描(0~180°, 步长1°): 取 "两排Pin沿法线投影组内方差之和" 最小的角度作为Pin排方向(对图像旋转不敏感),
// 再沿该法线投影, 在最大间隙处把Pin分成两排(两排插口; Pin不足4个则按一排处理); // 再沿该法线投影, 在最大间隙处把Pin分成两排(两排插口; Pin不足4个则按一排处理);
// 2) 每排做最小二乘直线拟合(cv::fitLine): pin中心到直线(沿法线方向)距离按成像精度换算为 mm, 超过 pin_y_offset(mm) 判 偏移; // 2) 每排做最小二乘直线拟合(cv::fitLine): pin中心到直线(沿法线方向)距离按成像精度换算为 mm, 超过 pin_y_offset(mm) 判 偏移;
@ -3147,7 +3181,6 @@ int ImgCheckAnalysisy::Pin_Direct_Check()
nCur, static_cast<int>(rows.size()), nMiss, nOffset); nCur, static_cast<int>(rows.size()), nMiss, nOffset);
return 0; return 0;
} }
#endif // PIN_USE_DIRECT_MATCH
// 获取指定 残点(blob) 是由哪个(哪些)检测模型检出的 // 获取指定 残点(blob) 是由哪个(哪些)检测模型检出的
// 做法:对各模型自己输出的全图 mask,在 blob 的 roi 内统计非零像素; // 做法:对各模型自己输出的全图 mask,在 blob 的 roi 内统计非零像素;

@ -1247,6 +1247,9 @@ struct Base_Function_Pin_Det
bool bOpen; // 是否开启 bool bOpen; // 是否开启
float pin_x_offset; // pin x 偏移 float pin_x_offset; // pin x 偏移
float pin_y_offset; // pin y 偏移 float pin_y_offset; // pin y 偏移
// "line_fitting" = 新方案(直接分析检测Pin: 分两排拟合直线判偏移 + 相邻间距判缺失, 不做模板对比)
// "BTB_Marix" = 旧方案(内定位仿射 + 模板Pin对比)
std::string Det_Method; // pin 检测方案
bool bDrawResult; // 是否绘制结果 bool bDrawResult; // 是否绘制结果
Base_Function_Pin_Det() Base_Function_Pin_Det()
@ -1258,6 +1261,7 @@ struct Base_Function_Pin_Det
bOpen = false; bOpen = false;
pin_x_offset = 0; pin_x_offset = 0;
pin_y_offset = 0; pin_y_offset = 0;
Det_Method = "BTB_Marix";
bDrawResult = false; bDrawResult = false;
} }
@ -1266,18 +1270,19 @@ struct Base_Function_Pin_Det
this->bOpen = tem.bOpen; this->bOpen = tem.bOpen;
this->pin_x_offset = tem.pin_x_offset; this->pin_x_offset = tem.pin_x_offset;
this->pin_y_offset = tem.pin_y_offset; this->pin_y_offset = tem.pin_y_offset;
this->Det_Method = tem.Det_Method;
this->bDrawResult = tem.bDrawResult; this->bDrawResult = tem.bDrawResult;
} }
void print(std::string str) void print(std::string str)
{ {
printf("%s>>bOpen %d pin_x_offset %f pin_y_offset %f bDrawResult %d\n", str.c_str(), printf("%s>>bOpen %d pin_x_offset %f pin_y_offset %f Det_Method %s bDrawResult %d\n", str.c_str(),
bOpen, pin_x_offset, pin_y_offset, bDrawResult); bOpen, pin_x_offset, pin_y_offset, Det_Method.c_str(), bDrawResult);
} }
std::string GetInfo(std::string str) std::string GetInfo(std::string str)
{ {
char buffer[256]; char buffer[256];
sprintf(buffer, "%s>>bOpen %d pin_x_offset %f pin_y_offset %f bDrawResult %d\n", str.c_str(), sprintf(buffer, "%s>>bOpen %d pin_x_offset %f pin_y_offset %f Det_Method %s bDrawResult %d\n", str.c_str(),
bOpen, pin_x_offset, pin_y_offset, bDrawResult); bOpen, pin_x_offset, pin_y_offset, Det_Method.c_str(), bDrawResult);
std::string str123 = buffer; std::string str123 = buffer;
return str123; return str123;
} }

@ -822,6 +822,10 @@ int BaseFuntonConfigJson::GetFunction(Json::Value value)
if (_config.pinDet.bOpen) if (_config.pinDet.bOpen)
{ {
if (value_f["form"]["Det_Config"]["Det_Method"])
{
_config.pinDet.Det_Method = value_f["form"]["Det_Config"]["Det_Method"].asString();
}
if (value_f["form"]["Det_Config"]["pin_x_offset"]) if (value_f["form"]["Det_Config"]["pin_x_offset"])
{ {
_config.pinDet.pin_x_offset = value_f["form"]["Det_Config"]["pin_x_offset"].asFloat(); _config.pinDet.pin_x_offset = value_f["form"]["Det_Config"]["pin_x_offset"].asFloat();

Loading…
Cancel
Save