pyqt5 分割瓦片显示超大图像

在使用pyqt5显示超大遥感影像时,程序卡顿特别严重,遂实现了一种思路,将影像分割成较小的瓦片,然后循环显示到QGraphicsItem中,同时在分片的基础上实现了影像的缩放、平移、范围选取和点选取。

完整代码下载连接:https://download.youkuaiyun.com/download/ZH_CS/85527400icon-default.png?t=M4ADhttps://download.youkuaiyun.com/download/ZH_CS/85527400

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
### 如何在 PyQt5 中使用瓦片数据加载地图 #### 1. 准备工作 为了在 PyQt5 中使用瓦片数据加载地图,需要安装必要的依赖包并获取相应的 API 密钥。 对于百度地图,在线地图的加载需使用 `webenginewidgets` 组件,并且仅支持 MSVC 编译器。此外,还需前往百度API平台申请个人 AK (Access Key)[^1]。 而对于天地图,则可以通过 Python 库 `tianditu-python` 来简化开发流程。此库由官方提供,能够帮助开发者更便捷地调用地图服务中的多种资源[^2]。 #### 2. 实现方案概述 实现思路主要分为两部分: - **网络请求模块**:负责向服务器发送 HTTP 请求以获取指定位置的地图切片图片; - **界面展示模块**:利用 Qt 的绘图功能绘制出完整的地图视图; 下面将以天地图为例给出具体实现方法。 #### 3. 示例代码 ##### 安装所需库 首先确保已安装所需的第三方库: ```bash pip install tianditu_python requests pyqt5 ``` ##### 主程序逻辑 创建一个新的 PyQt5 工程文件 main.py ,编写如下代码: ```python import sys from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * from tianditu.api import TdtMap, VectorTileLayer class MapWidget(QWidget): def __init__(self): super().__init__() self.map = TdtMap(api_key='your_api_key_here') # 替换成自己的 api key vector_layer = VectorTileLayer(self.map) layout = QVBoxLayout() layout.addWidget(vector_layer.widget()) self.setLayout(layout) if __name__ == '__main__': app = QApplication(sys.argv) widget = MapWidget() widget.setWindowTitle('PyQt5 Tile Map Example') widget.show() sys.exit(app.exec_()) ``` 这段代码实现了基本的地图显示窗口,其中包含了来自天地图的服务层。通过调整参数还可以进一步定制样式和行为。 请注意替换 `'your_api_key_here'` 为你自己从官方网站获得的有效密钥。
评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZH_CS

随缘吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值