Related
Here's my code:
import os
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"
import tensorflow as tf
from tensorflow import keras
from keras import layers
from keras.datasets import cifar10
from sklearn.model_selection import train_test_split
import numpy as np
import matplotlib.pyplot as plt
def main():
#loading data and image augmentation
(X_train, Y_train), (X_test, Y_test) = keras.datasets.cifar10.load_data()
X_train, X_val, Y_train, Y_val = train_test_split(X_train, Y_train, test_size=0.20, random_state=42)
X_test, X_train, X_val = X_test.astype("float32"), X_train.astype("float32"), X_val.astype("float32")
Y_train, Y_test, Y_val = keras.utils.to_categorical(Y_train, 10), keras.utils.to_categorical(Y_test, 10), keras.utils.to_categorical(Y_val, 10)
datagen = keras.preprocessing.image.ImageDataGenerator(rotation_range=15, width_shift_range=0.1, height_shift_range=0.1, horizontal_flip=True)
datagen.fit(X_train)
X_train = X_train.reshape(X_train.shape[0], 32, 32, 3)
X_test = X_test.reshape(X_test.shape[0], 32, 32, 3)
X_val = X_val.reshape(X_val.shape[0], 32, 32, 3)
mean = np.mean(X_train)
std = np.std(X_train)
X_test = (X_test - mean) / std
X_val = (X_val - mean) / std
X_train = (X_train - mean) / std
#constructing ResNet function
def residual_module(layer_in, n_filters, kernel_size, padding, initializer, activation, regularizer, triple=False):
activation2 = 'linear'
filters2 = layer_in.shape[-1]
size2 = 1
conv1 = layers.Conv2D(n_filters, kernel_size, padding=padding, kernel_initializer=initializer, kernel_regularizer=regularizer)(layer_in)
conv1 = layers.Activation(activation)(conv1)
batch1 = layers.BatchNormalization()(conv1)
conv2 = layers.Conv2D(filters2, size2, padding='same', kernel_regularizer=regularizer)(batch1)
conv2 = layers.Activation(activation2)(conv2)
batch2 = layers.BatchNormalization()(conv2)
if triple == True:
activation2 = activation
filters2 = n_filters
size2 = kernel_size
conv3 = layers.Conv2D(layer_in.shape[-1], 1, padding='same', activation='linear', kernel_regularizer=regularizer)(batch2)
batch3 = layers.BatchNormalization()(conv3)
layer_out = layers.add([batch3, layer_in])
layer_out = layers.Activation(activation)(layer_out)
else:
layer_out = layers.add([batch2, layer_in])
layer_out = layers.Activation(activation)(layer_out)
return layer_out
#VGG16 model with SIREN
weight_decay = 0.0005
model = keras.Sequential()
input_layer = layers.Input(shape=(32,32,3))
model.add(residual_module(input_layer, n_filters=64, kernel_size=(3,3), padding='same', initializer="he_uniform", activation=tf.math.sin, regularizer=keras.regularizers.l2(weight_decay)))
first = model.add(layers.MaxPooling2D(pool_size=(2, 2), strides=2))
model.add(residual_module(first, 128, (3,3), 'same', None, tf.math.sin, keras.regularizers.l2(weight_decay)))
second = model.add(layers.MaxPooling2D(pool_size=(2, 2), strides=2))
model.add(residual_module(second, 256, (3,3), 'same', None, tf.math.sin, keras.regularizers.l2(weight_decay), triple=True))
third = model.add(layers.MaxPooling2D(pool_size=(2, 2), strides=2))
model.add(residual_module(third, 512, (3,3), 'same', None, tf.math.sin, keras.regularizers.l2(weight_decay), triple=True))
model.add(layers.MaxPooling2D(pool_size=(2, 2), strides=2))
model.add(layers.GlobalAveragePooling2D())
model.add(layers.Dense(4096, activation="relu"))
model.add(layers.Dropout(0.5))
model.add(layers.Dense(4096, activation="relu"))
model.add(layers.Dropout(0.5))
model.add(layers.Dense(10))
'''
model.add(layers.Conv2D(64, (3, 3), padding='same', kernel_initializer="he_uniform", activation=tf.math.sin, input_shape=(32,32,3), kernel_regularizer=keras.regularizers.l2(weight_decay)))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(64, (3, 3), padding='same', activation=math.sin, kernel_regularizer=keras.regularizers.l2(weight_decay)))
model.add(layers.BatchNormalization())
model.add(layers.MaxPooling2D(pool_size=(2, 2), strides=2))
model.add(layers.Conv2D(128, (3, 3), padding='same', activation=math.sin, kernel_regularizer=keras.regularizers.l2(weight_decay)))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(128, (3, 3), padding='same', activation=math.sin, kernel_regularizer=keras.regularizers.l2(weight_decay)))
model.add(layers.BatchNormalization())
model.add(layers.MaxPooling2D(pool_size=(2, 2), strides=2))
model.add(layers.Conv2D(256, (3, 3), padding='same', activation=math.sin, kernel_regularizer=keras.regularizers.l2(weight_decay)))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(256, (3, 3), padding='same', activation=math.sin, kernel_regularizer=keras.regularizers.l2(weight_decay)))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(256, (3, 3), padding='same', activation=math.sin, kernel_regularizer=keras.regularizers.l2(weight_decay)))
model.add(layers.BatchNormalization())
model.add(layers.MaxPooling2D(pool_size=(2, 2), strides=2))
model.add(layers.Conv2D(512, (3, 3), padding='same', activation=math.sin, kernel_regularizer=keras.regularizers.l2(weight_decay)))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(512, (3, 3), padding='same', activation=math.sin, kernel_regularizer=keras.regularizers.l2(weight_decay)))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(512, (3, 3), padding='same', activation=math.sin, kernel_regularizer=keras.regularizers.l2(weight_decay)))
model.add(layers.BatchNormalization())
model.add(layers.MaxPooling2D(pool_size=(2, 2), strides=2))
model.add(layers.GlobalAveragePooling2D())
model.add(layers.Dense(4096, activation="relu"))
model.add(layers.Dropout(0.5))
model.add(layers.Dense(4096, activation="relu"))
model.add(layers.Dropout(0.5))
model.add(layers.Dense(10))
'''
#training model
lr = 0.001
loss = keras.losses.CategoricalCrossentropy(from_logits=True)
decayed_lr = tf.keras.optimizers.schedules.ExponentialDecay(lr, 10000, 0.85, True)
optim = keras.optimizers.SGD(decayed_lr, momentum=0.9, nesterov=True)
batch_size = 128
#optim = keras.optimizers.Adam(decayed_lr, beta_1=0.9, beta_2=0.999, epsilon=1e-08)
model.compile(loss=loss, optimizer=optim, metrics=["accuracy"])
checkpoint_filepath = '/Users/JamesRONewton/Documents/Programming/MachineLearning/SIREN_projects/BrainTumor/checkpoint.hdf5'
checkpoint = keras.callbacks.ModelCheckpoint(filepath = checkpoint_filepath, monitor='accuracy', verbose=2, save_best_only=True, save_weights_only=True, mode='auto', save_freq ="epoch")
try:
model.load_weights(checkpoint_filepath, custom_objects = {"sin": tf.math.sin})
except Exception as e:
pass
model.fit(datagen.flow(X_train, Y_train, batch_size=batch_size), steps_per_epoch = len(X_train) / batch_size, epochs=25, callbacks = [checkpoint], validation_data=(X_val, Y_val))
model.evaluate(X_test, Y_test, verbose=1)
#saving model
model.save("VGG16.h5")
if __name__ == '__main__':
main()
And here's the error I keep getting:
TypeError: The added layer must be an instance of class Layer. Received: layer=KerasTensor(type_spec=TensorSpec(shape=(None, 32, 32, 3), dtype=tf.float32, name=None), name='activation_2/Sin:0', description="created by layer 'activation_2'") of type <class 'keras.engine.keras_tensor.KerasTensor'>.
The errors so far have mostly been about inputting a custom activation function into the ResNet function I created. For example,
TypeError: The added layer must be an instance of class Layer. Received: layer=KerasTensor(type_spec=TensorSpec(shape=(None, 32, 32, 3), dtype=tf.float32, name=None), name='activation/Sin:0', description="created by layer 'activation'") of type <class 'keras.engine.keras_tensor.KerasTensor'>.
So I thought maybe using
layers.Activation(activation)
instead of just putting the activation in the Conv2D layer would fix it, but that clearly did not work, as you can see. I've also tried defining the custom activation function as a class inheriting from layers.Layer, but that also did not work. I used this code to try that:
class Sin(layers.Layer):
def __init__(self, **kwargs):
super(Sin, self).__init__(**kwargs)
def call(self, inputs):
return tf.math.sin(inputs)
But alas, it did not work.
-Update!
I tried using keras backend, but that failed. I also tried using a lambda layer in my ResNet function. Here's my most recent attempt, which combines both:
#custom sinusoidal activation function
def sin(x):
return K.sin(x)
#constructing ResNet function
def residual_module(layer_in, n_filters, kernel_size, padding, initializer, regularizer):
conv1 = layers.Conv2D(n_filters, kernel_size, padding=padding, kernel_initializer=initializer, kernel_regularizer=regularizer)(layer_in)
conv1 = layers.Lambda(lambda x: sin(x))(conv1)
batch1 = layers.BatchNormalization()(conv1)
conv2 = layers.Conv2D(layer_in.shape[-1], 1, padding='same', activation='linear', kernel_regularizer=regularizer)(batch1)
batch2 = layers.BatchNormalization()(conv2)
layer_out = layers.add([batch2, layer_in])
layer_out = layers.Lambda(lambda x: sin(x))(layer_out)
return layer_out
def residual_module_triple(layer_in, n_filters, kernel_size, padding, initializer, regularizer):
conv1 = layers.Conv2D(n_filters, kernel_size, padding=padding, kernel_initializer=initializer, kernel_regularizer=regularizer)(layer_in)
conv1 = layers.Lambda(lambda x: sin(x))(conv1)
batch1 = layers.BatchNormalization()(conv1)
conv2 = layers.Conv2D(n_filters, kernel_size, padding='same', kernel_regularizer=regularizer)(batch1)
conv2 = layers.Lambda(lambda x: sin(x))(conv2)
batch2 = layers.BatchNormalization()(conv2)
conv3 = layers.Conv2D(layer_in.shape[-1], 1, padding='same', activation='linear', kernel_regularizer=regularizer)(batch2)
batch3 = layers.BatchNormalization()(conv3)
layer_out = layers.add([batch3, layer_in])
layer_out = layers.Lambda(lambda x: sin(x))(layer_out)
return layer_out
I got it up and working so I can resume training!! Here's my fixed code:
def main():
import os
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"
import tensorflow as tf
from tensorflow import keras
from keras import layers
from keras.datasets import cifar10
from sklearn.model_selection import train_test_split
import numpy as np
import matplotlib.pyplot as plt
from keras import backend as K
#loading data and image augmentation
(X_train, Y_train), (X_test, Y_test) = keras.datasets.cifar10.load_data()
X_train, X_val, Y_train, Y_val = train_test_split(X_train, Y_train, test_size=0.20, random_state=42)
X_test, X_train, X_val = X_test.astype("float32"), X_train.astype("float32"), X_val.astype("float32")
Y_train, Y_test, Y_val = keras.utils.to_categorical(Y_train, 10), keras.utils.to_categorical(Y_test, 10), keras.utils.to_categorical(Y_val, 10)
datagen = keras.preprocessing.image.ImageDataGenerator(rotation_range=15, width_shift_range=0.1, height_shift_range=0.1, horizontal_flip=True)
datagen.fit(X_train)
X_train = X_train.reshape(X_train.shape[0], 32, 32, 3)
X_test = X_test.reshape(X_test.shape[0], 32, 32, 3)
X_val = X_val.reshape(X_val.shape[0], 32, 32, 3)
mean = np.mean(X_train)
std = np.std(X_train)
X_test = (X_test - mean) / std
X_val = (X_val - mean) / std
X_train = (X_train - mean) / std
#custom sinusoidal activation function
class sin(layers.Layer):
def __init__(self, **kwargs):
super(sin, self).__init__(**kwargs)
def call(self, inputs, **kwargs):
return K.sin(inputs)
#constructing ResNet function
def residual_module(layer_in, n_filters, kernel_size, padding, initializer, regularizer):
inputs = layer_in
conv1 = layers.Conv2D(n_filters, kernel_size, padding=padding, kernel_initializer=initializer, kernel_regularizer=regularizer)(layer_in)
conv1 = layers.Lambda(lambda x: sin()(x))(conv1)
batch1 = layers.BatchNormalization()(conv1)
conv2 = layers.Conv2D(layer_in.shape[-1], 1, padding='same', activation='linear', kernel_regularizer=regularizer)(batch1)
batch2 = layers.BatchNormalization()(conv2)
layer_out = layers.add([batch2, inputs])
layer_out = layers.Lambda(lambda x: sin()(x))(layer_out)
return layer_out
def residual_module_triple(layer_in, n_filters, kernel_size, padding, initializer, regularizer):
inputs = layer_in
conv1 = layers.Conv2D(n_filters, kernel_size, padding=padding, kernel_initializer=initializer, kernel_regularizer=regularizer)(layer_in)
conv1 = layers.Lambda(lambda x: sin()(x))(conv1)
batch1 = layers.BatchNormalization()(conv1, training=True)
conv2 = layers.Conv2D(n_filters, kernel_size, padding='same', kernel_regularizer=regularizer)(batch1)
conv2 = layers.Lambda(lambda x: sin()(x))(conv2)
batch2 = layers.BatchNormalization()(conv2, training=True)
conv3 = layers.Conv2D(layer_in.shape[-1], 1, padding='same', activation='linear', kernel_regularizer=regularizer)(batch2)
batch3 = layers.BatchNormalization()(conv3, training=True)
layer_out = layers.add([batch3, inputs])
layer_out = layers.Lambda(lambda x: sin()(x))(layer_out)
return layer_out
#VGG16 model with SIREN
weight_decay = 0.0005
inputs = layers.Input(shape=(32,32,3))
x = residual_module(inputs, n_filters=64, kernel_size=(3,3), padding='same', initializer="he_uniform", regularizer=keras.regularizers.l2(weight_decay))
x = layers.MaxPooling2D(pool_size=(2, 2), strides=2)(x)
x = residual_module(x, 128, (3,3), 'same', None, keras.regularizers.l2(weight_decay))
x = layers.MaxPooling2D(pool_size=(2, 2), strides=2)(x)
x = residual_module_triple(x, 256, (3,3), 'same', None, keras.regularizers.l2(weight_decay))
x = layers.MaxPooling2D(pool_size=(2, 2), strides=2)(x)
x = residual_module_triple(x, 512, (3,3), 'same', None, keras.regularizers.l2(weight_decay))
x = layers.MaxPooling2D(pool_size=(2, 2), strides=2)(x)
x = layers.GlobalAveragePooling2D()(x)
x = layers.Dense(4096, activation="relu")(x)
x = layers.Dropout(0.5)(x)
x = layers.Dense(4096, activation="relu")(x)
x = layers.Dropout(0.5)(x)
outputs = layers.Dense(10)(x)
model = keras.Model(inputs, outputs)
#training model
lr = 0.001
loss = keras.losses.CategoricalCrossentropy(from_logits=True)
decayed_lr = tf.keras.optimizers.schedules.ExponentialDecay(lr, 10000, 0.85, True)
optim = keras.optimizers.SGD(decayed_lr, momentum=0.9, nesterov=True)
batch_size = 128
model.compile(loss=loss, optimizer=optim, metrics=["accuracy"])
checkpoint_filepath = '/Users/JamesRONewton/Documents/Programming/MachineLearning/SIREN_projects/BrainTumor/checkpoint.hdf5'
checkpoint = keras.callbacks.ModelCheckpoint(filepath = checkpoint_filepath, monitor='accuracy', verbose=2, save_best_only=True, save_weights_only=True, mode='auto', save_freq ="epoch")
try:
model.load_weights(checkpoint_filepath, custom_objects = {"sin": tf.math.sin})
except Exception as e:
pass
model.fit(datagen.flow(X_train, Y_train, batch_size=batch_size), steps_per_epoch = len(X_train) / batch_size, epochs=25, callbacks = [checkpoint], validation_data=(X_val, Y_val))
model.evaluate(X_test, Y_test, verbose=1)
#saving model
model.save("VGG16.h5")
if __name__ == '__main__':
main()
Two issues with my code were causing the errors:
I found out that when I was adding a layer, it didn't return anything (e.g. "first" was just a NoneType), so I used "x" as the output of each variable and chained them together with the Model class.
I figured out how to modify the "sin" class I defined to accept multiple arguments. Also, I decided to pass a class function to the Lambda layer instead of a function because it kept passing the Tensor returned from function instead of the function itself.
I am learning to train a basic nn model for image classification, the error happened when I was trying to feed in image data into the model. I understand that I should input correct size of image data. My image data is 128*256 with 3 channels,4 classes, and the batch size is 4. What I don't understand is where does the size 113216 come from? I checked all related parameters or image meta data, but didn't find a clue. Here is my code:
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(3, 6, 5)
self.pool = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(6, 16, 5)
self.fc1 = nn.Linear(3*128*256, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
x = self.pool(F.relu(self.conv1(x)))
x = self.pool(F.relu(self.conv2(x)))
x = x.view(4, 3*128*256)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
net = Net()
for epoch in range(2): # loop over the dataset multiple times
print('round start')
running_loss = 0.0
for i, data in enumerate(trainloader, 0):
# get the inputs; data is a list of [inputs, labels]
inputs, labels = data
# zero the parameter gradients
optimizer.zero_grad()
# forward + backward + optimize
print(inputs.shape)
outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
# print statistics
running_loss += loss.item()
if i % 2000 == 1999: # print every 2000 mini-batches
print('[%d, %5d] loss: %.3f' %
(epoch + 1, i + 1, running_loss / 2000))
running_loss = 0.0
print('Finished Training')
Thanks for your help!
Shapes
Conv2d changes width and height of image without padding. Rule of thumb (if you want to keep the same image size with stride=1 (default)): padding = kernel_size // 2
You are changing number of channels, while your linear layer has 3 for some reason?
Use print(x.shape) after each step if you want to know how your tensor data is transformed!
Commented code
Fixed code with comments about shapes after each step:
class Net(torch.nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = torch.nn.Conv2d(3, 6, 5)
self.pool = torch.nn.MaxPool2d(2, 2)
self.conv2 = torch.nn.Conv2d(6, 16, 5)
# Output shape from convolution is input shape to fc
self.fc1 = torch.nn.Linear(16 * 29 * 61, 120)
self.fc2 = torch.nn.Linear(120, 84)
self.fc3 = torch.nn.Linear(84, 10)
def forward(self, x):
# In: (4, 3, 128, 256)
x = F.relu(self.conv1(x))
# (4, 3, 124, 252) because kernel_size=5 takes 2 pixels
x = self.pool(x)
# (4, 6, 62, 126) # Because pooling halving the size
x = F.relu(self.conv2(x))
# (4, 16, 58, 122) # Same reason as above
x = self.pool(x)
# (4, 16, 29, 61) Because pooling halving the size
# Better use torch.flatten(x, dim=1) so you don't have to input size here
x = x.view(-1, 16 * 29 * 61) # Use -1 to be batch size independent
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
Other things that might help
Try torch.nn.AdaptiveMaxPool2d(1) before ReLU, it will make your network width and height independent
Use flatten (or torch.nn.Flatten() layer) after this pooling
If so, pass num_channels set in last convolution as in_features for nn.Linear
I would like to know how to simply reverse the color order of a given colormap in order to use it with plot_surface.
The standard colormaps also all have reversed versions. They have the same names with _r tacked on to the end. (Documentation here.)
The solution is pretty straightforward. Suppose you want to use the "autumn" colormap scheme. The standard version:
cmap = matplotlib.cm.autumn
To reverse the colormap color spectrum, use get_cmap() function and append '_r' to the colormap title like this:
cmap_reversed = matplotlib.cm.get_cmap('autumn_r')
In matplotlib a color map isn't a list, but it contains the list of its colors as colormap.colors. And the module matplotlib.colors provides a function ListedColormap() to generate a color map from a list. So you can reverse any color map by doing
colormap_r = ListedColormap(colormap.colors[::-1])
As of Matplotlib 2.0, there is a reversed() method for ListedColormap and LinearSegmentedColorMap objects, so you can just do
cmap_reversed = cmap.reversed()
Here is the documentation.
As a LinearSegmentedColormaps is based on a dictionary of red, green and blue, it's necessary to reverse each item:
import matplotlib.pyplot as plt
import matplotlib as mpl
def reverse_colourmap(cmap, name = 'my_cmap_r'):
"""
In:
cmap, name
Out:
my_cmap_r
Explanation:
t[0] goes from 0 to 1
row i: x y0 y1 -> t[0] t[1] t[2]
/
/
row i+1: x y0 y1 -> t[n] t[1] t[2]
so the inverse should do the same:
row i+1: x y1 y0 -> 1-t[0] t[2] t[1]
/
/
row i: x y1 y0 -> 1-t[n] t[2] t[1]
"""
reverse = []
k = []
for key in cmap._segmentdata:
k.append(key)
channel = cmap._segmentdata[key]
data = []
for t in channel:
data.append((1-t[0],t[2],t[1]))
reverse.append(sorted(data))
LinearL = dict(zip(k,reverse))
my_cmap_r = mpl.colors.LinearSegmentedColormap(name, LinearL)
return my_cmap_r
See that it works:
my_cmap
<matplotlib.colors.LinearSegmentedColormap at 0xd5a0518>
my_cmap_r = reverse_colourmap(my_cmap)
fig = plt.figure(figsize=(8, 2))
ax1 = fig.add_axes([0.05, 0.80, 0.9, 0.15])
ax2 = fig.add_axes([0.05, 0.475, 0.9, 0.15])
norm = mpl.colors.Normalize(vmin=0, vmax=1)
cb1 = mpl.colorbar.ColorbarBase(ax1, cmap = my_cmap, norm=norm,orientation='horizontal')
cb2 = mpl.colorbar.ColorbarBase(ax2, cmap = my_cmap_r, norm=norm, orientation='horizontal')
EDIT
I don't get the comment of user3445587. It works fine on the rainbow colormap:
cmap = mpl.cm.jet
cmap_r = reverse_colourmap(cmap)
fig = plt.figure(figsize=(8, 2))
ax1 = fig.add_axes([0.05, 0.80, 0.9, 0.15])
ax2 = fig.add_axes([0.05, 0.475, 0.9, 0.15])
norm = mpl.colors.Normalize(vmin=0, vmax=1)
cb1 = mpl.colorbar.ColorbarBase(ax1, cmap = cmap, norm=norm,orientation='horizontal')
cb2 = mpl.colorbar.ColorbarBase(ax2, cmap = cmap_r, norm=norm, orientation='horizontal')
But it especially works nice for custom declared colormaps, as there is not a default _r for custom declared colormaps. Following example taken from http://matplotlib.org/examples/pylab_examples/custom_cmap.html:
cdict1 = {'red': ((0.0, 0.0, 0.0),
(0.5, 0.0, 0.1),
(1.0, 1.0, 1.0)),
'green': ((0.0, 0.0, 0.0),
(1.0, 0.0, 0.0)),
'blue': ((0.0, 0.0, 1.0),
(0.5, 0.1, 0.0),
(1.0, 0.0, 0.0))
}
blue_red1 = mpl.colors.LinearSegmentedColormap('BlueRed1', cdict1)
blue_red1_r = reverse_colourmap(blue_red1)
fig = plt.figure(figsize=(8, 2))
ax1 = fig.add_axes([0.05, 0.80, 0.9, 0.15])
ax2 = fig.add_axes([0.05, 0.475, 0.9, 0.15])
norm = mpl.colors.Normalize(vmin=0, vmax=1)
cb1 = mpl.colorbar.ColorbarBase(ax1, cmap = blue_red1, norm=norm,orientation='horizontal')
cb2 = mpl.colorbar.ColorbarBase(ax2, cmap = blue_red1_r, norm=norm, orientation='horizontal')
There is no built-in way (yet) of reversing arbitrary colormaps, but one simple solution is to actually not modify the colorbar but to create an inverting Normalize object:
from matplotlib.colors import Normalize
class InvertedNormalize(Normalize):
def __call__(self, *args, **kwargs):
return 1 - super(InvertedNormalize, self).__call__(*args, **kwargs)
You can then use this with plot_surface and other Matplotlib plotting functions by doing e.g.
inverted_norm = InvertedNormalize(vmin=10, vmax=100)
ax.plot_surface(..., cmap=<your colormap>, norm=inverted_norm)
This will work with any Matplotlib colormap.
There are two types of LinearSegmentedColormaps. In some, the _segmentdata is given explicitly, e.g., for jet:
>>> cm.jet._segmentdata
{'blue': ((0.0, 0.5, 0.5), (0.11, 1, 1), (0.34, 1, 1), (0.65, 0, 0), (1, 0, 0)), 'red': ((0.0, 0, 0), (0.35, 0, 0), (0.66, 1, 1), (0.89, 1, 1), (1, 0.5, 0.5)), 'green': ((0.0, 0, 0), (0.125, 0, 0), (0.375, 1, 1), (0.64, 1, 1), (0.91, 0, 0), (1, 0, 0))}
For rainbow, _segmentdata is given as follows:
>>> cm.rainbow._segmentdata
{'blue': <function <lambda> at 0x7fac32ac2b70>, 'red': <function <lambda> at 0x7fac32ac7840>, 'green': <function <lambda> at 0x7fac32ac2d08>}
We can find the functions in the source of matplotlib, where they are given as
_rainbow_data = {
'red': gfunc[33], # 33: lambda x: np.abs(2 * x - 0.5),
'green': gfunc[13], # 13: lambda x: np.sin(x * np.pi),
'blue': gfunc[10], # 10: lambda x: np.cos(x * np.pi / 2)
}
Everything you want is already done in matplotlib, just call cm.revcmap, which reverses both types of segmentdata, so
cm.revcmap(cm.rainbow._segmentdata)
should do the job - you can simply create a new LinearSegmentData from that. In revcmap, the reversal of function based SegmentData is done with
def _reverser(f):
def freversed(x):
return f(1 - x)
return freversed
while the other lists are reversed as usual
valnew = [(1.0 - x, y1, y0) for x, y0, y1 in reversed(val)]
So actually the whole thing you want, is
def reverse_colourmap(cmap, name = 'my_cmap_r'):
return mpl.colors.LinearSegmentedColormap(name, cm.revcmap(cmap._segmentdata))
I encountered a probem when I was using the WIC lib. And I found that I can't scale R32G32B32 images using IWICBitmapScaler... The code example shows below:
{
IWICImagingFactory* m_pWICFactory;
HRESULT hr = S_OK;
// Initialize COM
hr = CoInitialize(nullptr);
assert(SUCCEEDED(hr));
// Initialize Factory
hr = CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER,
__uuidof(IWICImagingFactory), (void**)&m_pWICFactory);
assert(SUCCEEDED(hr));
// 4x4 R32G32B32 image
XMFLOAT3 srcImg[] = { XMFLOAT3(1, 1, 1), XMFLOAT3(1, 1, 1), XMFLOAT3(1, 1, 1), XMFLOAT3(1, 1, 1),
XMFLOAT3(1, 1, 1), XMFLOAT3(1, 1, 1), XMFLOAT3(1, 1, 1), XMFLOAT3(1, 1, 1),
XMFLOAT3(1, 1, 1), XMFLOAT3(1, 1, 1), XMFLOAT3(1, 1, 1), XMFLOAT3(1, 1, 1),
XMFLOAT3(1, 1, 1), XMFLOAT3(1, 1, 1), XMFLOAT3(1, 1, 1), XMFLOAT3(1, 1, 1), };
// 2x2 R32G32B32 image
XMFLOAT3 dstImg[4];
CComPtr<IWICBitmap> pSrcBitmap;
hr = m_pWICFactory->CreateBitmapFromMemory(4, 4, GUID_WICPixelFormat96bppRGBFloat, 4 * sizeof(XMFLOAT3),
4 * sizeof(XMFLOAT3)* 4, (BYTE*)srcImg, &pSrcBitmap);
IWICBitmapSource *pSrcBitmapSource = pSrcBitmap.p;
// scale to 2x2
CComPtr<IWICBitmapScaler> pScaler;
hr = m_pWICFactory->CreateBitmapScaler(&pScaler);
hr = pScaler->Initialize(pSrcBitmapSource, 2, 2, WICBitmapInterpolationModeFant);
pSrcBitmapSource = pScaler.p;
// copy back
WICRect rect = { 0, 0, 2, 2 };
hr = pSrcBitmapSource->CopyPixels(&rect, 2 * sizeof(XMFLOAT3), 2 * sizeof(XMFLOAT3)* 2, (BYTE*)dstImg);
}
And I just get -1.#QNAN000 in the dstImg buffer :(
I'm not sure whether I did something wrong, or the IWICBitmapScaler just don't support such format?
Another ploblem is that when I use IWICFormatConverter to convert R32G32B32A32 (i.e. 128bppRGBFloat) images to R32Gray (i.e.32bppGrayFloat)format, it always clamp the value to [0, 1], is this a desired behavior? (Why???)
(My platform: Win 8.1 64bit + VS2013)
You are incorrectly assuming that the IWICBitmapScaler always returns the data in the same pixel format as it's input. It does not. You have to call GetPixelFormat to find out how the result is going to be formatted. Also, when working with a COM API you must be checking the HRESULT for every call that returns one to catch problems.
CComPtr<IWICBitmapScaler> pScaler;
hr = m_pWICFactory->CreateBitmapScaler(&pScaler);
if ( FAILED(hr) )
...
hr = pScaler->Initialize(pSrcBitmapSource, 2, 2, ICBitmapInterpolationModeFant);
if ( FAILED(hr) )
...
pSrcBitmapSource = pScaler.p;
WICPixelFormatGUID pfScaler;
hr = scaler->GetPixelFormat( &pfScaler );
if ( FAILED(hr) )
...
// In many cases, pfScaler will not be the same GUID as your pSrcBItmapSource.
You should take a look at DirctXTex for extensive examples of using WIC.
Is this the correct way to co-compute translation and rotation, or is there a better way? At the moment my code translates and then rotates, could that pose a problem?
Code
from math import cos, sin, radians
def trig(angle):
r = radians(angle)
return cos(r), sin(r)
def matrix(rotation=(0,0,0), translation=(0,0,0)):
xC, xS = trig(rotation[0])
yC, yS = trig(rotation[1])
zC, zS = trig(rotation[2])
dX = translation[0]
dY = translation[1]
dZ = translation[2]
return [[yC*xC, -zC*xS+zS*yS*xC, zS*xS+zC*yS*xC, dX],
[yC*xS, zC*xC+zS*yS*xS, -zS*xC+zC*yS*xS, dY],
[-yS, zS*yC, zC*yC, dZ],
[0, 0, 0, 1]]
def transform(point=(0,0,0), vector=(0,0,0)):
p = [0,0,0]
for r in range(3):
p[r] += vector[r][3]
for c in range(3):
p[r] += point[c] * vector[r][c]
return p
if __name__ == '__main__':
point = (7, 12, 8)
rotation = (0, -45, 0)
translation = (0, 0, 5)
matrix = matrix(rotation, translation)
print (transform(point, matrix))
Output
root#ubuntu:~$ python rotate.py
[-0.707106781186547, 12.0, 15.606601717798213]
well your matrix function is fine I got it working but for output I used this:
#def transform(point, vector):
# p = [0,0,0]
# for r in range(0,3):
# p[r] += vector[r][3]
# print p
# for c in range(3):
# p[r] += point[c] * vector[r][c]
# return p
def transform(point, TransformArray):
p = np.array([0,0,0,1])
for i in range (0,len(point)-1):
p[i] = point[i]
p=np.dot(TransformArray,np.transpose(p))
for i in range (0,len(point)-1):
point[i]=p[i]
return point
the theory behind it if instead of performing manual changes let the matrices sort it out. Here is where you can find the literature to better understand what I did: http://www.inf.ed.ac.uk/teaching/courses/cg/lectures/cg3_2013.pdf
And yes the way you perform your matrix function defines the way you perform the order of your transformations. There are 3 major transformations: Scaling, Translation, and Rotation. More on that in the link I sent.
Though matrix function works it seems you have the x and z rotations swapped by mistake now I could now follow any of your matrix indices so I rewrote it as such:
def matrix(rotation, translation):
xC, xS = trig(rotation[0])
yC, yS = trig(rotation[1])
zC, zS = trig(rotation[2])
dX = translation[0]
dY = translation[1]
dZ = translation[2]
Translate_matrix = np.array([[1, 0, 0, dX],
[0, 1, 0, dY],
[0, 0, 1, dZ],
[0, 0, 0, 1]])
Rotate_X_matrix = np.array([[1, 0, 0, 0],
[0, xC, -xS, 0],
[0, xS, xC, 0],
[0, 0, 0, 1]])
Rotate_Y_matrix = np.array([[yC, 0, yS, 0],
[0, 1, 0, 0],
[-yS, 0, yC, 0],
[0, 0, 0, 1]])
Rotate_Z_matrix = np.array([[zC, -zS, 0, 0],
[zS, zC, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]])
return np.dot(Rotate_Z_matrix,np.dot(Rotate_Y_matrix,np.dot(Rotate_X_matrix,Translate_matrix)))
As you can see the sequence of transforms in my return will change the output: since the last is the translation it will translate the point first then rotate in X , then rotate in Y and finally in Z.
Hope this helps cheers bud.
As this is a highly viewed post I thought it would be useful to lead people to the SciPy Rotation Class which I found very useful for rotations, and would have been a good solution for the question, had it been around at the time.