#include "controller.h" #include #include #include #include #include #include #include #include "filenames.h" using namespace std; using namespace cv; Controller::Controller(QObject* parent) : QObject(parent), detProc(), markers(detProc.getMarkers()) { string errors; ifstream file; file.open(FileNames::configName); bool ok = Json::parseFromStream(Json::CharReaderBuilder(), file, &config, &errors); file.close(); if (!ok) { cerr << "Error while reading " << FileNames::configName << ":\n" << errors << "\n"; exit(1); } detProc.init(config["detection"]); rateProc.init(config["rating"]["steps"]); net.init(config["rating"]["results"]); } Controller& Controller::inst() { static Controller ctrlr; return ctrlr; } const Mat* Controller::getCurImg() { return &cur_img; } const Mat* Controller::getCurNut() { return &nuts[current_nut].img; } void Controller::openImage() { filePath = QFileDialog::getOpenFileName(nullptr, tr("Öffnen"), "", tr("Bilder (*.png *.jpg)")); if (filePath.toStdString() == "") { return; } loadImage(); } void Controller::loadImage() { if ( !cur_img.empty() ){ cur_img.copyTo(prev_img); } cur_img = imread(filePath.toStdString(), IMREAD_COLOR); emit statusMessage("Bild geladen ..."); process(); } void Controller::process() { if (valid_nut) { if (nut_rating > 0) { emit statusMessage("Bewerte gegessene Nuss..."); rateProc.reset(); rateProc.setRateCurNut(false); rateProc.process(); rateProc.setRateCurNut(true); debugResultPrint(); net.saveNut(); } else { cout << "No score selected. Not saving Nut." << endl; } } detProc.reset(); emit newInputImage(cur_img); emit statusMessage("Erkenne Nüsse ..."); if (!detect()) { return; } emit newInputImage(detProc.getResult()); if (!prev_img.empty()) { vector results = {}; emit statusMessage("Extrahiere Nüsse ..."); extractNuts(results); if (matchNuts(results)) { nuts = results; valid_nut = true; } else { valid_nut = false; nuts = results; } } else { emit statusMessage("Extrahiere Nüsse ..."); extractNuts(); } nut_rating = -1; //debugPaint(); emit statusMessage("Bewerte Nüsse ..."); Mat withScores = Mat::zeros(cur_img.size(), CV_8UC3); for (int i = 0; i>& contours = rateProc.getContours(); vector rects(contours.size()); for (unsigned int i = 0; i max_rect_size) { max_rect_size = rects[i].height * rects[i].width; max_rect_index = i; } } drawContours(withScores, contours, max_rect_index, Scalar(static_cast(score * 100.0f *0.708333f), 255, 255), CV_FILLED, LINE_8, noArray(), INT_MAX, Point(nuts[current_nut].min_y, nuts[current_nut].min_x)); } emit statusMessage("Zeige Ergebnisse an ..."); cvtColor(withScores, withScores, CV_HSV2BGR); withScores = 0.5 *withScores + 0.5 * cur_img; paintScores(withScores); emit statusMessage("Fertig."); } void Controller::debugResultPrint() { ostringstream sstr; sstr << "Results: "; for (const auto& result : rateProc.getResults()) { sstr << result.first << ": " << result.second << ", "; } cout << sstr.str() << endl; } void Controller::paintScores(Mat& img) { for (unsigned int i = 0; i( chrono::steady_clock::now() - start); cout << "Detection took " << (float)duration.count()/1000.0 << " seconds." << endl; return success; } bool Controller::matchNuts(const vector& cur_results) { auto start = chrono::steady_clock::now(); vector min_dists = vector(nuts.size()); int count = 0; for(const auto& nut : nuts) { vector x_dist = vector(cur_results.size()); for (unsigned int i = 0; i y_dist = vector(cur_results.size()); for (unsigned int i = 0; i dist = vector(cur_results.size()); magnitude(x_dist, y_dist, dist); auto min = min_element(dist.begin(), dist.end()); min_dists[count] = *min; cout << "Minimum distance for nut " << count << ": " << *min << " (" << (*min/ (sqrt(pow(static_cast(cur_img.cols), 2) + pow(static_cast(cur_img.rows), 2))))*100.0 << "%)\n"; count++; } bool success = false; if (cur_results.size() == nuts.size() - 1) { success = true; int nut_index; auto max = max_element(min_dists.begin(), min_dists.end()); nut_index = distance(min_dists.begin(), max); cout << "Nut " << nut_index << " has been taken away.\n"; nuts[nut_index].img.copyTo(nut_to_rate); emit newNutToRate(nut_to_rate); } else { emit message("Keine Nuss erkannt"); } auto duration = chrono::duration_cast( chrono::steady_clock::now() - start); cout << "Matching took " << (float)duration.count()/1000.0 << " seconds." << endl; return success; } void Controller::extractNuts(vector& result_nuts) { auto start = chrono::steady_clock::now(); if (result_nuts.size() > 0) { return; } if (markers.empty()) { if (!detProc.process()) { return; } } int nut_count = detProc.getNutCount(); result_nuts = vector(nut_count); for (unsigned int i = 0; i(i, j) -2; if (index >= 0 && index < nut_count) { result_nuts[index].min_x = min(result_nuts[index].min_x, i); result_nuts[index].min_y = min(result_nuts[index].min_y, j); result_nuts[index].max_x = max(result_nuts[index].max_x, i); result_nuts[index].max_y = max(result_nuts[index].max_y, j); } } } for (unsigned int i = 0; i(i, j)-2; if (index >= 0 && index < nut_count) { result_nuts[index].img.at(i - result_nuts[index].min_x, j - result_nuts[index].min_y) = cur_img.at(i, j); } } } auto duration = chrono::duration_cast( chrono::steady_clock::now() - start); cout << "Nut extraction took " << (float)duration.count()/1000.0 << " seconds.\n"; cout << "Detected " << result_nuts.size() << " nuts." << endl; rateProc.reset(); if (rateProc.isInteractive()) { emit newNut(result_nuts[current_nut].img); } } void Controller::nextNut() { if (nuts.size() == 0 || nuts[current_nut].img.empty()) { return; } int size = nuts.size(); current_nut = min(current_nut + 1, size-1); newNut(); if (rateProc.isInteractive()) { emit newNut(nuts[current_nut].img); emit rateProc.requestUpdate(); } } void Controller::previousNut() { if (nuts.size() == 0 || nuts[current_nut].img.empty()) { return; } current_nut = max(current_nut - 1, 0); newNut(); if (rateProc.isInteractive()) { emit newNut(nuts[current_nut].img); } } void Controller::newNut() { rateProc.reset(); if (rateProc.isInteractive()) { rateProc.start(true); } } string Controller::runCmd(string cmd) { char buffer[128]; string result = ""; shared_ptr pipe(popen(cmd.c_str(), "r"), pclose); if (!pipe) throw runtime_error("popen() failed!"); while (!feof(pipe.get())) { if (fgets(buffer, 128, pipe.get()) != NULL) result += buffer; } return result; } void Controller::saveDetectionConfig() { int current_step = detProc.getCurrentStep(); config["detection"][current_step]["param1"]["default"] = detProc.getCurParams()[0].val; config["detection"][current_step]["param2"]["default"] = detProc.getCurParams()[1].val; ofstream file ("config.json"); file << Json::writeString(Json::StreamWriterBuilder(), config); file.close(); } void Controller::saveRatingConfig() { int current_step = rateProc.getCurrentStep(); config["rating"]["steps"][current_step]["param1"]["default"] = rateProc.getCurParams()[0].val; config["rating"]["steps"][current_step]["param2"]["default"] = rateProc.getCurParams()[1].val; ofstream file ("config.json"); file << Json::writeString(Json::StreamWriterBuilder(), config); file.close(); } void Controller::reset() { resetNuts(); detProc.reset(); rateProc.reset(); cur_img.release(); prev_img.release(); Mat empty; emit newInputImage(empty); emit newNutToRate(empty); } void Controller::resetNuts() { current_nut = 0; nut_rating = -1; nuts = {}; } void Controller::saveData() { cout << "... saving data ... " << endl; if (valid_nut) { if (nut_rating > 0) { net.saveNut(); } else { cout << "No score selected. Not saving Nut." << endl; } } } void Controller::currentRating(int score) { nut_rating = score; } int Controller::getCurRating() { return nut_rating; } int Controller::getN() { return net.getN(); } void Controller::neuralNetChange(int val) { if (val == Qt::Unchecked) { net.neuralNetEnabled(false); process(); } else if (val == Qt::Checked) { net.neuralNetEnabled(true); process(); } } const cv::Mat* Controller::getNutToRate() { return &nut_to_rate; }