I have about 1100+ images of size 64x64 that I'd like to classify as class 1.0 (positive) or -1.0 (negative) with a neural network from cv::ml::ANN_MLP. The input layer should have a size of 64x64=4096 and the output layer has a size of 2 for 1 and -1. I managed to get it working with SVMs, KNNs and R-Trees, but I appear to be making mistakes now that I am setting up a NN to do the same thing. That section is found in the below code where I commented: "//required neural network settings".
#include <iostream>
#include <iomanip>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/objdetect.hpp>
#include <opencv2/ml.hpp>
#include <fstream>
#include <string>
using namespace std;
int main()
{
try
{
//********************Just reading images********************
//read all .png images from the directory specied by prefix,
//image names are numbers from 0-599
std::string prefix = "true/";
std::string ext = ".png";
cv::Mat data, labels;
// loading positive training data
int numPosImages = 600;
cout << "loading images" << std::endl;
for (long i = 0; i < numPosImages; i++) {
std::string name(prefix);
std::ostringstream ss;
ss << i;
name += ss.str();
name += ext;
cv::Mat m = cv::imread(name, cv::IMREAD_GRAYSCALE);
m.convertTo(m, CV_32F);
m = m.reshape(0, 1);
data.push_back(m); // 1d single row
labels.push_back(1);
}
// loading negative training data
//read all .png images from the directory specied by prefix,
//image names are numbers from 0-596
std::string nprefix = "false/";
int numNegImages = 596;
for (long i = 0; i < numNegImages; i++) {
std::string name(nprefix);
std::ostringstream ss;
ss << i;
name += ss.str();
name += ext;
cv::Mat m = cv::imread(name, cv::IMREAD_GRAYSCALE);
m.convertTo(m, CV_32F);
m = m.reshape(0, 1);
data.push_back(m); // 1d single row
labels.push_back(-1);
}
//required neural network settings
data.convertTo(data, CV_32F);
labels.convertTo(labels, CV_32F);
cv::Ptr <cv::ml::ANN_MLP> ai = cv::ml::ANN_MLP::create();
cv::Mat layers(1, 3, CV_32SC1);
layers.at<int>(0, 0) = data.cols; //Enter the number of layer features
layers.at<int>(0, 1) = 16;
layers.at<int>(0, 2) = 2;
ai->setLayerSizes(layers);
ai->setActivationFunction(cv::ml::ANN_MLP::SIGMOID_SYM);
ai->setTrainMethod(cv::ml::ANN_MLP::BACKPROP);
// prepare the training data
cv::Ptr<cv::ml::TrainData> trainingData = cv::ml::TrainData::create(data, cv::ml::SampleTypes::ROW_SAMPLE, labels);
// ai training
cout << "training ai" << std::endl;
ai->train(trainingData);
The message I get in the console is:
OpenCV(4.4.0) Error: Bad argument (output training data should be a floating-point matrix with the number of rows equal to the number of training samples and the number of columns equal to the size of last (output) layer) in cv::ml::ANN_MLPImpl::prepare_to_train.
Which I don't understand... I've converted the training data and labels to float and how else am I to have 4096 inputs and 2 outputs?