diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..efef32d --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# IPython Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# docker +.docker_cid +Dockerfile diff --git a/Dockerfile.sample b/Dockerfile.sample new file mode 100644 index 0000000..6b06ccd --- /dev/null +++ b/Dockerfile.sample @@ -0,0 +1,36 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y zsh \ + vim \ + tmux \ + python3-numpy \ + python3-scipy \ + python3-matplotlib \ + ipython3 \ + python3-pillow \ + python3-pip + +RUN pip3 install jupyter scikit-image ipykernel + +# Use the same gid and uid as your user on the host system. You can find them +# out with the id programm. This way the file ownership in mapped directories is +# consistent with the host system. +RUN echo "%sudo ALL=(ALL) ALL" >> /etc/sudoers +RUN groupadd --gid 1000 user +RUN useradd --uid 1000 --gid user \ + --home-dir /home/user --shell /usr/bin/bash \ + --groups sudo,user \ + --password password \ + user + + +# set default passwords +RUN echo user:password | chpasswd && \ + echo root:password | chpasswd + +RUN mkdir -p /home/user && chown -R user:user /home/user + +USER user +WORKDIR /home/user' + +CMD ["sh", "-c", "jupyter notebook --ip 0.0.0.0"] diff --git a/README.md b/README.md index b8a4efd..4456688 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,81 @@ -# Hausaufgaben -Hausaufgaben und Musterlösungen für den Kurs Bildverarbeitung im SS 2018 +# FU Berlin - Image Processing SS 18 + +The assignments will be published to this repository. +All assignments will be IPython Notebooks. That you have to complete. + +## Work flow + +The rough workflow is: +1. You clone this repository. +2. Edit the exercises. +3. Push it to your private repository. +4. I fetch your code when the assignment is due. (Every Wednesday at 8:00 a.m.) +5. You fetch the latest assignments from this repository. + +It is required to use private git repositories. +The university offers free private repositories [here](https://git.imp.fu-berlin.de/) +or you can get [5 GitHub repositories for free](https://education.github.com/) as a student. + +First clone this repository: + +``` +$ git clone --origin upstream https://github.com/BildverarbeitungSS18/Hausaufgaben +``` + +Get into the new folder + +``` +$ cd Hausaufgaben +``` + +Add your remote + +``` +$ git remote add origin +``` + +Please clear the notebook's output before committing. Otherwise the repository +size can get pretty big. +The best thing is to setup a `pre-commit` hook that removes the outputs before +the files are committed: + +``` +$ ln -s ../../nb_strip_output.py .git/hooks/pre-commit +``` + +Otherwise you manually clean the output with `Cell -> All Output -> Clear` or +use the `nb_strip_output.py ` script. + +To get the latest assignments into your repository see [how to sync a fork](https://help.github.com/articles/syncing-a-fork/). + +Paste a link to your repository into the kvv assignment box. +Make sure that I have read and write rights on your repository. + +## Docker + +There exists a script for a [docker](https://www.docker.com/) image. +All the libraries we will use are included in this image. +It is recommended to use the image, but you are free to setup the environment +for yourself. + +First [install docker](https://docs.docker.com/engine/installation/) on your computer. + +Build the image: + +``` +$ ./docker_build.sh +``` +The build script will create a user with your username and uid inside the image. +It may take some minutes until the image is built. + +If you don't have a bash you can manually edit the `Dockerfile.sample`. +See the docker documentation for [details](https://docs.docker.com/) + +To run the image: + +``` +$ ./docker_start.sh +``` + +Now visit [localhost:8888](http://localhost:8888). Jupyter Notebook +should be ready to use. diff --git a/assignments/01_assignment.ipynb b/assignments/01_assignment.ipynb new file mode 100644 index 0000000..5e4def8 --- /dev/null +++ b/assignments/01_assignment.ipynb @@ -0,0 +1,273 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Image Processing SS 18 - Assignment - 01\n", + "\n", + "### Deadline is 25.4.2018 at 8:00\n", + "\n", + "Please solve the assignments together with a partner.\n", + "I will run every notebook. Make sure the code runs through, when clicked on `Kernel` -> `Restart & Run All`.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Introduction to Python / Numpy\n", + "\n", + "* [Learn Python in 15 minutes](https://learnxinyminutes.com/docs/python3/): We will use Python 3.\n", + "* [Numpy for Matlab Users](https://docs.scipy.org/doc/numpy-dev/user/numpy-for-matlab-users.html#general-purpose-equivalents)\n", + "* [Numpy Quickstart](https://docs.scipy.org/doc/numpy-dev/user/quickstart.html)\n", + "\n", + "## Libraries\n", + "\n", + "We will use the following libraries:\n", + "\n", + "* matplotlib\n", + "* numpy\n", + "* scipy\n", + "* skimage\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exercise 0 - Setup Development Enviroment - [1 Point]\n", + "\n", + "Find a partner, follow the steps in the [README](https://github.com/BildverarbeitungSS18/Hausaufgaben/blob/master/README.md) and paste a link to your repository, names and matriculation numbers into the KVV assignment box.\n", + "You do not need to upload any files to the KVV. I will clone your repository. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# display the plots inside the notebook\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import pylab\n", + "pylab.rcParams['figure.figsize'] = (12, 12) # This makes the plot bigger" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The [skimage](http://scikit-image.org/) library comes with multiple useful test images. Let's start with an image of an astronaut. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from skimage.data import astronaut" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "img = astronaut() # Get the image\n", + "print(img.shape) # the dimension of the image\n", + "print(img.dtype) # the image type" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We have a `(512, 512, 3)` array of unsigned bytes. At `img[x, y]` there are three values for R,G and B." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will always work with floating point arrays between 0 and 1. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "img = img / 255." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Lets display the image." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plt.imshow(img)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This is [Eileen Collins](https://en.wikipedia.org/wiki/Eileen_Collins). She was the first astronaut \n", + " to fly the Space Shuttle through a complete 360-degree pitch maneuver. What an inspiring woman." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 1 - Plot - [1 Point]\n", + "\n", + "Plot the R, G and B channels separately." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Your code here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 2 - RGB to HSV [6 Points]\n", + "\n", + "Implement the `rgb_to_hsv` and `hsv_to_rgb` functions. Don't use any color conversion functions from a library.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def rgb_to_hsv(x):\n", + " \"\"\"\n", + " Converts the numpy array `x` from RGB to the HSV. \n", + " \"\"\"\n", + " # Your code here\n", + " return x" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def hsv_to_rgb(x):\n", + " \"\"\"\n", + " Converts the numpy array `x` from HSV to the RGB. \n", + " \"\"\"\n", + " # Your code here\n", + " return x" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Plot the saturation of the astronaut image" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "img_as_hsv = rgb_to_hsv(img)\n", + "# your code" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Increase the saturation by a factor of 2, convert it back to RGB and plot the result." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# your code" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise 3 - Callculation [2 Points]\n", + "\n", + "In the figure below you can see the [CIE-XYZ](https://de.wikipedia.org/wiki/CIE-Normvalenzsystem) color space.\n", + "![](https://upload.wikimedia.org/wikipedia/commons/4/49/CIE-Normfarbtafel.png)\n", + "\n", + "What are the approximate x,y,z values for the following Adobe RGB colors:\n", + "* `(0, 0.5, 0.5)`\n", + "* `(0.33, 0.33, 0.33)`\n", + "\n", + "A sodium-vapor lamp shines with double the intensity of a mercury-vapor lamp\n", + ". The light from the sodium lamp only contains \n", + "the spectral line at `589,00nm` and the light from the mercury lamp only the\n", + "spectral line at `435,83 nm`.\n", + "\n", + "What color does a human experience? What are the approximate x,y,z values? \n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.5" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/docker_build.sh b/docker_build.sh new file mode 100644 index 0000000..1d5d0e1 --- /dev/null +++ b/docker_build.sh @@ -0,0 +1,83 @@ +#! /usr/bin/env bash + + +if [ "$1" == "-h" ] || [ "$1" == "--help" ]; then + echo "Usage: docker_build.sh" + echo "Builds a docker image with a user that matches the username and uid of the host user." +fi + +uid=$(id -u) +username=$(whoami) +password='password' # dummy password +out="Dockerfile" + +if [ "$1" == "sample" ]; then + out="Dockerfile.sample" + uid="1000" + username="user" +fi + +echo "Using username: $username with uid: $uid" +echo "The default password is: $password" + +cat << EOF > $out +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y zsh \\ + vim \\ + tmux \\ + git \\ + python3-numpy \\ + python3-scipy \\ + python3-matplotlib \\ + ipython3 \\ + python3-pip \\ + python-pillow \\ + python-pip \\ + python-numpy \\ + python-scipy \\ + python-matplotlib \\ + ipython \\ + python-pil \\ + python-pillow \\ + python-pip + + +ENV LC_ALL en_US.UTF-8 +RUN locale-gen en_US.UTF-8 + +RUN pip3 install jupyter scikit-image ipykernel +RUN pip install jupyter scikit-image ipykernel + +RUN ipython3 kernel install +RUN ipython kernel install + +# Use the same gid and uid as your user on the host system. You can find them +# out with the id programm. This way the file ownership in mapped directories is +# consistent with the host system. +RUN echo "%sudo ALL=(ALL) ALL" >> /etc/sudoers +RUN groupadd --gid $uid $username +RUN useradd --uid $uid --gid $username \\ + --home-dir /home/$username --shell /usr/bin/bash \\ + --groups sudo,$username \\ + --password $password \\ + $username + + +# set default passwords +RUN echo $username:$password | chpasswd && \\ + echo root:$password | chpasswd + +RUN mkdir -p /home/$username && chown -R $username:$username /home/$username + +USER $username +WORKDIR /home/$username' + +RUN echo "PATH=$PATH:/usr/local/bin:~/.local/bin/" > /home/$username/.bashrc + +CMD ["sh", "-c", "jupyter notebook --ip 0.0.0.0"] +EOF + +if [ "$1" != "sample" ]; then + docker build -t 'image_processing_ss16' . +fi diff --git a/docker_start.sh b/docker_start.sh new file mode 100644 index 0000000..c97bb86 --- /dev/null +++ b/docker_start.sh @@ -0,0 +1,21 @@ +#! /usr/bin/env bash + +PORT="8888" +CIDFILE=".docker_cid" +username=$(whoami) + +if [ -e $CIDFILE ]; then + CID=$(cat $CIDFILE) + CMD="docker start $CID" + $CMD +else + CMD="docker run \ + --cidfile=$CIDFILE \ + -p $PORT:$PORT \ + -v `pwd`:/home/$username/image_processing \ + -d \ + --name image_processing_ss16_container \ + image_processing_ss16" + echo "$CMD" + $CMD +fi diff --git a/nb_strip_output.py b/nb_strip_output.py new file mode 100644 index 0000000..5653e54 --- /dev/null +++ b/nb_strip_output.py @@ -0,0 +1,110 @@ +#! /usr/bin/env python3 +""" + strip output of IPython Notebooks + add this as `.git/hooks/pre-commit` + to run every time you commit a notebook + +strip outputs from an IPython Notebook Opens a notebook, strips its output, and +writes the outputless version to the original file. Useful mainly as a git +filter or pre-commit hook for users who don't want to track output in VCS. +This does mostly the same thing as the `Clear All Output` command in the +notebook UI. +LICENSE: Public Domain +Adapted from: https://gist.github.com/minrk/6176788 +""" + +import subprocess +from subprocess import PIPE, Popen +import io +import argparse +import os + +try: + # Jupyter >= 4 + from nbformat import read, write, NO_CONVERT +except ImportError: + # IPython 3 + try: + from IPython.nbformat import read, write, NO_CONVERT + except ImportError: + # IPython < 3 + from IPython.nbformat import current + + def read(f, as_version): + return current.read(f, 'json') + + def write(nb, f): + return current.write(nb, f, 'json') + + +def get_rev(): + command = "git rev-parse --verify HEAD".split(" ") + if subprocess.call(command, stdin=PIPE, stdout=PIPE, stderr=PIPE) == 0: + return 'HEAD' + else: + return '4b825dc642cb6eb9a060e54bf8d69288fbee4904' + + +def get_notebooks(against): + command = "git diff-index -z --cached {} --name-only".format(against) + p = Popen(command.split(" "), stdin=PIPE, stdout=PIPE, stderr=PIPE) + output, err = p.communicate() + assert p.returncode == 0, \ + "Command failed: {}\nstdout:\n{}\nstderr:\n{}"\ + .format(command, output, err) + files = [binary_fname.decode('utf8') + for binary_fname in output.split(b'\x00')] + return set([f for f in files if f.endswith(".ipynb")]) + + +def run_as_git_hook(): + against = get_rev() + for notebook_fname in get_notebooks(against): + print("Stripping output from: {}".format(notebook_fname)) + strip_output(notebook_fname) + + command = "git diff-index --check --cached {} --".format(against) + subprocess.call(command.split(" ")) + + +def _cells(nb): + """Yield all cells in an nbformat-insensitive manner""" + if nb.nbformat < 4: + for ws in nb.worksheets: + for cell in ws.cells: + yield cell + else: + for cell in nb.cells: + yield cell + + +def strip_output(filename): + """strip the outputs from a notebook""" + + with io.open(filename, 'r', encoding='utf8') as f: + nb = read(f, as_version=NO_CONVERT) + + nb.metadata.pop('signature', None) + for cell in _cells(nb): + if 'outputs' in cell: + cell['outputs'] = [] + if 'prompt_number' in cell: + cell['prompt_number'] = None + with io.open(filename, 'w', encoding='utf8') as f: + write(nb, f) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description='Strips the output from a notebook') + parser.add_argument('file', type=str, default='', nargs='?', + help='remove the output from this notebook') + args = parser.parse_args() + if args.file == '': + run_as_git_hook() + + else: + fname = args.file + if not os.path.exists(fname): + print("File {} does not exists.".format(fname)) + strip_output(fname)