# -*- coding: utf-8 -*- import math import os import sys from demo import * from PyQt5.QtGui import QPen, QImage, QCursor from PyQt5.QtWidgets import QWidget, QApplication, QFileDialog, \ QMainWindow from PyQt5.Qt import QPixmap, QPoint, Qt, QPainter from libs.canvas import Canvas from libs.tools import line_intersection, str_tuple, norm def read(filename, default=None): try: with open(filename, 'rb') as f: return f.read() except: return default class MyWindow(Ui_MainWindow, QMainWindow): def __init__(self): super().__init__() self.height = None self.width = None self.length = None self.setupUi(self) self.init_ui() def init_ui(self): self.canvas = Canvas() self.canvas.zoomRequest.connect(self.zoomRequest) self.scrollArea.setWidget(self.canvas) self.scrollArea.setWidgetResizable(True) self.scrollBars = { Qt.Vertical: self.scrollArea.verticalScrollBar(), Qt.Horizontal: self.scrollArea.horizontalScrollBar() } self.adjustZoomSlider.valueChanged.connect(self.adjustZoom) self.canvas.scrollRequest.connect(self.scrollRequest) self.canvas.newShape.connect(self.newShape) # self.canvas.shapeMoved.connect(self.setDirty) # self.canvas.selectionChanged.connect(self.shapeSelectionChanged) self.canvas.drawingPolygon.connect(self.toggleDrawingSensitive) self.canvas.updateData.connect(self.updateData) self.itemsToShapes = {} self.shapesToItems = {} # Application state. self.image = QImage() self.original_image = QImage() self.open_file.clicked.connect(self.open_image) self.btn1.clicked.connect(self.push_btn1) self.btn2.clicked.connect(self.push_btn2) self.btn3.clicked.connect(self.push_btn3) self.btn4.clicked.connect(self.push_btn4) self.btn5.clicked.connect(self.push_btn5) self.btn6.clicked.connect(self.push_btn6) self.btn7.clicked.connect(self.push_btn7) self.btn8.clicked.connect(self.push_btn8) self.btn9.clicked.connect(self.push_btn9) self.btn10.clicked.connect(self.push_btn10) self.btn_refLen1.clicked.connect(self.ref_len) self.btn_refLen2.clicked.connect(self.ref_width) self.btn_refheight.clicked.connect(self.ref_height) self.btn_height.clicked.connect(self.cal_height) self.btn_length.clicked.connect(self.cal_length) self.btn_width.clicked.connect(self.cal_width) def open_image(self): try: filename, _ = QFileDialog.getOpenFileName(None, "Open Image File", "", "All Files(*);;*.jpg;;*.png;;*.jpeg") if filename: if isinstance(filename, (tuple, list)): filename = filename[0] self.loadFile(filename) except Exception as ex: print(ex) def adjustZoom(self, value): self.adjustZoomNumLabel.setText(str.format("{value} %", value=value)) self.paintCanvas() def scrollRequest(self, delta, orientation): units = - delta / (8 * 15) bar = self.scrollBars[orientation] bar.setValue(bar.value() + bar.singleStep() * units) def newShape(self): """Pop-up and give focus to the label editor. position MUST be in global coordinates. """ self.canvas.setEditing(True) def toggleDrawingSensitive(self, drawing=True): """In the middle of drawing, toggling between modes should be disabled.""" pass def qpoint_tupleStr(self, qpoint): return str((int(qpoint.x()), int(qpoint.y()))) def zoomRequest(self, delta): # get the current scrollbar positions # calculate the percentages ~ coordinates h_bar = self.scrollBars[Qt.Horizontal] v_bar = self.scrollBars[Qt.Vertical] # get the current maximum, to know the difference after zooming h_bar_max = h_bar.maximum() v_bar_max = v_bar.maximum() # get the cursor position and canvas size # calculate the desired movement from 0 to 1 # where 0 = move left # 1 = move right # up and down analogous cursor = QCursor() pos = cursor.pos() relative_pos = QWidget.mapFromGlobal(self, pos) cursor_x = relative_pos.x() cursor_y = relative_pos.y() w = self.scrollArea.width() h = self.scrollArea.height() # the scaling from 0 to 1 has some padding # you don't have to hit the very leftmost pixel for a maximum-left movement margin = 0.1 move_x = (cursor_x - margin * w) / (w - 2 * margin * w) move_y = (cursor_y - margin * h) / (h - 2 * margin * h) # clamp the values from 0 to 1 move_x = min(max(move_x, 0), 1) move_y = min(max(move_y, 0), 1) # get the difference in scrollbar values # this is how far we can move d_h_bar_max = h_bar.maximum() - h_bar_max d_v_bar_max = v_bar.maximum() - v_bar_max # get the new scrollbar values new_h_bar_value = h_bar.value() + move_x * d_h_bar_max new_v_bar_value = v_bar.value() + move_y * d_v_bar_max h_bar.setValue(new_h_bar_value) v_bar.setValue(new_v_bar_value) def resetState(self): self.itemsToShapes.clear() self.shapesToItems.clear() self.canvas.resetState() def loadFile(self, filePath=None): """Load the specified file""" self.resetState() self.canvas.setEnabled(False) unicodeFilePath = str(filePath) if unicodeFilePath and os.path.exists(unicodeFilePath): # Load image: # read data first and store for saving into label file. imageData = read(unicodeFilePath, None) image = QImage.fromData(imageData) self.image = image self.original_image = image pixmap = QPixmap.fromImage(image) self.canvas.loadPixmap(pixmap) self.canvas.setEnabled(True) # self.adjustScale() self.paintCanvas() return True return False def paintCanvas(self): assert not self.image.isNull(), "cannot paint null image" self.canvas.scale = 0.01 * self.adjustZoomSlider.value() self.canvas.adjustSize() self.canvas.update() def updateData(self, x): for shape in self.canvas.shapes: if shape.label == 'line_x1': self.beg1.setText(self.qpoint_tupleStr(shape.points[0])) self.end1.setText(self.qpoint_tupleStr(shape.points[1])) elif shape.label == 'line_x2': self.beg2.setText(self.qpoint_tupleStr(shape.points[0])) self.end2.setText(self.qpoint_tupleStr(shape.points[1])) elif shape.label == 'line_y1': self.beg3.setText(self.qpoint_tupleStr(shape.points[0])) self.end3.setText(self.qpoint_tupleStr(shape.points[1])) elif shape.label == 'line_y2': self.beg4.setText(self.qpoint_tupleStr(shape.points[0])) self.end4.setText(self.qpoint_tupleStr(shape.points[1])) elif shape.label == 'line_z3': self.beg5.setText(self.qpoint_tupleStr(shape.points[0])) self.end5.setText(self.qpoint_tupleStr(shape.points[1])) elif shape.label == 'line_height': self.beg6.setText(self.qpoint_tupleStr(shape.points[0])) self.end6.setText(self.qpoint_tupleStr(shape.points[1])) elif shape.label == 'line_z1': self.beg7.setText(self.qpoint_tupleStr(shape.points[0])) self.end7.setText(self.qpoint_tupleStr(shape.points[1])) elif shape.label == 'line_z2': self.beg8.setText(self.qpoint_tupleStr(shape.points[0])) self.end8.setText(self.qpoint_tupleStr(shape.points[1])) elif shape.label == 'line_length': self.beg9.setText(self.qpoint_tupleStr(shape.points[0])) self.end9.setText(self.qpoint_tupleStr(shape.points[1])) elif shape.label == 'line_width': self.beg10.setText(self.qpoint_tupleStr(shape.points[0])) self.end10.setText(self.qpoint_tupleStr(shape.points[1])) def push_btn1(self): self.canvas.setEditing(False) self.canvas.line_number = 'line_x1' def push_btn2(self): self.canvas.setEditing(False) self.canvas.line_number = 'line_x2' def push_btn3(self): self.canvas.setEditing(False) self.canvas.line_number = 'line_y1' def push_btn4(self): self.canvas.setEditing(False) self.canvas.line_number = 'line_y2' def push_btn5(self): self.canvas.setEditing(False) self.canvas.line_number = 'line_z3' def push_btn6(self): self.canvas.setEditing(False) self.canvas.line_number = 'line_height' def push_btn7(self): self.canvas.setEditing(False) self.canvas.line_number = 'line_z1' def push_btn8(self): self.canvas.setEditing(False) self.canvas.line_number = 'line_z2' def push_btn9(self): self.canvas.setEditing(False) self.canvas.line_number = 'line_length' def push_btn10(self): self.canvas.setEditing(False) self.canvas.line_number = 'line_width' def ref_len(self): self.len = eval(self.refLen1.text()) def ref_width(self): self.wid = eval(self.refLen2.text()) def ref_height(self): self.hei = eval(self.refHei.text()) def cal_height(self): # x,y,z方向的灭点 xVanish = line_intersection([str_tuple(self.beg1.text()), str_tuple(self.end1.text())], [str_tuple(self.beg2.text()), str_tuple(self.end2.text())]) yVanish = line_intersection([str_tuple(self.beg3.text()), str_tuple(self.end3.text())], [str_tuple(self.beg4.text()), str_tuple(self.end4.text())]) zVanish = line_intersection([str_tuple(self.beg7.text()), str_tuple(self.end7.text())], [str_tuple(self.beg8.text()), str_tuple(self.end8.text())]) vertex = line_intersection([xVanish, yVanish], [str_tuple(self.beg5.text()), str_tuple(self.beg6.text())]) bot = str_tuple(self.beg6.text()) ref = line_intersection([vertex, str_tuple(self.end5.text())], [str_tuple(self.beg6.text()), str_tuple(self.end6.text())]) top = str_tuple(self.end6.text()) ref_height = self.hei height = (norm(top, bot)/norm(ref, bot)) * (norm(zVanish, ref)/norm(zVanish, top)) * ref_height self.height.setText(str(height)) def cal_length(self): beg = str_tuple(self.beg9.text()) end = str_tuple(self.end9.text()) refLen1 = self.len refLen2 = self.wid length = self.cal_distance(beg, end, refLen1, refLen2) self.length.setText(str(length)) def cal_width(self): beg = str_tuple(self.beg10.text()) end = str_tuple(self.end10.text()) refLen1 = self.len refLen2 = self.wid length = self.cal_distance(beg, end, refLen1, refLen2) self.width.setText(str(length)) def cal_distance(self, beg, end, refLen1, refLen2): # 矩形四条边交点 S1 = line_intersection([str_tuple(self.beg1.text()), str_tuple(self.end1.text())], [str_tuple(self.beg3.text()), str_tuple(self.end3.text())]) S2 = line_intersection([str_tuple(self.beg1.text()), str_tuple(self.end1.text())], [str_tuple(self.beg4.text()), str_tuple(self.end4.text())]) S3 = line_intersection([str_tuple(self.beg2.text()), str_tuple(self.end2.text())], [str_tuple(self.beg4.text()), str_tuple(self.end4.text())]) S4 = line_intersection([str_tuple(self.beg2.text()), str_tuple(self.end2.text())], [str_tuple(self.beg3.text()), str_tuple(self.end3.text())]) # x方向和y方向灭点 xVanish = line_intersection([str_tuple(self.beg1.text()), str_tuple(self.end1.text())], [str_tuple(self.beg2.text()), str_tuple(self.end2.text())]) yVanish = line_intersection([str_tuple(self.beg3.text()), str_tuple(self.end3.text())], [str_tuple(self.beg4.text()), str_tuple(self.end4.text())]) # 线与矩形四条边交点 B1 = line_intersection([str_tuple(self.beg1.text()), str_tuple(self.end1.text())], [beg, end]) B3 = line_intersection([str_tuple(self.beg4.text()), str_tuple(self.end4.text())], [beg, end]) B2 = line_intersection([str_tuple(self.beg2.text()), str_tuple(self.end2.text())], [beg, end]) B4 = line_intersection([str_tuple(self.beg3.text()), str_tuple(self.end3.text())], [beg, end]) if B1 == xVanish: vertex = line_intersection([xVanish, yVanish], [beg, S1[0]]) bot = beg ref = line_intersection([vertex, S1[1]], [beg, end]) top = end return (norm(top, bot)/norm(ref, bot))*(norm(xVanish, ref)/norm(xVanish, top)) * refLen1 elif B3 == yVanish: vertex = line_intersection([xVanish, yVanish], [beg, S2[0]]) bot = beg ref = line_intersection([vertex, S2[1]], [beg, end]) top = end return (norm(top, bot) / norm(ref, bot)) * (norm(yVanish, ref) / norm(yVanish, top)) * refLen2 else: vertex = line_intersection([xVanish, yVanish], [beg, end]) S1B1 = (norm(S1, B1) / norm(S1, S2)) * (norm(S2, xVanish) / norm(B1, xVanish)) * refLen1 S1B4 = (norm(S1, B4) / norm(S1, S4)) * (norm(S4, yVanish) / norm(B4, yVanish)) * refLen2 B1B4 = math.sqrt(S1B1**2 + S1B4**2) B4A1 = (norm(B4, end) / norm(B1, B4)) * (norm(B1, vertex) / norm(end, vertex)) * B1B4 return (norm(beg, end) / norm(B4, end)) * (norm(B4, vertex) / norm(beg, vertex)) * B4A1 if __name__ == '__main__': app = QApplication(sys.argv) w = MyWindow() w.show() app.exec()