首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

OpenCV 實戰:番茄葉片面積計算完整流程(下)— 大津法閾值、輪廓過濾、面積計算與標定

     編輯:關於C語言

核心算法:大津法自適應閾值

傳統 Canny/Sobel 需均勻光照,陰影干擾大。本專案採用 大津法:計算灰度直方圖,遍歷閾值最大化類間方差,獲得最佳二值化分割點,誤差控制在 1% 以內。

int Otsu(IplImage* src) {
    float hist[256] = {0};
    int h = src->height, w = src->width;
    // 統計灰度分布
    for (int y = 0; y < h; y++) {
        uchar* p = (uchar*)src->imageData + y * src->widthStep;
        for (int x = 0; x < w; x++) hist[p[x]]++;
    }
    // 歸一化
    int sz = h * w;
    for (int i = 0; i < 256; i++) hist[i] /= sz;
    // 遍歷閾值最大化類間方差
    float avg = 0; for (int i = 0; i < 256; i++) avg += i * hist[i];
    float maxVar = 0; int thresh = 0;
    float w = 0, u = 0;
    for (int i = 0; i < 256; i++) {
        w += hist[i];
        u += i * hist[i];
        float t = avg * w - u;
        float var = t * t / (w * (1 - w));
        if (var > maxVar) { maxVar = var; thresh = i; }
    }
    return thresh;
}

完整處理流水線

void ProcessImage() {
    IplImage* bin = cvCreateImage(cvGetSize(gray), 8, 1);
    int thresh = Otsu(gray);
    cvThreshold(gray, bin, thresh, 255, CV_THRESH_BINARY);
    FillInternalContours(bin, filterThresh);  // 面積過濾填充
    cvNamedWindow("Result"); cvShowImage("Result", bin);
    
    // 面積統計
    CvMemStorage* storage = cvCreateMemStorage(0);
    CvSeq* contours = 0;
    cvFindContours(bin, storage, &contours, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
    cvDrawContours(bin, contours, CV_RGB(255,255,255), CV_RGB(255,255,255), 2, CV_FILLED, 8);
    
    double maxArea = 0, secMax = 0;
    for (CvSeq* c = contours; c; c = c->h_next) {
        for (CvSeq* ic = c->v_next; ic; ic = ic->h_next) {
            double a = fabs(cvContourArea(ic, CV_WHOLE_SEQ));
            if (a <= filterThresh)  // 小噪聲填充白色
                cvDrawContours(bin, ic, CV_RGB(255,255,255), CV_RGB(255,255,255), 0, CV_FILLED, 8);
            if (a > maxArea) { secMax = maxArea; maxArea = a; }
            else if (a > secMax) secMax = a;
        }
    }
    // 顯示結果
    SetDlgItemText(IDC_EDIT1, FormatArea(maxArea));
    SetDlgItemText(IDC_EDIT2, FormatArea(secMax));
    cvReleaseMemStorage(&storage);
    cvReleaseImage(&bin);
}

關鍵參數

  • filterThresh:Combo Box 選擇,建議 5000(視圖片分辨率調整)
  • 參考物:一角硬幣固定面積 → 像素/實際面積換算系數
  • 最大輪廓 = 葉片,次大 = 硬幣(參考物)

工程收獲

  1. 大津法在非均勻光照下優於固定閾值/邊緣檢測
  2. 輪廓層級關係(外部/內部)配合面積過濾,有效去噪
  3. OpenCV C 介面雖繁瑣,但算法豐富,避免重複造輪子
  4. MFC + OpenCV 混合開發:UI 用 MFC,算法用 OpenCV,職責清晰

完整代碼已在上下兩篇覆蓋,可直接構建葉片面積測量工具。

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