# -*- 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 ImageBox(QWidget): def __init__(self): super(ImageBox, self).__init__() self.img = None self.scaled_img = None self.start_pos = QPoint(0, 0) self.end_pos = QPoint(0, 0) self.left_click = False self.wheel_flag = False self.scale = 1 self.old_scale = 1 self.point = QPoint(0, 0) self.x = -1 self.y = -1 self.new_height = -1 self.new_width = -1 def init_ui(self): self.setWindowTitle("ImageBox") def set_image(self, img_path): self.img = QPixmap(img_path) print(type(img_path)) global path_img path_img = img_path width, height = self.img.width(), self.img.height() if height / width > 1000 / 1800: new_height = 1000 new_width = width * 1000 / height else: new_height = height * 1800 / width new_width = 1800 self.point = QPoint(int((1800 - new_width) * 0.5), int((1000 - new_height) * 0.5)) self.img = self.img.scaled(new_width, new_height, Qt.KeepAspectRatio) self.scaled_img = self.img self.new_height = new_height self.new_width = new_width self.scale = 1 # def set_image(self, img_path): # self.img = QPixmap(img_path) # print(type(img_path)) # global path_img # path_img = img_path # width, height = self.img.width(), self.img.height() # if height / width > 990 / 660: # new_height = 990 # new_width = width * 990 / height # else: # new_height = height * 660 / width # new_width = 660 # self.point = QPoint(int((660 - new_width) * 0.5), int((990 - new_height) * 0.5)) # self.img = self.img.scaled(new_width, new_height, Qt.KeepAspectRatio) # self.scaled_img = self.img # # self.new_height = new_height # self.new_width = new_width # self.scale = 1 def paintEvent(self, e): if self.scaled_img: painter = QPainter(self) painter.begin(self) # 设置画笔的颜色, 字体大小, 线的实心样式 pen = QPen(Qt.red, 3) painter.setPen(pen) painter.scale(self.scale, self.scale) if self.wheel_flag: # 定点缩放 self.wheel_flag = False # 判断当前鼠标pos在不在图上 this_left_x = self.point.x() * self.old_scale this_left_y = self.point.y() * self.old_scale this_scale_width = self.new_width * self.old_scale this_scale_height = self.new_height * self.old_scale # 鼠标点在图上,以鼠标点为中心动作 gap_x = self.x - this_left_x gap_y = self.y - this_left_y if 0 < gap_x < this_scale_width and 0 < gap_y < this_scale_height: new_left_x = int(self.x / self.scale - gap_x / self.old_scale) new_left_y = int(self.y / self.scale - gap_y / self.old_scale) self.point = QPoint(new_left_x, new_left_y) # 鼠标点不在图上,固定左上角进行缩放 else: true_left_x = int(self.point.x() * self.old_scale / self.scale) true_left_y = int(self.point.y() * self.old_scale / self.scale) self.point = QPoint(true_left_x, true_left_y) painter2 = QPainter(self.scaled_img) painter2.drawLine(self.start_pos, self.end_pos) # self.start_pos = self.end_pos # painter.drawPoint(self.start_pos) # painter2 = QPainter(self) painter.drawPixmap(0, 0, self.scaled_img) # 此函数中还会用scale对point进行处理 painter.end() def wheelEvent(self, event): angle = event.angleDelta() / 8 # 返回QPoint对象,为滚轮转过的数值,单位为1/8度 angleY = angle.y() self.old_scale = self.scale self.x, self.y = event.x(), event.y() self.wheel_flag = True # 获取当前鼠标相对于view的位置 if angleY > 0: self.scale *= 1.08 else: # 滚轮下滚 self.scale *= 0.92 if self.scale < 0.3: self.scale = 0.3 self.adjustSize() self.update() def mouseMoveEvent(self, e): if self.left_click: self.end_pos = e.pos() self.update() # if self.left_click: # self.end_pos = e.pos() - self.start_pos # 当前位置-起始位置=差值 # self.point = self.point + self.end_pos / self.scale # 左上角的距离变化 # self.start_pos = e.pos() # self.repaint() def mousePressEvent(self, e): if e.button() == Qt.LeftButton: self.left_click = True self.start_pos = e.pos() def mouseReleaseEvent(self, e): if e.button() == Qt.LeftButton: self.left_click = False self.end_pos = e.pos() self.update() 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: if self.canvas.shapes: self.canvas_clear() self.set_default() 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 canvas_clear(self): self.canvas.setEditing(True) self.canvas.shapes.clear() self.canvas.line_number = None self.canvas.current = None self.canvas.selectedShape = None def set_default(self): self.beg1.setText('null') self.end1.setText('null') self.beg2.setText('null') self.end2.setText('null') self.beg3.setText('null') self.end3.setText('null') self.beg4.setText('null') self.end4.setText('null') self.beg5.setText('null') self.end5.setText('null') self.beg6.setText('null') self.end6.setText('null') self.beg7.setText('null') self.end7.setText('null') self.beg8.setText('null') self.end8.setText('null') self.beg9.setText('null') self.end9.setText('null') self.beg10.setText('null') self.end10.setText('null') self.refLen1.setText('') self.refLen2.setText('') self.refHei.setText('') self.height.setText('result1') self.length.setText('result2') self.width.setText('result3') 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): if self.refLen1.text() != '': self.len = eval(self.refLen1.text()) def ref_width(self): if self.refLen2.text() != '': self.wid = eval(self.refLen2.text()) def ref_height(self): if self.refHei.text() != '': self.hei = eval(self.refHei.text()) def cal_height(self): try: # 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)) except: self.height.setText('请检查数据输入是否完整且正确!') def cal_length(self): try: 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)) except: self.length.setText('请检查数据输入是否完整且正确!') def cal_width(self): try: 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)) except: self.width.setText('请检查数据输入是否完整且正确!') 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()