超像素提取加svm训练,鼠标点击选择标签(左键为正样本,右键为负样本)

自己写的demo记个笔记用

替换掉图片路径和保存路径svm训练的模型路径就可以跑

效果我觉的不行,目前也不知到如何优化、希望有大佬可以给点建议

流程

处理超像素

选择超像素

提取HOG、颜色直方图、LBP直方图特征

训练

预测

cpp 复制代码
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/ximgproc.hpp>
#include <opencv2/ml.hpp>

using namespace cv;
using namespace std;
using namespace cv::ml;
Mat g_LabelSlic;  
Mat g_MaskSlic;
int g_NumSuperPixels;

//目标图像和标签
multimap<int, Mat>g_mapImgSuperPixelsOfTarget;
multimap<int, Mat>g_mapImgSuperPixelsOfNonTarget;

struct MouseCallbackData {
    Mat img;      // 原始图像
    Mat imgClone; // 克隆图像
};

Mat GetSuperPixelsByLabel(const Mat& img, int superpixelID)
{
    int minX = img.cols, minY = img.rows, maxX = 0, maxY = 0;

    for (int y = 0; y < img.rows; y++) {
        for (int x = 0; x < img.cols; x++) {
            if (g_LabelSlic.at<int>(y, x) == superpixelID) {
                // 更新边界框坐标
                if (x < minX) minX = x;
                if (y < minY) minY = y;
                if (x > maxX) maxX = x;
                if (y > maxY) maxY = y;
            }
        }
    }

    // 确保边界框有效
    if (minX > maxX || minY > maxY) {
        cout << "未找到有效的超像素!" << endl;
        return Mat();  
    }
    
    
    Rect superPixelBoundingBox(minX, minY, maxX - minX + 1, maxY - minY + 1);
    Mat croppedRegion = img(superPixelBoundingBox).clone();  

    
    for (int y = 0; y < croppedRegion.rows; y++) {
        for (int x = 0; x < croppedRegion.cols; x++) {
            int origX = x + minX;
            int origY = y + minY;
            if (g_LabelSlic.at<int>(origY, origX) != superpixelID) {
                croppedRegion.at<Vec3b>(y, x) = Vec3b(0, 0, 0); 
            }
        }
    }
    return croppedRegion; 
}


vector<float> GetHOGDescriptor(Mat img)
{
    if (img.empty()) {
        std::cerr << "输入图像为空!" << std::endl;
        return {};
    }

    resize(img, img, Size(64, 64));

    Mat imgGray;
    cvtColor(img, imgGray, COLOR_BGR2GRAY);

    HOGDescriptor hog(
        Size(32, 32),  // 图像窗口大小
        Size(8, 8),   // 块大小
        Size(4, 4),     // 块步长
        Size(4, 4),     // cell 大小
        9               // 梯度方向 bins 数
    );

    vector<float> descriptors;
    hog.compute(imgGray, descriptors);
    return descriptors;
}

// 提取 LBP 特征及其直方图
void ExtractLBPFeatures(Mat img, Mat& lbp, Mat& lbpHist)
{
    resize(img, img, Size(64, 64));
    // 转换为灰度图
    Mat gray;
    if (img.channels() == 3) {
        cvtColor(img, gray, COLOR_BGR2GRAY);
    }
    else {
        gray = img.clone();
    }

    // 初始化 LBP 特征矩阵
    lbp = Mat(gray.size(), CV_8UC1, Scalar(0));

    for (int y = 1; y < gray.rows - 1; y++) {
        for (int x = 1; x < gray.cols - 1; x++) {
            uchar center = gray.at<uchar>(y, x);
            uchar code = 0;
            code |= (gray.at<uchar>(y - 1, x - 1) > center) << 7; // 128
            code |= (gray.at<uchar>(y - 1, x) > center) << 6;     // 64
            code |= (gray.at<uchar>(y - 1, x + 1) > center) << 5; // 32
            code |= (gray.at<uchar>(y, x + 1) > center) << 4;     // 16
            code |= (gray.at<uchar>(y + 1, x + 1) > center) << 3; // 8
            code |= (gray.at<uchar>(y + 1, x) > center) << 2;     // 4
            code |= (gray.at<uchar>(y + 1, x - 1) > center) << 1; // 2
            code |= (gray.at<uchar>(y, x - 1) > center);           // 1

            lbp.at<uchar>(y, x) = code; // 将计算的 LBP 值存储
        }
    }

    // 计算 LBP 直方图
    const int histSize = 256; // LBP 特征值的范围
    const float range[] = { 0, 256 };
    const float* histRange = { range };

    calcHist(&lbp, 1, 0, Mat(), lbpHist, 1, &histSize, &histRange);
    normalize(lbpHist, lbpHist);
}

Mat ExtractHSVHistogram(Mat img)
{
    resize(img, img, Size(64, 64));
    Mat hsv_img;
    cvtColor(img, hsv_img, cv::COLOR_BGR2HSV); 

    vector<cv::Mat> hsv_planes;
    split(hsv_img, hsv_planes);  // 分割 H, S, V 通道

    int histSize = 256;  // 直方图分为 256 个区间
    float h_range[] = { 0, 180 };  // H 通道范围是 0-180
    float s_v_range[] = { 0, 256 };  // S 和 V 通道范围是 0-256

    const float* h_histRange = { h_range };
    const float* sv_histRange = { s_v_range };

    Mat h_hist, s_hist, v_hist;
    calcHist(&hsv_planes[0], 1, 0, cv::Mat(), h_hist, 1, &histSize, &h_histRange, true, false);  // H 通道直方图
    calcHist(&hsv_planes[1], 1, 0, cv::Mat(), s_hist, 1, &histSize, &sv_histRange, true, false);  // S 通道直方图
    calcHist(&hsv_planes[2], 1, 0, cv::Mat(), v_hist, 1, &histSize, &sv_histRange, true, false);  // V 通道直方图

    // 合并 H, S, V 直方图
    Mat hist;
    hconcat(h_hist, s_hist, hist);
    hconcat(hist, v_hist, hist);
    Mat normalizedHist;
    normalize(hist, normalizedHist);
    return normalizedHist;  // 返回归一化后的直方图
}




void OnMouse(int event, int x, int y, int flags, void* param)
{
    MouseCallbackData* data = static_cast<MouseCallbackData*>(param);
    Mat& img = data->img;
    Mat& imgClone = data->imgClone;
    
    int mouseButtonClicked = 0;
    if (event == EVENT_LBUTTONDOWN) {
        mouseButtonClicked = 1;
        if (x >= 0 && x < img.cols && y >= 0 && y < img.rows) {
            int superpixelID = g_LabelSlic.at<int>(y, x);
            cout << "点击目标超像素ID: " << superpixelID << endl;
            g_mapImgSuperPixelsOfTarget.insert({ mouseButtonClicked, GetSuperPixelsByLabel(img, superpixelID) });
            circle(imgClone, Point(x, y), 3, Scalar(0, 255, 0), -1);
            imshow("Imageview", imgClone);
        }
    }
    else if (event == EVENT_RBUTTONDOWN) {
        mouseButtonClicked = 2;
        if (x >= 0 && x < img.cols && y >= 0 && y < img.rows) {
            int superpixelID = g_LabelSlic.at<int>(y, x);
            cout << "点击非目标超像素ID: " << superpixelID << endl;
            g_mapImgSuperPixelsOfNonTarget.insert({ mouseButtonClicked, GetSuperPixelsByLabel(img, superpixelID) });
            circle(imgClone, Point(x, y), 3, Scalar(0, 0, 255), -1);
            imshow("Imageview", imgClone);
        }
    }
}

void SvmClassifier(
    multimap<int, vector<float>> HOGDescriptorOFTarget,
    multimap<int, Mat> lbpHistOFTarget,
    multimap<int, Mat> hsvHistOFTarget,
    multimap<int, vector<float>> HOGDescriptorOFNonTarget,
    multimap<int, Mat> lbpHistOFNonTarget,
    multimap<int, Mat> hsvHistOFNonTarget)
{
    cout << "star svm model train ..." << endl;
    Mat featureList;
    Mat labels;

    for (const auto& pair : HOGDescriptorOFTarget) {
        
        Mat hogMat(pair.second, CV_32F);
        normalize(hogMat, hogMat, 0, 1, NORM_MINMAX);
        hogMat = hogMat.reshape(1, 1);
       
        Mat lbpHist = lbpHistOFTarget.find(pair.first)->second;
        lbpHist.convertTo(lbpHist, CV_32F);
        lbpHist = lbpHist.reshape(1, 1);  // 展平

        
        Mat hsvHist = hsvHistOFTarget.find(pair.first)->second;
        hsvHist.convertTo(hsvHist, CV_32F);
        hsvHist = hsvHist.reshape(1, 1);  // 展平

       
        Mat combinedFeature;
        hconcat(hogMat, lbpHist, combinedFeature);  
        hconcat(combinedFeature, hsvHist, combinedFeature);  

       
        featureList.push_back(combinedFeature);
        labels.push_back(1); 
    }

    for (const auto& pair : HOGDescriptorOFNonTarget) {

        Mat hogMat(pair.second, CV_32F);
        normalize(hogMat, hogMat, 0, 1, NORM_MINMAX); 
        hogMat = hogMat.reshape(1, 1);

        Mat lbpHist = lbpHistOFNonTarget.find(pair.first)->second;
        lbpHist.convertTo(lbpHist, CV_32F);
        lbpHist = lbpHist.reshape(1, 1); 


        Mat hsvHist = hsvHistOFNonTarget.find(pair.first)->second;
        hsvHist.convertTo(hsvHist, CV_32F);
        hsvHist = hsvHist.reshape(1, 1); 


        Mat combinedFeature;
        hconcat(hogMat, lbpHist, combinedFeature);
        hconcat(combinedFeature, hsvHist, combinedFeature);

        featureList.push_back(combinedFeature);
        labels.push_back(0);  
    }
    
    Mat trainingData;
    vconcat(featureList, trainingData); 

    //Mat labelsMat;// = Mat(labels).reshape(1, 1);
    Mat labelsMat = labels;

    trainingData.convertTo(trainingData, CV_32F);
    labelsMat.convertTo(labelsMat, CV_32S);


    Ptr<SVM> svm = SVM::create();
    svm->setKernel(SVM::RBF);
    svm->setType(SVM::C_SVC);
    svm->trainAuto(trainingData,ROW_SAMPLE,labelsMat,10);
    /*svm->setC(1.5);
    svm->setGamma(0.5);
    svm->setTermCriteria(cv::TermCriteria(cv::TermCriteria::MAX_ITER, 200, 1e-6));
    svm->train(trainingData, ROW_SAMPLE, labelsMat);*/
    svm->save("C:/Users/svs/Desktop/svm_model2.xml"); // 保存训练好的模型
}


void DrawSuperpixelRegion(Mat& img, int targetLabel) {
    for (int y = 0; y < img.rows; y++) {
        for (int x = 0; x < img.cols; x++) {
            if (g_LabelSlic.at<int>(y, x) == targetLabel) {
                img.at<Vec3b>(y, x) = Vec3b(0, 255, 0); 
            }
        }
    }
}


int main() {

    Mat img = imread("C:/Users/svs/Desktop/test.jpeg");
    if (img.empty()) {
        cerr << "无法读取图片!" << endl;
        return -1;
    }

    //图片进行超像素分割
    int region_size = 50;
    float ruler = 20.0;
    int num_iterations = 100;
  
    Ptr<ximgproc::SuperpixelSLIC> slic = ximgproc::createSuperpixelSLIC(img, ximgproc::SLICO,region_size, ruler);
    slic->iterate(num_iterations);

    
    slic->getLabels(g_LabelSlic);
    slic->getLabelContourMask(g_MaskSlic);
    g_NumSuperPixels = slic->getNumberOfSuperpixels();
    
    Mat imgWithContours;
    img.copyTo(imgWithContours, ~g_MaskSlic);
    imshow("Superpixel Contours", imgWithContours);

    cout << "请点击选择一个超像素区域...\n";
    namedWindow("Imageview", WINDOW_AUTOSIZE);
    imshow("Image", img);
    Mat imgClone = img.clone();
    imshow("Imageview", imgClone);
    MouseCallbackData data;
    data.img = img;
    data.imgClone = imgClone;
    setMouseCallback("Imageview", OnMouse, &data);
    
    // 等待用户按 'q' 退出
    while (true) {
        const char key = waitKey(0);
        if (key == 'q') {
            break;
        }
    }

    /*提取获取图片的特征*/
	multimap<int, vector<float> >HOGDescriptorOFTarget;
	multimap<int, Mat >lbpHistOFTarget;
	multimap<int, Mat >hsvHistOFTarget;


    multimap<int, vector<float> >HOGDescriptorOFNonTarget;
    multimap<int, Mat>lbpHistOFNonTarget;
    multimap<int, Mat>hisHistOFNonTarget;

    for (const auto& pair : g_mapImgSuperPixelsOfTarget) 
    {
        vector<float> vectorHOGDescriptor = GetHOGDescriptor(pair.second);
        HOGDescriptorOFTarget.insert({ pair.first, vectorHOGDescriptor});
        Mat lbpImg, lbpHist;
        ExtractLBPFeatures(pair.second, lbpImg, lbpHist);
        lbpHistOFTarget.insert({ pair.first, lbpHist });
        Mat hsvHist;
        hsvHist = ExtractHSVHistogram(pair.second);
        hsvHistOFTarget.insert({ pair.first,hsvHist });
        /*imshow("true", pair.second);
        waitKey(0);*/
    }

    for (const auto& pair : g_mapImgSuperPixelsOfNonTarget)
    {
        vector<float> vectorHOGDescriptor = GetHOGDescriptor(pair.second);
        HOGDescriptorOFNonTarget.insert({ pair.first,vectorHOGDescriptor });
        Mat lbpImg, lbpHist;
        ExtractLBPFeatures(pair.second, lbpImg, lbpHist);
        lbpHistOFNonTarget.insert({ pair.first, lbpHist });
        Mat hsvHist;
        hsvHist = ExtractHSVHistogram(pair.second);
        hisHistOFNonTarget.insert({ pair.first,hsvHist});
       /* imshow("false", pair.second);
        waitKey(0);*/
    }


    SvmClassifier(HOGDescriptorOFTarget, lbpHistOFTarget, hsvHistOFTarget,
        HOGDescriptorOFNonTarget,lbpHistOFNonTarget, hisHistOFNonTarget);


    Ptr<SVM> svm = SVM::load("C:/Users/svs/Desktop/svm_model2.xml");

    if (svm.empty()) {
        std::cerr << "模型加载失败!\n";
        return -1;
    }


    //进行预测
    cout << "star predict ...\n";
    multimap<int, Mat> testSuperPixelsImg;
    vector<float> testHOGDescriptor;
    Mat testLbpHist;
    Mat testHsvHist;
    
	// 遍历每个超像素块
    for (int superpixelID = 0; superpixelID < g_NumSuperPixels; ++superpixelID) {
        Mat superpixelRegion = GetSuperPixelsByLabel(img, superpixelID);
        testSuperPixelsImg.insert({ superpixelID,  superpixelRegion });
    }
    for (const auto& pairs : testSuperPixelsImg) {
        /*imshow("test", pairs.second);
        waitKey(0);*/
        testHOGDescriptor = GetHOGDescriptor(pairs.second);
        Mat lbpImg;
        ExtractLBPFeatures(pairs.second, lbpImg,testLbpHist);
        testHsvHist = ExtractHSVHistogram(pairs.second);
        if (testHOGDescriptor.empty())
        {
            cerr << "HOG特征为空,超像素ID: \n";
        }
        if (testLbpHist.empty())
        {
            cerr << "LBP特征为空,超像素ID: \n";
        }
        if(testHsvHist.empty())
        {
            cerr << "Hsv直方图为空,超像素ID:\n";
        }

        Mat testHogMat(testHOGDescriptor, CV_32F);
        normalize(testHogMat, testHogMat, 0, 1, NORM_MINMAX);
        testHogMat = testHogMat.reshape(1, 1);

        testLbpHist.convertTo(testLbpHist, CV_32F);
        testLbpHist = testLbpHist.reshape(1, 1);  


        testHsvHist.convertTo(testHsvHist, CV_32F);
        testHsvHist = testHsvHist.reshape(1, 1);  


        Mat combinedFeature;
        hconcat(testHogMat, testLbpHist, combinedFeature);
        hconcat(combinedFeature, testHsvHist, combinedFeature);

       
        // 进行预测
        float response;
        response = svm->predict(combinedFeature);
        
        if (response == 1) 
        {
            
        }
        else 
        {
            DrawSuperpixelRegion(img, pairs.first);
        }
        
    }

    imshow("Image with Green Superpixel", img);
    cout << "predict successful\n";
    waitKey(0);
    destroyAllWindows();

    return 0;
}
相关推荐
西猫雷婶42 分钟前
python学opencv|读取图像(二十一)使用cv2.circle()绘制圆形进阶
开发语言·python·opencv
湫ccc1 小时前
《Opencv》基础操作详解(3)
人工智能·opencv·计算机视觉
西西弗Sisyphus4 小时前
探索多模态大语言模型(MLLMs)的推理能力
人工智能·计算机视觉·语言模型·大模型
yinqinggong4 小时前
从源码编译支持FFmpeg的OpenCV
opencv·ffmpeg
864记忆6 小时前
关于opencv、Qt、msvc编译器之间的关系
人工智能·qt·opencv
aworkholic6 小时前
opencv sdk for java中提示无stiching模块接口的问题
java·c++·opencv·jni·opencv4android·stiching
pk_xz1234566 小时前
OpenCV实现实时人脸检测和识别
人工智能·opencv·计算机视觉
是十一月末7 小时前
Opencv实现图片和视频的加噪、平滑处理
人工智能·python·opencv·计算机视觉·音视频
MUTA️7 小时前
RT-DETR学习笔记(2)
人工智能·笔记·深度学习·学习·机器学习·计算机视觉
jndingxin8 小时前
OpenCV相机标定与3D重建(26)计算两个二维点集之间的部分仿射变换矩阵(2x3)函数 estimateAffinePartial2D()的使用
opencv·3d