This code is supposed to learn colors from many many data images, and then recognize color using an algorithm that I made. Eventually, I want the program to make its own algorithm.
Data input and test cases are on GitHub.
And now, the actual code:
// By Dat HA
#include "stdafx.h" // visual studio mandatory include file
#include <opencv2\opencv.hpp> // open cv libraries
#include <opencv2/core/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <Windows.h> // windows library
#include <fstream> // std libraries
#include <ios>
#include <iostream>
#include <string>
#include <vector>
const int NUM_FILE = 10; // number of images per color, NUM_FILE & NUM_COLOR are temporary until I get Boost working
const int NUM_COLOR = 7; // number of colors
const float NUM_VERSION = 1.3; // version number
const std::string TRAIN_DATA_FOLDER = "../TrainData/"; // training data location
struct Color { // define a new color that we learned of compare
std::string colorName; // name of the color, ex. red, blue
cv::Scalar bgr; // blue, green, and red values in that order
cv::Scalar difference; // what is the difference between, blue and green, green and red, and red and blue
};
cv::Scalar getAvg(std::vector<cv::Scalar> imgData) { // get the average BGR of a vector of images BGR value
cv::Scalar avg = { 0,0,0,0 }; // new scalar
int num = imgData.size(); // size of vector
for (int rgb = 0; rgb < 3; rgb++) { // cycle through the colors
for (int i = 0; i < num; i++) // cycle through the pictures
avg[rgb] += imgData[i][rgb]; // add them up
avg[rgb] /= num; // divide them by the total
}
return avg; // return the average
}
cv::Scalar getBgrDifference(cv::Scalar bgr) { // get the difference between, blue and green, green and red, and red and blue
cv::Scalar difference; // new scalar
difference[0] = bgr[0] - bgr[1]; // difference between blue and green
difference[1] = bgr[1] - bgr[2]; // difference between green and red
difference[2] = bgr[2] - bgr[0]; // difference between red and blue
return difference; // return the difference scalar
}
void training(std::vector<Color> &color) { // train the neural network
for (int j = 0; j < NUM_COLOR; j++) { // cycle through the colors
std::ifstream file; // new file
std::string nfname = TRAIN_DATA_FOLDER + std::to_string(j) + "/name.txt"; // file name, contains the color name
file.open(nfname); // open text file
std::string colorName; // create string for the color name
file >> colorName; // get the string frmo text file to color name variable
file.close(); // close text file
std::vector<cv::Scalar> imgData; // vector of image BGRs in a scalar format
for (int i = 0; i < NUM_FILE; i++) { // cycle through the images' data
std::string fname = TRAIN_DATA_FOLDER + std::to_string(j) + "/" + std::to_string(i) + ".jpg"; // get the image file name
cv::Mat image = cv::imread(fname, cv::IMREAD_COLOR); // read the image
cv::Scalar imgBgr = cv::mean(image); // get the image's average BGR value
imgData.push_back(imgBgr); // add it to vector
cv::waitKey(1); // wait a bit
}
Color currentColor; // create a temporary new color
currentColor.colorName = colorName; // set its name
currentColor.bgr = getAvg(imgData); // set its BGR value
currentColor.difference = getBgrDifference(currentColor.bgr); // set its difference value
color.push_back(currentColor); // add temporary color to our main color vector
std::cout << color[j].colorName << " : " << color[j].bgr << std::endl; // print the color name and its BGR value
}
std::cout << std::endl; // jump a line
}
double getColorAccuracy(cv::Scalar color1, cv::Scalar color2) { // get, in percentage, the ressemblance between 2 color
double accuracy = 0; // create a double for our accuracy
for (int i = 0; i < 3; i++) // cycle throught all 3 differences
accuracy += fabs(color1[i] - color2[i]); // add them up
return 1 - ((accuracy / 3) / 255); // divide and conquer them!, just kidding, divide and return it
}
Color getColorGuest(std::vector<Color> color, cv::Mat image) { // guest the color
cv::Scalar imgBgr = cv::mean(image); // get average BGR value of image
cv::Scalar imgDifference = getBgrDifference(imgBgr); // get BGR's difference
std::vector<double> accuracy; // create a vector for accuracy, higher the better
for (int i = 0; i < color.size(); i++) // cycle through colors that we learned
accuracy.push_back((getColorAccuracy(imgDifference, color[i].difference))); // add that color's ressemblence, in percentage, to the know color
Color bestColor = color[std::distance(accuracy.begin(), std::find(accuracy.begin(), accuracy.end(), *std::max_element(accuracy.begin(), accuracy.end())))]; // get the best match color
std::cout << imgBgr << std::endl; // print the image average BGR value
for (int i = 0; i < color.size(); i++) // cycle through the colors that we learned
std::cout << color[i].colorName << " : " << accuracy[i] << std::endl; // print color name and how accurate it is
std::cout << bestColor.colorName << std::endl << std::endl; // print out the best match
return bestColor; // return the best match color
}
// main
int main() {
std::cout << NUM_VERSION << std::endl << std::endl; // print code version
std::vector<Color> color; // color vector
training(color); // train neural net and store learned color in vector
// TESTTING SEGMENTS
getColorGuest(color, cv::imread("../TestData/yellow.jpg", cv::IMREAD_COLOR)); // get the best match color for our image
while (1);
}