sayakpaul's picture
sayakpaul HF staff
add files
c4b2b37
raw
history blame
8.18 kB
import matplotlib.cm
import numpy as np
import skimage.feature
import skimage.filters
import skimage.io
def vec2im(V, shape=()):
"""
Transform an array V into a specified shape - or if no shape is given assume a square output format.
Parameters
----------
V : numpy.ndarray
an array either representing a matrix or vector to be reshaped into an two-dimensional image
shape : tuple or list
optional. containing the shape information for the output array if not given, the output is assumed to be square
Returns
-------
W : numpy.ndarray
with W.shape = shape or W.shape = [np.sqrt(V.size)]*2
"""
if len(shape) < 2:
shape = [np.sqrt(V.size)] * 2
shape = map(int, shape)
return np.reshape(V, shape)
def enlarge_image(img, scaling=3):
"""
Enlarges a given input matrix by replicating each pixel value scaling times in horizontal and vertical direction.
Parameters
----------
img : numpy.ndarray
array of shape [H x W] OR [H x W x D]
scaling : int
positive integer value > 0
Returns
-------
out : numpy.ndarray
two-dimensional array of shape [scaling*H x scaling*W]
OR
three-dimensional array of shape [scaling*H x scaling*W x D]
depending on the dimensionality of the input
"""
if scaling < 1 or not isinstance(scaling, int):
print("scaling factor needs to be an int >= 1")
if len(img.shape) == 2:
H, W = img.shape
out = np.zeros((scaling * H, scaling * W))
for h in range(H):
fh = scaling * h
for w in range(W):
fw = scaling * w
out[fh : fh + scaling, fw : fw + scaling] = img[h, w]
elif len(img.shape) == 3:
H, W, D = img.shape
out = np.zeros((scaling * H, scaling * W, D))
for h in range(H):
fh = scaling * h
for w in range(W):
fw = scaling * w
out[fh : fh + scaling, fw : fw + scaling, :] = img[h, w, :]
return out
def repaint_corner_pixels(rgbimg, scaling=3):
"""
DEPRECATED/OBSOLETE.
Recolors the top left and bottom right pixel (groups) with the average rgb value of its three neighboring pixel (groups).
The recoloring visually masks the opposing pixel values which are a product of stabilizing the scaling.
Assumes those image ares will pretty much never show evidence.
Parameters
----------
rgbimg : numpy.ndarray
array of shape [H x W x 3]
scaling : int
positive integer value > 0
Returns
-------
rgbimg : numpy.ndarray
three-dimensional array of shape [scaling*H x scaling*W x 3]
"""
# top left corner.
rgbimg[0:scaling, 0:scaling, :] = (
rgbimg[0, scaling, :] + rgbimg[scaling, 0, :] + rgbimg[scaling, scaling, :]
) / 3.0
# bottom right corner
rgbimg[-scaling:, -scaling:, :] = (
rgbimg[-1, -1 - scaling, :]
+ rgbimg[-1 - scaling, -1, :]
+ rgbimg[-1 - scaling, -1 - scaling, :]
) / 3.0
return rgbimg
def digit_to_rgb(X, scaling=3, shape=(), cmap="binary"):
"""
Takes as input an intensity array and produces a rgb image due to some color map
Parameters
----------
X : numpy.ndarray
intensity matrix as array of shape [M x N]
scaling : int
optional. positive integer value > 0
shape: tuple or list of its , length = 2
optional. if not given, X is reshaped to be square.
cmap : str
name of color map of choice. default is 'binary'
Returns
-------
image : numpy.ndarray
three-dimensional array of shape [scaling*H x scaling*W x 3] , where H*W == M*N
"""
# create color map object from name string
cmap = eval("matplotlib.cm.{}".format(cmap))
image = enlarge_image(vec2im(X, shape), scaling) # enlarge
image = cmap(image.flatten())[..., 0:3].reshape(
[image.shape[0], image.shape[1], 3]
) # colorize, reshape
return image
def hm_to_rgb(R, X=None, scaling=3, shape=(), sigma=2, cmap="bwr", normalize=True):
"""
Takes as input an intensity array and produces a rgb image for the represented heatmap.
optionally draws the outline of another input on top of it.
Parameters
----------
R : numpy.ndarray
the heatmap to be visualized, shaped [M x N]
X : numpy.ndarray
optional. some input, usually the data point for which the heatmap R is for, which shall serve
as a template for a black outline to be drawn on top of the image
shaped [M x N]
scaling: int
factor, on how to enlarge the heatmap (to control resolution and as a inverse way to control outline thickness)
after reshaping it using shape.
shape: tuple or list, length = 2
optional. if not given, X is reshaped to be square.
sigma : double
optional. sigma-parameter for the canny algorithm used for edge detection. the found edges are drawn as outlines.
cmap : str
optional. color map of choice
normalize : bool
optional. whether to normalize the heatmap to [-1 1] prior to colorization or not.
Returns
-------
rgbimg : numpy.ndarray
three-dimensional array of shape [scaling*H x scaling*W x 3] , where H*W == M*N
"""
# create color map object from name string
cmap = eval("matplotlib.cm.{}".format(cmap))
if normalize:
R = R / np.max(np.abs(R)) # normalize to [-1,1] wrt to max relevance magnitude
R = (R + 1.0) / 2.0 # shift/normalize to [0,1] for color mapping
R = enlarge_image(R, scaling)
rgb = cmap(R.flatten())[..., 0:3].reshape([R.shape[0], R.shape[1], 3])
# rgb = repaint_corner_pixels(rgb, scaling) #obsolete due to directly calling the color map with [0,1]-normalized inputs
if not X is None: # compute the outline of the input
# X = enlarge_image(vec2im(X,shape), scaling)
xdims = X.shape
Rdims = R.shape
# if not np.all(xdims == Rdims):
# print 'transformed heatmap and data dimension mismatch. data dimensions differ?'
# print 'R.shape = ',Rdims, 'X.shape = ', xdims
# print 'skipping drawing of outline\n'
# else:
# #edges = skimage.filters.canny(X, sigma=sigma)
# edges = skimage.feature.canny(X, sigma=sigma)
# edges = np.invert(np.dstack([edges]*3))*1.0
# rgb *= edges # set outline pixels to black color
return rgb
def save_image(rgb_images, path, gap=2):
"""
Takes as input a list of rgb images, places them next to each other with a gap and writes out the result.
Parameters
----------
rgb_images : list , tuple, collection. such stuff
each item in the collection is expected to be an rgb image of dimensions [H x _ x 3]
where the width is variable
path : str
the output path of the assembled image
gap : int
optional. sets the width of a black area of pixels realized as an image shaped [H x gap x 3] in between the input images
Returns
-------
image : numpy.ndarray
the assembled image as written out to path
"""
sz = []
image = []
for i in range(len(rgb_images)):
if not sz:
sz = rgb_images[i].shape
image = rgb_images[i]
gap = np.zeros((sz[0], gap, sz[2]))
continue
if not sz[0] == rgb_images[i].shape[0] and sz[1] == rgb_images[i].shape[2]:
print("image", i, "differs in size. unable to perform horizontal alignment")
print("expected: Hx_xD = {0}x_x{1}".format(sz[0], sz[1]))
print(
"got : Hx_xD = {0}x_x{1}".format(
rgb_images[i].shape[0], rgb_images[i].shape[1]
)
)
print("skipping image\n")
else:
image = np.hstack((image, gap, rgb_images[i]))
image *= 255
image = image.astype(np.uint8)
print("saving image to ", path)
skimage.io.imsave(path, image)
return image