You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于颜色而非形状的多图像OpenCV模型训练:香蕉成熟度检测器开发技术问询

解决香蕉成熟度检测的SVM训练问题

Hey there, let's fix up your SVM training code so it uses color features (since that's what you care about, not grayscale shapes) and gets your ripeness detector working. Here's a step-by-step breakdown with modified code:

1. 先修正特征提取逻辑:用颜色特征代替灰度图

Right now your code is leaning on grayscale images for prediction, but we need to focus on color data. Let's switch to HSV color space—it's perfect for this task because the Hue channel directly captures the core color difference between unripe (green), ripe (yellow), and overripe (brown) bananas. We'll extract a histogram of the Hue channel as our feature, since it's simple and effective for color-based classification.

First, add a helper function to pull color features from an image:

// Extract color features (Hue channel histogram) from a color image
Mat extractColorFeatures(const Mat& img) {
    Mat hsv;
    cvtColor(img, hsv, COLOR_BGR2HSV); // Convert OpenCV's default BGR to HSV

    // Isolate the Hue channel (index 0 in HSV)
    vector<Mat> hsv_channels;
    split(hsv, hsv_channels);
    Mat hue = hsv_channels[0];

    // Define histogram settings: 32 bins covers the full 0-179 Hue range (OpenCV's 8-bit HSV)
    int histSize = 32;
    float hueRange[] = {0, 180};
    const float* ranges = {hueRange};
    Mat hist;

    // Calculate the Hue channel histogram
    calcHist(&hue, 1, 0, Mat(), hist, 1, &histSize, &ranges, true, false);

    // Normalize the histogram to make it scale-invariant (works for different image sizes)
    normalize(hist, hist, 0, 1, NORM_MINMAX, -1, Mat());

    // Flatten the 2D histogram into a 1D feature vector for SVM input
    return hist.reshape(1, 1);
}

2. 准备训练数据并完成SVM训练

Next, we need to convert all your training images into feature vectors and format them correctly for OpenCV's SVM. Replace the empty training section in your main function with this:

int main(int argc, const char** argv) {
    Mat frame;
    //-- 1. Load the cascades
    if (!banana_cascade.load(banana_cascade_name)) {
        printf("--(!)Error loading cascade\n");
        return -1;
    };
    string fileName = string("resources//csv.ext");
    vector<Mat> images; // Training images (color)
    vector<int> labels; // Corresponding ripeness labels
    read_csv(fileName, images, labels);

    // Check if training data loaded correctly
    if (images.empty()) {
        printf("--(!)No training images found\n");
        return -1;
    }

    // Initialize training data matrix (each row = one image's feature vector)
    int featureCount = extractColorFeatures(images[0]).cols;
    Mat trainingData(images.size(), featureCount, CV_32F);
    Mat trainingLabels(images.size(), 1, CV_32S);

    // Fill training data and labels
    for (size_t i = 0; i < images.size(); i++) {
        Mat features = extractColorFeatures(images[i]);
        features.copyTo(trainingData.row(i));
        trainingLabels.at<int>(i) = labels[i];
    }

    // Configure SVM parameters for multi-class classification
    model = SVM::create();
    model->setType(SVM::C_SVC); // Multi-class support
    model->setKernel(SVM::RBF); // RBF kernel works well for color feature patterns
    model->setC(10.0); // Regularization parameter (adjust based on dataset size)
    model->setGamma(0.5); // Gamma value for RBF kernel

    // Train the SVM
    Ptr<TrainData> trainData = TrainData::create(trainingData, ROW_SAMPLE, trainingLabels);
    model->train(trainData);

    // Optional: Save the trained model to avoid retraining every time
    model->save("banana_ripeness_svm.xml");

    //-- 3. Run detection loop (your existing code, with fixes below)
    while (true) {
        frame = imread("banana_example.jpg");
        if (!frame.empty()) {
            detectAndDisplayBanana(frame);
        } else {
            printf("No banana image!");
            break;
        }
        int c = waitKey(10);
        if ((char)c == 'c') {
            break;
        }
    }
    return 0;
}

3. 修正预测逻辑:用颜色区域而非灰度图

Your detectAndDisplayBanana function was using a grayscale crop for prediction—we need to use the color region instead. Update that function to match our feature extraction pipeline:

void detectAndDisplayBanana(Mat frame) {
    string ripeStage;
    std::vector<Rect> bananas;
    Mat frame_gray;
    cvtColor(frame, frame_gray, COLOR_BGR2GRAY);
    equalizeHist(frame_gray, frame_gray);
    //-- Detect bananas using the cascade classifier
    banana_cascade.detectMultiScale(frame_gray, bananas, 1.1, 2, 0 | CASCADE_SCALE_IMAGE, Size(30, 30));

    for (size_t i = 0; i < bananas.size(); i++) {
        Rect banana_i = bananas[i];
        // Extract the COLOR banana region from the original frame (not grayscale!)
        Mat banana_color = frame(banana_i);
        Mat banana_resized;
        // Resize to match training image dimensions (critical for consistent features)
        resize(banana_color, banana_resized, Size(im_width, im_height), 1.0, 1.0, INTER_CUBIC);

        // Extract color features and predict ripeness
        Mat features = extractColorFeatures(banana_resized);
        float raw_prediction = model->predict(features);
        int ripeLabel = static_cast<int>(raw_prediction);

        // Map label to ripeness stage
        switch (ripeLabel) {
            case 1:
                ripeStage = "Unripe";
                break;
            case 2:
                ripeStage = "Ripe";
                break;
            case 3:
                ripeStage = "Overripe";
                break;
            default:
                ripeStage = "Unknown";
        }
        string box_text = format("%s", ripeStage.c_str());
        cout << box_text << endl;

        // Optional: Draw bounding box and label on the frame for visualization
        rectangle(frame, banana_i, Scalar(0, 255, 0), 2);
        putText(frame, box_text, Point(banana_i.x, banana_i.y - 10), FONT_HERSHEY_SIMPLEX, 0.7, Scalar(0, 255, 0), 2);
    }
    //-- Show the result
    imshow(window_name, frame);
}

4. 关键优化建议

  • Tune SVM Parameters: If predictions are inconsistent, replace manual parameter setting with model->trainAuto(trainData)—this lets OpenCV automatically find optimal C and Gamma values for your dataset.
  • Expand Feature Set: You can add the Saturation channel histogram to your feature vector for better accuracy (just modify extractColorFeatures to include it).
  • Consistent Image Sizes: Ensure all training images are the same size. If not, modify your read_csv function to resize images as they're loaded.

内容的提问来源于stack exchange,提问作者TheCulprit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 10:12:35