Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # An image scale measurement tool (in pixels). Place all the images in the current folder
- from PyQt5 import QtCore, QtGui, QtWidgets
- import math
- import os
- import sys
- from PyQt5.QtCore import QEvent, Qt, pyqtSignal, pyqtSlot, QPointF, QPoint, QRectF
- from PyQt5.QtGui import QPixmap, QPainter, QPen, QPalette
- from PyQt5.QtWidgets import QMainWindow, QGraphicsScene, QGraphicsPixmapItem, QGraphicsView, QGraphicsLineItem, QFrame
- from PyQt5.QtWidgets import QApplication, QMessageBox
- class Ui_Window(object):
- def setupUi(self, MainWindow):
- MainWindow.setObjectName("MainWindow")
- MainWindow.resize(1017, 639)
- self.centralwidget = QtWidgets.QWidget(MainWindow)
- self.centralwidget.setObjectName("centralwidget")
- self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
- self.gridLayout.setObjectName("gridLayout")
- self.frame = QtWidgets.QFrame(self.centralwidget)
- self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
- self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
- self.frame.setObjectName("frame")
- self.gridLayout_8 = QtWidgets.QGridLayout(self.frame)
- self.gridLayout_8.setObjectName("gridLayout_8")
- self.pushButton = QtWidgets.QPushButton(self.frame)
- self.pushButton.setObjectName("pushButton")
- self.gridLayout_8.addWidget(self.pushButton, 1, 0, 1, 1)
- self.listWidget = QtWidgets.QListWidget(self.frame)
- self.listWidget.setObjectName("listWidget")
- self.gridLayout_8.addWidget(self.listWidget, 0, 0, 1, 1)
- self.gridLayout.addWidget(self.frame, 0, 0, 1, 1)
- MainWindow.setCentralWidget(self.centralwidget)
- self.statusbar = QtWidgets.QStatusBar(MainWindow)
- self.statusbar.setObjectName("statusbar")
- MainWindow.setStatusBar(self.statusbar)
- self.retranslateUi(MainWindow)
- QtCore.QMetaObject.connectSlotsByName(MainWindow)
- def retranslateUi(self, MainWindow):
- _translate = QtCore.QCoreApplication.translate
- MainWindow.setWindowTitle(_translate("MainWindow", "Image Analyzer"))
- self.pushButton.setText(_translate("MainWindow", "Update Location"))
- class Window(Ui_Window, QMainWindow):
- def __init__(self):
- super(Window, self).__init__()
- self.setupUi(self)
- self.form = ImageCheck(self) # The view image form window where we can also measure distances
- self.img_files = [] # Source image file paths
- self.listWidget.itemDoubleClicked.connect(self.item_click)
- self.pushButton.clicked.connect(self.update)
- self.listWidget.clear()
- # To determine what happens when clicked on the text editor
- def item_click(self):
- path = self.listWidget.currentItem().text() # A local Variable called "path"
- if os.path.isfile(path):
- self.form.setImage(path)
- self.form.show()
- def update(self):
- for root, dirs, files in os.walk(os.getcwd()):
- for name in files:
- if ".jpg" in name:
- self.img_files.append(os.path.join(root, name))
- self.listWidget.addItem("Current source folder has the following images")
- for i in range(len(self.img_files)):
- self.listWidget.addItem(self.img_files[i]) # In their order of discovery
- self.listWidget.addItem("\n")
- class Ui_ImageWindow(object):
- def setupUi(self, MainWindow):
- MainWindow.setObjectName("MainWindow")
- MainWindow.resize(977, 928)
- self.centralwidget = QtWidgets.QWidget(MainWindow)
- self.centralwidget.setObjectName("centralwidget")
- self.gridLayout_2 = QtWidgets.QGridLayout(self.centralwidget)
- self.gridLayout_2.setObjectName("gridLayout_2")
- self.frame_1 = QtWidgets.QFrame(self.centralwidget)
- self.frame_1.setFrameShape(QtWidgets.QFrame.StyledPanel)
- self.frame_1.setFrameShadow(QtWidgets.QFrame.Raised)
- self.frame_1.setObjectName("frame_1")
- self.gridLayout_3 = QtWidgets.QGridLayout(self.frame_1)
- self.gridLayout_3.setObjectName("gridLayout_3")
- self.frame_3 = QtWidgets.QFrame(self.frame_1)
- self.frame_3.setFrameShape(QtWidgets.QFrame.StyledPanel)
- self.frame_3.setFrameShadow(QtWidgets.QFrame.Raised)
- self.frame_3.setObjectName("frame_3")
- self.gridLayout = QtWidgets.QGridLayout(self.frame_3)
- self.gridLayout.setObjectName("gridLayout")
- self.pushButton_2 = QtWidgets.QPushButton(self.frame_3)
- self.pushButton_2.setMaximumSize(QtCore.QSize(200, 30))
- self.pushButton_2.setObjectName("pushButton_2")
- self.gridLayout.addWidget(self.pushButton_2, 0, 3, 1, 1)
- self.pushButton_1 = QtWidgets.QPushButton(self.frame_3)
- self.pushButton_1.setMaximumSize(QtCore.QSize(200, 30))
- self.pushButton_1.setObjectName("pushButton_1")
- self.gridLayout.addWidget(self.pushButton_1, 0, 4, 1, 1)
- self.lcdNumber_1 = QtWidgets.QLCDNumber(self.frame_3)
- font = QtGui.QFont()
- font.setFamily("Arial")
- font.setPointSize(10)
- font.setBold(True)
- font.setWeight(75)
- self.lcdNumber_1.setFont(font)
- self.lcdNumber_1.setAutoFillBackground(False)
- self.lcdNumber_1.setFrameShape(QtWidgets.QFrame.Box)
- self.lcdNumber_1.setFrameShadow(QtWidgets.QFrame.Plain)
- self.lcdNumber_1.setSmallDecimalPoint(False)
- self.lcdNumber_1.setDigitCount(5)
- self.lcdNumber_1.setMode(QtWidgets.QLCDNumber.Dec)
- self.lcdNumber_1.setSegmentStyle(QtWidgets.QLCDNumber.Flat)
- self.lcdNumber_1.setObjectName("lcdNumber_1")
- self.gridLayout.addWidget(self.lcdNumber_1, 0, 1, 1, 1)
- self.label_1 = QtWidgets.QLabel(self.frame_3)
- self.label_1.setObjectName("label_1")
- self.gridLayout.addWidget(self.label_1, 0, 0, 1, 1)
- spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
- self.gridLayout.addItem(spacerItem, 0, 2, 1, 1)
- self.gridLayout_3.addWidget(self.frame_3, 2, 0, 1, 1)
- self.frame_2 = QtWidgets.QFrame(self.frame_1)
- self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel)
- self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised)
- self.frame_2.setObjectName("frame_2")
- self.gridLayout_8 = QtWidgets.QGridLayout(self.frame_2)
- self.gridLayout_8.setObjectName("gridLayout_8")
- self.graphicsView = QtWidgets.QGraphicsView(self.frame_2)
- self.graphicsView.setObjectName("graphicsView")
- self.gridLayout_8.addWidget(self.graphicsView, 2, 0, 1, 2)
- self.gridLayout_3.addWidget(self.frame_2, 1, 0, 1, 1)
- self.gridLayout_2.addWidget(self.frame_1, 0, 0, 1, 1)
- MainWindow.setCentralWidget(self.centralwidget)
- self.retranslateUi(MainWindow)
- QtCore.QMetaObject.connectSlotsByName(MainWindow)
- def retranslateUi(self, MainWindow):
- _translate = QtCore.QCoreApplication.translate
- MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
- self.pushButton_2.setText(_translate("MainWindow", "Cancel"))
- self.pushButton_1.setText(_translate("MainWindow", "OK"))
- self.label_1.setText(_translate("MainWindow", "Distance"))
- # The Image show window upon double click list widget, where we can also measure the distances
- class ImageCheck(Ui_ImageWindow, QMainWindow):
- pointChanged = pyqtSignal(QPointF, QPointF, float) # The value is passed from the view upon mouse button clicks
- def __init__(self, parent=None):
- super(ImageCheck, self).__init__()
- self.setupUi(self)
- self.crop_ratio_w = 1 # resolution difference in image when window resize
- self.crop_ratio_h = 1 # resolution difference in image when window resize
- self.path = None
- self.pixmap = None
- self.lineItem = None
- self.pushButton_1.clicked.connect(self.click1) # OK
- self.pushButton_2.clicked.connect(self.click2) # Cancel
- # My Scene
- self.scene = QGraphicsScene()
- self.scene.clear()
- # My Image
- self.image_item = QGraphicsPixmapItem()
- # My View
- self.view = Click_QGraphicsView(self.graphicsView)
- self.view.setScene(self.scene)
- # My View Initial Geometry
- self.view.setGeometry(self.geometry().x() + 10, self.geometry().y() + 39, self.geometry().width() - 55,
- self.geometry().height() - 110)
- # My View Setting Scene with line
- self.view.pointChanged.connect(self.line_plot)
- # My View Attributes
- self.view.setBackgroundRole(QPalette.Dark)
- self.view.setAlignment(Qt.AlignCenter)
- self.view.setFrameShape(QFrame.NoFrame)
- self.view.setRenderHint(QPainter.Antialiasing, False)
- # OK button
- def click1(self):
- self.close()
- # Cancel button
- def click2(self):
- self.close()
- # The path of the image is received here
- def setImage(self, path):
- self.setWindowTitle("Image Analyzer")
- self.path = path
- self.pixmap = QPixmap(self.path)
- # pixmap_item = self.view.scene().addPixmap(self.pixmap)
- # pixmap_item.setShapeMode(QGraphicsPixmapItem.BoundingRectShape)
- self.crop_ratio_w = self.pixmap.width() / self.view.width()
- self.crop_ratio_h = self.pixmap.height() / self.view.height()
- smaller_pixmap = self.pixmap.scaled(self.view.width(), self.view.height(),
- Qt.IgnoreAspectRatio, Qt.FastTransformation)
- self.image_item.setPixmap(smaller_pixmap)
- self.scene.addItem(self.image_item)
- self.scene.setSceneRect(0, 0, self.view.width(), self.view.height())
- self.view.setGeometry(0, 0, self.view.width(), self.view.height())
- self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
- self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
- self.view.setScene(self.scene)
- self.view.setSceneSize()
- # When window is resized, view size is changed and image is set again (refresh)
- def resizeEvent(self, event):
- self.view.setGeometry(self.geometry().x() + 10, self.geometry().y() + 39,
- self.geometry().width() - 55, self.geometry().height() - 110)
- self.setImage(self.path)
- # self.view.fitInView(self.view.sceneRect(), Qt.KeepAspectRatio)
- super(ImageCheck, self).resizeEvent(event)
- # The images will be closed with any line drawn and its measurement
- def closeEvent(self, event):
- self.lcdNumber_1.display(0.0)
- self.scene.removeItem(self.lineItem)
- self.close()
- # The line is plotted here
- @pyqtSlot(QPointF, QPointF, float)
- def line_plot(self, start, end, div):
- self.scene.removeItem(self.lineItem)
- self.lineItem = QGraphicsLineItem()
- self.lineItem.setPen(QPen(Qt.blue, 2.0 + div))
- self.lineItem.setLine(float(start.x()), float(start.y()), float(end.x()), float(end.y()))
- x1 = start.x() * self.crop_ratio_w
- x2 = end.x() * self.crop_ratio_w
- y1 = start.y() * self.crop_ratio_h
- y2 = end.y() * self.crop_ratio_h
- dist = math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
- self.lcdNumber_1.display(dist)
- self.scene.addItem(self.lineItem)
- # The click associated events in view are coded here
- class Click_QGraphicsView(QGraphicsView):
- pointChanged = pyqtSignal(QPointF, QPointF, float) # The value passed from view upon mouse button clicks
- scene_size = (0, 0) # changing scene size
- start_pos = None # Starting position upon click
- between_pos = None # The positions in-between during mouse drag
- end_pos = None # The final position during click release
- shift = False # To check if Shift key is pressed
- div = 0 # This sets the line thickness during mouse scroll
- # During shift key press for a straight line
- def keyPressEvent(self, event):
- if event.key() == Qt.Key_Shift:
- self.shift = True
- # When shift key released
- def keyReleaseEvent(self, event):
- self.shift = False
- # The wheel scroll can increase or decrease thickness (only while redraw of line, including movements)
- def wheelEvent(self, event):
- wheel_counter = event.angleDelta()
- if wheel_counter.y() / 120 == -1:
- self.div -= 0.3
- elif wheel_counter.y() / 120 == 1:
- self.div += 0.3
- # When mouse button is pressed
- def mousePressEvent(self, event):
- self.start_pos = self.mapToScene(event.pos())
- if self.start_pos.x() < 0:
- self.start_pos.setX(0)
- elif self.start_pos.x() > self.scene_size[0] - 1:
- self.start_pos.setX(self.scene_size[0] - 1)
- if self.start_pos.y() < 0:
- self.start_pos.setY(0)
- elif self.start_pos.y() > self.scene_size[1] - 1:
- self.start_pos.setY(self.scene_size[1] - 1)
- # When mouse button is released
- def mouseReleaseEvent(self, event):
- self.end_pos = self.mapToScene(event.pos())
- if self.end_pos.x() < 0:
- self.end_pos.setX(0)
- elif self.end_pos.x() > self.scene_size[0] - 1:
- self.end_pos.setX(self.scene_size[0] - 1)
- if self.end_pos.y() < 0:
- self.end_pos.setY(0)
- elif self.end_pos.y() > self.scene_size[1] - 1:
- self.end_pos.setY(self.scene_size[1] - 1)
- if self.shift is True:
- self.end_pos.setY(self.start_pos.y())
- self.pointChanged.emit(self.start_pos, self.end_pos, self.div)
- # When mouse is moved
- def mouseMoveEvent(self, event):
- self.between_pos = self.mapToScene(event.pos())
- if self.between_pos.x() < 0:
- self.between_pos.setX(0)
- elif self.between_pos.x() > self.scene_size[0] - 1:
- self.between_pos.setX(self.scene_size[0] - 1)
- if self.between_pos.y() < 0:
- self.between_pos.setY(0)
- elif self.between_pos.y() > self.scene_size[1] - 1:
- self.between_pos.setY(self.scene_size[1] - 1)
- if self.shift is True:
- self.between_pos.setY(self.start_pos.y())
- self.pointChanged.emit(self.start_pos, self.between_pos, self.div)
- # To determine changing scene size for comparison, if the clicked point is outside our scope
- def setSceneSize(self):
- rect = self.scene().sceneRect()
- self.scene_size = (rect.width(), rect.height())
- def catch_exceptions(t, val, tb):
- QMessageBox.critical(None, "An exception was raised",
- "Exception type: {}".format(t))
- old_hook(t, val, tb)
- old_hook = sys.excepthook
- sys.excepthook = catch_exceptions
- def main():
- app = QApplication(sys.argv)
- window = Window()
- window.show()
- app.exec_()
- if __name__ == '__main__': main()
Add Comment
Please, Sign In to add comment