Okay, after digging more deeply into docs and examples, I'll probably answer this question by myself.
The hover effect on image (2d signal) data makes no sense in the way how this functionality is designed in Bokeh. If one needs to add some extra information attached to the data point it needs to put the data into the proper data model - the flat one.
tidying the data
Basically, one needs to tidy his data into a tabular format with x,y and value columns (see Tidy Data article by H.Wickham). Now every row represents a data point, and one can naturally add any contextual information as additional columns.
For example, the following code will do the work:
def flatten(matrix: np.ndarray,
            extent: Optional[Tuple[float, float, float, float]] = None,
            round_digits: Optional[int] = 0) -> pd.DataFrame:
    if extent is None:
        extent = (0, matrix.shape[1], 0, matrix.shape[0])
    x_min, x_max, y_min, y_max = extent
    df = pd.DataFrame(data=matrix)\
        .stack()\
        .reset_index()\
        .rename(columns={'level_0': 'y', 'level_1': 'x', 0: 'value'})
    df.x = df.x / df.x.max() * (x_max - x_min) + x_min
    df.y = df.y / df.y.max() * (y_max - y_min) + y_min
    if round_digits is not None:
        df = df.round({'x': round_digits, 'y': round_digits})
    return df
rect glyph and ColumnDataSource
Then, use rect glyph instead of image with x,y mapped accordingly and the value column color-mapped properly to the color aesthetics of the glyph.
color mapping for values
- here you can use a min-max normalization with the following multiplication by the number of colors you want to use and the 
round 
- use bokeh builtin palettes to map from computed integer value to a particular color value.
 
With all being said, here's an example chart function:
def InteractiveImage(img: pd.DataFrame,
          x: str,
          y: str,
          value: str,
          width: Optional[int] = None,
          height: Optional[int] = None,
          color_pallete: Optional[List[str]] = None,
          tooltips: Optional[List[Tuple[str]]] = None) -> Figure:
    """
    Notes
    -----
        both x and y should be sampled with a constant rate
    Parameters
    ----------
    img
    x
        Column name to map on x axis coordinates
    y
        Column name to map on y axis coordinates 
    value
        Column name to map color on
    width
        Image width
    height
        Image height
    color_pallete
        Optional. Color map to use for values
    tooltips
        Optional.
    Returns
    -------
        bokeh figure
    """
    if tooltips is None:
        tooltips = [
            (value, '@' + value),
            (x, '@' + x),
            (y, '@' + y)
        ]
    if color_pallete is None:
        color_pallete = bokeh.palettes.viridis(50)
    x_min, x_max = img[x].min(), img[x].max()
    y_min, y_max = img[y].min(), img[y].max()
    if width is None:
        width = 500 if height is None else int(round((x_max - x_min) / (y_max - y_min) * height))
    if height is None:
        height = int(round((y_max - y_min) / (x_max - x_min) * width))
    img['color'] = (img[value] - img[value].min()) / (img[value].max() - img[value].min()) * (len(color_pallete) - 1)
    img['color'] = img['color'].round().map(lambda x: color_pallete[int(x)])
    source = ColumnDataSource(data={col: img[col] for col in img.columns})
    fig = figure(width=width,
                 height=height,
                 x_range=(x_min, x_max),
                 y_range=(y_min, y_max),
                 tools='pan,wheel_zoom,box_zoom,reset,hover,save')
    def sampling_period(values: pd.Series) -> float:
        # @TODO think about more clever way
        return next(filter(lambda x: not pd.isnull(x) and 0 < x, values.diff().round(2).unique()))
    x_unit = sampling_period(img[x])
    y_unit = sampling_period(img[y])
    fig.rect(x=x, y=y, width=x_unit, height=y_unit, color='color', line_color='color', source=source)
    fig.select_one(HoverTool).tooltips = tooltips
    return fig
#### Note: however this comes with a quite high computational price