Search code examples
imagescipybokehpython-3.7

Bokeh rotated image blocks underlying image


I'm placeing a rotated image on top of another image of different anchor point in the same figure. However the top image partially covers the bottom image, shown below. Is there a way to remove the black border of the rotated image? enter image description here

Sample codes here:

from bokeh.server.server import Server
from bokeh.application import Application
from bokeh.application.handlers.function import FunctionHandler
from bokeh.plotting import figure, ColumnDataSource, show
from bokeh.layouts import column
from bokeh.models.tools import PanTool, BoxZoomTool, WheelZoomTool, \
UndoTool, RedoTool, ResetTool, SaveTool, HoverTool

import numpy as np
from collections import namedtuple
from scipy import ndimage

def make_document(doc):

    p = figure(match_aspect=True)

    Anchor = namedtuple('Anchor', ['x', 'y'])
    img1 = np.random.rand(256, 256)
    anchor1 = Anchor(x=0, y=0)

    img2= np.random.rand(256, 256)
    anchor2 = Anchor(x=100, y=100)

    img2 = ndimage.rotate(img2, 45, reshape=True)
    p.image(image=[img1], x=anchor1.x, y=anchor1.y, 
            dw=img1.shape[0], dh=img1.shape[1], palette="Greys256")
    p.image(image=[img2], x=anchor2.x, y=anchor2.y, 
            dw=img2.shape[0], dh=img2.shape[1], palette="Greys256")
    doc.add_root(column(p, sizing_mode='stretch_both'))

apps = {'/': make_document}

server = Server(apps)
server.start()
server.io_loop.add_callback(server.show, "/")
try:
    server.io_loop.start()
except KeyboardInterrupt:
    print('keyboard interruption')
print('Done')

Solution

  • When you rotate an image, the new empty regions (black triangles on your image) are by default initialized with 0 (check out the mode and cval options at https://docs.scipy.org/doc/scipy/reference/generated/scipy.ndimage.rotate.html).

    If you have a value that you know for sure will never be used in an image, you can pass it as cval. Then, you should be able to manually create a color mapper that maps that value to a transparent pixel and use the mapper instead of the palette (the arg name would be color_mapper).

    If you don't have such a value, then you will have to use image_rgba and just make sure that whatever cval you decide to use will result in a transparent pixel.