首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

C++ 圖像處理:石英片劃痕/殘缺自動分類檢測方案 (MFC + OpenCV)

     編輯:程式設計綜合問答

需求分析

  • 輸入:矩形石英片圖像 (工業相機拍攝、均勻背光)
  • 輸出:三類判定 — **正常**、**有劃痕**、**有殘缺**、劃痕+殘缺
  • 環境:MFC 對話框程式,C++,建議引入 OpenCV 4.x

整體檢測流程


1. 圖像獲取 → 2. 預處理 → 3. ROI 定位 → 4. 特徵提取 → 5. 缺陷分類 → 6. 結果輸出

關鍵步驟實現

1. 預處理:統一光照、去噪


cv::Mat preprocess(const cv::Mat& src) {
    cv::Mat gray, blur, binary;
    cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);
    // 自適應直方圖均衡化 (CLAHE) 消除光照不均
    cv::Ptr clahe = cv::createCLAHE(2.0, cv::Size(8,8));
    clahe->apply(gray, gray);
    // 高斯模糊去噪
    cv::GaussianBlur(gray, blur, cv::Size(5,5), 0);
    // 自適應二值化 (OTSU 或局部自適應)
    cv::threshold(blur, binary, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
    return binary;
}

2. ROI 定位:提取石英片區域


cv::Rect locateROI(const cv::Mat& binary) {
    std::vector> contours;
    cv::findContours(binary, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
    double maxArea = 0;
    cv::Rect bestRect;
    for (auto& cnt : contours) {
        double area = cv::contourArea(cnt);
        if (area > maxArea && area > 1000) {  // 面積閾值濾除噪點
            maxArea = area;
            bestRect = cv::boundingRect(cnt);
        }
    }
    // 可選:最小外接矩形旋轉校正
    // cv::RotatedRect rrect = cv::minAreaRect(cnt);
    // cv::Mat rotMat = cv::getRotationMatrix2D(rrect.center, rrect.angle, 1.0);
    // cv::warpAffine(src, aligned, rotMat, src.size());
    return bestRect;
}

3. 劃痕檢測:形態學 + 連通域分析


bool detectScratch(const cv::Mat& roiGray, const cv::Mat& roiBinary) {
    // 形態學開運算去除雜訊
    cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3,3));
    cv::Mat clean;
    cv::morphologyEx(roiBinary, clean, cv::MORPH_OPEN, kernel);
    
    // 連通域分析
    std::vector> contours;
    cv::findContours(clean, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
    
    for (auto& cnt : contours) {
        double area = cv::contourArea(cnt);
        cv::Rect r = cv::boundingRect(cnt);
        double aspectRatio = (double)r.width / r.height;
        // 劃痕特徵:細長、面積小、灰度值低於背景
        if (area > 10 && area < 500 && aspectRatio > 5.0) {
            // 進一步驗證:灰度均值
            cv::Mat mask = cv::Mat::zeros(roiGray.size(), CV_8UC1);
            cv::drawContours(mask, std::vector>{cnt}, 0, 255, -1);
            cv::Scalar meanVal = cv::mean(roiGray, mask);
            if (meanVal[0] < 100) return true;  // 判定為劃痕
        }
    }
    return false;
}

4. 殘缺檢測:邊緣輪廓比對 / 缺口檢測


bool detectDefect(const cv::Mat& roiBinary, const cv::Rect& expectedRect) {
    // 方法一:標準矩形模板匹配
    cv::Mat templateImg = cv::Mat::ones(expectedRect.height, expectedRect.width, CV_8UC1) * 255;
    cv::Mat diff;
    cv::absdiff(roiBinary, templateImg, diff);
    // 統計差異像素
    int diffPixels = cv::countNonZero(diff);
    if (diffPixels > EXPECTED_DEFECT_THRESHOLD) return true;
    
    // 方法二:凸包缺陷檢測
    std::vector contour;
    cv::findContours(roiBinary, contour, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
    std::vector hull;
    cv::convexHull(contour[0], hull);
    std::vector defects;
    cv::convexityDefects(contour[0], hull, defects);
    for (auto& d : defects) {
        float depth = d[3] / 256.0f;  // 缺口深度
        if (depth > 10.0f) return true;  // 存在明顯缺口
    }
    return false;
}

5. 綜合判定邏輯


enum ClassResult { NORMAL, SCRATCH_ONLY, DEFECT_ONLY, SCRATCH_AND_DEFECT };

ClassResult classify(const cv::Mat& src) {
    cv::Mat binary = preprocess(src);
    cv::Rect roiRect = locateROI(binary);
    cv::Mat roiGray = src(roiRect);
    cv::Mat roiBinary = binary(roiRect);
    
    bool hasScratch = detectScratch(roiGray, roiBinary);
    bool hasDefect = detectDefect(roiBinary, roiRect);
    
    if (hasScratch && hasDefect) return SCRATCH_AND_DEFECT;
    if (hasScratch) return SCRATCH_ONLY;
    if (hasDefect) return DEFECT_ONLY;
    return NORMAL;
}

MFC 整合要點


// 對話框類成員
cv::Mat m_srcImage;  // 當前圖像
CStatic m_picCtrl;   // 圖片顯示控件 (IDC_PIC)

// 顯示 OpenCV Mat 到 CStatic
void ShowMatInStatic(const cv::Mat& img, CStatic& ctrl) {
    if (img.empty()) return;
    cv::Mat rgb;
    if (img.channels() == 1) cv::cvtColor(img, rgb, cv::COLOR_GRAY2BGR);
    else if (img.channels() == 3) cv::cvtColor(img, rgb, cv::COLOR_BGR2RGB);
    else return;
    
    CRect rect;
    ctrl.GetClientRect(&rect);
    cv::Mat display;
    cv::resize(rgb, display, cv::Size(rect.Width(), rect.Height()));
    
    CClientDC dc(&ctrl);
    BITMAPINFO bmi = {0};
    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmi.bmiHeader.biWidth = display.cols;
    bmi.bmiHeader.biHeight = -display.rows;  // 自上而下
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biBitCount = 24;
    bmi.bmiHeader.biCompression = BI_RGB;
    
    SetDIBitsToDevice(dc.GetSafeHdc(), 0, 0, display.cols, display.rows,
                      0, 0, 0, display.rows, display.data, &bmi, DIB_RGB_COLORS);
}

// 按鈕點擊處理
void OnBnClickedBtnDetect() {
    CFileDialog dlg(TRUE, _T("bmp"), NULL, OFN_FILEMUSTEXIST, _T("圖片|*.bmp;*.jpg;*.png||"));
    if (dlg.DoModal() == IDOK) {
        m_srcImage = cv::imread(CT2A(dlg.GetPathName()));
        if (!m_srcImage.empty()) {
            ShowMatInStatic(m_srcImage, m_picCtrl);
            ClassResult result = classify(m_srcImage);
            CString msg;
            switch(result) {
                case NORMAL: msg = _T("正常"); break;
                case SCRATCH_ONLY: msg = _T("有劃痕"); break;
                case DEFECT_ONLY: msg = _T("有殘缺"); break;
                case SCRATCH_AND_DEFECT: msg = _T("劃痕+殘缺"); break;
            }
            AfxMessageBox(_T("檢測結果: ") + msg);
        }
    }
}

OpenCV 依賴配置 (VS2019/2022)

  1. NuGet 安裝:`Install-Package OpenCV -Version 4.8.0`
  2. 或手動:屬性 → VC++ 目錄 → 包含目錄添加 `opencv/build/include`,庫目錄添加 `opencv/build/x64/vc16/lib`
  3. 鏈接器 → 輸入 → 附加依賴項:`opencv_world480.lib` (Release) / `opencv_world480d.lib` (Debug)
  4. 運行時將 `opencv_world480.dll` 放在 exe 同級目錄或系統 PATH

進階優化方向

  • 深度學習:YOLOv8-seg / Mask R-CNN 實例分割,標註數據訓練,精度遠超傳統算法
  • 多光源融合:環形光 + 同軸光 + 暗場光,分離表面劃痕與邊緣殘缺
  • 亞像素邊緣定位:提升殘缺尺寸測量精度至 0.01mm
  • Halcon / VisionPro:商業視覺庫,開發效率高、算子優化好、技術支援強

結論:基於 OpenCV 的傳統圖像處理 (形態學、輪廓分析、模板匹配) 可快速實現石英片劃痕/殘缺分類,**MFC + OpenCV 是經典可行組合**。量產項目建議引入深度學習提升魯棒性。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved