Подготовка cv::mat к svm::predict

Я новичок в OpenCv и перехожу с OpenCv2.4 на OpenCv3... Я обучил классификатор SVM, хранящийся в файле *.xml.

Моя проблема во время перехода заключается в том, как правильно подготовить cv::Mat, чтобы его можно было ввести в прогноз cv::ml::SVM.

CvMat* NumExtractor::prepareDataSVM(cv::Mat & other){
      resize(other, other, Size(28,28));
      cv::Size s = other.size();
      int width = (int)s.width;
      int height = (int)s.height;
      cv::Mat ret = other.clone();
      CvMat* mat = cvCreateMat(width*height, 1, CV_32FC1);
      for(int i = 0; i < height; ++i)
      {
          for(int j = 0; j < width; ++j)
          {
             mat.data.fl[i*width+j] = (float)other.at<uchar>(i,j);
          }
      }
      return mat;
   }

Но я изо всех сил пытаюсь сделать это с помощью cv::Mat. Кто-нибудь может мне помочь?

РЕДАКТИРОВАТЬ: я понял это. Я использовал неправильный API для хранения значений.


person Steva    schedule 09.07.2015    source источник
comment
что такое other? а почему вы ресайзите на 28х28?   -  person Miki    schedule 10.07.2015
comment
Другое входное изображение с цифрой на нем, которое я хочу передать svm для классификации. Я изменяю его размер, потому что я тренировал svm на образцах 28x28.   -  person Steva    schedule 10.07.2015
comment
Итак, каковы ваши 1D-функции?   -  person Miki    schedule 10.07.2015
comment
Ну, есть проблема, или она была... мне нужно перевести свое изображение в 1d и сохранить его в cv::mat, чтобы я мог передать его в svm. Я не знал, как поместить это в мат, но я понял это только сейчас. :)   -  person Steva    schedule 10.07.2015
comment
ну, тогда решено.. :D Всего несколько советов: верните Mat1f (без указателя), сделайте other Mat1b, создайте mat, например: Mat1f mat(width*height, 1, 0.f), установите данные в mat, например: mat(i*width+j) = float(other(i,j)).   -  person Miki    schedule 10.07.2015


Ответы (1)


Следующий код поможет вам начать работу с функциями train() и predict() в cv::ml::SVM; вот объяснение кода (код хорошо работает в opencv4.2). Входное изображение представляет собой подводное изображение из набора данных (тест доступен здесь https://li-chongyi.github.io/proj_benchmark.html). Первая часть кода имеет дело с компенсацией красного канала изображения, которая улучшает смещение цвета к голубоватому цвету изображения. Для компенсации красного канала использовалось уравнение 8 из статьи «Коррекция цвета на основе CFA» и «Улучшение на основе Retinex с плотными пикселями для подводных изображений». Изображение с компенсацией красного канала хранится в коде image2.

Затем в качестве обучающих данных выбирается прямоугольная часть изображения, содержащая только водяные пиксели. Данные обучения сортируются в матрицу из трех столбцов, в каждом из которых содержатся значения интенсивности красного, зеленого и синего соответственно (например, mx3).

Поскольку нам нужны два очка, то прямоугольная часть изображения, содержащая неводные пиксели, выбирается в качестве другой части данных.

Затем как данные только о воде, так и данные, не связанные с водой, объединяются для формирования обучающих данных. Матрица меток устроена так, что она содержит + 1 для пикселей воды и - 1 пикселей воды. Затем SVM управляется для работы с линейным ядром, но гамма также устанавливается со значением для работы с ядром RBF. {входное изображение}

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/ml/ml.hpp>
using namespace cv;
using namespace cv::ml;
using namespace std;


int main()
{
    std::cout << "Hello World!\n";
    //read an image
    Mat image = imread("9554.png", 1);
    //check for existance of data
    if (!image.data) 
    { printf("no image data.\n"); return -1; }
    //planes is a vector for holding rgb channels separately
    //std::vector<Mat> planes;
    Mat planes[3];

    //split the image into channels
    //planes[2] is the red channel
    split(image, planes);

    // converting planes from uchar to double
    planes[0].convertTo(planes[0], CV_64FC1);
    planes[1].convertTo(planes[1], CV_64FC1);
    planes[2].convertTo(planes[2], CV_64FC1);

    // defining coefficients of green and blue channel for blending
    double a = 0.05, b = 0.95;
    
    //sum_im stores pixelwise sum of Red, Green and Blue planes
    Mat imBlendNormal_B_G, sum_im;

    //converting to double
    imBlendNormal_B_G.convertTo(imBlendNormal_B_G, CV_64FC1);
    sum_im.convertTo(sum_im, CV_64FC1);

    //blending green and blue planes with a and b coefficients
    // and 0.0 offset(or gamma)
    addWeighted(planes[1], a, planes[0], b, 0.0, imBlendNormal_B_G);

    // sum of red, green and blue pixel in two addWeighted calls
    addWeighted(planes[2], 1.0, planes[1], 1.0, 0.0, sum_im);
    addWeighted(planes[0], 1.0, sum_im, 1.0, 0.0, sum_im);

    //dividing blended green and blue image to total RGB sum
    divide(imBlendNormal_B_G, sum_im, imBlendNormal_B_G);

    //defining average kernel 3x3
    Mat avg3x3_kernel = (Mat_<double>(3, 3) << 1.0 / 9.0, 1.0 / 9.0, 1.0 / 9.0, 1.0 / 9.0, 1.0 / 9.0, 1.0 / 9.0, 1.0 / 9.0, 1.0 / 9.0, 1.0 / 9.0);
    
    //defining matrices for storing 3x3 average of blue and green planes
    Mat blueAverage, greenAverage;
    // converting to double type
    blueAverage.convertTo(blueAverage, CV_64FC1);
    greenAverage.convertTo(greenAverage, CV_64FC1);

    // taking 3x3 average
    filter2D(planes[0], blueAverage, planes[0].depth(), avg3x3_kernel);
    filter2D(planes[1], greenAverage, planes[1].depth(), avg3x3_kernel);

    //imBlendAverage_B_G_R: for blending of averaged green and blue channels
    Mat imBlendAverage_B_G_R; 
    //convert to double
    imBlendAverage_B_G_R.convertTo(imBlendAverage_B_G_R, CV_64FC1);

    //blend averaged green and blue with a and b coeffs
    addWeighted(greenAverage, a, blueAverage, b, 0.0, imBlendAverage_B_G_R);
    
    //differentiate red values
    addWeighted(imBlendAverage_B_G_R, 1.0, planes[2], -1.0, 0.0, imBlendAverage_B_G_R);

    //CompensationTermRed: storing finally compensated red channel intensities
    Mat CompensationTermRed; 
    //coverting to double
    CompensationTermRed.convertTo(CompensationTermRed, CV_64FC1);

    //multiplication term
    CompensationTermRed = imBlendAverage_B_G_R.mul(imBlendNormal_B_G);

    //final add term
    addWeighted(CompensationTermRed, 1.0, planes[2], 1.0, 0.0, CompensationTermRed);
    
    // assign new red channel values to planes[2]
    planes[2] = CompensationTermRed;

    Mat image2;
    cv::merge(planes, 3, image2); 
    image2.convertTo(image2, CV_8UC3);
    imshow("merge",image2);
    printf("\ndims of image2 (merge): %d  %d\n", image2.rows, image2.cols);
    //defining rectangle of coordination
    Rect waterrect(5,5,365,135);
    
    // water only image 
    Mat WaterOnlyImage = image(waterrect);
    imshow("water only image", WaterOnlyImage);    
    
    // separating WaterOnlyImage planes
    Mat WaterOnlyPlanes[3];
    split(WaterOnlyImage, WaterOnlyPlanes);
    printf("size of WaterOnlyPlanes[0]: %d  %d  %d\n", WaterOnlyPlanes[0].rows,WaterOnlyPlanes[0].cols, WaterOnlyPlanes[0].channels());

    // vector of each plane
    Mat WaterOnlyRedVector, WaterOnlyGreenVector, WaterOnlyBlueVector;

    // reshape each plane into vector separately
    // column vector
    WaterOnlyRedVector = WaterOnlyPlanes[2].reshape(0, 1).t();
    WaterOnlyGreenVector = WaterOnlyPlanes[1].reshape(0, 1).t();
    WaterOnlyBlueVector = WaterOnlyPlanes[0].reshape(0, 1).t();
    printf("WaterOnlyRedVector size: %d  %d  %d\n", WaterOnlyRedVector.rows, WaterOnlyRedVector.cols, WaterOnlyRedVector.channels());
    
    // (row*com)x3 vector holding all RGB pixels of water
    // (WaterOnlyRedVector.rows, 3);
    Mat WaterOnlyRGBVector;

    // concatenation of three vectors values using hconcat
    // hconcate: horizontal concatenation
    hconcat(WaterOnlyRedVector, WaterOnlyGreenVector, WaterOnlyRGBVector);
    hconcat(WaterOnlyRGBVector, WaterOnlyBlueVector, WaterOnlyRGBVector);
    printf("WaterOnlyRGBVector dims is: %d  %d  %d\n", WaterOnlyRGBVector.rows, WaterOnlyRGBVector.cols, WaterOnlyRGBVector.channels());
    
    // label vector for water pixels, all preset one
    Mat WaterOnlyLabelVector_float = Mat::ones(WaterOnlyRGBVector.rows, 1, CV_32SC1);
    printf("WaterOnlyLabelVector_float dims: %d\t%d\t%d\t\n", WaterOnlyLabelVector_float.rows, WaterOnlyLabelVector_float.cols, WaterOnlyLabelVector_float.channels());
    //std::cout << WaterOnlyLabelVector_float << "\n";

    // defining non water coordination
    Rect nonWaterRect(1, 400, 640, 320);
    //non water image
    Mat NonWaterImage = image(nonWaterRect);
    imshow("non water image", NonWaterImage);

    //holding plited nonwater image planes
    Mat NonWaterPlanes[3];

    //split nonwater image sample
    split(NonWaterImage, NonWaterPlanes);
    printf("NonWaterPlanes[0] dims: %d\t%d\t%d \n", NonWaterPlanes[0].rows, NonWaterPlanes[0].cols, NonWaterPlanes[0].channels());

    // 3 column vector for each of rgb planes
    Mat NonWaterRedVector, NonWaterGreenVector, NonWaterBlueVector;

    // reshaping each plane to get a column vector Mx1
    NonWaterRedVector = NonWaterPlanes[2].reshape(0, 1).t();//red 1st
    NonWaterGreenVector = NonWaterPlanes[1].reshape(0, 1).t();//green 2nd
    NonWaterBlueVector = NonWaterPlanes[0].reshape(0, 1).t();//blue
    printf("NonWaterGreenVector size is: %d\t%d\t%d\t\n", NonWaterGreenVector.rows, NonWaterGreenVector.cols, NonWaterGreenVector.channels());
    
    // Mx3 vector holding all RGB pixels of NonWater
    Mat NonWaterRGBVector;

    // concatenate 3 column vec into one place (Mx3)
    cv::hconcat(NonWaterRedVector, NonWaterGreenVector, NonWaterRGBVector);
    cv::hconcat(NonWaterRGBVector, NonWaterBlueVector, NonWaterRGBVector);
    printf("NonWaterRGBVector dims: %d\t%d\t%d\t\n", NonWaterRGBVector.rows, NonWaterRGBVector.cols, NonWaterRGBVector.channels());

    // label vector for NonWater pixels
    Mat NonWaterLabelVector_float = cv::Mat::zeros(NonWaterRGBVector.rows, 1, CV_32SC1) - 1.0;
    printf("NonWaterLabelVector_float dims: %d\t%d\t%d\t\n", NonWaterLabelVector_float.rows, NonWaterLabelVector_float.cols, NonWaterLabelVector_float.channels());
    //cout << NonWaterLabelVector_float << "\n";
    
    // label matrix for all data
    Mat AllLabelVector_float;
    cv::vconcat(WaterOnlyLabelVector_float, NonWaterLabelVector_float, AllLabelVector_float);
    printf("AllLabelVector_float dims:  %d\t%d\t%d\t\n", AllLabelVector_float.rows, AllLabelVector_float.cols, AllLabelVector_float.channels());

    //concatenation of all training data
    // uchar mat
    Mat AllTrainingDataVector_uchar;
    cv::vconcat(WaterOnlyRGBVector, NonWaterRGBVector, AllTrainingDataVector_uchar);
    // convert to double
    Mat AllTrainingDataVector_float;
    AllTrainingDataVector_uchar.convertTo(AllTrainingDataVector_float, CV_32F);
    printf("AllTrainingDataVector_float dims: %d\t%d\t%d\t\n", AllTrainingDataVector_float.rows, AllTrainingDataVector_float.cols, AllTrainingDataVector_float.channels());
    //std::cout << AllTrainingDataVector_float << "\n";
    
    // define support vector machine
    Ptr<ml::SVM> WaterSVMParams = ml::SVM::create();
    WaterSVMParams->setType(cv::ml::SVM::C_SVC);
    WaterSVMParams->setKernel(cv::ml::SVM::RBF);
    WaterSVMParams->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER,100,1e-6));
    WaterSVMParams->setGamma(0.000000001);
    // train data
    WaterSVMParams->train(AllTrainingDataVector_float, ROW_SAMPLE, AllLabelVector_float);

    // prediction responses image
    Mat WaterPredictionImage = Mat::zeros(image.rows, image.cols, CV_8UC3);

    // blue for water and green for nonwater
    Vec3b green(0, 255, 0), blue(255, 0, 0);

    // loop to fill the response image with prediction colors
    for (int i = 0; i < image.rows; i++)
    {
        for (int j = 0; j < image.cols; j++) {
            // getting one pixel at (i,j)
            Vec3b oneTestPixel = image.at<Vec3b>(i, j);
            // getting rgb vals
            float oneTestPixelRed = (float)oneTestPixel.val[2];
            float oneTestPixelGreen = (float)oneTestPixel.val[1];
            float oneTestPixelBlue = (float)oneTestPixel.val[0];

            Mat samplePixelMat = (Mat_<float>(1, 3) << oneTestPixelRed, oneTestPixelGreen, oneTestPixelBlue);
            //cout <<"curret test pixel:\t" << samplePixelMat << "\n";
            float responseSVM = WaterSVMParams->predict(samplePixelMat);
            if (responseSVM == 1.0) {
                WaterPredictionImage.at<Vec3b>(i, j) = blue;
            }
            if (responseSVM == -1.0) {
                WaterPredictionImage.at<Vec3b>(i, j) = green;
            }
        }//end of for j

    }//end of for i
    
    imshow("WaterPredictionImage-Linear Kernel", WaterPredictionImage);
        

    waitKey(0);
    return 0;

}
person vahid_rowghanian    schedule 03.02.2021