In this notebook, some template code has already been provided for you, and you will need to implement additional functionality to successfully complete this project. You will not need to modify the included code beyond what is requested. Sections that begin with '(IMPLEMENTATION)' in the header indicate that the following block of code will require additional functionality which you must provide. Instructions will be provided for each section, and the specifics of the implementation are marked in the code block with a 'TODO' statement. Please be sure to read the instructions carefully!
Note: Once you have completed all of the code implementations, you need to finalize your work by exporting the iPython Notebook as an HTML document. Before exporting the notebook to html, all of the code cells need to have been run so that reviewers can see the final implementation and output. You can then export the notebook by using the menu above and navigating to \n", "File -> Download as -> HTML (.html). Include the finished document along with this notebook as your submission.
In addition to implementing code, there will be questions that you must answer which relate to the project and your implementation. Each section where you will answer a question is preceded by a 'Question X' header. Carefully read each question and provide thorough answers in the following text boxes that begin with 'Answer:'. Your project submission will be evaluated based on your answers to each of the questions and the implementation you provide.
Note: Code and Markdown cells can be executed using the Shift + Enter keyboard shortcut. Markdown cells can be edited by double-clicking the cell to enter edit mode.
The rubric contains optional "Stand Out Suggestions" for enhancing the project beyond the minimum requirements. If you decide to pursue the "Stand Out Suggestions", you should include the code in this IPython notebook.
In this notebook, you will make the first steps towards developing an algorithm that could be used as part of a mobile or web app. At the end of this project, your code will accept any user-supplied image as input. If a dog is detected in the image, it will provide an estimate of the dog's breed. If a human is detected, it will provide an estimate of the dog breed that is most resembling. The image below displays potential sample output of your finished project (... but we expect that each student's algorithm will behave differently!).
In this real-world setting, you will need to piece together a series of models to perform different tasks; for instance, the algorithm that detects humans in an image will be different from the CNN that infers dog breed. There are many points of possible failure, and no perfect algorithm exists. Your imperfect solution will nonetheless create a fun user experience!
We break the notebook into separate steps. Feel free to use the links below to navigate the notebook.
In the code cell below, we import a dataset of dog images. We populate a few variables through the use of the load_files
function from the scikit-learn library:
train_files
, valid_files
, test_files
- numpy arrays containing file paths to imagestrain_targets
, valid_targets
, test_targets
- numpy arrays containing onehot-encoded classification labels dog_names
- list of string-valued dog breed names for translating labelsfrom sklearn.datasets import load_files
from keras.utils import np_utils
import numpy as np
from glob import glob
# define function to load train, test, and validation datasets
def load_dataset(path):
data = load_files(path)
dog_files = np.array(data['filenames'])
dog_targets = np_utils.to_categorical(np.array(data['target']), 133)
return dog_files, dog_targets
# load train, test, and validation datasets
train_files, train_targets = load_dataset('./data/dog_images/train')
valid_files, valid_targets = load_dataset('./data/dog_images/valid')
test_files, test_targets = load_dataset('./data/dog_images/test')
# load list of dog names
dog_names = [item[20:-1] for item in sorted(glob("./data/dog_images/train/*/"))]
# print statistics about the dataset
print('There are %d total dog categories.' % len(dog_names))
print('There are %s total dog images.\n' % len(np.hstack([train_files, valid_files, test_files])))
print('There are %d training dog images.' % len(train_files))
print('There are %d validation dog images.' % len(valid_files))
print('There are %d test dog images.'% len(test_files))
In the code cell below, we import a dataset of human images, where the file paths are stored in the numpy array human_files
.
import random
random.seed(8675309)
# load filenames in shuffled human dataset
human_files = np.array(glob("./data/lfw/*/*"))
random.shuffle(human_files)
# print statistics about the dataset
print('There are %d total human images.' % len(human_files))
We use OpenCV's implementation of Haar feature-based cascade classifiers to detect human faces in images. OpenCV provides many pre-trained face detectors, stored as XML files on github. We have downloaded one of these detectors and stored it in the haarcascades
directory.
In the next code cell, we demonstrate how to use this detector to find human faces in a sample image.
import cv2
import matplotlib.pyplot as plt
%matplotlib inline
# extract pre-trained face detector
face_cascade = cv2.CascadeClassifier('haarcascades/haarcascade_frontalface_alt.xml')
# load color (BGR) image
img = cv2.imread(human_files[5])
# convert BGR image to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# find faces in image
faces = face_cascade.detectMultiScale(gray)
# print number of faces detected in the image
print('Number of faces detected:', len(faces))
# get bounding box for each detected face
for (x,y,w,h) in faces:
# add bounding box to color image
cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
# convert BGR image to RGB for plotting
cv_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# display the image, along with bounding box
plt.imshow(cv_rgb)
plt.show()
Before using any of the face detectors, it is standard procedure to convert the images to grayscale. The detectMultiScale
function executes the classifier stored in face_cascade
and takes the grayscale image as a parameter.
In the above code, faces
is a numpy array of detected faces, where each row corresponds to a detected face. Each detected face is a 1D array with four entries that specifies the bounding box of the detected face. The first two entries in the array (extracted in the above code as x
and y
) specify the horizontal and vertical positions of the top left corner of the bounding box. The last two entries in the array (extracted here as w
and h
) specify the width and height of the box.
We can use this procedure to write a function that returns True
if a human face is detected in an image and False
otherwise. This function, aptly named face_detector
, takes a string-valued file path to an image as input and appears in the code block below.
# returns "True" if face is detected in image stored at img_path
def face_detector(img_path):
img = cv2.imread(img_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray)
return len(faces) > 0
Question 1: Use the code cell below to test the performance of the face_detector
function.
human_files
have a detected human face? dog_files
have a detected human face?  You will see that our algorithm falls short of this goal, but still gives acceptable performance. We extract the file paths for the first 100 images from each of the datasets and store them in the numpy arrays human_files_short
and dog_files_short
.
Answer:
99.0% of the first 100 images in human_files have a detected human face.
11.0% of the first 100 images in dog_files have a detected human face.
human_files_short = human_files[:100]
dog_files_short = train_files[:100]
# Do NOT modify the code above this line.
## TODO: Test the performance of the face_detector algorithm
## on the images in human_files_short and dog_files_short.https://d2l.ai/index.html
human_detected = 0
num_test = 0
for file in human_files_short:
if face_detector(file):
human_detected += 1
num_test += 1
print(str(float(human_detected)/float(num_test)*100)+ \
"% of the first 100 images in human_files have a detected human face.")
human_detected = 0
num_test = 0
for file in dog_files_short:
if face_detector(file):
human_detected += 1
num_test += 1
print(str(float(human_detected)/float(num_test)*100)+ \
"% of the first 100 images in dog_files have a detected human face.")
Question 2: This algorithmic choice necessitates that we communicate to the user that we accept human images only when they provide a clear view of a face (otherwise, we risk having unneccessarily frustrated users!). In your opinion, is this a reasonable expectation to pose on the user? If not, can you think of a way to detect humans in images that does not necessitate an image with a clearly presented face?
Answer:
In my opinion, it is not reasonable to expect our algorthm can only use for the clear images. It is easy for many people to identify the human face even for the nearsighted or shortsighted people. The human faces has critical image features even the image is not so clear or just a parial face such as wearing sunglasses people.To solve the human face identification for the unclear images, we need select our training database including the clear images, unclear images, partial covered human faces or unfocus images. And the algorthm would recommend to use the CNN base neural network to extract the critical features for human faces. I think the method would assist to develop the method to dectect human face whilc in unclear images.
We suggest the face detector from OpenCV as a potential way to detect human images in your algorithm, but you are free to explore other approaches, especially approaches that make use of deep learning :). Please use the code cell below to design and test your own face detection algorithm. If you decide to pursue this optional task, report performance on each of the datasets.
## (Optional) TODO: Report the performance of another
## face detection algorithm on the LFW dataset
### Feel free to use as many code cells as needed.
In this section, we use a pre-trained ResNet-50 model to detect dogs in images. Our first line of code downloads the ResNet-50 model, along with weights that have been trained on ImageNet, a very large, very popular dataset used for image classification and other vision tasks. ImageNet contains over 10 million URLs, each linking to an image containing an object from one of 1000 categories. Given an image, this pre-trained ResNet-50 model returns a prediction (derived from the available categories in ImageNet) for the object that is contained in the image.
from keras.applications.resnet50 import ResNet50
# define ResNet50 model
ResNet50_model = ResNet50(weights='imagenet')
When using TensorFlow as backend, Keras CNNs require a 4D array (which we'll also refer to as a 4D tensor) as input, with shape
$$ (\text{nb_samples}, \text{rows}, \text{columns}, \text{channels}), $$where nb_samples
corresponds to the total number of images (or samples), and rows
, columns
, and channels
correspond to the number of rows, columns, and channels for each image, respectively.
The path_to_tensor
function below takes a string-valued file path to a color image as input and returns a 4D tensor suitable for supplying to a Keras CNN. The function first loads the image and resizes it to a square image that is $224 \times 224$ pixels. Next, the image is converted to an array, which is then resized to a 4D tensor. In this case, since we are working with color images, each image has three channels. Likewise, since we are processing a single image (or sample), the returned tensor will always have shape
The paths_to_tensor
function takes a numpy array of string-valued image paths as input and returns a 4D tensor with shape
Here, nb_samples
is the number of samples, or number of images, in the supplied array of image paths. It is best to think of nb_samples
as the number of 3D tensors (where each 3D tensor corresponds to a different image) in your dataset!
from keras.preprocessing import image
from tqdm import tqdm
def path_to_tensor(img_path):
# loads RGB image as PIL.Image.Image type
img = image.load_img(img_path, target_size=(224, 224))
# convert PIL.Image.Image type to 3D tensor with shape (224, 224, 3)
x = image.img_to_array(img)
# convert 3D tensor to 4D tensor with shape (1, 224, 224, 3) and return 4D tensor
return np.expand_dims(x, axis=0)
def paths_to_tensor(img_paths):
list_of_tensors = [path_to_tensor(img_path) for img_path in tqdm(img_paths)]
return np.vstack(list_of_tensors)
Getting the 4D tensor ready for ResNet-50, and for any other pre-trained model in Keras, requires some additional processing. First, the RGB image is converted to BGR by reordering the channels. All pre-trained models have the additional normalization step that the mean pixel (expressed in RGB as $[103.939, 116.779, 123.68]$ and calculated from all pixels in all images in ImageNet) must be subtracted from every pixel in each image. This is implemented in the imported function preprocess_input
. If you're curious, you can check the code for preprocess_input
here.
Now that we have a way to format our image for supplying to ResNet-50, we are now ready to use the model to extract the predictions. This is accomplished with the predict
method, which returns an array whose $i$-th entry is the model's predicted probability that the image belongs to the $i$-th ImageNet category. This is implemented in the ResNet50_predict_labels
function below.
By taking the argmax of the predicted probability vector, we obtain an integer corresponding to the model's predicted object class, which we can identify with an object category through the use of this dictionary.
from keras.applications.resnet50 import preprocess_input, decode_predictions
def ResNet50_predict_labels(img_path):
# returns prediction vector for image located at img_path
img = preprocess_input(path_to_tensor(img_path))
return np.argmax(ResNet50_model.predict(img))
While looking at the dictionary, you will notice that the categories corresponding to dogs appear in an uninterrupted sequence and correspond to dictionary keys 151-268, inclusive, to include all categories from 'Chihuahua'
to 'Mexican hairless'
. Thus, in order to check to see if an image is predicted to contain a dog by the pre-trained ResNet-50 model, we need only check if the ResNet50_predict_labels
function above returns a value between 151 and 268 (inclusive).
We use these ideas to complete the dog_detector
function below, which returns True
if a dog is detected in an image (and False
if not).
### returns "True" if a dog is detected in the image stored at img_path
def dog_detector(img_path):
prediction = ResNet50_predict_labels(img_path)
return ((prediction <= 268) & (prediction >= 151))
Question 3: Use the code cell below to test the performance of your dog_detector
function.
human_files_short
have a detected dog? dog_files_short
have a detected dog?Answer:
1.0% of the first 100 images in human_files have a detected dog face.
100.0% of the first 100 images in dog_files have a detected dog face.
### TODO: Test the performance of the dog_detector function
### on the images in human_files_short and dog_files_short.
dog_detected = 0
num_test = 0
for file in human_files_short:
if dog_detector(file):
dog_detected += 1
num_test += 1
print(str(float(dog_detected)/float(num_test)*100)+ \
"% of the first 100 images in human_files have a detected dog face.")
dog_detected = 0
num_test = 0
for file in dog_files_short:
if dog_detector(file):
dog_detected += 1
num_test += 1
print(str(float(dog_detected)/float(num_test)*100)+ \
"% of the first 100 images in dog_files have a detected dog face.")
Now that we have functions for detecting humans and dogs in images, we need a way to predict breed from images. In this step, you will create a CNN that classifies dog breeds. You must create your CNN from scratch (so, you can't use transfer learning yet!), and you must attain a test accuracy of at least 1%. In Step 5 of this notebook, you will have the opportunity to use transfer learning to create a CNN that attains greatly improved accuracy.
Be careful with adding too many trainable layers! More parameters means longer training, which means you are more likely to need a GPU to accelerate the training process. Thankfully, Keras provides a handy estimate of the time that each epoch is likely to take; you can extrapolate this estimate to figure out how long it will take for your algorithm to train.
We mention that the task of assigning breed to dogs from images is considered exceptionally challenging. To see why, consider that even a human would have great difficulty in distinguishing between a Brittany and a Welsh Springer Spaniel.
| Brittany | Welsh Springer Spaniel |
|---|---|
It is not difficult to find other dog breed pairs with minimal inter-class variation (for instance, Curly-Coated Retrievers and American Water Spaniels).
| Curly-Coated Retriever | American Water Spaniel |
|---|---|
Likewise, recall that labradors come in yellow, chocolate, and black. Your vision-based algorithm will have to conquer this high intra-class variation to determine how to classify all of these different shades as the same breed.
| Yellow Labrador | Chocolate Labrador | Black Labrador |
|---|---|---|
We also mention that random chance presents an exceptionally low bar: setting aside the fact that the classes are slightly imabalanced, a random guess will provide a correct answer roughly 1 in 133 times, which corresponds to an accuracy of less than 1%.
Remember that the practice is far ahead of the theory in deep learning. Experiment with many different architectures, and trust your intuition. And, of course, have fun!
We rescale the images by dividing every pixel in every image by 255.
from PIL import ImageFile
ImageFile.LOAD_TRUNCATED_IMAGES = True
# pre-process the data for Keras
train_tensors = paths_to_tensor(train_files).astype('float32')/255
valid_tensors = paths_to_tensor(valid_files).astype('float32')/255
test_tensors = paths_to_tensor(test_files).astype('float32')/255
Create a CNN to classify dog breed. At the end of your code cell block, summarize the layers of your model by executing the line:
model.summary()
We have imported some Python modules to get you started, but feel free to import as many modules as you need. If you end up getting stuck, here's a hint that specifies a model that trains relatively fast on CPU and attains >1% test accuracy in 5 epochs:
Question 4: Outline the steps you took to get to your final CNN architecture and your reasoning at each step. If you chose to use the hinted architecture above, describe why you think that CNN architecture should work well for the image classification task.
Answer:
Since our current target is to create a classifier whose test accuracy is greater than 1%. We already know that a random guess will provide a correct answer roughly 1 in 133 times, which corresponds to an accuracy of less than 1%. I think the hinted architecture above should work well for the image classification task. It contains three convolutional layers sequentially. It can already extract some high level features from input pictures. Besides, it puts a global average pooling layer before the last fully connected layer instead of a simple flatten dense layer. It effectively reduces the number of parameters. I think such CNN architecture is suitable as a starter.
from keras.layers import Conv2D, MaxPooling2D, GlobalAveragePooling2D
from keras.layers import Dropout, Flatten, Dense
from keras.models import Sequential
model = Sequential()
model.add(Conv2D(filters=16, kernel_size=2, padding='same', activation='relu',input_shape=(224, 224, 3)))
model.add(MaxPooling2D(pool_size=2))
model.add(Conv2D(filters=32, kernel_size=2, padding='same', activation='relu'))
model.add(MaxPooling2D(pool_size=2))
model.add(Conv2D(filters=64, kernel_size=2, padding='same', activation='relu'))
model.add(MaxPooling2D(pool_size=2))
model.add(Dropout(0.2))
model.add(GlobalAveragePooling2D())
#add more dense layer
model.add(Dense(256, activation='relu'))
model.add(Dropout(0.4))
model.add(Dense(133, activation='softmax'))
model.summary()
model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy'])
Train your model in the code cell below. Use model checkpointing to save the model that attains the best validation loss.
You are welcome to augment the training data, but this is not a requirement.
from keras.callbacks import ModelCheckpoint
### TODO: specify the number of epochs that you would like to use to train the model.
epochs = 20
### Do NOT modify the code below this line.
checkpointer = ModelCheckpoint(filepath='saved_models/weights.best.from_scratch.hdf5',
verbose=1, save_best_only=True)
model.fit(train_tensors, train_targets,
validation_data=(valid_tensors, valid_targets),
epochs=epochs, batch_size=20, callbacks=[checkpointer], verbose=1)
model.load_weights('saved_models/weights.best.from_scratch.hdf5')
Try out your model on the test dataset of dog images. Ensure that your test accuracy is greater than 1%.
# get index of predicted dog breed for each image in test set
dog_breed_predictions = [np.argmax(model.predict(np.expand_dims(tensor, axis=0))) for tensor in test_tensors]
# report test accuracy
test_accuracy = 100*np.sum(np.array(dog_breed_predictions)==np.argmax(test_targets, axis=1))/len(dog_breed_predictions)
print('Test accuracy: %.4f%%' % test_accuracy)
bottleneck_features = np.load('./data/bottleneck_features/DogVGG16Data.npz')
train_VGG16 = bottleneck_features['train']
valid_VGG16 = bottleneck_features['valid']
test_VGG16 = bottleneck_features['test']
The model uses the the pre-trained VGG-16 model as a fixed feature extractor, where the last convolutional output of VGG-16 is fed as input to our model. We only add a global average pooling layer and a fully connected layer, where the latter contains one node for each dog category and is equipped with a softmax.
VGG16_model = Sequential()
VGG16_model.add(GlobalAveragePooling2D(input_shape=train_VGG16.shape[1:]))
VGG16_model.add(Dense(133, activation='softmax'))
VGG16_model.summary()
VGG16_model.compile(loss='categorical_crossentropy', optimizer='rmsprop', metrics=['accuracy'])
checkpointer = ModelCheckpoint(filepath='saved_models/weights.best.VGG16.hdf5',
verbose=1, save_best_only=True)
VGG16_model.fit(train_VGG16, train_targets,
validation_data=(valid_VGG16, valid_targets),
epochs=20, batch_size=20, callbacks=[checkpointer], verbose=1)
VGG16_model.load_weights('saved_models/weights.best.VGG16.hdf5')
Now, we can use the CNN to test how well it identifies breed within our test dataset of dog images. We print the test accuracy below.
# get index of predicted dog breed for each image in test set
VGG16_predictions = [np.argmax(VGG16_model.predict(np.expand_dims(feature, axis=0))) for feature in test_VGG16]
# report test accuracy
test_accuracy = 100*np.sum(np.array(VGG16_predictions)==np.argmax(test_targets, axis=1))/len(VGG16_predictions)
print('Test accuracy: %.4f%%' % test_accuracy)
from extract_bottleneck_features import *
def VGG16_predict_breed(img_path):
# extract bottleneck features
bottleneck_feature = extract_VGG16(path_to_tensor(img_path))
# obtain predicted vector
predicted_vector = VGG16_model.predict(bottleneck_feature)
# return dog breed that is predicted by the model
return dog_names[np.argmax(predicted_vector)]
You will now use transfer learning to create a CNN that can identify dog breed from images. Your CNN must attain at least 60% accuracy on the test set.
In Step 4, we used transfer learning to create a CNN using VGG-16 bottleneck features. In this section, you must use the bottleneck features from a different pre-trained model. To make things easier for you, we have pre-computed the features for all of the networks that are currently available in Keras. These are already in the workspace, at /data/bottleneck_features. If you wish to download them on a different machine, they can be found at:
The files are encoded as such:
Dog{network}Data.npz
where {network}
, in the above filename, can be one of VGG19
, Resnet50
, InceptionV3
, or Xception
.
The above architectures are downloaded and stored for you in the /data/bottleneck_features/
folder.
This means the following will be in the /data/bottleneck_features/
folder:
DogVGG19Data.npz
DogResnet50Data.npz
DogInceptionV3Data.npz
DogXceptionData.npz
In the code block below, extract the bottleneck features corresponding to the train, test, and validation sets by running the following:
bottleneck_features = np.load('/data/bottleneck_features/Dog{network}Data.npz')
train_{network} = bottleneck_features['train']
valid_{network} = bottleneck_features['valid']
test_{network} = bottleneck_features['test']
### TODO: Obtain bottleneck features from another pre-trained CNN.
Resnet50_bottleneck_features = np.load('./data/bottleneck_features/DogResnet50Data.npz')
train_Resnet50 = Resnet50_bottleneck_features['train']
valid_Resnet50 = Resnet50_bottleneck_features['valid']
test_Resnet50 = Resnet50_bottleneck_features['test']
Create a CNN to classify dog breed. At the end of your code cell block, summarize the layers of your model by executing the line:
<your model's name>.summary()
Question 5: Outline the steps you took to get to your final CNN architecture and your reasoning at each step. Describe why you think the architecture is suitable for the current problem.
Answer:
From a quick preview of each possible candidates, I think all of them have quite powerful ability to extract enough feature information for classifying the dog breed from an input image. I simply choose ResNet-50 as the basic architecture of my CNN object classifier. I choose to use a GlobalAveragePooling layer instead of simply flattening the last convolutional layer of ResNet-50. This step can efficiently reduce the number of fitting parameters. A fully connected layer is added after the global average pooling layer. It contains one node for each dog category and is equipped with an activation function 'softmax'.
To sum up, we made a transfer learning by making ResNet-50 suitable for our study. We can say that we only replace the last original fully connected layer with a new fully connected layer matching the number of classes in the new data set.
from keras import regularizers
### TODO: Define your architecture.
Resnet50_model = Sequential()
Resnet50_model.add(GlobalAveragePooling2D(input_shape=train_Resnet50.shape[1:]))
Resnet50_model.add(Dense(133, activation='softmax'))
Resnet50_model.summary()
### TODO: Compile the model.
Resnet50_model.compile(loss='categorical_crossentropy', optimizer='rmsprop', metrics=['accuracy'])
Train your model in the code cell below. Use model checkpointing to save the model that attains the best validation loss.
You are welcome to augment the training data, but this is not a requirement.
### TODO: Train the model.
checkpointer = ModelCheckpoint(filepath='saved_models/weights.best.Resnet50.hdf5',
verbose=1, save_best_only=True)
Resnet50_model.fit(train_Resnet50, train_targets,
validation_data=(valid_Resnet50, valid_targets),
epochs=20, batch_size=20, callbacks=[checkpointer], verbose=1)
### TODO: Load the model weights with the best validation loss.
Resnet50_model.load_weights('saved_models/weights.best.Resnet50.hdf5')
Try out your model on the test dataset of dog images. Ensure that your test accuracy is greater than 60%.
### TODO: Calculate classification accuracy on the test dataset.
# get index of predicted dog breed for each image in test set
Resnet50_predictions = [np.argmax(Resnet50_model.predict(np.expand_dims(feature, axis=0))) for feature in test_Resnet50]
# report test accuracy
test_accuracy = 100*np.sum(np.array(Resnet50_predictions)==np.argmax(test_targets, axis=1))/len(Resnet50_predictions)
print('Test accuracy: %.4f%%' % test_accuracy)
Write a function that takes an image path as input and returns the dog breed (Affenpinscher
, Afghan_hound
, etc) that is predicted by your model.
Similar to the analogous function in Step 5, your function should have three steps:
dog_names
array defined in Step 0 of this notebook to return the corresponding breed.The functions to extract the bottleneck features can be found in extract_bottleneck_features.py
, and they have been imported in an earlier code cell. To obtain the bottleneck features corresponding to your chosen CNN architecture, you need to use the function
extract_{network}
where {network}
, in the above filename, should be one of VGG19
, Resnet50
, InceptionV3
, or Xception
.
### TODO: Write a function that takes a path to an image as input
### and returns the dog breed that is predicted by the model.
def ResNet50_predict_breed(img_path):
# extract bottleneck features
bottleneck_feature = extract_Resnet50(path_to_tensor(img_path))
# obtain predicted vector
predicted_vector = Resnet50_model.predict(bottleneck_feature)
# return dog breed that is predicted by the model
return dog_names[np.argmax(predicted_vector)]
Write an algorithm that accepts a file path to an image and first determines whether the image contains a human, dog, or neither. Then,
You are welcome to write your own functions for detecting humans and dogs in images, but feel free to use the face_detector
and dog_detector
functions developed above. You are required to use your CNN from Step 5 to predict dog breed.
Some sample output for our algorithm is provided below, but feel free to design your own user experience!
### TODO: Write your algorithm.
### Feel free to use as many code cells as needed.
import matplotlib.image as mpimg
def my_image_classifier(img_path):
if dog_detector(img_path):
creature = "dog"
elif face_detector(img_path):
creature = "human"
else:
plt.imshow(mpimg.imread(img_path))
raise ValueError("Can't recognize the object shown in the picture...")
breed = ResNet50_predict_breed(img_path)
plt.imshow(mpimg.imread(img_path))
print ("We find a {} in this picture!".format(creature))
if creature == "dog":
print ("It looks like a ... {}".format(breed))
elif creature == "human":
print ("And this human looks like a {}".format(breed))
In this section, you will take your new algorithm for a spin! What kind of dog does the algorithm think that you look like? If you have a dog, does it predict your dog's breed accurately? If you have a cat, does it mistakenly think that your cat is a dog?
Test your algorithm at least six images on your computer. Feel free to use any images you like. Use at least two human and two dog images.
Question 6: Is the output better than you expected :) ? Or worse :( ? Provide at least three possible points of improvement for your algorithm.
Answer:
In my evaluation cases, my algorithm can precisely identify the human face or dog face. It can also idenifiy the image is not dog or human if I input a bird picture. It looks workable as a decter for the dogs and human faces. However, the second part of this algorithm is to identify the dog's breed, it still has some thing to be improve although it is demonstrated good prediction accuracy for my four test images by 75%.
For the case1, Shih Tzu is a kind of long haired dog, the Resnet50 looks it like a Pekigese that is also kind of long haired dog. They looks very simular, I think is not easy to seperate them by image for people. If we can prepare more data for each dogs for training, I think we can get a more accuracy model. For the case 2 to case 4, the breed preditor works very good. I think the Resnet's model is originally well trained.
For the case 5 to case 7, the human dector work well and the dog's breed model shows some interesting results. Jeremy_Lin was predited to the 'Nova_scotia_duck_tolling_retriever', I think his orange color jersey looks like a dog's hair to our resnet50 model. The other 2 cases, it look likes the face induced since the color of clothes are not simular to the color of each dog's hair.
Improvement:
Our algorithm should take the background of the picture into account. Maybe some preprocessing of picture can help us reducing the influence of unnecessary background. Data augmentation. Through using this technique, we can increase the size of training data set and also make our classifier more robust. It can learn more general features which are scale, rotation or translation invariance. Using different CNN architectures. Maybe InceptionV3, or Xception are worth to give it a try. Maybe they can extract much more detailed and important features and make much more reasonable predictions.
## TODO: Execute your algorithm from Step 6 on
## at least 6 images on your computer.
## Feel free to use as many code cells as needed.
print ("Case 1")
my_image_classifier('./images/Shih_Tzu_Male_Single_Coat.jpg')
print ("Photo Taken From: https://en.wikipedia.org/wiki/Shih_Tzu")
print ("Case 2")
my_image_classifier('./images/Pudel_Grossschwarz.jpg')
print ("Photo Taken From: https://en.wikipedia.org/wiki/Poodle")
print ("Case 3")
my_image_classifier('./images/Woody_Puppy.jpg')
print ("Photo Taken From: https://en.wikipedia.org/wiki/Husky")
print ("Case 4")
my_image_classifier('./images/Tibetan Mastiff.jpg')
print ("Photo Taken From: https://en.wikipedia.org/wiki/Tibetan_Mastiff")
print ("Case 5")
my_image_classifier('./images/Jeremy_Lin_March_2012.jpg')
print ("Photo Taken From: https://en.wikipedia.org/wiki/Jeremy_Lin")
print ("Case 6")
my_image_classifier('./images/Kobe_Bryant_8.jpg')
print ("Photo Taken From: https://en.wikipedia.org/wiki/Kobe_Bryant")
print ("Case 7")
my_image_classifier('./images/Bill_Gates_2018.jpg')
print ("Photo Taken From: https://en.wikipedia.org/wiki/Bill_Gates")
print ("Case 8")
my_image_classifier('./images/Green-headed_Tanager_Ubatuba.jpg')
print ("Photo Taken From: https://en.wikipedia.org/wiki/Tanager")
In order to submit, please do the following:
zip -r dog-project.zip dog-project


Brand posters created for a fictitious company named Spring body & soul.
Two versions of magazine designs for a fictitious Agency named Missus.
School project featuring two versions of book and bookcover designs.
Poster designs for a pet show, hosted by a non-profit organisation.
School project design of two travel brochures made for Maldives.
Maldives was the destination of choice for this school project.
Converse was the sports company of choice for this school project.
Surrealism artwork titled "vision of Hope" in the pandemic era.
Commissioned, uncommissioned and school project logo designs.
Done as a school project to showcase the achievements of Converse.
A school project showcasing the products and history of Converse.
Commissioned, uncommissioned and school project print designs.


Add custom search services¶
If you want to access a custom data source, you can create your own search plug-in and access it as a search tab definition in Google Earth Enterprise Server. A custom search plug-in will create requests and responses using the common Python-based search framework, letting you adapt your search to any data source. Your custom search plug-in will receive search requests directly from Google Earth Enterprise Client (EC), or any other clients in the form of URL parameters.
For example, with custom search plug-ins you can use Maps API and Places API to leverage the power of their data sets. You can also use a proprietary database, e.g., power conversion sites, then search for the sites using internal IDs or city names.
A custom search plug-in may also provide a solution if you want to search data that is not on your Google Earth Enterprise Server or you want to combine Google Earth Enterprise databases in new ways. For example, you may want to combine a Places search with your own vector point data set, enabling your users to search by city name or facility name. The custom search plug-in would forward your request to both the POI Search plug-in and the Places plug-in and return a merged set.
Note
Google Maps API and Places API access services over the internet, and require licenses to use.
Note
You will need some familiarity with Python to work with custom search plug-ins.
- Configure search queries for Google Earth EC and Google Maps
- Access Search Plug-ins
- Implement your custom search plug-in
Configure search queries for Google Earth EC and Google Maps
Any web service, servlet, or web application you configure the search tabs to query:
- Must return valid KML to Google Earth EC.
- Must return valid JSONP in the specified structure.
Warning
Because search tabs are returned as JSONP, they must originate from the same server as the HTML page containing the 2D map.
Access Search Plug-ins
The Google Earth Enterprise search plug-ins are stored in a
default directory that you can use to add or delete your custom
plug-ins as required. You can also modify the configuration
file /opt/google/gehttpd/conf.d/mod_wsgi-ge.conf
to
register new search plug-ins with Google Earth Enterprise Server
instead of creating search tabs. The configuration file provides a
convenient method for managing search plug-ins with scripts, for
example, to register newly created plug-in endpoints so that they
can be accessible when you view your database in Google Earth EC.
You can access the plug-ins that are installed with Google Earth Enterprise Server at:
/opt/google/gehttpd/wsgi-bin/search/plugin
For example, access /gesearch/ExampleSearch
in your browser as
follows:
http://your.gee.server/gesearch/ExampleSearch
The plug-in end points are for Google Earth Enterprise search
plug-ins are defined in
/opt/google/gehttpd/conf.d/mod_wsgi-ge.conf
.
# Handles Places search requests.
WSGIScriptAlias /gesearch/PlacesSearch /opt/google/gehttpd/wsgi-bin/search/plugin/geplaces_search_app.py
# Handles Coordinate search requests.
WSGIScriptAlias /gesearch/CoordinateSearch /opt/google/gehttpd/wsgi-bin/search/plugin/coordinate_search_app.py
# Handles Federated search requests.
WSGIScriptAlias /gesearch/FederatedSearch /opt/google/gehttpd/wsgi-bin/search/plugin/federated_search_app.py
# Handles Example search requests.
WSGIScriptAlias /gesearch/ExampleSearch /opt/google/gehttpd/wsgi-bin/search/plugin/example_search_app.py
# Handles POI search requests.
WSGIScriptAlias /POISearch /opt/google/gehttpd/wsgi-bin/search/plugin/poi_search_app.py
Implement a custom search plug-in
You implement a custom search plug-in by creating your own Python search application using WSGI, then registering the new search plug-in so that it can be added as you publish databases.
To implement a custom search plug-in:
Create your search application, using the WSGI framework. See the Example Search Python module for example code.
Locate your search plug-in, for example
custom_search.py
, in the/opt/google/gehttpd/wsgi-bin/search/plugin/
directory.Register your plug-in by adding its definition in the Python module configuration file:
/opt/google/gehttpd/conf.d/mod_wsgi-ge.conf
. Your registration in the configuration file should look something like the following:# Handles My Custom search requests. WSGIScriptAlias /gesearch/CustomSearch /opt/google/gehttpd/wsgi-bin/search/plugin/mycustom_search_app.py
Restart Google Earth Enterprise Server:
# sudo /etc/init.d/geserver restart
Open the Google Earth Enterprise Server Admin console and click Search tabs. The list of Search tabs definitions appears.
Click Create New to create a new search definition.
Add a name and label.
In the URL field, add the
WSGIScriptAlias
that you specified in the/opt/google/gehttpd/conf.d/mod_wsgi-ge.conf
file. In this example, you would entergesearch/CustomSearch
.If you want to add query parameters that are hidden from Google Earth EC, such as the way the results will be sorted or the number of results displayed at a time, enter them in the Additional Query Parameters field. The syntax is key1=value1&key2;=value2. For example, sortby=name&numresults;=10 sorts by the name field and displays 10 results at a time. The search application must be able to understand and respond to these key/value pairs, so you must be very familiar with the search application to use this field.
Set the fields and other options as needed and click Save. Your new custom search definition is added to the list on the Search tabs page.
When you publish a database, add your search definition from the Search tabs drop-down list in the Publish dialog.


Additional remarks for Account.Category_03
The [Cicmpy.Category] field stores the third account category.


--- layout : blog title : Join Us active : join-us ---
Py_Contributors is an open-source community for Python, Machine learning, Web Development and Data Science. Most of us are students and are continuously learning from each other's experiences.
Open source projects bring many benefits to those who participate in them, and such experience is great for your CV and greater for your knowledge and skills. By joining a community of like-minded people and polishing up your skills, you can give yourself a step up as an aspiring developer.
There are several reasons to contribute to OSS (open-source software) :
🔵 First, there are a lot of enthusiasts who simply believe that code should be open. They're idealists who want to make the world a better place, and it drives them to contribute code. The desire to share can be a powerful motivator.
🔵 Second, OSS gives you a great start. Beginners might start by fixing minor things, such as a bug in a library, sending a pull request, or even writing a piece of documentation. However, beginner developers can also learn to write so-called "clean code" – code that is readable and maintainable – while contributing to open source projects.
🔵 Third, you get the chance to be part of an active open source community where you can meet like-minded people and supporters. Moreover, if you're a freelancer and actively contribute to open source projects, you increase your chances of being noticed by potential employers.
You can find many projects, you are free to participate on GitHub – a developer-oriented platform with a simple but essential set of functionality. You can contribute to free software in many ways. Developers can fork projects, make changes to code, and send pull requests. And quality assurance is always appreciated. Sometimes developers are too busy or too lazy to check the quality of their code. So go ahead and report a bug or try to fix it – your help is appreciated.


TeeGofer
Here. From Husein Choroomi: "TeeGofer is a tool designed specifically for the .NET Component writer. Written in 100% native C# code, it works by reflection to read in metadata from .NET Assemblies (.DLLs or .EXEs) to create first class quality online help documentation. The Tool is extremely easy to work with, presenting a tree navigator of the entire structure of any Assemblies selected for the Help Project."
Really Cool!


Assignments
TOTAL : {{tasks|length}}
COMPLETED : {{ completedTasks }}
PENDING : {{ pendingTasks }}
There are no tasks. Create one above!
{% else %}| {{ task.assignment }} | {{ task.due_date.date() }} | {{ task.course }} |


File manager configuration information
Defines the number of times the file manager will attempt to reupload SDLArtwork
files in the event of a failed upload to Core.
Defaults to 1. To disable reuploads, set to 0.
@property (nonatomic) UInt8 artworkRetryCount;
var artworkRetryCount: UInt8 { get set }
Defines the number of times the file manager will attempt to reupload general SDLFile
s in the event of a failed upload to Core.
Defaults to 1. To disable reuploads, set to 0.
@property (nonatomic) UInt8 fileRetryCount;
var fileRetryCount: UInt8 { get set }
Creates a default file manager configuration.
+ (nonnull instancetype)defaultConfiguration;
class func `default`() -> Self
A default configuration that may be customized.
Use defaultConfiguration
instead
- (nonnull instancetype)init;
Creates a file manager configuration with customized upload retry counts.
- (nonnull instancetype)initWithArtworkRetryCount:(UInt8)artworkRetryCount
fileRetryCount:(UInt8)fileRetryCount;
init(artworkRetryCount: UInt8, fileRetryCount: UInt8)
The configuration


- Associate -
%for u in userlist: %if u[2] & (1 << USER_PERM_BIT['sales']):
${u[1]|h}
%endif %endfor
<% lk = 0 %> %for n in price_lvls:
${n|h}
<% lk += 1 %> %endfor
Find
Quit
#
ID
ALU
Desc
Qty
Price
ExtPrice
Disc
!009
!10000
!TEST
!test
!2
!ea
!0.99
!0.99
Remove
Disc
Hist
+
-
Subtotal:
Disc:
Total:
Save
Cancel
Clear
Hist
No Disc
5%
10%
15%
%
Discard?
Status:
Close
Open
Total:
UNPAID
PAID
Please Check
Discard and Quit?


Div, Span, Float, Merge, Class
Basically, this isn't about the movie. learning about floats just reminded me of this scene and I need some filler in the center to make sure everything is looking correct. This paragraph will probably have some spans thrown in as well to make sure I'm understanding the tag correctly. Basically every time I span or float they will have their own respective CSS class while the left, right, and center elements will be wrapped in their own div tags.


Cultural Blog Post
Gregorc Thinking Style
Perceptual Quality § Concrete: This quality enables you to register information directly through your five senses: sight, smell, touch, taste, and hearing. When you are using your concrete ability, you are dealing with the obvious, the "here and now." You are not looking for hidden meanings, or making relationships between ideas or concepts. "It is what it is." § Abstract: This quality allows you to visualize, to conceive ideas, to understand or believe that which you cannot actually see. When you are using your abstract quality, you are using your intuition, your imagination, and you are looking beyond “what is” to the more subtle implications. "It is not always what it seems." Although all people have both concrete and abstract perceptual abilities to some extent, each person is usually comfortable using one more than the other. The person whose natural strength in the concrete, for example, may communicate in a direct, literal, no-nonsense manner. The person whose natural strength is the abstract may use more subtle ways to get a point across.
Ordering Ability § Sequential: Allows your mind to organize information in a linear, step-by-step manner. When using your sequential ability, you are following a logical train of thought, a traditional approach to dealing with information. You may also prefer to have a plan and to follow it, rather than relying on impulse. § Random: Lets your mind organize information by chunks, and in no particular order. When you are using your random ability, you may often be able to skip steps in a procedure and still produce the desired result. You may even start in the middle, or at the end, and work backwards. You may also prefer your life to be more impulsive, or spur of the moment, than planned.
Fixed vs Growth mindset
In a fixed mindset, people believe their basic qualities, like their intelligence or talent, are simply fixed traits. They spend their time documenting their intelligence or talent instead of developing them. They also believe that talent alone creates success—without effort. They’re wrong.
In a growth mindset, people believe that their most basic abilities can be developed through dedication and hard work—brains and talent are just the starting point. This view creates a love of learning and a resilience that is essential for great accomplishment. Virtually all great people have had these qualities. Teaching a growth mindset creates motivation and productivity.


Thank you for your interest in the Zombie Research Labs, Inc. (ZRLI). We at the ZRLI take a keen interest in zombie defense tools and strive to bring the scientific method to a previously ad-hoc field.


Break
-
5
+
mins
Set time
-
25
+
mins
Start Timer
25
mins
Work>
:
00
Pomodoro Clock
Reset
Designed by HridayPratim


This is a collection of the different projects, proof-of-concepts, boilerplates, and skeletons I have either created or forked.
Go to my projectsI've been a developer for over 30 years. I've programmed in most technologies both on the front-end and the back-end. I specialize in .Net development, but I'm also skilled in Node.js, PHP, Python, and other platforms and languages.
My goal is to write a SaaS application that I can work on full-time.
Core Values!I believe a great user experience is key to a successful product. Learning new, modern development languages and techniques helps keep my products fresh and interactive.
A good user experience is only as good as the foundation it sits on. A strong, solid middle-tier and back-end platform are what adds value to the product.
Good communication is another pillar of a good developer. Being in the business for 30 years the most important thing I've learned is to establish a strong partnership with the customer.
I've been passionate about development since I wrote my first program. I take pride in delivering high quality products.
If you're looking for development work, collaboration, or just want to talk code email me!


Get started with your app
Follow these steps to try out your new app:
This app will forward incoming calls to another number during business hours (by default Monday to Friday 8:00-18:59 UTC) and will otherwise direct to a voicemail. The voicemail will record a message and send a link of the recording via SMS to the configured phone number.
- Call your Twilio phone number
- If the call occurs during the configured business hours, you should receive a forwarded call
- If it is outside the business hours, you'll get a voicemail recording. Leave a message!
- You should receive a text message with a link to the recorded voicemail
- Want to modify the business hours? Try editing the config
Troubleshooting
- Check the phone number configuration and make sure the Twilio phone number you want your app has a voice webhook configured to point at
/voicemail


Navigation
Single molecule plots
3D principal component analysis
Import of data
Anova
Factor associations
Multiple molecule plots
Factor chart
Single molecule plots
Missing values
Factor summary
Data set summary
3D principal component analysis
Filter molecules
P-value histogram
Sample normalization
2D principal component analysis
Data set table
Hierarchical clustering
Paired test plot
Edit factor
Pairwise test
Linear regression
3D principal component analysis
Logarithmic transformation
Result files


THREESOME A film review by Steve Rhodes Copyright 1995 Steve Rhodes
RATING (0 TO ****): * 1/2
THREESOME is one of those movies where you must be able to suspend disbelief from the start; otherwise, the movie has no chance of working. Here we have 2 men and a woman who are assigned to the same room in a coed dorm, but are unable to get reassigned. Sure. Actually, it was made plausible enough in the movie (it is actually a suite with a private single (woman), a private double (men), and a shared bath) that suspending disbelief turned out to be easy for me.
The premise of the movie is that person A is attracted to person B, B to C, and C to A whereas B is not attracted to A, nor C to B, and nor A to C. This simple equation gets much more complex as the movie advances. All along, they are all quite good friends and have great times together.
The show has several points to commend it. The plot is quite intriguing. The character of the woman (Lara Flynn Boyle best seen in RED ROCK WEST) is well written and well acted. It is easy to get swept up in some of the scenes and have vicarious fun along with them. Boyle's smile and physical emotions were well done and catching.
On the other hand, the guy's parts were poorly written, especially the handsome, dumb jock type character (Stephen Baldwin). Baldwin needs to take some acting classes rather than relying on getting roles because of his good looks and his famous brother. The other guy played by Josh Charles was mediocre. I did not believe either of the male characters.
With the same plot, but a much better script writer (Andrew Fleming), a recasting of all of the roles except for Boyle, tighter editing, and perhaps a different director (Andrew Fleming), this movie could have worked since it actually had a lot of possibilities. It was not a bad movie, but did not come close to what it could have been.
THREESOME runs only 1:33, but seems longer. It is rated R for the seriousness of its material I guess. I can not recommend it as constructed although it had good potential. For Boyle's acting and energy, I award it * 1/2.
**** = One of the top few films of this or any year. A must see film. *** = Excellent show. Look for it. ** = Average movie. Kind of enjoyable. * = Poor show.  Totally unbearable.
REVIEW WRITTEN ON: April 9, 1994
Opinions expressed are mine and not meant to reflect my employer's.
The review above was posted to the
rec.arts.movies.reviews newsgroup (de.rec.film.kritiken for German reviews).
The Internet Movie Database accepts no responsibility for the contents of the
review and has no editorial control. Unless stated otherwise, the copyright
belongs to the author.
Please direct comments/criticisms of the review to relevant newsgroups.
Broken URLs inthe reviews are the responsibility of the author.
The formatting of the review is likely to differ from the original due
to ASCII to HTML conversion.
Related links: index of all rec.arts.movies.reviews reviews


Great Forest [ap24], forest, in Mandoria, peasants: 177
Last updated Turn #144
Great Forest [ap24], forest, in Mandoria, peasants: 177
------------------------------------------------------------------------
30: The population grows by one peasant.
Routes leaving Great Forest:
North, forest, to Great Forest [ao24], 8 days
East, forest, to Great Forest [ap25], 8 days
Garrison [ht9y], garrison, uncontrolled, with two peasants
South, mountain, to Mandor Mountains [aq24], 10 days
West, mountain, to Mandor Mountains [ap23], 10 days
Garrison [es0b], garrison, uncontrolled, with ten workers
Seen here:
Garrison [ib8u], garrison, uncontrolled, with ten peasants


Mapping Utah Avalanches |
GIS Data from Utah GIS Portal- http://agrc.its.state.ut.us/ Connect to U.S. Avalanche Centers and get other Avalanche beta- http://www.avalanche.org/ National Snow and Ice Data Center- http://nsidc.org/snow/avalanche Friends of the Utah Avalanche Center- http://utahavalanchecenter.org/ The U.S. Forest Service National Avalanche Center- http://www.fsavalanche.org/ The American Institute for Avalanche Research and Education- http://avtraining.org/ |
|
Page Created by Patrick Gorman, Last Updated 05.08.14
|


Use the arrow keys to move and rotate the pieces along the board.
Right arrow key will move your puzzle piece to the right
Left arrow key will move your puzzle piece to the left
Down arrow key will move your puzzle piece down faster than the timer
Up arrow key will rotate your puzzle piece
Stack puzzle pieces.


LOST & FOUND A film review by Christie Tan Copyright 1997 Flying Inkpot
Directed by: Lee Chi-Ngai Written by: Lee Chi-Ngai Cast: Kelly Chan Wai-Lum (Chai Lam), Takeshi Kaneshiro (Mr. Worm) Michael Wong (Ted), Cheung Tat-Ming (Ming), Jordan Chan Siu-Chun (cameo), Josie Ho Chiu-Yee, Hilary Tsui Ho-Ying, Maria Codero, Moses Chan Ho, Henry Fong Ping, Ma Chun-Wai, Yim Lei-Ming Produced by : UFO / Golden Harvest Rating : *** Run Time: Approx. 120 Minutes
Watching LOST AND FOUND, I was struck by a sense of deja-vu. LOST AND FOUND feels like a Taiwanese tearjerker caught on the Chunking Express, only without the latter's edginess. This was partly because of the film's female protagonist, songbird Kelly Chen , who is a dead ringer for 70s soap queen Lin Chin Hsia. And the male lead, Aniki Jin, also acted in the latter film.
The opening paean establishes the subdued, melancholy, slightly dissipated tone of the film as the camera pans along the dirty streets and sad faces of the inhabitants to convey the desolation and alienation of modern life.
Predictably, but engagingly so, the film brightens up with the appearance of Cheng (Aniki Jin), who bursts upon the screen in a furore of energy, rummaging through the dustbin for lost wallets and giving directions on his handphone simultaneously. The loss of his handphone provides the opportunity for the two protagonists to meet. Kelly discovers that Cheng specializes in finding lost things, his motto being "nothing is lost forever." A note of existential angst creeps in when Kelly asks Cheng to help herfind her "hope."
Cheng then shows his perceptiveness when he asks Kelly whether hope is a thing or a person. In a series of flashbacks, we are shown Kelly's recent history from a first-person point of view. Kelly is the daughter of the second wife of a self-made shipping
magnate with twelve children. A new graduate from an overseas university, she is determined to prove herself not only in her father's firm, but to her father, with whom she has an uneasy love-hate relationship. Being equally unable to articulate their fee
lings, their stubborn nature drives them to set up an employment interview for Kelly at the family film. Shockingly, Kelly takes this public opportunity to break the news of her leukaemia to her father.
Running from her imminent death, and her dysfunctional father-daughter relationship, Kelly meets Ted, a sailor (Michael Wong) who comes from a barren rock in the North Sea off the coast of Scotland. It's a place the natives call "the End of the World," where everybody has left, and only returns to be buried. In her wretched state, Kelly responds to the doomed gloominess of the place, and, briefly, to Ted. When her treatment leaves her too depressed, she decides to give up hope and face death as romanticism. But Ted has disappeared.
The rest of the plot is predictably straightforward. She hires Cheng to find Ted for her, and succeeds after an odyssey through the labyrinth of the city. Ted is about to leave for his grandfather's funeral, but he invites Kelly to join him once his grandfather's ashes are ready to be taken home to the island.
Meanwhile, Kelly volunteers to help Cheng. Searching for things ranging from the most trivial to the most bizarre, Kelly is fuelled by Cheng's zest for life and upbeat optimism in the face of impossible odds. She realizes that Cheng is essentially a lonely man whose job is an excuse to reach out to people by helping them. In between searching for wild ducks, and accepting the sobering proximity of death, Kelly falls for Cheng. However, she decides to leave him in order to spare him the heartbreak of eventually losing her to the illness, and leaves for Scotland. Will Kelly find true love? Will they find each other again? Unfortunately for my patience, the forgone conclusion was dragged out by Kelly's Scottish sojurn.
The leitmotif behind the film is the constant search for identity. in a metaphorical vein, Cheng's attempts to define Kelly turn out to be wrong because only she can decide who she is. Cheng is insistent upon the correct term of address, that his name is "The Worm," not "Mr Worm" or "Mr The." Later, in Scotland, we see that Ted's venture into traditional highland dress is totally commercial, a tourist side-show. Unfortunately the development of this motif isn't consistent. The ending, where Kelly is identified through her place in the family she has left, seems to be a compromise. Instead of an individual decision, social, monetary and familial constraints have together bound her to an identity she is only able to escape by virtue of her death.
I enjoyed the film's obligatory singing scene, though it was rather sentimental. Both Kelly's and Aniki's singing skills were adequately showcased, and the mood was joyously retro, especially the dancing scene -- hence very modern. The soundtrack, on the whole, was engaging, especially the traditional "Griogal Cridhe" in the Scottish scenes. At some parts, however, I was uncomfortably reminded of SIA and British Airways advertisements, and I felt that the film was unrealistic for not only glorifying foreign lands but also in the saving grace of humnan relationships.
In the end, LOST AND FOUND didn't make me cry, but some time during the screening, I found myself a little more hopeful about relationships again.
The Flying Inkpot Rating System:
* Wait for the TV2 broadcast.
** A little creaky, but still better than staying at home with Gotcha!
*** Pretty good, bring a friend.
**** Amazing, potent stuff.
***** Perfection. See it twice.
_____________________________________________________
This movie review was written for THE FLYING INKPOT: an arts and
entertainment magazine from Singapore. For reviews of the latest films,
concerts, album releases, books and plays in Singapore, swing by
http://webvisions.com/inkpot
The review above was posted to the
rec.arts.movies.reviews newsgroup (de.rec.film.kritiken for German reviews).
The Internet Movie Database accepts no responsibility for the contents of the
review and has no editorial control. Unless stated otherwise, the copyright
belongs to the author.
Please direct comments/criticisms of the review to relevant newsgroups.
Broken URLs inthe reviews are the responsibility of the author.
The formatting of the review is likely to differ from the original due
to ASCII to HTML conversion.
Related links: index of all rec.arts.movies.reviews reviews


Education is the most powerful weapon which you can use to change the world.- Nelson Mandela
If you are losing your leisure, look out!-- It may be you are losing your soul.- Virginia Woolf
If you aren't making difference in other people's lives, you shouldn't be in business- it's that simple.- Richard Branson
There is a difference between being 'literate' and being 'educated'. Literacy is knowing how to read and write. Education is to be able to reason, to use your ability to read and write to your benefit and to be able to gain your spectrum of knowledge by trying to surge deeper into the literate knowledge imparted to you.
We are open in following domains and adding more continuously.
CRENNOVA™ Coaching Classes (Std. 1- Std. 12)
CRENNOVA™ Computer Classes
CRENNOVA™ Spoken English Classes
Interested in joining us as a Teacher? Click here.
Interested in getting educated from us? Click here.
There is simply no reason not to have a few.
Join us for 'Cricket, Singing, Dance, Guitar, Flute, Drawing, Karate' and many more on the way...
Interested in joining us as a Teacher? Click here.
Interested in learning hobbies from us? Click here.
Small businesses are vital to the success of the economy. Not only as they provide the success stories of the future, but also because they meet local needs. They serve the requirements of larger businesses.
Currently in planning stage for implementation of our projects.
"Every child is an artist, the problem is staying an artist when you grow up."-Pablo Picasso
Creativity is one of the greatest qualities
any of us can be blessed with , yet
many never allow their true
creativity to be
expressed.
"Innovation distinguishes between a leader and a follower."-Steve Jobs
Innovation is the process of creating something new. Innovation makes our lives easier,
enhances our productivity, improves
our health, entertains us, and
broadens our ability to
communicate and
connect on a
global scale
CREativity + iNNOVAtion.
Crennova™ aims at making people self-reliant by providing them the necessary education,
guidance and platforms to find and
pursue their true interests in
the form of career
opportunities.
If you are craving to fly, we'll give you wings to go high!


Lilith:
A present...? What is this...!
Did you really think that I would be pleased with such a thing? Could you have possibly thought that I would forget my 1,000 years of pain for the gift of a simple ornament?
That's the way of the Dwarf, isn't it? You people know of nothing but worldly goods. Go away!
Beg her to give the Mark of Health


| Not Confident | A little Confident | Somewhat Confident | Mostly Confident | Super Confident | I don't know |
|---|---|---|---|---|---|
| Not Confident | A little Confident | Somewhat Confident | Mostly Confident | Super Confident | I don't know |
|---|---|---|---|---|---|
| Not Confident | A little Confident | Somewhat Confident | Mostly Confident | Super Confident | I don't know |
|---|---|---|---|---|---|
| Not Confident | A little Confident | Somewhat Confident | Mostly Confident | Super Confident | I don't know |
|---|---|---|---|---|---|
| Not Confident | A little Confident | Somewhat Confident | Mostly Confident | Super Confident | I don't know |
|---|---|---|---|---|---|


{% extends "base.html" %} {% load frontend_extras %} {% load staticfiles %} {% block content %}
This recipe contains no mashing program. It will not be synced to your PicoBrew machine.


This project implements the Swagger REST API definitions for the OpenCMIS specifications. The models defined in types are used as properties and generate a dynamic swagger definition to consume it over HTTP REST. The below APIs are exposed for every type,
-
GET (/getAll) - Retrieve one or many objects.
-
POST - Insert a new `cmis:folder` or `cmis:document` or `cmis:item`
-
PUT - Update an existing object based on ObjectID.
-
DEL - Delete an existing object based on ObjectID.
This gives us very easy consumption in client applications using simple HTTP APIs.


Recipe 1.24. Making Some Strings Case-Insensitive
Credit: Dale Strickland-Clark, Peter Cogolo, Mark
McMahon
Problem
You want to treat some strings so that all comparisons and lookups
are case-insensitive, while all other uses of the strings preserve
the original case.
Solution
The best solution is to wrap the specific strings in question into a
suitable subclass of str:
class iStr(str):
"""
Case insensitive string class.
Behaves just like str, except that all comparisons and lookups
are case insensitive.
"""
def _ _init_ _(self, *args):
self._lowered = str.lower(self)
def _ _repr_ _(self):
return '%s(%s)' % (type(self)._ _name_ _, str._ _repr_ _(self))
def _ _hash_ _(self):
return hash(self._lowered)
def lower(self):
return self._lowered
def _make_case_insensitive(name):
''' wrap one method of str into an iStr one, case-insensitive '''
str_meth = getattr(str, name)
def x(self, other, *args):
''' try lowercasing 'other', which is typically a string, but
be prepared to use it as-is if lowering gives problems,
since strings CAN be correctly compared with non-strings.
'''
try: other = other.lower( )
except (TypeError, AttributeError, ValueError): pass
return str_meth(self._lowered, other, *args)
# in Python 2.4, only, add the statement: x.func_name = name
setattr(iStr, name, x)
# apply the _make_case_insensitive function to specified methods
for name in 'eq lt le gt gt ne cmp contains'.split( ):
_make_case_insensitive('_ _%s_ _' % name)
for name in 'count endswith find index rfind rindex startswith'.split( ):
_make_case_insensitive(name)
# note that we don't modify methods 'replace', 'split', 'strip', ...
# of course, you can add modifications to them, too, if you prefer that.
del _make_case_insensitive # remove helper function, not needed any more
Discussion
Some implementation choices in class
iStr are worthy of notice. First, we choose to
generate the lowercase version once and for all, in method _
_init_ _, since we envision that in typical uses of
iStr instances, this version will be required
repeatedly. We hold that version in an attribute that is private, but
not overly so (i.e., has a name that begins with one underscore, not
two), because if iStr gets subclassed (e.g., to make
a more extensive version that also offers case-insensitive splitting,
replacing, etc., as the comment in the
"Solution" suggests),
iStr's subclasses are quite likely
to want to access this crucial "implementation
detail" of superclass iStr!
We do not offer "case-insensitive"
versions of such methods as replace, because
it's anything but clear what kind of input-output
relation we might want to establish in the general case.
Application-specific subclasses may therefore be the way to provide
this functionality in ways appropriate to a given application. For
example, since the replace method is not wrapped,
calling replace on an instance of
iStr returns an instance of str,
not of iStr. If that is a
problem in your application, you may want to wrap all
iStr methods that return strings, simply to ensure
that the results are made into instances of iStr.
For that purpose, you need another, separate helper function, similar
but not identical to the _make_case_insensitive one
shown in the
"Solution":
def _make_return_iStr(name):
str_meth = getattr(str, name)
def x(*args):
return iStr(str_meth(*args))
setattr(iStr, name, x)
and you need to call this helper function
_make_return_iStr on all the names of relevant
string methods returning strings such as:
for name in 'center ljust rjust strip lstrip rstrip'.split( ):
_make_return_iStr(name)
Strings have about 20 methods (including special methods such as
_ _add_ _ and _ _mul_ _) that
you should consider wrapping in this way. You can also wrap in this
way some additional methods, such as split and
join, which may require special handling, and
others, such as encode and
decode, that you cannot deal with unless you also
define a case-insensitive unicode subtype. In
practice, one can hope that not every single one of these methods
will prove problematic in a typical application. However, as you can
see, the very functional richness of Python strings makes it a bit of
work to customize string subtypes fully, in a general way without
depending on the needs of a specific application.
The implementation of iStr is careful to avoid the
boilerplate code (meaning repetitious and therefore bug-prone code)
that we'd need if we just overrode each needed
method of str in the normal way, with
def statements in the class body. A custom
metaclass or other such advanced technique would offer no special
advantage in this case, so the boilerplate avoidance is simply
obtained with one helper function that generates and installs wrapper
closures, and two loops using that function, one for normal methods
and one for special ones. The loops need to be placed
after the class statement, as
we do in this recipe's Solution, because they need
to modify the class object iStr, and the class
object doesn't exist yet (and thus cannot be
modified) until the class statement has completed.
In Python 2.4, you can reassign the func_name
attribute of a function object, and in this case, you should do so to
get clearer and more readable results when introspection (e.g., the
help function in an interactive interpreter
session) is applied to an iStr instance. However,
Python 2.3 considers attribute func_name of
function objects to be read-only; therefore, in this
recipe's Solution, we have indicated this
possibility only in a comment, to avoid losing Python 2.3
compatibility over such a minor issue.
Case-insensitive (but case-preserving) strings have many uses, from
more tolerant parsing of user input, to filename matching on
filesystems that share this characteristic, such as all of Windows
filesystems and the Macintosh default filesystem. You might easily
find yourself creating a variety of
"case-insensitive" container types,
such as dictionaries, lists, sets, and so onmeaning containers
that go out of their way to treat string-valued keys or items as if
they were case-insensitive. Clearly a better architecture is to
factor out the functionality of
"case-insensitive" comparisons and
lookups once and for all; with this recipe in your toolbox, you can
just add the required wrapping of strings into iStr
instances wherever you may need it, including those times when
you're making case-insensitive container types.
For example, a list whose items are basically strings, but are to be
treated case-insensitively (for sorting purposes and in such methods
as count and index), is
reasonably easy to build on top of iStr:
class iList(list):
def _ _init_ _(self, *args):
list._ _init_ _(self, *args)
# rely on _ _setitem_ _ to wrap each item into iStr...
self[:] = self
wrap_each_item = iStr
def _ _setitem_ _(self, i, v):
if isinstance(i, slice): v = map(self.wrap_each_item, v)
else: v = self.wrap_each_item(v)
list._ _setitem_ _(self, i, v)
def append(self, item):
list.append(self, self.wrap_each_item(item))
def extend(self, seq):
list.extend(self, map(self.wrap_each_item, seq))
Essentially, all we're doing is ensuring that every
item that gets into an instance of iList gets
wrapped by a call to iStr, and everything else takes
care of itself.
Incidentally, this example class iList is accurately
coded so that you can easily make customized subclasses of
iList to accommodate application-specific subclasses
of iStr: all such a customized subclass of
iList needs to do is override the single class-level
member named wrap_each_item.
See Also
Library Reference and Python in a
Nutshell sections on str, string
methods, and special methods used in comparisons and hashing.
|


BARTLEBY A film review by Christopher Null Copyright 2001 filmcritic.com filmcritic.com
Destined to inspire new lows in workplace slackerdom, Jonathan Parker's Bartleby is a cryptic take on workplace politics and motivation, courtesy of Herman Melville's short story, "Bartleby the Scrivener."
Given a weirdly futuristic spin, Jonathan Parker's interpretation of Bartleby takes him out of a law office and into a public records commission, subtly morphing from typist to file clerk. More notably than all that is Parker's balls-out casting, with the certifiably unhinged Crispin Glover taking the role of the lowest-of-low-key peons.
Unfortunately, the bulk of innovation within Bartleby is found within Glover's casting, and it doesn't spill over to the rest of the movie. >From its nauseating spinning credits sequence to a very talented but underutilized supporting cast, Bartleby squanders as much as it gives out.
The one-joke premise is a simple one. Bartleby, the only applicant who responds to David Paymer's help wanted ad, begins his filing job with diligence, but soon inexplicably turns into an unmotivated drone, staring at the a/c vent and responding to requests that he do the tasks he was hired to do only with the phrase: "I would prefer not to."
This naturally perturbs both the boss and Bartleby's co-workers (including Maury Chaykin, Glenne Headly, and Joe Piscopo!), to the point where Paymer's character is forced to fire Bartleby. And yet the man still won't leave!
Things get weirder and weirder in the fashion of Brazil or The Metamorphosis, until, well, until things just stop making sense. Much of Bartleby is lacking in the appropriate context, with random oddities (notably vignettes featuring Piscopo and Chaykin) peppering the production (for obvious padding time) but never going anywhere. Despite its 83 minute running time, the film quickly becomes tedious, Bartleby's mantra degenerating into a monotonous whine instead of the working-class battle cry it ought to be.
That said, Bartleby has its moments, and it's those aforementioned disjointed bits that are ironically the movie's most memorable. The story of Bartleby himself, I fear, is one that will soon be forgotten.
Screened at the movie's world premiere at the 2001 SXSW film festival.

Visit filmcritic.com on the Web at http://www.filmcritic.com
The review above was posted to the
rec.arts.movies.reviews newsgroup (de.rec.film.kritiken for German reviews).
The Internet Movie Database accepts no responsibility for the contents of the
review and has no editorial control. Unless stated otherwise, the copyright
belongs to the author.
Please direct comments/criticisms of the review to relevant newsgroups.
Broken URLs inthe reviews are the responsibility of the author.
The formatting of the review is likely to differ from the original due
to ASCII to HTML conversion.
Related links: index of all rec.arts.movies.reviews reviews


An Ordinary Day was created by Audrey Kintisch, Garcia Lu, Krystal Kim, and Ethan Foster for MIT's 2016 Hackathon, and has been continued by Audrey Kintisch.
How to Play
You are walking along a path. At every intersection, you must decide whether you will follow in others' footsteps or venture off of the trail.
In order to trailblaze, however, you must first have an idea of where you are going.
You must determine the location of the next intersection, any items found or used, and what happens along the trail.
Once you have created a path, it will be available as an action for others to take.
If they so chose, they can create paths that branch off of yours, as you can do theirs'.
Please be respectful of the trails: don't target others, curse, reveal personal information, or spam.


Engineered with simplicity and efficency to maximize accessibility for everyone.
Designed by: Angelo Sarno WebDesigner | Univents - 2020 | All Rights Reserved.


You should see three svg logo images with green fill above here.
If any of the logos are shown in orange that means the browser failed to access the DOM of the referenced svg resource.
From left to right we have <object>, <embed> and <iframe> that all reference the same svg file.
The script gets the referenced svg document either with contentDocument
or getSVGDocument()
and then sets the fill color
to lime green.
View source to see how this works.


Hi, Watch out for those tables in the east. We're going to go ahead and need you to come in on Saturday... Cheers, Bill Lumbergh
Airflow & Tableau Demo Dashboard


This website is for sharing hope, knowledge and action.
We're here to make a change. As we've said, we're here to share hope, knowledge and action. We want to make people more comfortable whether they be the patient, the carer or the relative. Pancreatic Cancer doesn't get as much as attention as what we would call 'The Big 4' and we want to change that but we can only do that with your help and your donations.
You're Not Alone. We provide information for all involved, including carers, relatives and the patients themselves.
As you can see from the graph, in 2013 773 people were diagnosed with Pancreatic Cancer in Scotland alone. Together we can do more to raise awareness for these people, their families and their friends.
To see more graphs like these, please follow this link.


Seized placenta to be used in South Dakota rape case
by The Associated PressRAPID CITY, S.D. — A placenta sample taken from an abortion clinic without a warrant will be used as evidence in a statutory rape trial in South Dakota.
The Rapid City Journal reports the South Dakota Supreme Court said last month that it would not hear the case, clearing the way for the evidence to be used.
A Rapid City girl mentioned while getting an abortion in Denver in 2018 that she was 15 when she became pregnant by her 25-year-old boyfriend. The clinic told Denver police, who turned over a placenta sample to a Rapid City detective.
DNA testing showed that the boyfriend, Nathan Hankins, couldn’t be excluded as the father. He was charged in September with fourth-degree rape.
Hankins has pleaded not guilty and is scheduled for trial on Jan. 28.
The Associated Press


{% extends "layout.html" %} {% block body %}
Family annotated: {{ family_annotated }} of {{ total }}
Genus annotated: {{ genus_annotated }} of {{ total }}
Species annotated: {{ species_annotated }} of {{ total }}
Marked as junk: {{ total_junk }} of {{ total }}
{% endblock %}


{% extends "internal_base.html" %} {% block page_content %}
Year 404 (CDIV) was a leap year starting on Friday (link will display the full calendar) of the Julian calendar. At the time, it was known as the Year of the Consulship of Honorius and Aristaenetus (or, less frequently, year 1157 Ab urbe condita). The denomination 404 for this year has been used since the early medieval period, when the Anno Domini calendar era became the prevalent method in Europe for naming years.
(Source: https://en.wikipedia.org/wiki/404, 2015-07-19) {% endblock %}


iOS Development
Shayes Apps has been developing iOS apps since 2010 and knows what it takes to create great iOS experiences. We have a wide range of capabilities and can work with you to create the iPhone/iPad app of your dreams! Email us today to get started!
Skills
- Over a decade of iOS experience
- Extensive knowledge of the iOS SDK
- Objective-C and Swift
- Storyboards and Autolayout
- XML, JSON, and Web Services
- Core Data and Realm
- WatchOS + Complications
- Widgets
- iCloud & CloudKit
- In-App Purchases
- Git and SVN
- Localization
- Dynamic Type/Accessibility
- Unit & UI Testing
- Local & Push Notifications
- Custom Animations
- CocoaPods, Carthage, & Swift Package Manager
Contact Us
Want to hire Shayes Apps? Or just want to chat? Shoot us an email!
Email Us


Installed Command-T successfully, but seg faults when accessing \t
-
Jonathan Hart
I have vim +ruby installed, built with Ruby 2.0, and ran "rake make" that was also built with 2.0.
I can load vim successfully, but once I try to access it via "\t" it crashes:
Vim: Caught deadly signal SEGV Vim: Finished. Segmentation fault: 11
Any ideas?
-
Greg Hurrell
It's almost certainly miscompiled. For an example of a recent bug report like this, see here; that one turned out to be some old files left around from a previous install.
I suggest having a look through that thread carefully for an example trouble-shooting process, and also reading the trouble-shooting sections in the docs. This comment is a good starting point for collecting more information.
Reply
This topic is now closed.


Fabolous Announces 'Summertime Shoutout 3: The Coldest Summer Ever' Release Date
by Trent ClarkIt appears fans won’t have to wait until next year for Fabolous’ next project.
After teasing the masses with the single “B.O.M.B.S.” and “Choosy,” a tropical single featuring Jeremih and Davido, Loso has officially unveiled the release date for Summertime Shoutout 3: The Coldest Summer Ever to coincide with Black Friday 2019.
The news of the upcoming mixtape also coincides with the Brooklyn rap star’s 42nd birthday.
Summertime Shoutout 3: The Coldest Summer Ever marks Fab’s first major release since Friday On Elm Street, his 2017-closing, star-studded collaborative album with Jadakiss.
The project drops on November 29. Watcht the trailer down below.
[This post has been updated. The following was originally published on November 15, 2019.]
Back when Michael Jordan and the Chicago Bulls were dominating the NBA throughout the 1990s, the six-time championship team used to drive fear into visiting opponent’s hearts when they entered the United Center as an ominous sample of The Alan Parsons Project’s “Sirius” blared through the sound system.
Brooklyn’s own Fabolous is attempting to bring that feeling back with his new single, “B.O.M.B.S,” an acryonm for “back on my bullshit” and what he says is the first taste for his upcoming mixtape, Summertime Shoutout 3.
“I’m that bull in the hood/New Lamb truck, got the bull in the hood/Black and red lookin’ like the Bulls at the hood
23’s on it, got the Bulls sitting good,” he quips.
According to the song’s outro, the aforementioned project will be released in 2020 when it gets warm.
Stream Fabolous’ “B.O.M.B.S” above.


BasicLSTMCell
DEPRECATED: Please use tf.compat.v1.nn.rnn_cell.LSTMCell
instead.
Basic LSTM recurrent network cell.
The implementation is based on: http://arxiv.org/abs/1409.2329.
We add forget_bias (default: 1) to the biases of the forget gate in order to reduce the scale of forgetting in the beginning of the training.
It does not allow cell clipping, a projection layer, and does not use peep-hole connections: it is the basic baseline.
For advanced models, please use the full tf.compat.v1.nn.rnn_cell.LSTMCell
that follows.
Note that this cell is not optimized for performance. Please use
tf.contrib.cudnn_rnn.CudnnLSTM
for better performance on GPU, or
tf.contrib.rnn.LSTMBlockCell
and tf.contrib.rnn.LSTMBlockFusedCell
for
better performance on CPU.
__init__
__init__( num_units, forget_bias=1.0, state_is_tuple=True, activation=None, reuse=None, name=None, dtype=None, **kwargs )
Initialize the basic LSTM cell. (deprecated)
Warning: THIS FUNCTION IS DEPRECATED. It will be removed in a future version. Instructions for updating: This class is equivalent as tf.keras.layers.LSTMCell, and will be replaced by that in Tensorflow 2.0.
num_units
: int, The number of units in the LSTM cell.forget_bias
: float, The bias added to forget gates (see above). Must set
to 0.0
manually when restoring from CudnnLSTM-trained checkpoints.state_is_tuple
: If True, accepted and returned states are 2-tuples of the
c_state
and m_state
. If False, they are concatenated along the
column axis. The latter behavior will soon be deprecated.activation
: Activation function of the inner states. Default: tanh
. It
could also be string that is within Keras activation function names.reuse
: (optional) Python boolean describing whether to reuse variables in
an existing scope. If not True
, and the existing scope already has
the given variables, an error is raised.name
: String, the name of the layer. Layers with the same name will share
weights, but to avoid mistakes we require reuse=True in such cases.dtype
: Default dtype of the layer (default of None
means use the type of
the first input). Required when build
is called before call
.**kwargs
: Dict, keyword named properties for common layer attributes, like
trainable
etc when constructing the cell from configs of get_config().
When restoring from CudnnLSTM-trained checkpoints, must use
CudnnCompatibleLSTMCell
instead.graph
DEPRECATED FUNCTION
Warning: THIS FUNCTION IS DEPRECATED. It will be removed in a future version. Instructions for updating: Stop using this property because tf.layers layers no longer track their graph.
output_size
Integer or TensorShape: size of outputs produced by this cell.
scope_name
state_size
size(s) of state(s) used by this cell.
It can be represented by an Integer, a TensorShape or a tuple of Integers or TensorShapes.
get_initial_state
get_initial_state( inputs=None, batch_size=None, dtype=None )
zero_state
zero_state( batch_size, dtype )
Return zero-filled state tensor(s).
batch_size
: int, float, or unit Tensor representing the batch size.dtype
: the data type to use for the state.If state_size
is an int or TensorShape, then the return value is a
N-D
tensor of shape [batch_size, state_size]
filled with zeros.
If state_size
is a nested list or tuple, then the return value is
a nested list or tuple (of the same structure) of 2-D
tensors with
the shapes [batch_size, s]
for each s in state_size
.


---
layout: single
title: "Georeferencing images like a caveman"
date: 2021-03-17
categories: projects
gallery:
- url: tallinn-historical-maps/
image_path: /assets/images/old_map.png
alt: "image 1"
title: "Old map"
---
The map
Github
I've been intrigued by local history and urban development for as long as I can remember. A natural exercise for those who share this interest is georeferencing - overlaying a raster image (such as an old map) on a modern digital map.
I found it frustrating that all the guides for doing this referred to which buttons to press on proprietary software such as ArcGIS or Google Earth. After all, isn't it basically just about mapping from one two-dimensional coordinate system to another one, using some data points? I set out to do this from scratch.
First, I downloaded a 1910 historical map from Rahvusarhiiv and it is actually the first map of Tallinn printed in the Estonian language.
Using tkinter and opencv, I triggered a simple dialogue box on clicking the raster map, that asks for the latitude and longitude of the point. I looked up the coordinates from Google Maps, and appended each added point to a .csv file. This generates the reference points necessary to learn the mapping between the pixels of the raster image and their real life locations.
Finding reference points is a fun exercise on its own - essentially you are trying to find bits and pieces of the city that have remained unchanged for 100+ years. It wasn't too hard for the high definition 1910 map, but proved to be quite tough for a hand drawn map from 1764! For example, the Russalka Memorial in Tallinn was erected in 1902, so it exists on both the 1910 map and today. In a similar manner, old monuments, lighthouses, railway intersections and natural boundaries are your best bet for good reference points.
After collecting the reference points, the next step is to map them. Here comes the caveman part: I simply used two univariate linear regressions on latitude and longitude separately, trying to predict the in-sample coordinates of the references. This worked surprisingly well! The first sign of this is the high R2 coefficient (above 95%) - meaning the simple line drawn through the points captures their variance well.
To actually overlay the raster image correctly on the map, I simply predicted the bounding box of the map, using its four corners as the model input. This implies you'd want to gather enough reference points around the edge of the map (especially with more complex non-linear regressors) for it to fit nicely. I was surprised how well the end result turned up - even though I hadn't spent any time thinking about map projections, rotation etc. It provided for a smooth viewing experience where toggling between the layers leaves the location more or less intact.
It should be noted that this simple methodology did not work on older maps, probably as combination of it being overly simplistic and the poor quality of maps (at least for Estonia) before the turn of the 20th century.


App Builder
Lightning fast app development
A powerful, locally-installed visual development environment that makes it easy to build stunning apps in minutes.
Ionic’s enterprise app development platform gives you everything you need to build award-winning apps at incredible scale, faster than ever.
A powerful, locally-installed visual development environment that makes it easy to build stunning apps in minutes.
Build high-performance, native mobile and desktop apps for iOS, Android, Windows, PWAs, and more - all from a single codebase.
Build with intuitive UI components that accelerate app development, and can be deployed virtually anywhere.
Automate every phase of app delivery - from native app builds to realtime updates - all from a central hub with secure access for the whole team.
From community plugins to premium supported integrations, Ionic has you covered. Unlock unmatched native power, speed, and core functionality across all your apps.
Tackle your biggest challenges with tailored solutions and expert services for every phase of the app lifecycle.