Search code examples
pythonimagemayavi

How to draw a color image in mayavi (imshow)


Is it possible to draw a image with 3 color channels using mayavi? According to the documentation for mayavi, mayavi.mlab.imshow can only handle images of shape (n x m).


Solution

  • Method

    I had to make use of mayavi's custom colormaps, see http://docs.enthought.com/mayavi/mayavi/auto/example_custom_colormap.html .

    I made a colormap that consists of all the pixles in the original (n x m x 3) image as rows. I also included an alpha channel so that transparent png's can be displayed correctly. Next I used a grayscale image as a lookup table, with pixle values as indices to the original pixles stored in the colormap. I created an imshow object with the lookup table as the input image and replaced the imshow object's colormap with my custom colormap.

    Code

    Here is some working code with a test case for those interested. Pylab can be replaced by Numpy (Pylab wraps Numpy) everywhere except in the testcase at pl.imread(...). Tested on Python2.7 with Mayavi 4.3.0 on Windows 7. (Unfortunately I had to first fix the following mayavi bug on Windows https://github.com/enthought/mayavi/pull/96/files).

    import pylab as pl
    from mayavi import mlab
    
    def mlab_imshowColor(im, alpha=255, **kwargs):
        """
        Plot a color image with mayavi.mlab.imshow.
        im is a ndarray with dim (n, m, 3) and scale (0->255]
        alpha is a single number or a ndarray with dim (n*m) and scale (0->255]
        **kwargs is passed onto mayavi.mlab.imshow(..., **kwargs)
        """
        try:
            alpha[0]
        except:
            alpha = pl.ones(im.shape[0] * im.shape[1]) * alpha
        if len(alpha.shape) != 1:
            alpha = alpha.flatten()
    
        # The lut is a Nx4 array, with the columns representing RGBA
        # (red, green, blue, alpha) coded with integers going from 0 to 255,
        # we create it by stacking all the pixles (r,g,b,alpha) as rows.
        myLut = pl.c_[im.reshape(-1, 3), alpha]
        myLutLookupArray = pl.arange(im.shape[0] * im.shape[1]).reshape(im.shape[0], im.shape[1])
    
        #We can display an color image by using mlab.imshow, a lut color list and a lut lookup table.
        theImshow = mlab.imshow(myLutLookupArray, colormap='binary', **kwargs) #temporary colormap
        theImshow.module_manager.scalar_lut_manager.lut.table = myLut
        mlab.draw()
    
        return theImshow
    
    def test_mlab_imshowColor():
        """
        Test if mlab_imshowColor displays correctly by plotting the wikipedia png example image
        """
    
        #load a png with a scale 0->1 and four color channels (an extra alpha channel for transparency).
        from urllib import urlopen
        url = 'http://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png'
        im = pl.imread(urlopen(url), format='png')
        im *= 255
    
        mlab_imshowColor(im[:, :, :3], im[:, :, -1])
    
        mlab.points3d([-200, 300, -200, 300],
                      [-200, 300, 200, -300],
                      [300, 300, 300, 300])
        mlab.show()
    
    if __name__ == "__main__":
        test_mlab_imshowColor()
    

    Results

    enter image description here enter image description here