#include <iostream>
#include <fstream>
#include <vector>
#include <iomanip>
#include <opencv2/opencv.hpp>

int main() {
    const std::string inputFile = "input.tiff";
    const std::string outputFile = "rechtecke.txt";
    
    // Konstanten für die DPI-Umrechnung (1200 DPI -> 1 Inch = 25.4 mm)
    const double DPI = 1200.0;
    const double MM_PER_INCH = 25.4;
    const double PX_TO_MM = MM_PER_INCH / DPI; // Umrechnungsfaktor: ca. 0.0211667 mm pro Pixel

    // 1. Bild einlesen (im Graustufenmodus, da es sich um Binär/Leiterplattendaten handelt)
    cv::Mat img = cv::imread(inputFile, cv::IMREAD_GRAYSCALE);
    if (img.empty()) {
        std::cerr << "Fehler: Konnte " << inputFile << " nicht oeffnen!" << std::endl;
        return 1;
    }

    // 2. Binarisierung (Sicherstellen, dass das Bild rein Schwarz/Weiss ist)
    // Da Kupfer meist schwarz ist, invertieren wir hier ggf. mit THRESH_BINARY_INV,
    // weil OpenCV Konturen als weisse Objekte auf schwarzem Grund sucht.
    cv::Mat binary;
    cv::threshold(img, binary, 128, 255, cv::THRESH_BINARY_INV);

    // 3. Konturen finden
    std::vector<std::vector<cv::Point>> contours;
    cv::findContours(binary, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);

    // 4. Ausgabedatei oeffnen
    std::ofstream outFile(outputFile);
    if (!outFile.is_open()) {
        std::cerr << "Fehler: Konnte Ausgabedatei " << outputFile << " nicht erstellen!" << std::endl;
        return 1;
    }

    // Header für die Textdatei schreiben
    outFile << std::fixed << std::setprecision(3);
    outFile << "Gefundene Rechtecke (1200 DPI)\n";
    outFile << "=================================================================================\n";
    outFile << "ID\tSchwerpunkt_X(px)\tSchwerpunkt_Y(px)\tBreite(px)\tHoehe(px)\tX(mm)\tY(mm)\tW(mm)\tH(mm)\n";
    outFile << "---------------------------------------------------------------------------------\n";

    int rectCount = 0;

    for (size_t i = 0; i < contours.size(); i++) {
        // Kontur approximieren, um die Anzahl der Ecken zu reduzieren
        std::vector<cv::Point> approx;
        // epsilon bestimmt die Genauigkeit (Abweichung von der Originalkontur)
        double epsilon = 0.02 * cv::arcLength(contours[i], true);
        cv::approxPolyDP(contours[i], approx, epsilon, true);

        // Ein Rechteck/Quadrat hat nach der Approximation idealerweise 4 Ecken
        // Zudem filtern wir zu kleine Rausch-Flächen aus (z.B. kleiner als 100 Pixel Flaeche)
        if (approx.size() == 4 && cv::contourArea(approx) > 100) {
            rectCount++;

            // Achsenparalleles Begrenzungsrechteck bestimmen
            cv::Rect rect = cv::boundingRect(approx);

            // Schwerpunkt ueber die Bildmomente (Moments) exakt berechnen
            cv::Moments m = cv::moments(approx);
            double cx_px = m.m10 / m.m00;
            double cy_px = m.m01 / m.m00;

            // Maße in Pixeln
            double width_px = rect.width;
            double height_px = rect.height;

            // Umrechnung in Millimeter
            double cx_mm = cx_px * PX_TO_MM;
            double cy_mm = cy_px * PX_TO_MM;
            double width_mm = width_px * PX_TO_MM;
            double height_mm = height_px * PX_TO_MM;
            
            if (width_mm < 1.0f) continue;
            if (height_mm < 1.0f) continue;

            // In Datei schreiben
            outFile << rectCount << "\t"
                    << cx_px << "\t\t" << cy_px << "\t\t"
                    << width_px << "\t\t" << height_px << "\t\t"
                    << cx_mm << "\t" << cy_mm << "\t"
                    << width_mm << "\t" << height_mm << "\n";
        }
    }

    outFile << "=================================================================================\n";
    outFile << "Gesamtzahl erkannter Rechtecke: " << rectCount << "\n";
    outFile.close();

    std::cout << "Analyse beendet. " << rectCount << " Rechtecke erkannt und in '" << outputFile << "' gespeichert." << std::endl;
    return 0;
}
