545 lines
21 KiB
Python
545 lines
21 KiB
Python
# -*- 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()
|
||
|