已修改9个文件
422 ■■■■■ 文件已修改
EdgeInspector_App/Data/DefectStorage.cpp 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
EdgeInspector_App/Data/PostProcess.cpp 180 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
EdgeInspector_App/Defect.h 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
EdgeInspector_App/EdgeInspector_App.rc 补丁 | 查看 | 原始文档 | blame | 历史
EdgeInspector_App/Process/InspectCamera.cpp 192 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
EdgeInspector_App/Recipe/HardwareSettings.cpp 39 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
EdgeInspector_App/Recipe/HardwareSettings.h 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
EdgeInspector_App/View/ViewMain_HWSetting.cpp 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
EdgeInspector_App/resource.h 补丁 | 查看 | 原始文档 | blame | 历史
EdgeInspector_App/Data/DefectStorage.cpp
@@ -309,6 +309,8 @@
    pDefect->m_bJudge_NG = TRUE;
    pDefect->m_dSizeX_um = dMeasureResult_um;
    pDefect->m_dSizeY_um = dMeasureDiff_um;
    pDefect->m_dChamfer_um = dMeasureResult_um;
    pDefect->m_dChamferOff_um = dMeasureDiff_um;
    pDefect->m_DefectInfo = defect;
    if(m_pGrabber->GetSmallImage(iScan,pDefect->m_Image
EdgeInspector_App/Data/PostProcess.cpp
@@ -180,6 +180,9 @@
    if (glass_id.IsEmpty() == TRUE)
        glass_id.Format(_T("MANUAL_ID"));
    // 获取当前产品加载时间
    CTime tGlassLoading = m_pGlassData->GetLoadingTime();
    CString measure_data;
    CString chip_data;
    CString defect_data;
@@ -241,42 +244,19 @@
        m_pGlassData->GetSideData(DIMENSION_C)->m_nTopCornerHeight,
        m_pGlassData->GetSideData(DIMENSION_C)->m_nBottomCornerWidth,
        m_pGlassData->GetSideData(DIMENSION_C)->m_nBottomCornerHeight
        );
    );
    measure_data.Append(_T("\r\n"));
    CString measure_file_path;
    if (m_pHardware->m_bSaveResultByHour) {
        // 按小时保存结果
        measure_file_path.Format(_T("%s\\%s_%02d_MeasureData.csv"), m_strResultFolder, g_pBase->m_strLoadingDay, tGlassLoading.GetHour());
    }
    else {
        // 不按小时保存结果
        measure_file_path.Format(_T("%s\\%s_MeasureData.csv"), m_strResultFolder, g_pBase->m_strLoadingDay);
    }
    // 获取当前时间
    std::time_t m_now = std::time(nullptr);
    // 使用localtime_s代替localtime
    std::tm m_nowTm;
    localtime_s(&m_nowTm, &m_now);
    if (m_nowTm.tm_hour < 4)
    {
        measure_file_path.Format(_T("%s\\%s_%02d_MeasureData.csv"), m_strResultFolder, g_pBase->m_strLoadingDay,24);
    }
    else if(m_nowTm.tm_hour > 3 && m_nowTm.tm_hour < 9)
    {
        measure_file_path.Format(_T("%s\\%s_%02d_MeasureData.csv"), m_strResultFolder, g_pBase->m_strLoadingDay, 4);
    }
    else if (m_nowTm.tm_hour > 7 && m_nowTm.tm_hour < 13)
    {
        measure_file_path.Format(_T("%s\\%s_%02d_MeasureData.csv"), m_strResultFolder, g_pBase->m_strLoadingDay, 8);
    }
    else if (m_nowTm.tm_hour > 11 && m_nowTm.tm_hour < 17)
    {
        measure_file_path.Format(_T("%s\\%s_%02d_MeasureData.csv"), m_strResultFolder, g_pBase->m_strLoadingDay, 12);
    }
    else if (m_nowTm.tm_hour > 15 && m_nowTm.tm_hour < 21)
    {
        measure_file_path.Format(_T("%s\\%s_%02d_MeasureData.csv"), m_strResultFolder, g_pBase->m_strLoadingDay, 16);
    }
    else if (m_nowTm.tm_hour > 19)
    {
        measure_file_path.Format(_T("%s\\%s_%02d_MeasureData.csv"), m_strResultFolder, g_pBase->m_strLoadingDay, 20);
    }
    CheckDirectory(measure_file_path);
    CFile measure_module;
@@ -434,31 +414,13 @@
    }
    CString Chip_file_path;
    localtime_s(&m_nowTm, &m_now);
    if (m_nowTm.tm_hour < 4)
    {
        Chip_file_path.Format(_T("%s\\%s_%02d_ChipData.csv"), m_strResultFolder, g_pBase->m_strLoadingDay,24);
    if (m_pHardware->m_bSaveResultByHour) {
        // 按小时保存结果
        Chip_file_path.Format(_T("%s\\%s_%02d_ChipData.csv"), m_strResultFolder, g_pBase->m_strLoadingDay, tGlassLoading.GetHour());
    }
    else if (m_nowTm.tm_hour > 3 && m_nowTm.tm_hour < 9)
    {
        Chip_file_path.Format(_T("%s\\%s_%02d_ChipData.csv"), m_strResultFolder, g_pBase->m_strLoadingDay, 4);
    }
    else if (m_nowTm.tm_hour > 7 && m_nowTm.tm_hour < 13)
    {
        Chip_file_path.Format(_T("%s\\%s_%02d_ChipData.csv"), m_strResultFolder, g_pBase->m_strLoadingDay, 8);
    }
    else if (m_nowTm.tm_hour > 11 && m_nowTm.tm_hour < 17)
    {
        Chip_file_path.Format(_T("%s\\%s_%02d_ChipData.csv"), m_strResultFolder, g_pBase->m_strLoadingDay, 12);
    }
    else if (m_nowTm.tm_hour > 15 && m_nowTm.tm_hour < 21)
    {
        Chip_file_path.Format(_T("%s\\%s_%02d_ChipData.csv"), m_strResultFolder, g_pBase->m_strLoadingDay, 16);
    }
    else if (m_nowTm.tm_hour > 19)
    {
        Chip_file_path.Format(_T("%s\\%s_%02d_ChipData.csv"), m_strResultFolder, g_pBase->m_strLoadingDay, 20);
    else {
        // 不按小时保存结果
        Chip_file_path.Format(_T("%s\\%s_ChipData.csv"), m_strResultFolder, g_pBase->m_strLoadingDay);
    }
    
    CheckDirectory(Chip_file_path);
@@ -481,32 +443,15 @@
    }
    CString Defect_file_path;
    if (m_pHardware->m_bSaveResultByHour) {
        // 按小时保存结果
        Defect_file_path.Format(_T("%s\\%s_%02d_DefectData.csv"), m_strResultFolder, g_pBase->m_strLoadingDay, tGlassLoading.GetHour());
    }
    else {
        // 不按小时保存结果
        Defect_file_path.Format(_T("%s\\%s_DefectData.csv"), m_strResultFolder, g_pBase->m_strLoadingDay);
    }
    if (m_nowTm.tm_hour < 4)
    {
        Defect_file_path.Format(_T("%s\\%s_%02d_DefectData.csv"), m_strResultFolder, g_pBase->m_strLoadingDay, 24);
    }
    else if (m_nowTm.tm_hour > 3 && m_nowTm.tm_hour < 9)
    {
        Defect_file_path.Format(_T("%s\\%s_%02d_DefectData.csv"), m_strResultFolder, g_pBase->m_strLoadingDay, 4);
    }
    else if (m_nowTm.tm_hour > 7 && m_nowTm.tm_hour < 13)
    {
        Defect_file_path.Format(_T("%s\\%s_%02d_DefectData.csv"), m_strResultFolder, g_pBase->m_strLoadingDay, 8);
    }
    else if (m_nowTm.tm_hour > 11 && m_nowTm.tm_hour < 17)
    {
        Defect_file_path.Format(_T("%s\\%s_%02d_DefectData.csv"), m_strResultFolder, g_pBase->m_strLoadingDay, 12);
    }
    else if (m_nowTm.tm_hour > 15 && m_nowTm.tm_hour < 21)
    {
        Defect_file_path.Format(_T("%s\\%s_%02d_DefectData.csv"), m_strResultFolder, g_pBase->m_strLoadingDay, 16);
    }
    else if (m_nowTm.tm_hour > 19)
    {
        Defect_file_path.Format(_T("%s\\%s_%02d_DefectData.csv"), m_strResultFolder, g_pBase->m_strLoadingDay, 20);
    }
    CheckDirectory(Defect_file_path);
    CFile defect_module;
@@ -642,14 +587,22 @@
BOOL CPostProcess::SaveDefectImage_with_Title(CDefect* pDefect, CSize szImage,CRect rectDefect,CString strFile, CvScalar color)
{
    Lock();
    if(pDefect == NULL || pDefect->m_Image == NULL)
    if (pDefect == NULL || pDefect->m_Image == NULL) {
        return FALSE;
    }
    // 标题文本
    CString strTitle;
    int nSideIdx = (0 <= pDefect->m_DefectInfo.m_nSideIdx && pDefect->m_DefectInfo.m_nSideIdx < MAX_SIDE_COUNT) ? pDefect->m_DefectInfo.m_nSideIdx : MAX_SIDE_COUNT;
    int nCategoryIdx = (0 <= pDefect->m_DefectInfo.m_DefectLoc && pDefect->m_DefectInfo.m_DefectLoc < DefectLoc_None) ? pDefect->m_DefectInfo.m_DefectLoc : DefectLoc_Unknown;
    strTitle.Format(_T("SIDE[%s] CAT[%s] SIZE[%d,%d]"), g_SideName[nSideIdx], g_strDefectType[nCategoryIdx], (int)pDefect->m_dSizeX_um, (int)pDefect->m_dSizeY_um);
    DefectLocation eCategory = pDefect->m_DefectInfo.m_DefectLoc;
    if (eCategory == DefectLoc_Notch_Dimension || eCategory == DefectLoc_Notch_Chamfer) {
        strTitle.Format(_T("SIDE[%s] CAT[%s] SIZE[%d,%d] distance[%d,%d] "), g_SideName[nSideIdx], g_strDefectType[nCategoryIdx], (int)pDefect->m_dSizeX_um, (int)pDefect->m_dSizeY_um, (int)pDefect->m_dChamfer_um, (int)pDefect->m_dChamferOff_um);
    }
    else {
        strTitle.Format(_T("SIDE[%s] CAT[%s] SIZE[%d,%d]"), g_SideName[nSideIdx], g_strDefectType[nCategoryIdx], (int)pDefect->m_dSizeX_um, (int)pDefect->m_dSizeY_um);
    }
    Unlock();
    // 成功标志
@@ -1052,47 +1005,28 @@
    // Save Path
    CString strFilePath;
    // 获取当前时间
    std::time_t m_now = std::time(nullptr);
    // 使用localtime_s代替localtime
    std::tm m_nowTm;
    localtime_s(&m_nowTm, &m_now);
    if (m_nowTm.tm_hour < 4)
    {
        strFilePath.Format(_T("D:\\Data\\%s\\%s\\%d\\%02d\\%02d\\%s_%s_%02d.csv"), m_pHardware->GetMachineName(), m_pHardware->GetLineID()
            , tLoadingTime.GetYear(), tLoadingTime.GetMonth(), tLoadingTime.GetDay()
            , m_pGlassData->GetGlassRecipe()->GetRecipeName(), tLoadingTime.Format(_T("%Y%m%d")),24 );
    if (m_pHardware->m_bSaveResultByHour) {
        // 按小时保存,绑定玻璃 Loading Time
        strFilePath.Format(_T("D:\\Data\\%s\\%s\\%d\\%02d\\%02d\\%s_%s_%02d.csv"),
            m_pHardware->GetMachineName(),
            m_pHardware->GetLineID(),
            tLoadingTime.GetYear(),
            tLoadingTime.GetMonth(),
            tLoadingTime.GetDay(),
            g_pBase->m_strRecipeName,
            g_pBase->m_strLoadingDay,
            tLoadingTime.GetHour());
    }
    else if (m_nowTm.tm_hour > 3 && m_nowTm.tm_hour < 8)
    {
        strFilePath.Format(_T("D:\\Data\\%s\\%s\\%d\\%02d\\%02d\\%s_%s_%02d.csv"), m_pHardware->GetMachineName(), m_pHardware->GetLineID()
            , tLoadingTime.GetYear(), tLoadingTime.GetMonth(), tLoadingTime.GetDay()
            , m_pGlassData->GetGlassRecipe()->GetRecipeName(), tLoadingTime.Format(_T("%Y%m%d")), 4);
    }
    else if (m_nowTm.tm_hour > 7 && m_nowTm.tm_hour < 12)
    {
        strFilePath.Format(_T("D:\\Data\\%s\\%s\\%d\\%02d\\%02d\\%s_%s_%02d.csv"), m_pHardware->GetMachineName(), m_pHardware->GetLineID()
            , tLoadingTime.GetYear(), tLoadingTime.GetMonth(), tLoadingTime.GetDay()
            , m_pGlassData->GetGlassRecipe()->GetRecipeName(), tLoadingTime.Format(_T("%Y%m%d")), 8);
    }
    else if (m_nowTm.tm_hour > 11 && m_nowTm.tm_hour < 16)
    {
        strFilePath.Format(_T("D:\\Data\\%s\\%s\\%d\\%02d\\%02d\\%s_%s_%02d.csv"), m_pHardware->GetMachineName(), m_pHardware->GetLineID()
            , tLoadingTime.GetYear(), tLoadingTime.GetMonth(), tLoadingTime.GetDay()
            , m_pGlassData->GetGlassRecipe()->GetRecipeName(), tLoadingTime.Format(_T("%Y%m%d")), 12);
    }
    else if (m_nowTm.tm_hour > 15 && m_nowTm.tm_hour < 20)
    {
        strFilePath.Format(_T("D:\\Data\\%s\\%s\\%d\\%02d\\%02d\\%s_%s_%02d.csv"), m_pHardware->GetMachineName(), m_pHardware->GetLineID()
            , tLoadingTime.GetYear(), tLoadingTime.GetMonth(), tLoadingTime.GetDay()
            , m_pGlassData->GetGlassRecipe()->GetRecipeName(), tLoadingTime.Format(_T("%Y%m%d")), 16);
    }
    else if (m_nowTm.tm_hour > 19)
    {
        strFilePath.Format(_T("D:\\Data\\%s\\%s\\%d\\%02d\\%02d\\%s_%s_%02d.csv"), m_pHardware->GetMachineName(), m_pHardware->GetLineID()
            , tLoadingTime.GetYear(), tLoadingTime.GetMonth(), tLoadingTime.GetDay()
            , m_pGlassData->GetGlassRecipe()->GetRecipeName(), tLoadingTime.Format(_T("%Y%m%d")), 20);
    else {
        // 按天保存,绑定玻璃 Loading Time
        strFilePath.Format(_T("D:\\Data\\%s\\%s\\%d\\%02d\\%02d\\%s_%s.csv"),
            m_pHardware->GetMachineName(),
            m_pHardware->GetLineID(),
            tLoadingTime.GetYear(),
            tLoadingTime.GetMonth(),
            tLoadingTime.GetDay(),
            g_pBase->m_strRecipeName,
            g_pBase->m_strLoadingDay);
    }
    CheckDirectory(strFilePath);
EdgeInspector_App/Defect.h
@@ -148,6 +148,8 @@
        m_dSizeX_um = 0.0;
        m_dSizeY_um = 0.0;
        m_dChamfer_um = 0.0;
        m_dChamferOff_um = 0.0;
        m_nDefectMergeCount = 0;
        m_bDefectMergeRemoved = FALSE;
@@ -174,6 +176,8 @@
    double            m_dSizeX_um;
    double            m_dSizeY_um;
    double            m_dChamfer_um;
    double            m_dChamferOff_um;
    // Merge
    int                m_nDefectMergeCount;
EdgeInspector_App/EdgeInspector_App.rc
Binary files differ
EdgeInspector_App/Process/InspectCamera.cpp
@@ -3720,13 +3720,6 @@
BOOL CInspectCamera::Notch_Process(int iThread,DimensionDir emDim, stFrameIndex stFrame)
{
    //CTime tCurrentTime = CTime::GetCurrentTime();
    //CTime tLimitTime = CTime(2023,3,31,11,59,59);
    //CTimeSpan tSpanTime = tLimitTime - tCurrentTime;
    //if(tSpanTime.GetTotalSeconds() < 0)
    //    return FALSE;
    if(m_pGlassData == NULL)
        return FALSE;
@@ -3782,24 +3775,20 @@
        pEdgeImage = cvCloneImage(pOriginImage);
        pBinImage = cvCloneImage(pOriginImage);
        g_pLog->DisplayMessage(_T("1. Notch_Process %s : %d, idx %d"),g_SideName[(int) emDim], stFrame.nFrameIdx,i);
        // 1. Image PreProcess..
        g_pLog->DisplayMessage(_T("1. Notch_Process %s : %d, idx %d"), g_SideName[(int)emDim], stFrame.nFrameIdx, i);
        Notch_Process_PreProcess(emDim, stFrame, i, pOriginImage, pEdgeImage, pBinImage, rtRotateArea);
        // Notch_Process_PreProcess_2(emDim, stFrame, i, pOriginImage, pEdgeImage, pBinImage, rtRotateArea);
        g_pLog->DisplayMessage(_T("2. Notch_Process %s : %d, idx %d"),g_SideName[(int) emDim], stFrame.nFrameIdx,i);
        // 2. Notch Dimension/Chamfer Find..
        g_pLog->DisplayMessage(_T("2. Notch_Process %s : %d, idx %d"), g_SideName[(int)emDim], stFrame.nFrameIdx, i);
        Notch_Process_Measure(emDim, stFrame, i, pOriginImage, pEdgeImage, pBinImage, rtRotateArea);
        g_pLog->DisplayMessage(_T("3. Notch_Process %s : %d, idx %d"),g_SideName[(int) emDim], stFrame.nFrameIdx,i);
        // 3. Notch Dimension/Chamfer Calculate Result..
        g_pLog->DisplayMessage(_T("3. Notch_Process %s : %d, idx %d"), g_SideName[(int)emDim], stFrame.nFrameIdx, i);
        bool bResult = Notch_Process_Calculate(emDim, stFrame, i, pOriginImage, pEdgeImage, pBinImage, rtRotateArea);
        g_pLog->DisplayMessage(_T("4. Notch_Process %s : %d, idx %d"),g_SideName[(int) emDim], stFrame.nFrameIdx,i);
        // 4. Notch Dimension/Chamfer Judge
        g_pLog->DisplayMessage(_T("4. Notch_Process %s : %d, idx %d"), g_SideName[(int)emDim], stFrame.nFrameIdx, i);
        Notch_Process_Judge(emDim, stFrame, i, pOriginImage, pEdgeImage, pBinImage, rtRotateArea);
        if (!bResult)
@@ -3822,21 +3811,19 @@
            pSideData->m_bNotchInspection_Complete = TRUE;
            return FALSE;
        }
        g_pLog->DisplayMessage(_T("5. Notch_Process %s : %d, idx %d"),g_SideName[(int) emDim], stFrame.nFrameIdx,i);
        // 5. Notch Defect Inspect (Chip/Crack)
        g_pLog->DisplayMessage(_T("5. Notch_Process %s : %d, idx %d"), g_SideName[(int)emDim], stFrame.nFrameIdx, i);
        Notch_Process_Defect(emDim, stFrame, i, pOriginImage, pEdgeImage, pBinImage, rtRotateArea);
        g_pLog->DisplayMessage(_T("6. Notch_Process %s : %d, idx %d"),g_SideName[(int) emDim], stFrame.nFrameIdx,i);
        // 6. Notch Find Circle
        g_pLog->DisplayMessage(_T("6. Notch_Process %s : %d, idx %d"), g_SideName[(int)emDim], stFrame.nFrameIdx, i);
        Notch_Process_FindCircle(emDim, stFrame, i);
        // 7. Notch Process End
        g_pLog->DisplayMessage(_T("7. Notch_Process %s : %d, idx %d"),g_SideName[(int) emDim], stFrame.nFrameIdx,i);
        cvReleaseImageHeader(&pOriginImage);
        cvReleaseImage(&pEdgeImage);
        cvReleaseImage(&pBinImage);
@@ -3844,79 +3831,47 @@
    pSideData->m_bNotchInspection_Complete = TRUE;
    g_pLog->DisplayMessage(_T("7. Notch_Process End %s : %d"),g_SideName[(int) emDim], stFrame.nFrameIdx);
    return TRUE;
}
void CInspectCamera::Notch_Process_PreProcess(DimensionDir emDim, stFrameIndex stFrame, int nNotchIdx, IplImage* scr, IplImage* img_Edge, IplImage* img_Bin, CRect rtROI)
{
    if(m_pRecipe == NULL)
    if (m_pRecipe == nullptr) {
        return;
    }
    if(nNotchIdx < 0 || MAX_SIDE_NOTCH_COUNT <= nNotchIdx)
    if (nNotchIdx < 0 || nNotchIdx >= MAX_SIDE_NOTCH_COUNT) {
        return;
    }
    CString strTemp;
    // 中值滤波器大小,用于去噪,必须为奇数(若偶数会自动减1)
    const int nSmoothFilter = m_pRecipe->m_SideParam[(int)emDim].m_NotchPrm[nNotchIdx].m_nSmooth_Filter;
    int sigma1 = m_pRecipe->m_SideParam[(int) emDim].m_NotchPrm[nNotchIdx].m_nSmooth_Filter;
    int sigma2 = 7;
    // 磨边区域阈值,控制反二值化阈值,主要用于提取 Notch 边缘特征
    const int nGrindThreshold = m_pRecipe->m_SideParam[(int)emDim].m_NotchPrm[nNotchIdx].m_nGrind_Threshold;
    if(sigma1 % 2 == 0)
        sigma1 = sigma1 - 1;
    // 玻璃区域阈值,控制正二值化阈值,用于提取玻璃主体区域
    const int nGlassThreshold = m_pRecipe->m_SideParam[(int)emDim].m_NotchPrm[nNotchIdx].m_nGlass_Threshold;
    if(1 < sigma1)
        cvSmooth(scr,img_Bin,CV_MEDIAN,sigma1);
    // 确保奇数滤波器大小
    int nFilterSize = (nSmoothFilter % 2 == 0) ? (nSmoothFilter - 1) : nSmoothFilter;
//     double th1 = (double) m_pRecipe->m_SideParam[(int) emDim].m_NotchPrm[nNotchIdx].m_nGrind_Threshold * 10;
//     double th2 = 40.0;
//     int sigma=5;
//
//     cvCanny(img_Bin,img_Edge,th1,th2,sigma);
    if (nFilterSize > 1) {
        // 中值滤波降噪
        cvSmooth(scr, img_Bin, CV_MEDIAN, nFilterSize);
    }
    double th1 = (double) m_pRecipe->m_SideParam[(int) emDim].m_NotchPrm[nNotchIdx].m_nGrind_Threshold;
    // Edge图:反二值化阈值处理
    cvThreshold(scr, img_Edge, nGrindThreshold, 255, CV_THRESH_BINARY_INV);
    CString strEdgeFileName;
    strEdgeFileName.Format(_T("Notch\\Notch_%d_Edge.jpg"), nNotchIdx);
    SaveDebugImage(emDim, stFrame, img_Edge, strEdgeFileName);
    cvThreshold(scr,img_Edge,th1,255,CV_THRESH_BINARY_INV);
    strTemp.Format(_T("Notch\\Notch_%d_Edge.jpg"), nNotchIdx);
    SaveDebugImage(emDim, stFrame, img_Edge, strTemp);
    th1 = m_pRecipe->m_SideParam[(int) emDim].m_NotchPrm[nNotchIdx].m_nGlass_Threshold;
    cvThreshold(scr,img_Bin,th1,255,CV_THRESH_BINARY);
    strTemp.Format(_T("Notch\\Notch_%d_Bin.jpg"), nNotchIdx);
    SaveDebugImage(emDim, stFrame, img_Bin, strTemp);
}
void CInspectCamera::Notch_Process_PreProcess_2(DimensionDir emDim, stFrameIndex stFrame, int nNotchIdx, IplImage* scr, IplImage* img_Edge, IplImage* img_Bin, CRect rtROI)
{
    if(m_pRecipe == NULL)
        return;
    if(nNotchIdx < 0 || MAX_SIDE_NOTCH_COUNT <= nNotchIdx)
        return;
    int sigma1 = m_pRecipe->m_SideParam[(int) emDim].m_NotchPrm[nNotchIdx].m_nSmooth_Filter;
    CString strTemp;
    cvThreshold(scr,img_Edge,sigma1,255,CV_THRESH_BINARY_INV);
    double th1 = (double) m_pRecipe->m_SideParam[(int) emDim].m_NotchPrm[nNotchIdx].m_nGrind_Threshold;
    double th2 = 40.0;
    int sigma=5;
    cvCanny(img_Edge, img_Edge,th1,th2,sigma);
    strTemp.Format(_T("Notch\\Notch_%d_Edge.jpg"), nNotchIdx);
    SaveDebugImage(emDim, stFrame, img_Edge, strTemp);
    th1 = m_pRecipe->m_SideParam[(int) emDim].m_NotchPrm[nNotchIdx].m_nGlass_Threshold;
    cvThreshold(scr,img_Bin,th1,255,CV_THRESH_BINARY);
    strTemp.Format(_T("Notch\\Notch_%d_Bin.jpg"), nNotchIdx);
    SaveDebugImage(emDim, stFrame, img_Bin, strTemp);
    // Bin图:正常二值化
    cvThreshold(scr, img_Bin, nGlassThreshold, 255, CV_THRESH_BINARY);
    CString strBinFileName;
    strBinFileName.Format(_T("Notch\\Notch_%d_Bin.jpg"), nNotchIdx);
    SaveDebugImage(emDim, stFrame, img_Bin, strBinFileName);
}
void CInspectCamera::Notch_Process_Measure(DimensionDir emDim, stFrameIndex stFrame, int nNotchIdx, IplImage* scr,IplImage* img_Edge,IplImage* img_Bin, CRect rtROI)
@@ -4088,7 +4043,6 @@
                        break;
            }
            if(bEdgeCheck == FALSE && (bEdgeFind == TRUE || bBinEdgeFind == TRUE))
            {
                if(bFindEdge == FALSE && bEdgeFind == TRUE)
@@ -4156,6 +4110,21 @@
        CPoint ptDim_pxl = m_pGlassData->GetSideData(emDim)->m_ptNotch_Dimension_Edge[nNotchIdx][nMeasureIdx];
        CPoint ptChamfer_pxl = m_pGlassData->GetSideData(emDim)->m_ptNotch_Chamfer_Edge[nNotchIdx][nMeasureIdx];
        if (ptRef_pxl.x < 0 || ptRef_pxl.y < 0) {
            g_pLog->DisplayMessage(_T("[ERROR] Invalid Ref Point at Notch_Process_Calculate, NotchIdx: %d, MeasureIdx: %d, Point: (%d, %d)"), nNotchIdx, nMeasureIdx, ptRef_pxl.x, ptRef_pxl.y);
            continue;
        }
        if (ptDim_pxl.x < 0 || ptDim_pxl.y < 0) {
            g_pLog->DisplayMessage(_T("[ERROR] Invalid Dim Point at Notch_Process_Calculate, NotchIdx: %d, MeasureIdx: %d, Point: (%d, %d)"), nNotchIdx, nMeasureIdx, ptDim_pxl.x, ptDim_pxl.y);
            continue;
        }
        if (ptChamfer_pxl.x < 0 || ptChamfer_pxl.y < 0) {
            g_pLog->DisplayMessage(_T("[ERROR] Invalid Chamfer Point at Notch_Process_Calculate, NotchIdx: %d, MeasureIdx: %d, Point: (%d, %d)"), nNotchIdx, nMeasureIdx, ptChamfer_pxl.x, ptChamfer_pxl.y);
            continue;
        }
        // Dimension
        double dX_dim_um = (double)(ptRef_pxl.x - ptDim_pxl.x) * m_dPixelSizeX;
        double dY_dim_um = (double)(ptRef_pxl.y - ptDim_pxl.y) * m_dPixelSizeY;
@@ -4169,9 +4138,9 @@
        m_pGlassData->GetSideData(emDim)->m_dNotch_Chamfer_Edge_Result_um[nNotchIdx][nMeasureIdx] = dChamfer;
        if (dDimension > 2000 && dChamfer > 2000)
        {
            return FALSE;
        if (dDimension > 2000.0 && dChamfer > 2000.0) {
            g_pLog->DisplayMessage(_T("[ERROR] Abnormal Dimension & Chamfer too large at Notch_Process_Calculate, NotchIdx: %d, MeasureIdx: %d, Dimension: %.2f, Chamfer: %.2f"), nNotchIdx, nMeasureIdx, dDimension, dChamfer);
            continue;
        }
    }
@@ -4242,8 +4211,7 @@
            //选取测量研磨尺寸最大值
            if (m_nChamferOffset_um < dChamfer_um)
            {
                    m_nChamferOffset_um = dChamfer_um;
                m_nChamferOffset_um = dChamfer_um;
            }
            m_pGlassData->GetSideData(emDim)->m_dNotch_Chamfer_Edge_Result_Diff_um[nNotchIdx][nMeasureIdx] = dChamfer_std_um - dChamfer_um;
            m_pGlassData->GetSideData(emDim)->m_dNotch_Chamfer_Edge_Judge_Std_um[nNotchIdx][nMeasureIdx] = dChamfer_std_um;
@@ -4308,7 +4276,6 @@
    
    CString strTemp;
        
    int nSide = (int) emDim;
    int nThreshold = pNotchParam->m_nNotch_Inspect_Defect_Threshold;
    int nOffset = pNotchParam->m_nNotch_Inspect_Defect_Offset;
@@ -4353,8 +4320,7 @@
        vecDefectCandidateList.push_back(defectInfo);
    }
    m_pDefectControl->ExtractDefect_Notch(emDim, m_iCamera, stFrame.nScanIdx, nNotchIdx, &vecDefectCandidateList);
#else
#else
    nOffset = m_nChamferOffset_um / m_pGlassData->GetSideData(emDim)->m_dPixelSizeX;
    nOffset += pNotchParam->m_nNotch_Inspect_Defect_Offset;
    m_nChamferOffset_um = 0;
@@ -4518,27 +4484,21 @@
        CRect rtSet_Area = pNotchParam->m_rtNotch_Circle_Area_pxl[nCircleIdx];
        CRect rtRotateArea;
        if(GetAlignRotate(emDim, ptSet_TopMark, ptSet_BotMark, rtSet_Area, rtRotateArea) == FALSE)
        if (GetAlignRotate(emDim, ptSet_TopMark, ptSet_BotMark, rtSet_Area, rtRotateArea) == FALSE) {
            g_pLog->DisplayMessage(_T("Notch Circle %d Rotate Area Error"), nCircleIdx);
            continue;
        }
        CRect rtROI = rtRotateArea;
        if (rtROI.Width() <= 0 || rtROI.Height() <= 0) {
            g_pLog->DisplayMessage(_T("Invalid ROI size: %d x %d"), rtROI.Width(), rtROI.Height());
            continue;
        }
        pSideData->m_rtNotchCircleArea_pxl[nNotchIdx][nCircleIdx] = rtROI;
        VectorDouble vectorX;
        VectorDouble vectorY;
        VectorDouble vectorR;
        /*
        for(int nMeasureIdx=0; nMeasureIdx<MAX_SIDE_NOTCH_MEASURE_COUNT; nMeasureIdx++)
        {
            if(pSideData->m_nNotch_Dimension_Edge_Judge[nMeasureIdx] ==0)
                continue;
            vectorX.push_back((double) pSideData->m_ptNotch_Dimension_Edge[nNotchIdx][nMeasureIdx].x);
            vectorY.push_back((double) pSideData->m_ptNotch_Dimension_Edge[nNotchIdx][nMeasureIdx].y);
        }
        */
        // 2. Get Edge Line
        int nThreshold = m_pRecipe->m_SideParam[(int) emDim].m_nChamferLineThreshold;
@@ -4548,22 +4508,27 @@
        IplImage* pEdgeImage = cvCreateImage(cvSize(rtROI.Width(), rtROI.Height()), 8, 1);
        IplImage* pCannyEdgeImage = cvCreateImage(cvSize(rtROI.Width(), rtROI.Height()), 8, 1);
        for(int i=0; i<rtROI.Height(); i++)
            memcpy(&pEdgeImage->imageData[(i*pEdgeImage->widthStep)], (pFrameBuffer + ((rtROI.top+i)*m_nFrameWidth) + rtROI.left), rtROI.Width());
        for (int i = 0; i < rtROI.Height(); i++) {
            memcpy(&pEdgeImage->imageData[(i * pEdgeImage->widthStep)], (pFrameBuffer + ((rtROI.top + i) * m_nFrameWidth) + rtROI.left), rtROI.Width());
        }
        int sigma1 = m_pRecipe->m_SideParam[(int) emDim].m_NotchPrm[nNotchIdx].m_nSmooth_Filter;
        int nMedianFilterSize = m_pRecipe->m_SideParam[(int)emDim].m_NotchPrm[nNotchIdx].m_nSmooth_Filter;
        nMedianFilterSize = std::max(3, std::min(nMedianFilterSize, 31));
        if (nMedianFilterSize % 2 == 0) {
            nMedianFilterSize--;
        }
        cvSmooth(pEdgeImage, pEdgeImage, CV_MEDIAN, nMedianFilterSize);
        if(sigma1 % 2 == 0)
            sigma1 = sigma1 - 1;
        double th1 = 40.0;
        double th2 = std::max(1.0, std::min((double)m_pRecipe->m_SideParam[(int)emDim].m_NotchPrm[nNotchIdx].m_nGrind_Threshold * 10, 255.0));
        if(1 < sigma1)
            cvSmooth(pEdgeImage,pEdgeImage,CV_MEDIAN,sigma1);
        if (th1 > th2) {
            std::swap(th1, th2);
        }
        double th1 = (double) m_pRecipe->m_SideParam[(int) emDim].m_NotchPrm[nNotchIdx].m_nGrind_Threshold * 10;
        double th2 = 40.0;
        int sigma=5;
        g_pLog->DisplayMessage(_T("Smooth Filter: %d, Canny th1: %.1f, th2: %.1f"), nMedianFilterSize, th1, th2);
        cvCanny(pEdgeImage,pCannyEdgeImage,th1,th2,sigma);
        cvCanny(pEdgeImage, pCannyEdgeImage, th1, th2, nMedianFilterSize);
        CString strTemp;
        strTemp.Format(_T("Notch\\Notch_%d_Circle_%d_Ori.jpg"), nNotchIdx, nCircleIdx);
@@ -4647,7 +4612,6 @@
            {
                sprintf(pSideData->m_strNotchCircle_Radius_Comment[nNotchIdx][nCircleIdx], "Rad. [OK] %.1f um / %.1f um", dRadiuse_um, dResult_um);
            }
        }
    }
}
@@ -5565,8 +5529,6 @@
    return TRUE;
}
BOOL CInspectCamera::Measure_TopCorner_RCut(int iThread,DimensionDir emDim, stFrameIndex stFrame)
{
    if(m_pGlassData == NULL || m_pRecipe == NULL)
@@ -5938,13 +5900,11 @@
BOOL CInspectCamera::OnThreadEnd(int iThread, CInspectThread *pInspectThread)
{
    return TRUE;
}
BOOL CInspectCamera::OnThreadEndAll()
{
    return TRUE;
}
EdgeInspector_App/Recipe/HardwareSettings.cpp
@@ -1031,6 +1031,9 @@
        m_bUse_SaveDebugImage = rhs.m_bUse_SaveDebugImage;
        // ly,2025.07.10
        m_bSaveResultByHour = rhs.m_bSaveResultByHour;
        // ly,2025.07.07
        m_bEnableAutoCopy = rhs.m_bEnableAutoCopy;
        m_strCopyToolExePath = rhs.m_strCopyToolExePath;
@@ -1262,6 +1265,10 @@
    else if((void *)&m_nSaveImageQuality == pValue)
        str = _T("SAVEIMAGE_QUALITY");
    // ly,2025.07.10
    else if ((void*)&m_bSaveResultByHour == pValue)
        str = _T("SAVE_RESULT_BY_HOUR");
    // ly,2025.07.07
    else if ((void*)&m_bEnableAutoCopy == pValue)
        str = _T("ENABLE_AUTOCOPY");
@@ -1426,7 +1433,13 @@
    BasicInfoFile.GetItemValue((TCHAR*)(LPCTSTR)str,nTemp);
    m_bUse_SaveDebugImage = (BOOL) nTemp;
    // ly.2025.07.07
    // ly,2025.07.10
    str = GetFileString((void*)&m_bSaveResultByHour);
    if (str.IsEmpty() == TRUE)
        return FALSE;
    BasicInfoFile.GetItemValue((TCHAR*)(LPCTSTR)str, m_bSaveResultByHour, FALSE);
    // ly,2025.07.07
    str = GetFileString((void*)&m_bEnableAutoCopy);
    if (str.IsEmpty() == TRUE)
        return FALSE;
@@ -1600,7 +1613,13 @@
    Register.GetItemValue((TCHAR*)(LPCTSTR)str,nTemp);
    m_bUse_SaveDebugImage = (BOOL) nTemp;
    // ly.2025.07.07
    // ly,2025.07.10
    str = GetFileString((void*)&m_bSaveResultByHour);
    if (str.IsEmpty() == TRUE)
        return FALSE;
    Register.GetItemValue((TCHAR*)(LPCTSTR)str, m_bSaveResultByHour, FALSE);
    // ly,2025.07.07
    str = GetFileString((void*)&m_bEnableAutoCopy);
    if (str.IsEmpty() == TRUE)
        return FALSE;
@@ -1757,7 +1776,13 @@
        return FALSE;
    Register.SetItemValue((TCHAR*)(LPCTSTR)str,(int) m_bUse_SaveDebugImage);
    // ly.2025.07.07
    // ly,2025.07.10
    str = GetFileString((void*)&m_bSaveResultByHour);
    if (str.IsEmpty() == TRUE)
        return FALSE;
    Register.SetItemValue((TCHAR*)(LPCTSTR)str, (int)m_bSaveResultByHour);
    // ly,2025.07.07
    str = GetFileString((void*)&m_bEnableAutoCopy);
    if (str.IsEmpty() == TRUE)
        return FALSE;
@@ -1923,7 +1948,13 @@
        return FALSE;
    BasicInfoFile.SetItemValue((TCHAR*)(LPCTSTR)str,m_bUse_SaveDebugImage);
    // ly.2025.07.07
    // ly,2025.07.10
    str = GetFileString((void*)&m_bSaveResultByHour);
    if (str.IsEmpty() == TRUE)
        return FALSE;
    BasicInfoFile.SetItemValue((TCHAR*)(LPCTSTR)str, (int)m_bSaveResultByHour);
    // ly,2025.07.07
    str = GetFileString((void*)&m_bEnableAutoCopy);
    if (str.IsEmpty() == TRUE)
        return FALSE;
EdgeInspector_App/Recipe/HardwareSettings.h
@@ -204,6 +204,9 @@
    BOOL                        m_bUse_SaveDebugImage;
public:
    BOOL                        m_bSaveResultByHour;
public:
    BOOL                        m_bEnableAutoCopy;
    CString                        m_strCopyToolExePath;
    CString                        m_strCopyToolConfigPath;
EdgeInspector_App/View/ViewMain_HWSetting.cpp
@@ -83,6 +83,8 @@
    DDX_Check(pDX,IDC_CHECK_USE_SAVE_DEBUG_IMAGE,m_pDlgHDSettingParm->m_bUse_SaveDebugImage);    
    DDX_Check(pDX, IDC_CHECK_USE_SAVE_ALL_DMP, g_bUse_SaveAllDMP);
    DDX_Check(pDX, IDC_CHECK_SAVE_RESULT_BY_HOUR, m_pDlgHDSettingParm->m_bSaveResultByHour);        // ly,2025.07.10
    DDX_Check(pDX, IDC_CHECK_ENABLE_AUTO_COPY, m_pDlgHDSettingParm->m_bEnableAutoCopy);                // ly,2025.07.07
    DDX_Text(pDX, IDC_EDIT_COPY_TOOL_EXE_PATH, m_pDlgHDSettingParm->m_strCopyToolExePath);
    DDX_Text(pDX, IDC_EDIT_COPY_TOOL_CONFIG_PATH, m_pDlgHDSettingParm->m_strCopyToolConfigPath);
EdgeInspector_App/resource.h
Binary files differ