Matplotlib imshow,基于缩放动态重新采样 [英] Matplotlib imshow, dynamically resample based on zoom

查看:82
本文介绍了Matplotlib imshow,基于缩放动态重新采样的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在 matplotlib 中复制 MATLAB imagesc() 调用的行为 - 特别是:- 对于非常大的图像,缩小图像- 当用户放大时,以较少的抽取显示图像.

I'm trying to replicate the behavior of MATLAB imagesc() call in matplotlib - specifically: - for very large images, decimate the image - as the user zooms in, show the image with less decimation.

我已经编写了一个可以做到这一点的类,但我的解决方案似乎过于复杂.有人知道更好的方法吗?

I've written a class that will do it, but my solution seems overly complex. Does anybody know a better way?

预先感谢

布莱恩

推荐答案

由 OP 回答,已编辑出问题:

这是我的解决方法:

基本思想是:

  • 捕获xlim_changed或ylim_changed事件
  • 根据图像尺寸和所需的像素数计算所需的步幅
  • 绘画

https://github.com/flailingsquirrel/cmake_scipy_ctypes_example/blob/master/src/python/FastImshow.py

#!/usr/bin/env python

'''
Fast Plotter for Large Images - Resamples Images to a target resolution on each zoom.
Example::
    sz = (10000,20000) # rows, cols
    buf = np.arange(sz[0]*sz[1]).reshape(sz)
    extent = (100,150,1000,2000)
    fig = plt.figure()
    ax  = fig.add_subplot(111)
    im = FastImshow(buf,extent,ax)
    im.show()
    plt.show()
'''

import numpy as np
import matplotlib.pyplot as plt


class FastImshow:
    '''
    Fast plotter for large image buffers
    Example::
        sz = (10000,20000) # rows, cols
        buf = np.arange(sz[0]*sz[1]).reshape(sz)
        extent = (100,150,1000,2000)
        fig = plt.figure()
        ax  = fig.add_subplot(111)
        im = FastImshow(buf,extent,ax)
        im.show()
        plt.show()
    '''
    def __init__(self,buf,ax,extent=None,tgt_res=512):
        '''
        [in] img buffer
        [in] extent
        [in] axis to plot on
        [in] tgt_res(default=512) : target resolution
        '''
        self.buf = buf
        self.sz = self.buf.shape
        self.tgt_res = tgt_res
        self.ax = ax

        # Members required to account for mapping extent to buf coordinates
        if extent:
            self.extent = extent
        else:
            self.extent = [ 0, self.sz[1], 0, self.sz[0] ]
        self.startx = self.extent[0]
        self.starty = self.extent[2]
        self.dx = self.sz[1] / (self.extent[1] - self.startx ) # extent dx
        self.dy = self.sz[0] / (self.extent[3] - self.starty ) # extent dy

    # end __init__

    def get_strides( self,xstart=0, xend=-1, ystart=0, yend=-1, tgt_res=512 ):
        '''
        Get sampling strides for a given bounding region. If none is provided,
           use the full buffer size
        '''
        # size = (rows,columns)
        if xend == -1:
            xend = self.sz[1]
        if yend == -1:
            yend = self.sz[0]
        if (xend-xstart) <= self.tgt_res:
            stridex = 1
        else:
            stridex = max(int((xend - xstart) / self.tgt_res),1)

        if (yend-ystart) <= self.tgt_res:
            stridey = 1
        else:
            stridey = max(int((yend - ystart) / self.tgt_res),1)

        return stridex,stridey
    # end get_strides

    def ax_update(self, ax):
        '''
        Event handler for re-plotting on zoom
        - gets bounds in img extent coordinates
        - converts to buffer coordinates
        - calculates appropriate strides
        - sets new data in the axis
        '''
        ax.set_autoscale_on(False)  # Otherwise, infinite loop

        # Get the range for the new area
        xstart, ystart, xdelta, ydelta = ax.viewLim.bounds
        xend = xstart + xdelta
        yend = ystart + ydelta

        xbin_start = int(self.dx * ( xstart - self.startx ))
        xbin_end   = int(self.dx * ( xend - self.startx ))
        ybin_start = int(self.dy * ( ystart - self.starty ))
        ybin_end   = int(self.dy * ( yend - self.starty ))

        # Update the image object with our new data and extent
        im = ax.images[-1]

        stridex,stridey = self.get_strides( xbin_start,xbin_end,ybin_start,ybin_end)

        im.set_data( self.buf[ybin_start:ybin_end:stridey,xbin_start:xbin_end:stridex] )

        im.set_extent((xstart, xend, ystart, yend))

        ax.figure.canvas.draw_idle()
    # end ax_update

    def show(self):
        '''
        Initial plotter for buffer
        '''
        stridex, stridey = self.get_strides()
        self.ax.imshow( buf[::stridex,::stridey],extent=self.extent,origin='lower',aspect='auto' )
        self.ax.figure.canvas.draw_idle() 

        self.ax.callbacks.connect('xlim_changed', self.ax_update)
        self.ax.callbacks.connect('ylim_changed', self.ax_update)
    # end show

# end ImgDisplay

if __name__=="__main__":
    sz = (10000,20000) # rows, cols
    buf = np.arange(sz[0]*sz[1]).reshape(sz)
    extent = (100,150,1000,2000)
    fig = plt.figure()
    ax  = fig.add_subplot(111)
    im = FastImshow(buf,ax,extent=extent,tgt_res=1024)
    im.show()

    plt.show()

这篇关于Matplotlib imshow,基于缩放动态重新采样的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆