Rotation von Messlinien die sich zu einem Rechteck was nicht im winkel ist mit drehen!

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
kasialars
User
Beiträge: 1
Registriert: Mittwoch 24. Januar 2024, 11:53

Hallo bin Kasialars,
habe ein Prob. bin an einem Projekt wo mein Code ein Objekt einmessen soll. Leider bin ich in der Frage wie ich ein Objekt was per def measure_object ein gemessen werden soll die Rotation setzen muss.
Objekt ist 380x80mm und wird per Scanner ein gelesen. Konturen werden erkannt und messung der Breite wird per def measure_line gemessen. Leider funktioniert die Rotation vom Kontur Rechteck nicht wenn es nicht im Winkel eingemessen wird.
Hier mal ein Codebereich der dafür verantwortlich sein soll:
def measure_object(self, file_path):
try:
# Bild laden
image = cv2.imread(file_path)

# Vorverarbeitung: Glättung mit Gauss-Filter
smoothed = cv2.GaussianBlur(image, (5, 5), 0)

# Graustufenkonvertierung
gray = cv2.cvtColor(smoothed, cv2.COLOR_BGR2GRAY)

# Adaptive Schwellenwerte anwenden
edges = cv2.Canny(gray, 50, 150)

# Morphologische Operationen
kernel = np.ones((3, 3), np.uint8)
edges = cv2.dilate(edges, kernel, iterations=1)
edges = cv2.erode(edges, kernel, iterations=1)

# Konturen finden, aber keine Schließung verwenden (closed=False)
contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# Filtere Konturen nach ihrer Größe (Bereich)
min_contour_area = 500 # Passen Sie dies an Ihre Anforderungen an
contours = [cnt for cnt in contours if cv2.contourArea(cnt) > min_contour_area]

# Alle Konturen nach ihrem Umfang sortieren
sorted_contours = sorted(contours, key=lambda x: cv2.arcLength(x, closed=True), reverse=True)

# Die Kontur mit dem längsten Umfang auswählen
longest_perimeter_contour = sorted_contours[0]

# Winkel des grünen Rechtecks extrahieren
self.angle = longest_perimeter_contour[2]
print(f"Winkel des grünen Rechtecks: {self.angle} Grad")

# Linienwinkel entsprechend dem Winkel des grünen Rechtecks setzen
self.line_angle = self.angle # oder passen Sie dies nach Ihren Anforderungen an

# Schwerpunkt der Kontur berechnen
M = cv2.moments(longest_perimeter_contour)
cx = int(M["m10"] / M["m00"]) if M["m00"] != 0 else 0
cy = int(M["m01"] / M["m00"]) if M["m00"] != 0 else 0

# Rotation Center setzen
self.rotation_center = (cx, cy)

# Minimal umschließendes Rechteck (Bounding Box) um die Kontur
rect = cv2.minAreaRect(longest_perimeter_contour)
box = cv2.boxPoints(rect)
box = np.intp(box)

# Linienbreite für das Rechteck erhöhen auf 4 Pixel (kann nach Bedarf angepasst werden)
rectangle_thickness = 20

# Die Kontur mit dem längsten Umfang auswählen
x, y, w, h = cv2.boundingRect(longest_perimeter_contour)

cv2.drawContours(image, [box], 0, (0, 255, 0), rectangle_thickness)

# Winkel des grünen Rechtecks
angle = rect[2]
print(f"Winkel des grünen Rechtecks: {angle} Grad")

# Konturapproximation
epsilon = 0.02 * cv2.arcLength(longest_perimeter_contour, True)
longest_contour_approx = cv2.approxPolyDP(longest_perimeter_contour, epsilon, True)

# Messung der Breite und Höhe in Pixeln
width_pixel = w
height_pixel = h

# Umrechnung in Millimeter (angenommene DPI: 200)
dpi = 200
width_mm = width_pixel / dpi * 24.8
height_mm = height_pixel / dpi * 25.35

# Rote waagerechte Linien hinzufügen
middle_measurement_y = y + h // 2
outer_measurement_y1 = y + 200
outer_measurement_y2 = y + h - 200

line_name_middle = "Mitte"
line_name_outer1 = "Links"
line_name_outer2 = "Rechts"

# Übergeben Sie den Winkel des Rechtecks und das Rotationszentrum an die measure_line-Methode
self.measure_line(image, (x, middle_measurement_y), (x + w, middle_measurement_y), width_mm,
line_name_middle, angle, self.rotation_center)
self.measure_line(image, (x, outer_measurement_y1), (x + w, outer_measurement_y1), width_mm,
line_name_outer1, angle, self.rotation_center)
self.measure_line(image, (x, outer_measurement_y2), (x + w, outer_measurement_y2), width_mm,
line_name_outer2, angle, self.rotation_center)


# Berechne prozentuale Deckung der erkannten Kante
coverage_percentage = self.calculate_coverage(edges, (x, y, x + w, y + h))
print(f"Prozentuale Deckung der erkannten Kante: {coverage_percentage:.2f}%")

# Bild verkleinern und anzeigen
target_size = (500, 950)
small_image = cv2.resize(image, target_size)
self.last_image = small_image # Bild für die PDF speichern
self.display_image(small_image)

# Messwerte speichern
self.measurement_data = {
"width_mm": width_mm,
"height_mm": height_mm,
"line_name_outer1": line_name_outer1,
"line_name_middle": line_name_middle,
"line_name_outer2": line_name_outer2,
"coverage_percentage": coverage_percentage
}

# Messwerte in der App anzeigen
self.display_measurement()

except Exception as e:
print(f"Fehler beim Verarbeiten des Bildes: {e}")

def measure_line(self, image, start_point, end_point, width_mm, line_name, angle=None, rotation_center=None):
# ... (vorheriger Code)
# Linienbreite für die roten Linien erhöhen auf 4 Pixel (kann nach Bedarf angepasst werden)
line_thickness = 6

# Falls ein Winkel gegeben ist, rotiere die Start- und Endpunkte
if angle is not None and rotation_center is not None:
print(f"Vor der Rotation - Startpunkt: {start_point}, Endpunkt: {end_point}")
rotated_start_point = self.rotate_point(start_point, angle, rotation_center)
rotated_end_point = self.rotate_point(end_point, angle, rotation_center)
print(
f"Nach der Rotation - Rotierter Startpunkt: {rotated_start_point}, Rotierter Endpunkt: {rotated_end_point}")

start_point = rotated_start_point
end_point = rotated_end_point

# Überprüfen Sie, ob die verschobenen und rotierten Punkte im sichtbaren Bereich liegen
height, width, _ = image.shape
if 0 <= start_point[0] < width and 0 <= start_point[1] < height and 0 <= end_point[0] < width and 0 <= \
end_point[1] < height:
# Nachricht ausgeben
print(f"{line_name} Breite: {width_mm:.2f} mm")
print(f"Rotierter {line_name} - Startpunkt: {start_point}, Endpunkt: {end_point}")
return width_mm
else:
# Wenn die Linie außerhalb des sichtbaren Bereichs liegt, geben Sie einen Fehler aus
print(f"Fehler: {line_name} Linie liegt außerhalb des sichtbaren Bereichs")
return None

def rotate_point(self, point, angle, center):
x, y = point
cx, cy = center

adjusted_x = x - cx
adjusted_y = y - cy

angle_rad = math.radians(angle)

rotated_x = int(adjusted_x * math.cos(angle_rad) - adjusted_y * math.sin(angle_rad))
rotated_y = int(adjusted_x * math.sin(angle_rad) + adjusted_y * math.cos(angle_rad))

rotated_x += cx
rotated_y += cy

print(f"Ursprünglicher Punkt: ({x}, {y})")
print(f"Rotierter Punkt: ({rotated_x}, {rotated_y})")

return rotated_x, rotated_y

def rotate_point(self, point, angle, center):
x, y = point
cx, cy = center

adjusted_x = x - cx
adjusted_y = y - cy

angle_rad = math.radians(angle)

rotated_x = int(adjusted_x * math.cos(angle_rad) - adjusted_y * math.sin(angle_rad))
rotated_y = int(adjusted_x * math.sin(angle_rad) + adjusted_y * math.cos(angle_rad))

rotated_x += cx
rotated_y += cy

return rotated_x, rotated_y
Vielleicht kann mir jemand helfen.
Vielen Dank im voraus.
Grüße
Benutzeravatar
Kebap
User
Beiträge: 689
Registriert: Dienstag 15. November 2011, 14:20
Wohnort: Dortmund

Hier derselbe Code in Code-Tags:
kasialars hat geschrieben: Donnerstag 25. Januar 2024, 00:07 Hallo bin Kasialars,
habe ein Prob. bin an einem Projekt wo mein Code ein Objekt einmessen soll. Leider bin ich in der Frage wie ich ein Objekt was per def measure_object ein gemessen werden soll die Rotation setzen muss.
Objekt ist 380x80mm und wird per Scanner ein gelesen. Konturen werden erkannt und messung der Breite wird per def measure_line gemessen. Leider funktioniert die Rotation vom Kontur Rechteck nicht wenn es nicht im Winkel eingemessen wird.
Hier mal ein Codebereich der dafür verantwortlich sein soll:

Code: Alles auswählen

    def measure_object(self, file_path):
        try:
            # Bild laden
            image = cv2.imread(file_path)

            # Vorverarbeitung: Glättung mit Gauss-Filter
            smoothed = cv2.GaussianBlur(image, (5, 5), 0)

            # Graustufenkonvertierung
            gray = cv2.cvtColor(smoothed, cv2.COLOR_BGR2GRAY)

            # Adaptive Schwellenwerte anwenden
            edges = cv2.Canny(gray, 50, 150)

            # Morphologische Operationen
            kernel = np.ones((3, 3), np.uint8)
            edges = cv2.dilate(edges, kernel, iterations=1)
            edges = cv2.erode(edges, kernel, iterations=1)

            # Konturen finden, aber keine Schließung verwenden (closed=False)
            contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

            # Filtere Konturen nach ihrer Größe (Bereich)
            min_contour_area = 500  # Passen Sie dies an Ihre Anforderungen an
            contours = [cnt for cnt in contours if cv2.contourArea(cnt) > min_contour_area]

            # Alle Konturen nach ihrem Umfang sortieren
            sorted_contours = sorted(contours, key=lambda x: cv2.arcLength(x, closed=True), reverse=True)

            # Die Kontur mit dem längsten Umfang auswählen
            longest_perimeter_contour = sorted_contours[0]

            # Winkel des grünen Rechtecks extrahieren
            self.angle = longest_perimeter_contour[2]
            print(f"Winkel des grünen Rechtecks: {self.angle} Grad")

            # Linienwinkel entsprechend dem Winkel des grünen Rechtecks setzen
            self.line_angle = self.angle  # oder passen Sie dies nach Ihren Anforderungen an

            # Schwerpunkt der Kontur berechnen
            M = cv2.moments(longest_perimeter_contour)
            cx = int(M["m10"] / M["m00"]) if M["m00"] != 0 else 0
            cy = int(M["m01"] / M["m00"]) if M["m00"] != 0 else 0

            # Rotation Center setzen
            self.rotation_center = (cx, cy)

            # Minimal umschließendes Rechteck (Bounding Box) um die Kontur
            rect = cv2.minAreaRect(longest_perimeter_contour)
            box = cv2.boxPoints(rect)
            box = np.intp(box)

            # Linienbreite für das Rechteck erhöhen auf 4 Pixel (kann nach Bedarf angepasst werden)
            rectangle_thickness = 20

            # Die Kontur mit dem längsten Umfang auswählen
            x, y, w, h = cv2.boundingRect(longest_perimeter_contour)

            cv2.drawContours(image, [box], 0, (0, 255, 0), rectangle_thickness)

            # Winkel des grünen Rechtecks
            angle = rect[2]
            print(f"Winkel des grünen Rechtecks: {angle} Grad")

            # Konturapproximation
            epsilon = 0.02 * cv2.arcLength(longest_perimeter_contour, True)
            longest_contour_approx = cv2.approxPolyDP(longest_perimeter_contour, epsilon, True)

            # Messung der Breite und Höhe in Pixeln
            width_pixel = w
            height_pixel = h

            # Umrechnung in Millimeter (angenommene DPI: 200)
            dpi = 200
            width_mm = width_pixel / dpi * 24.8
            height_mm = height_pixel / dpi * 25.35

            # Rote waagerechte Linien hinzufügen
            middle_measurement_y = y + h // 2
            outer_measurement_y1 = y + 200
            outer_measurement_y2 = y + h - 200

            line_name_middle = "Mitte"
            line_name_outer1 = "Links"
            line_name_outer2 = "Rechts"

            # Übergeben Sie den Winkel des Rechtecks und das Rotationszentrum an die measure_line-Methode
            self.measure_line(image, (x, middle_measurement_y), (x + w, middle_measurement_y), width_mm,
                              line_name_middle, angle, self.rotation_center)
            self.measure_line(image, (x, outer_measurement_y1), (x + w, outer_measurement_y1), width_mm,
                              line_name_outer1, angle, self.rotation_center)
            self.measure_line(image, (x, outer_measurement_y2), (x + w, outer_measurement_y2), width_mm,
                              line_name_outer2, angle, self.rotation_center)


            # Berechne prozentuale Deckung der erkannten Kante
            coverage_percentage = self.calculate_coverage(edges, (x, y, x + w, y + h))
            print(f"Prozentuale Deckung der erkannten Kante: {coverage_percentage:.2f}%")

            # Bild verkleinern und anzeigen
            target_size = (500, 950)
            small_image = cv2.resize(image, target_size)
            self.last_image = small_image  # Bild für die PDF speichern
            self.display_image(small_image)

            # Messwerte speichern
            self.measurement_data = {
                "width_mm": width_mm,
                "height_mm": height_mm,
                "line_name_outer1": line_name_outer1,
                "line_name_middle": line_name_middle,
                "line_name_outer2": line_name_outer2,
                "coverage_percentage": coverage_percentage
            }

            # Messwerte in der App anzeigen
            self.display_measurement()

        except Exception as e:
            print(f"Fehler beim Verarbeiten des Bildes: {e}")

    def measure_line(self, image, start_point, end_point, width_mm, line_name, angle=None, rotation_center=None):
        # ... (vorheriger Code)
        # Linienbreite für die roten Linien erhöhen auf 4 Pixel (kann nach Bedarf angepasst werden)
        line_thickness = 6

        # Falls ein Winkel gegeben ist, rotiere die Start- und Endpunkte
        if angle is not None and rotation_center is not None:
            print(f"Vor der Rotation - Startpunkt: {start_point}, Endpunkt: {end_point}")
            rotated_start_point = self.rotate_point(start_point, angle, rotation_center)
            rotated_end_point = self.rotate_point(end_point, angle, rotation_center)
            print(
                f"Nach der Rotation - Rotierter Startpunkt: {rotated_start_point}, Rotierter Endpunkt: {rotated_end_point}")

            start_point = rotated_start_point
            end_point = rotated_end_point

            # Überprüfen Sie, ob die verschobenen und rotierten Punkte im sichtbaren Bereich liegen
            height, width, _ = image.shape
            if 0 <= start_point[0] < width and 0 <= start_point[1] < height and 0 <= end_point[0] < width and 0 <= \
                    end_point[1] < height:
                # Nachricht ausgeben
                print(f"{line_name} Breite: {width_mm:.2f} mm")
                print(f"Rotierter {line_name} - Startpunkt: {start_point}, Endpunkt: {end_point}")
                return width_mm
            else:
                # Wenn die Linie außerhalb des sichtbaren Bereichs liegt, geben Sie einen Fehler aus
                print(f"Fehler: {line_name} Linie liegt außerhalb des sichtbaren Bereichs")
                return None

    def rotate_point(self, point, angle, center):
        x, y = point
        cx, cy = center

        adjusted_x = x - cx
        adjusted_y = y - cy

        angle_rad = math.radians(angle)

        rotated_x = int(adjusted_x * math.cos(angle_rad) - adjusted_y * math.sin(angle_rad))
        rotated_y = int(adjusted_x * math.sin(angle_rad) + adjusted_y * math.cos(angle_rad))

        rotated_x += cx
        rotated_y += cy

        print(f"Ursprünglicher Punkt: ({x}, {y})")
        print(f"Rotierter Punkt: ({rotated_x}, {rotated_y})")

        return rotated_x, rotated_y

    def rotate_point(self, point, angle, center):
        x, y = point
        cx, cy = center

        adjusted_x = x - cx
        adjusted_y = y - cy

        angle_rad = math.radians(angle)

        rotated_x = int(adjusted_x * math.cos(angle_rad) - adjusted_y * math.sin(angle_rad))
        rotated_y = int(adjusted_x * math.sin(angle_rad) + adjusted_y * math.cos(angle_rad))

        rotated_x += cx
        rotated_y += cy

        return rotated_x, rotated_y
Vielleicht kann mir jemand helfen.
Vielen Dank im voraus.
Grüße
Grundsätzlich wäre es schlau, ein möglichst kleines, aber selbständig lauffähiges Beispiel zu bauen, um den Fehler zu verdeutlichen.
Das macht nicht nur die Fehlersuche leichter, aber manchmal findet man dabei auch selbst schon den Fehler und braucht gar nicht fragen.
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich habe das Problem noch nicht verstanden. Und der Code sieht arg nach ChatGPT aus.
Benutzeravatar
__blackjack__
User
Beiträge: 13131
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Anmerkung: `rotate_point()` ist zweimal definiert, und das ist eigentlich auch gar keine Methode sondern eine Funktion, die das Objekt gar nicht benötigt. Genau wie `measure_line()` auch eine Funktion ist/sein sollte. Und `measure_line()` ist auch kaputt. Wenn man die ”optionalen” Argumente `angle` und `rotation_center` nicht angibt, liefert die Funktion *implizit* `None` zurück. Das heisst die Argumente sind gar nicht optional. Allerdings benutzt auch keiner der drei Aufrufe den Rückgabewert.

`measure_object()` ist ziemlich lang und die Methode verändert den Zustand des Objekts. Was repräsemtiert dieses Objekt denn überhaupt?
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
Benutzeravatar
grubenfox
User
Beiträge: 434
Registriert: Freitag 2. Dezember 2022, 15:49

__deets__ hat geschrieben: Donnerstag 25. Januar 2024, 10:12 Und der Code sieht arg nach ChatGPT aus.
Scheint zu passen.... https://www.heise.de/news/Schlechte-Cod ... 09271.html
Antworten