0
votes

I'm trying to train my svm with 4 image. all of my images are 300*400. I resize them to 304*400 so i can get the HOGDescriptor of my images because of 16*16 block. then I use Core.hconcat(mats, trainData) to gather all of my images into one Mat. after that when I try to set lables for my trainData, in train part I get below Error. I'm new to openCV. what is wrong?

    Mat rose1 = new Mat();
    Mat rose2 = new Mat();
    Mat rose3 = new Mat();
    Mat rose4 = new Mat();
    Mat rose5 = new Mat();

    try {
        rose1 = org.opencv.android.Utils.loadResource(
                getApplicationContext(), R.drawable.rose1);
        rose2 = org.opencv.android.Utils.loadResource(
                getApplicationContext(), R.drawable.rose2);
        rose3 = org.opencv.android.Utils.loadResource(
                getApplicationContext(), R.drawable.rose3);
        rose4 = org.opencv.android.Utils.loadResource(
                getApplicationContext(), R.drawable.rose4);
        rose5 = org.opencv.android.Utils.loadResource(
                getApplicationContext(), R.drawable.rose5);
    } catch (IOException e) {
        e.printStackTrace();
    }

    Mat rose1Resized = new Mat();
    Mat rose2Resized = new Mat();
    Mat rose3Resized = new Mat();
    Mat rose4Resized = new Mat();

    Size sz = new Size(304, 400);

    Imgproc.resize(rose1, rose1Resized, sz);
    Imgproc.resize(rose2, rose2Resized, sz);
    Imgproc.resize(rose3, rose3Resized, sz);
    Imgproc.resize(rose4, rose4Resized, sz);

    // HOG
    MatOfFloat rose1Float = new MatOfFloat();
    MatOfFloat rose2Float = new MatOfFloat();
    MatOfFloat rose3Float = new MatOfFloat();
    MatOfFloat rose4Float = new MatOfFloat();

    HOGDescriptor hog = new HOGDescriptor(new Size(304, 400), new Size(16,
            16), new Size(new Point(8, 8)), new Size(new Point(8, 8)), 9);
    hog.compute(rose1Resized, rose1Float);
    hog.compute(rose2Resized, rose2Float);
    hog.compute(rose3Resized, rose3Float);
    hog.compute(rose4Resized, rose4Float);

    ArrayList<Mat> mats = new ArrayList<>();
    mats.add(rose1Float);
    mats.add(rose2Float);
    mats.add(rose3Float);
    mats.add(rose4Float);

    // SVM
    Mat trainData = new Mat();
    Core.hconcat(mats, trainData);

    float[] lableFloat = { 1, 1, 1, 1 };
    Mat lables = new Mat(1, 4, CvType.CV_32FC1);
    lables.put(0, 0, lableFloat);

    CvSVM svm = new CvSVM();
    CvSVMParams params = new CvSVMParams();
    params.set_svm_type(CvSVM.C_SVC);
    params.set_kernel_type(CvSVM.LINEAR);
    params.set_term_crit(new TermCriteria(TermCriteria.EPS, 100, 1e-6));

    svm.train(trainData, lables, new Mat(), new Mat(), params);

Error is: E/AndroidRuntime(27347): CvException [org.opencv.core.CvException: cv::Exception: /home/reports/ci/slave_desktop/50-SDK/opencv/modules/ml/src/inner_functions.cpp:671: error: (-209) Response array must contain as many elements as the total number of samples in function cvPreprocessCategoricalResponses

1
try : Mat lables = new Mat(4, 1, CvType.CV_32FC1); . also, if you want to do a classification, not a regression, you will need integer labels, not float ones. - berak
@berak i changed it to int[] lableFloat = { 1, 1, 1, 1 }; lables = new Mat(4, 1, CvType.CV_32SC1); still same error... - user3313781
look at the outcome of ` Core.hconcat(mats, trainData);` trainData needs to have exactly 4 rows, too. - berak
rather use trainData.push_back(rose1Float); trainData.push_back(rose2Float); , etc, than hconcat and your ArayList. nextproblem then will be: you only got a single class label(1), you need at least 2 different ones. - berak
@berak exactlyyyy...first of all i used reshape(1,1) after i get hog from my MatOfFloats. becasue rose1Float was 65268*1 and it should be 1*65268. after that as u said, i used push_back, then i got that problem that i only have one lable as u said again. thank u very much. it works now perfectly fine. - user3313781

1 Answers

1
votes

first of all i reshape MatOfFloat after get HOG. because rose1Float was 65268*1 and i need it in one row Mat.

    Mat roseReshaped1 = rose1Float.reshape(1, 1);
    Mat roseReshaped2 = rose2Float.reshape(1, 1);
    Mat roseReshaped3 = rose3Float.reshape(1, 1);
    Mat roseReshaped4 = rose4Float.reshape(1, 1);

then i used push_back instead of "Core.hconcat(mats, trainData)"

    Mat trainData = new Mat(0, sizeOfCols, CvType.CV_32FC1);
    trainData.push_back(roseReshaped1);
    trainData.push_back(roseReshaped2);
    trainData.push_back(roseReshaped3);
    trainData.push_back(roseReshaped4);

my trainData would be 4*65268 and this is my label. or as opencv say, response!

    int[] l = { 1, 2, 3, 4 };
    Mat lables = new Mat(4, 1, CvType.CV_32SC1);
    lables.put(0, 0, l);

now everything works perfectly fine. Thanks to @berak.