/
Sementr
/
microscope1
Обзор
Документация
Войти
/
Sementr
/
microscope1
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
7
Аналитика
Безопасность
patch3
3.py
302 строки
14 KB
Sementr
update 3.py
27 фев 2025, 15:33
27 фев 2025, 15:33
8ccc28a
Код
Авторство
О чём код?
import sys import cv2 import numpy as np from PyQt6.QtWidgets import ( QApplication, QMainWindow, QWidget, QVBoxLayout, QSlider, QPushButton, QLabel, QHBoxLayout, QFileDialog, QStatusBar, QMessageBox, QLineEdit ) from PyQt6.QtGui import QImage, QPixmap, QColorDialog, QPainter, QPen from PyQt6.QtCore import Qt, QTimer, QPoint from datetime import datetime class ImageEditor(QWidget): def __init__(self, image=None): # настройки приложения при старте super().__init__() self.setWindowTitle("Редактор изображений") self.image = image self.temp_image = image.copy() if image is not None else None self.drawing = False self.last_point = QPoint() self.pen_color = Qt.GlobalColor.black self.tool = "pen" self.points = [] # Список точек, которые будут добавляться self.scale_factor = 1 # Фактор для калибровки (см. шаг калибровки) self.area = 0 self.perimeter = 0 self.scale_line_start = None self.scale_line_end = None # Начало и конец линии линейки self.scale_length_real = None # Реальная длина линейки self.is_scaling = False # Флаг для калибровки self.initUI() def initUI(self): layout = QVBoxLayout(self) # создание окна self.image_label = QLabel(self) layout.addWidget(self.image_label) # Инструменты btn_layout = QHBoxLayout() self.load_btn = QPushButton("Загрузить") self.load_btn.clicked.connect(self.load_image) # кнопка загрузить btn_layout.addWidget(self.load_btn) self.save_btn = QPushButton("Сохранить") self.save_btn.clicked.connect(self.save_image) # кнопка сохранить btn_layout.addWidget(self.save_btn) self.pen_btn = QPushButton("Карандаш") self.pen_btn.clicked.connect(lambda: self.select_tool("pen")) # кнопка карандашшшшшшш btn_layout.addWidget(self.pen_btn) self.eraser_btn = QPushButton("Ластик") self.eraser_btn.clicked.connect(lambda: self.select_tool("eraser")) # кнопка ластичка btn_layout.addWidget(self.eraser_btn) self.arrow_btn = QPushButton("Стрелка") self.arrow_btn.clicked.connect(lambda: self.select_tool("arrow")) # кнопка стреличка btn_layout.addWidget(self.arrow_btn) self.text_btn = QPushButton("Текст") self.text_btn.clicked.connect(lambda: self.select_tool("text")) # кнопка текст btn_layout.addWidget(self.text_btn) self.color_btn = QPushButton("Цвет") self.color_btn.clicked.connect(self.select_color) # кнопка выборы выборы цвееееета btn_layout.addWidget(self.color_btn) layout.addLayout(btn_layout) # Калибровка calib_layout = QFormLayout() self.scale_input = QLineEdit(self) self.scale_input.setPlaceholderText("Введите калибровку (см/пиксель)") calib_layout.addRow("Калибровка:", self.scale_input) self.scale_input.returnPressed.connect(self.set_scale_factor) layout.addLayout(calib_layout) # Площадь и периметр self.area_label = QLabel(f"Площадь: {self.area} см²", self) self.perimeter_label = QLabel(f"Периметр: {self.perimeter} см", self) layout.addWidget(self.area_label) layout.addWidget(self.perimeter_label) self.setLayout(layout) if self.image is not None: self.set_image(self.image) def load_image(self): file_path, _ = QFileDialog.getOpenFileName(self, "Выберите изображение", "", "Images (*.png *.jpg *.jpeg)") # кнопка для выбора файла для редоктир if file_path: self.image = cv2.imread(file_path) self.temp_image = self.image.copy() # сохраняем копию для редактирования self.set_image(self.image) def set_image(self, image): height, width, ch = image.shape bytes_per_line = ch * width q_img = QImage(image.data, width, height, bytes_per_line, QImage.Format.Format_BGR888) # разбивка для рисования pixmap = QPixmap.fromImage(q_img) self.image_label.setPixmap(pixmap) def save_image(self): if self.image is not None: file_path, _ = QFileDialog.getSaveFileName(self, "Сохранить изображение", "", "Images (*.png *.jpg *.jpeg)") # кнопка сохранить if file_path: cv2.imwrite(file_path, self.image) QMessageBox.information(self, "Сохранено", "Изображение успешно сохранено!") def select_tool(self, tool): # для выбора инструмеееента self.tool = tool def select_color(self): color = QColorDialog.getColor(self.pen_color, self) # выбор цвита if color.isValid(): self.pen_color = color def set_scale_factor(self): try: scale = float(self.scale_input.text()) # калебратор if scale > 0: self.scale_factor = scale else: QMessageBox.warning(self, "Ошибка", "Невозможно установить отрицательное значение!") except ValueError: QMessageBox.warning(self, "Ошибка", "Введите числовое значение для калибровки!") def mousePressEvent(self, event): if event.button() == Qt.MouseButton.LeftButton: self.last_point = event.pos() if self.tool == "pen": self.drawing = True elif self.tool == "scale" and self.is_scaling: # ивент для понятия где мышь повесилась # Начало рисования линейки self.scale_line_start = event.pos() elif self.tool == "text": # Место для добавления текста pass def mouseMoveEvent(self, event): if self.drawing and self.tool == "pen": painter = QPainter(self.temp_image) painter.setPen(QPen(self.pen_color, 5, Qt.PenStyle.SolidLine)) # размер painter.drawLine(self.last_point, event.pos()) self.last_point = event.pos() self.update() elif self.tool == "scale" and self.is_scaling: self.scale_line_end = event.pos() self.update() def mouseReleaseEvent(self, event): if self.drawing and self.tool == "pen": self.drawing = False # площадь периметр self.points.append(self.last_point) # Добавляем точку # Пересчитываем площадь и периметр self.update_area_and_perimeter() elif self.tool == "scale" and self.is_scaling: self.is_scaling = False self.scale_line_end = event.pos() # Конец линейки self.update() # Расчет реальной длины линии self.ask_for_scale_length() def ask_for_scale_length(self): # Диалог для ввода реальной длины линии length, ok = QInputDialog.getDouble(self, "Введите длину линейки", "Длина (см):", 1, 0, 1000, 2) if ok and length > 0: self.scale_length_real = length # Сохраняем длину линейки в см # колебровка self.calculate_scale_factor() def calculate_scale_factor(self): # Вычисляем калибровку: пиксели на 1 см pixel_distance = np.linalg.norm( np.array([self.scale_line_end.x(), self.scale_line_end.y()]) - np.array([self.scale_line_start.x(), self.scale_line_start.y()]) ) self.scale_factor = pixel_distance / self.scale_length_real # Калибровка: пиксели/см self.scale_input.setText(f"{self.scale_factor:.2f}") def update_area_and_perimeter(self): # Вычисляем периметр и площадь по точкам if len(self.points) < 3: self.area = 0 self.perimeter = 0 else: # Вычисляем периметр и площадь по точкам contours = np.array([[(point.x(), point.y()) for point in self.points]], dtype=np.int32) area = cv2.contourArea(contours) perimeter = cv2.arcLength(contours, True) # Переводим в реальные единицы с учетом калибровки self.area = area / (self.scale_factor ** 2) # Площадь в см² self.perimeter = perimeter / self.scale_factor # Периметр в см self.area_label.setText(f"Площадь: {self.area:.2f} см²") self.perimeter_label.setText(f"Периметр: {self.perimeter:.2f} см") def paintEvent(self, event): painter = QPainter(self) painter.drawPixmap(0, 0, self.image_label.pixmap()) # Отображаем изображение if self.points: pen = QPen(self.pen_color) pen.setWidth(5) painter.setPen(pen) for point in self.points: painter.drawEllipse(point, 5, 5) # Отображаем точки # Отображаем линейку if self.scale_line_start and self.scale_line_end: painter.setPen(QPen(Qt.GlobalColor.red, 3, Qt.PenStyle.DashLine)) painter.drawLine(self.scale_line_start, self.scale_line_end) # Рисуем линейку painter.end() class MicroscopeControl(QMainWindow): def __init__(self): super().__init__() self.capture = None self.timer = QTimer() self.save_directory = None # Путь для сохранения self.image = None # Добавлено для хранения захваченного изображения self.initUI() def initUI(self): self.setWindowTitle('Microscope Control') self.setGeometry(100, 100, 800, 600) central_widget = QWidget() self.setCentralWidget(central_widget) layout = QVBoxLayout(central_widget) # Элементы управления self.captureButton = QPushButton('Захват кадра') self.captureButton.clicked.connect(self.captureFrame) self.openEditorButton = QPushButton('Открыть редактор') self.openEditorButton.clicked.connect(self.openImageEditor) # Кнопка для открытия редактора layout.addWidget(self.captureButton) layout.addWidget(self.openEditorButton) self.statusBar = QStatusBar() self.setStatusBar(self.statusBar) self.timer.timeout.connect(self.updateFrame) self.startVideoCapture() def startVideoCapture(self): # Подключение к камере self.capture = cv2.VideoCapture('http://<IP_Raspberry_Pi>:5000/video_feed') # Вставьте IP Raspberry Pi self.timer.start(30) def updateFrame(self): if self.capture is not None: ret, frame = self.capture.read() if ret: self.image = frame # Сохраняем захваченное изображение # Отображаем его на экране в интерфейсе (можно добавить сюда обработку через QPixmap) def captureFrame(self): if self.capture is not None: ret, frame = self.capture.read() if ret: # Сохраняем кадр в файл now = datetime.now() timestamp = now.strftime("%Y.%m.%d-%H.%M.%S") file_path = f"{self.save_directory}/captured_frame_{timestamp}.png" cv2.imwrite(file_path, frame) QMessageBox.information(self, 'Захват кадра', f'Кадр сохранён: {file_path}') # Открытие редактора с захваченным изображением self.openImageEditor(frame) def openImageEditor(self, frame=None): if frame is None and self.image is None: QMessageBox.warning(self, "Ошибка", "Нет изображения для открытия в редакторе!") return editor = ImageEditor(image=frame if frame is not None else self.image) # Передаем захваченное изображение в редактор editor.show() def chooseDirectory(self): folder = QFileDialog.getExistingDirectory(self, "Выберите папку для сохранения кадра") if folder: self.save_directory = folder QMessageBox.information(self, 'Выбор папки', f'Папка выбрана: {folder}') else: QMessageBox.warning(self, 'Выбор папки', 'Папка не выбрана.') def closeEvent(self, event): if self.capture is not None: self.capture.release() event.accept() if __name__ == '__main__': app = QApplication(sys.argv) ex = MicroscopeControl() ex.show() sys.exit(app.exec())