Rotation von Messlinien die sich zu einem Rechteck was nicht im winkel ist mit drehen!
Verfasst: 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:
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
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