在使用pyqt5显示超大遥感影像时,程序卡顿特别严重,遂实现了一种思路,将影像分割成较小的瓦片,然后循环显示到QGraphicsItem中,同时在分片的基础上实现了影像的缩放、平移、范围选取和点选取。
mport pyqtgraph as pg
from PyQt5.QtCore import Qt, QRectF, pyqtSignal
from PyQt5.QtGui import QColor, QPalette, QPixmap
from PyQt5.QtWidgets import QGraphicsView, QGraphicsScene
from view.image.ImageItem import ImageItem
class ImageView(QGraphicsView):
# 鼠标悬停像素的信号
signal_pixel_selected = pyqtSignal(str, int)
signal_progress = pyqtSignal(object, object)
item: ImageItem = None
pixmap: QPixmap = None
# 影像名称和item的对应关系
item_dict = {}
def __init__(self):
super(ImageView, self).__init__()
pg.ImageView()
pg.ImageItem()
self.QImg = None
self.image = None
self.image_array = None
self.background_color = QColor()
self.background_color.setNamedColor('#ffffff')
self.palette = QPalette()
self.palette.setColor(QPalette.Window, self.background_color)
self.__init_view()
def __init_view(self):
self.setAutoFillBackground(True)
self.setPalette(self.palette)
self.setAlignment(Qt.AlignCenter)
# 创建场景
self.scene = QGraphicsScene()
# 显示整幅图像
def showImage(self):
self.setSceneRect(QRectF(-(self.width() / 2), -(self.height() / 2), self.width() - 10, self.height() - 10))
self.setScene(self.scene)
self.item = ImageItem(self.image, self.signal_pixel_selected, self.signal_progress)
self.item.setQGraphicsViewWH(self.width(), self.height())
self.scene.clear()
self.scene.addItem(self.item)
def showLayer(self, image):
self.image = image
if image is None:
return
self.image = image
self.showImage()
# 清理显示的图层
def cleanLayer(self, image):
self.scene.clear()
# 设置图像的显示状态
def setItemStatus(self, status, tool):
if self.item is not None:
self.item.setStatus(status)
self.item.setCurrentTool(tool)
影像显示控件继承了QGraphicsItem,在这里实现缩放和平移
from PyQt5.QtCore import Qt, QPoint, QRectF
from PyQt5.QtGui import QPainter, QPixmap, QColor, QPen, QImage
from PyQt5.QtWidgets import QStyleOptionGraphicsItem, QWidget, QGraphicsItem, QApplication
from image import OpticalImage
from system.System import System
class ImageItem(QGraphicsItem):
def __init__(self, image: OpticalImage, signal_pixel_selected, signal_progress):
super(ImageItem, self).__init__()
# 影像在横轴偏移量
self.w_offset = 0
# 影像在纵轴的偏移量
self.h_offset = 0
# 鼠标当前所在的像素位置
self.w_cur_pos = 0
self.h_cur_pos = 0
# 当前正在显示的影像
self.image = None
# 信号
self.signal_pixel_selected = None
# 选择状态
self.image_view_status = System.v_image_show
# 当前的矩形几何
self.show_rect = []
# 当前选择的点
self.show_point = []
# 当前正在画的点
self.current_paint_point = None
# 当前正在画的矩形
self.current_paint_rect = None
# 当前鼠标按下的键
self.mouse_click_button = None
# pixmap瓦片
self.pixmap_tiles = {}
self.image = image
self.setAcceptDrops(True)
self.m_scaleValue = 1
self.m_scaleDafault = 1
self.m_isMove = False
self.m_isRect = False
self.m_startPos = None
self.setAcceptHoverEvents(True)
self.signal_pixel_selected = signal_pixel_selected
self.signal_progress = signal_progress
self.currentTool = System.v_image_show
self.setStatus(System.v_image_show)
self.create_pixmap_tiles()
def boundingRect(self):
"""
重写原有方法
:return:
"""
self.w_offset = int(self.image.width / 2)
self.h_offset = int(self.image.height / 2)
return QRectF(-self.w_offset, -self.h_offset, self.image.width, self.image.height)
def paint(self, painter, const, widget=None):
"""
重写方法
:param painter:
:param const:
:param widget:
:return:
"""
self.painter_tiles(painter)
self.paintShowChecked(painter, const, widget)
def painter_tiles(self, painter):
"""
将影像瓦片展示到控件
:param painter:
:return:
"""
tiles_size = self.image.tiles.size
length = len(self.pixmap_tiles)
cur = 0
for key, value in self.pixmap_tiles.items():
h_index, w_index = key
h_offset = h_index * tiles_size - self.h_offset
w_offset = w_index * tiles_size - self.w_offset
if value is None:
continue
painter.drawPixmap(w_offset, h_offset, value)
cur = cur + 1
def create_pixmap_tiles(self):
"""
根据显示的图层创建pixmap的瓦片
:return:
"""
length = len(self.image.get_show_layer())
cur = 0
for key, value in self.image.get_show_layer().items():
pixmap = self.create_pixmap(value)
self.pixmap_tiles[key] = pixmap
cur = cur + 1
System.signal.signal_progress.emit("正在创建瓦片:", cur * 100 / length)
QApplication.processEvents()
print("pixmap瓦片创建完成")
# self.image.start_image_static()
def create_pixmap(self, image_array):
"""
根据给定的数组生成pixmap
:param image_array:
:return:
"""
shape = image_array.shape
height = 0
width = 0
bytesPerComponent = 1
if len(shape) == 2:
height, width = shape
elif len(shape) == 3:
height, width, bytesPerComponent = shape
bytesPerLine = bytesPerComponent * width
if bytesPerComponent == 1:
# 显示灰度图像
QImg = QImage(image_array.tobytes(), width, height, bytesPerLine, QImage.Format_Grayscale8)
elif bytesPerComponent == 3:
# 显示GGB图像
QImg = QImage(image_array.tobytes(), width, height, bytesPerLine, QImage.Format_RGB888)
else:
# 如果不符合就不显示
return
return QPixmap.fromImage(QImg)
def paintEvent(self):
pass
# 将主界面的控件QGraphicsView的width和height传进本类中,并根据图像的长宽和控件的长宽的比例来使图片缩放到适合控件的大小
def setQGraphicsViewWH(self, nwidth: int, nheight: int):
nImgWidth = self.image.width
nImgHeight = self.image.height
t_width = nwidth / nImgWidth
t_height = nheight / nImgHeight
if t_width > t_height:
self.m_scaleDafault = t_height
else:
self.m_scaleDafault = t_width
self.setSca

https://download.youkuaiyun.com/download/ZH_CS/85527400
最低0.47元/天 解锁文章
6335





