#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";
    
    // 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; // ~0.0211667 mm pro Pixel

    // 1. Bild im Graustufenmodus laden
    cv::Mat img = cv::imread(inputFile, cv::IMREAD_GRAYSCALE);
    if (img.empty()) {
        std::cerr << "Fehler: Konnte " << inputFile << " nicht oeffnen!" << std::endl;
        return 1;
    }

    // 2. Binarisieren: Kupfer muss für die Distanztransformation WEISS (255) sein
    cv::Mat binary;
    cv::threshold(img, binary, 128, 255, cv::THRESH_BINARY_INV);

    // 3. Distanztransformation berechnen
    // DIST_L2 berechnet den echten euklidischen Abstand
    cv::Mat dist;
    cv::distanceTransform(binary, dist, cv::DIST_L2, 5);

    // 4. Lokale Maxima finden (Zentren der maximal ausfüllbaren Formen)
    // Wir isolieren die Spitzenwerte, indem wir ein lokales Maximum-Filter anwenden
    cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5));
    cv::Mat localMax;
    cv::dilate(dist, localMax, kernel);
    
    // Wo dist == localMax und dist > Schwellwert (Rauschen unterdrücken, z.B. > 2 Pixel Radius)
    cv::Mat peakMask = (dist == localMax) & (dist > 2.0f);

    // 5. Punkte extrahieren und in Datei schreiben
    std::ofstream outFile(outputFile);
    if (!outFile.is_open()) {
        std::cerr << "Fehler bei Dateierstellung!" << std::endl;
        return 1;
    }

    outFile << std::fixed << std::setprecision(4);
    outFile << "Ermittelte Leiterbahnzentren und maximale In-Rechtecke (1200 DPI)\n";
    outFile << "=================================================================================\n";
    outFile << "ID\tZentrum_X(px)\tZentrum_Y(px)\tBreite(px)\tHoehe(px)\tX(mm)\tY(mm)\tBreite(mm)\n";
    outFile << "---------------------------------------------------------------------------------\n";

    int count = 0;
    for (int y = 0; y < peakMask.rows; y++) {
        for (int x = 0; x < peakMask.cols; x++) {
            if (peakMask.at<uchar>(y, x) > 0) {
                // Radius an dieser Stelle abfragen
                float radius = dist.at<float>(y, x);
                
                // Die maximale Breite des voll ausgefüllten Quadrats/Rechtecks an dieser Stelle
                // Durchmesser = 2 * radius
                float edge_px = radius * 2.0f; 

                count++;

                // Umrechnung in mm
                double cx_mm = x * PX_TO_MM;
                double cy_mm = y * PX_TO_MM;
                double width_mm = edge_px * PX_TO_MM;
                
                if (cx_mm < 30.0f) continue;
                if (cx_mm > 50.0f) continue;
                
                if (cy_mm < 20.0f) continue;
                if (cy_mm > 30.0f) continue;
                
                if (width_mm < 0.3f) continue;
               
                if (width_mm > 1.0f) continue;
                
                // Ausgabe: Da es das größte quadratisch ausfüllbare Rechteck ist, 
                // sind Breite und Höhe in Pixeln hier identisch (edge_px).
                outFile << count << "\t"
                        << x << "\t\t" << y << "\t\t"
                        << edge_px << "\t\t" << edge_px << "\t\t"
                        << cx_mm << "\t" << cy_mm << "\t"
                        << width_mm << "\n";
            }
        }
    }

    // outFile << "=================================================================================\n";
    // outFile << "Gesamtzahl ermittelter Messpunkte: " << count << "\n";
    outFile.close();

    std::cout << "Analyse abgeschlossen. Messpunkte in '" << outputFile << "' gespeichert." << std::endl;
    return 0;
}
