add tutorial content
authorMimmmo Cosenza <mimmo.cosenza@gmail.com>
Wed, 11 Dec 2013 12:30:52 +0000 (13:30 +0100)
committerMimmmo Cosenza <mimmo.cosenza@gmail.com>
Wed, 11 Dec 2013 12:30:52 +0000 (13:30 +0100)
doc/tutorials/introduction/clojure_dev_intro/clojure_dev_intro.rst [new file with mode: 0644]
doc/tutorials/introduction/clojure_dev_intro/images/blurred.png [new file with mode: 0644]
doc/tutorials/introduction/clojure_dev_intro/images/lena.png [new file with mode: 0644]

diff --git a/doc/tutorials/introduction/clojure_dev_intro/clojure_dev_intro.rst b/doc/tutorials/introduction/clojure_dev_intro/clojure_dev_intro.rst
new file mode 100644 (file)
index 0000000..248abdf
--- /dev/null
@@ -0,0 +1,728 @@
+.. _clojure_dev_intro:
+
+Introduction to OpenCV Development with Clojure
+***********************************************
+
+As of OpenCV 2.4.4, OpenCV supports desktop Java development using
+nearly the same interface as for Android development.
+
+`Clojure <http://clojure.org/>`_ is a contemporary LISP dialect hosted
+by the Java Virtual Machine and it offers a complete interoperability
+with the underlying JVM. This means that we should even be able to use
+the Clojure REPL (Read Eval Print Loop) as and interactive programmable
+interface to the underlying OpenCV engine.
+
+What we'll do in this tutorial
+==============================
+
+This tutorial will help you in setting up a basic Clojure environment
+for interactively learning OpenCV within the fully programmable
+CLojure REPL.
+
+Tutorial source code
+--------------------
+
+You can find a runnable source code of the sample in the
+:file:`samples/java/clojure/simple-sample` folder of the OpenCV
+repository. After having installed OpenCV and Clojure as explained in
+the tutorial, issue the following command to run the sample from the
+command line.
+
+.. code:: bash
+
+    cd path/to/samples/java/clojure/simple-sample
+    lein run
+
+Preamble
+========
+
+For detailed instruction on installing OpenCV with desktop Java support
+refer to the `corresponding tutorial <http://docs.opencv.org/2.4.4-beta/doc/tutorials/introduction/desktop_java/java_dev_intro.html>`_.
+
+If you are in hurry, here is a minimum quick start guide to install
+OpenCV on Mac OS X:
+
+    NOTE 1: I'm assuming you already installed
+    `xcode <https://developer.apple.com/xcode/>`_,
+    `jdk <http://www.oracle.com/technetwork/java/javase/downloads/index.html>`_
+    and `Cmake <http://www.cmake.org/cmake/resources/software.html>`_.
+
+.. code:: bash
+
+    cd ~/
+    mkdir opt
+    git clone https://github.com/Itseez/opencv.git
+    cd opencv
+    git checkout 2.4
+    mkdir build
+    cd build
+    cmake -DBUILD_SHARED_LIBS=OFF ..
+    ...
+    ...
+    make -j8
+    # optional
+    # make install
+
+Install Leiningen
+=================
+
+Once you installed OpenCV with desktop java support the only other
+requirement is to install
+`Leiningeng <https://github.com/technomancy/leiningen>`_ which allows
+you to manage the entire life cycle of your CLJ projects.
+
+The available `installation guide <https://github.com/technomancy/leiningen#installation>`_ is very easy to be followed:
+
+1. `Download the script <https://raw.github.com/technomancy/leiningen/stable/bin/lein>`_
+2. Place it on your ``$PATH`` (cf. ``~/bin`` is a good choice if it is
+   on your ``path``.)
+3. Set the script to be executable. (i.e. ``chmod 755 ~/bin/lein``).
+
+If you work on Windows, follow `this instruction <https://github.com/technomancy/leiningen#windows>`_
+
+You now have both the OpenCV library and a fully installed basic Clojure
+environment. What is now needed is to configure the Clojure environment
+to interact with the OpenCV library.
+
+Install the localrepo Leiningen plugin
+=======================================
+
+The set of commands (tasks in Leiningen parlance) natively supported by
+Leiningen can be very easily extended by various plugins. One of them is
+the `lein-localrepo <https://github.com/kumarshantanu/lein-localrepo>`_
+plugin which allows to install any jar lib as an artifact in the local
+maven repository of your machine (typically in the ``~/.m2/repository``
+directory of your username).
+
+We're going to use this ``lein`` plugin to add to the local maven
+repository the opencv components needed by Java and Clojure to use the
+opencv lib.
+
+Generally speaking, if you want to use a plugin on project base only, it
+can be added directly to a CLJ project created by ``lein``.
+
+Instead, when you want a plugin to be available to any CLJ project in
+your username space, you can add it to the ``profiles.clj`` in the
+``~/.lein/`` directory.
+
+The ``lein-localrepo`` plugin will be useful to me in other CLJ
+projects where I need to call native libs wrapped by a Java interface.
+So I decide to make it available to any CLJ project:
+
+.. code:: bash
+
+    mkdir ~/.lein
+
+Create a file named ``profiles.clj`` in the ``~/.lein`` directory and
+copy into it the following content:
+
+.. code:: clojure
+
+    {:user {:plugins [[lein-localrepo "0.5.2"]]}}
+
+Here we're saying that the version release ``"0.5.2"`` of the
+``lein-localrepo`` plugin will be available to the ``:user`` profile for
+any CLJ project created by ``lein``.
+
+You do not need to do anything else to install the plugin because it
+will be automatically downloaded from a remote repository the very first
+time you issue any ``lein`` task.
+
+Install the java specific libs as local repository
+==================================================
+
+If you followed the standard documentation for installing OpenCV on your
+computer, you should find the following two libs under the directory
+where you built OpenCV:
+
+-  the ``build/bin/opencv-247.jar`` java lib
+-  the ``build/lib/libopencv_java247.dylib`` native lib (or ``.so`` in
+   you built OpenCV a GNU/Linux OS)
+
+They are the only opencv libs needed by the JVM to interact with OpenCV.
+
+Take apart the needed opencv libs
+---------------------------------
+
+Create a new directory to store in the above two libs. Start by copying
+into it the ``opencv-247.jar`` lib.
+
+.. code:: bash
+
+    cd ~/opt
+    mkdir clj-opencv
+    cd clj-opencv
+    cp ~/opt/opencv/build/bin/opencv-247.jar .
+
+First lib done.
+
+Now, to be able to add the ``libopencv_java247.dylib`` shared native lib
+to the local maven repository, we first need to package it as a jar
+file.
+
+The native lib has to be copied into a directories layout which mimics
+the names of your operating system and architecture. I'm using a Mac OS
+X with a X86 64 bit architecture. So my layout will be the following:
+
+.. code:: bash
+
+    mkdir -p native/macosx/x86_64
+
+Copy into the ``x86_64`` directory the ``libopencv_java247.dylib`` lib.
+
+.. code:: bash
+
+    cp ~/opt/opencv/build/lib/libopencv_java247.dylib native/macosx/x86_64/
+
+If you're running OpenCV from a different OS/Architecture pair, here
+is a summary of the mapping you can choose from.
+
+.. code:: bash
+
+        OS
+
+        Mac OS X -> macosx
+        Windows  -> windows
+        Linux    -> linux
+        SunOS    -> solaris
+
+        Architectures
+
+        amd64    -> x86_64
+        x86_64   -> x86_64
+        x86      -> x86
+        i386     -> x86
+        arm      -> arm
+        sparc    -> sparc
+
+Package the native lib as a jar
+-------------------------------
+
+Next you need to package the native lib in a jar file by using the
+``jar`` command to create a new jar file from a directory.
+
+.. code:: bash
+
+    jar -cMf opencv-native-247.jar native
+
+Note that ehe ``M`` option instructs the ``jar`` command to not create
+a MANIFEST file for the artifact.
+
+Your directories layout should look like the following:
+
+.. code:: bash
+
+    tree
+    .
+    |__ native
+    |   |__ macosx
+    |       |__ x86_64
+    |           |__ libopencv_java247.dylib
+    |
+    |__ opencv-247.jar
+    |__ opencv-native-247.jar
+
+    3 directories, 3 files
+
+Locally install the jars
+------------------------
+
+We are now ready to add the two jars as artifacts to the local maven
+repository with the help of the ``lein-localrepo`` plugin.
+
+.. code:: bash
+
+    lein localrepo install opencv-247.jar opencv/opencv 2.4.7
+
+Here the ``localrepo install`` task creates the ``2.4.7.`` release of
+the ``opencv/opencv`` maven artifact from the ``opencv-247.jar`` lib and
+then installs it into the local maven repository. The ``opencv/opencv``
+artifact will then be available to any maven compliant project
+(Leiningen is internally based on maven).
+
+Do the same thing with the native lib previously wrapped in a new jar
+file.
+
+.. code:: bash
+
+    lein localrepo install opencv-native-247.jar opencv/opencv-native 2.4.7
+
+Note that the groupId, ``opencv``, of the two artifacts is the same. We
+are now ready to create a new CLJ project to start interacting with
+OpenCV.
+
+Create a project
+----------------
+
+Create a new CLJ project by using the ``lein new`` task from the
+terminal.
+
+.. code:: bash
+
+    # cd in the directory where you work with your development projects (e.g. ~/devel)
+    lein new simple-sample
+    Generating a project called simple-sample based on the 'default' template.
+    To see other templates (app, lein plugin, etc), try `lein help new`.
+
+The above task creates the following ``simple-sample`` directories
+layout:
+
+.. code:: bash
+
+    tree simple-sample/
+    simple-sample/
+    |__ LICENSE
+    |__ README.md
+    |__ doc
+    |   |__ intro.md
+    |
+    |__ project.clj
+    |__ resources
+    |__ src
+    |   |__ simple_sample
+    |       |__ core.clj
+    |__ test
+        |__ simple_sample
+            |__ core_test.clj
+
+    6 directories, 6 files
+
+We need to add the two ``opencv`` artifacts as dependencies of the newly
+created project. Open the ``project.clj`` and modify its dependencies
+section as follows:
+
+.. code:: bash
+
+    (defproject simple-sample "0.1.0-SNAPSHOT"
+      :description "FIXME: write description"
+      :url "http://example.com/FIXME"
+      :license {:name "Eclipse Public License"
+                :url "http://www.eclipse.org/legal/epl-v10.html"}
+      :dependencies [[org.clojure/clojure "1.5.1"]
+                     [opencv/opencv "2.4.7"] ; added line
+                     [opencv/opencv-native "2.4.7"]]) ;added line
+
+
+Note that The Clojure Programming Language is a jar artifact too. This
+is why Clojure is called an hosted language.
+
+To verify that everything went right issue the ``lein deps`` task. The
+very first time you run a ``lein`` task it will take sometime to
+download all the required dependencies before executing the task
+itself.
+
+.. code:: bash
+
+    cd simple-sample
+    lein deps
+    ...
+
+The ``deps`` task reads and merges from the ``project.clj`` and the
+``~/.lein/profiles.clj`` files all the dependencies of the
+``simple-sample`` project and verifies if they have already been
+cached in the local maven repository. If the task returns without
+messages about not being able to retrieve the two new artifacts your
+installation is correct, otherwise go back and double check that you
+did everything right.
+
+REPLing with OpenCV
+-------------------
+
+Now ``cd`` in the ``simple-sample`` directory and issue the following
+``lein`` task:
+
+.. code:: bash
+
+    cd simple-sample
+    lein repl
+    ...
+    ...
+    nREPL server started on port 50907 on host 127.0.0.1
+    REPL-y 0.3.0
+    Clojure 1.5.1
+        Docs: (doc function-name-here)
+              (find-doc "part-of-name-here")
+      Source: (source function-name-here)
+     Javadoc: (javadoc java-object-or-class-here)
+        Exit: Control+D or (exit) or (quit)
+     Results: Stored in vars *1, *2, *3, an exception in *e
+
+    user=>
+
+You can immediately interact with the REPL by issuing any CLJ expression
+to be evaluated.
+
+.. code:: clojure
+
+    user=> (+ 41 1)
+    42
+    user=> (println "Hello, OpenCV!")
+    Hello, OpenCV!
+    nil
+    user=> (defn foo [] (str "bar"))
+    #'user/foo
+    user=> (foo)
+    "bar"
+
+When ran from the home directory of a lein based project, even if the
+``lein repl`` task automatically loads all the project dependencies, you
+still need to load the opencv native library to be able to interact with
+the OpenCV.
+
+.. code:: clojure
+
+    user=> (clojure.lang.RT/loadLibrary org.opencv.core.Core/NATIVE_LIBRARY_NAME)
+    nil
+
+Then you can start interacting with OpenCV by just referencing the fully
+qualified names of its classes.
+
+    NOTE 2: `Here <http://docs.opencv.org/java/>`_ you can find the
+    full OpenCV Java API.
+
+.. code:: clojure
+
+    user=> (org.opencv.core.Point. 0 0)
+    #<Point {0.0, 0.0}>
+
+Here we created a two dimensions opencv ``Point`` instance. Even if all
+the java packages included within the java interface to OpenCV are
+immediately available from the CLJ REPL, it's very annoying to prefix
+the ``Point.`` instance constructors with the fully qualified package
+name.
+
+Fortunately CLJ offer a very easy way to overcome this annoyance by
+directly importing the ``Point`` class.
+
+.. code:: clojure
+
+    user=> (import 'org.opencv.core.Point)
+    org.opencv.core.Point
+    user=> (def p1 (Point. 0 0))
+    #'user/p1
+    user=> p1
+    #<Point {0.0, 0.0}>
+    user=> (def p2 (Point. 100 100))
+    #'user/p2
+
+We can even inspect the class of an instance and verify if the value of
+a symbol is an instance of a ``Point`` java class.
+
+.. code:: clojure
+
+    user=> (class p1)
+    org.opencv.core.Point
+    user=> (instance? org.opencv.core.Point p1)
+    true
+
+If we now want to use the opencv ``Rect`` class to create a rectangle,
+we again have to fully qualify its constructor even if it leaves in
+the same ``org.opencv.core`` package of the ``Point`` class.
+
+.. code:: clojure
+
+    user=> (org.opencv.core.Rect. p1 p2)
+    #<Rect {0, 0, 100x100}>
+
+Again, the CLJ importing facilities is very handy and let you to map
+more symbols in one shot.
+
+.. code:: clojure
+
+    user=> (import '[org.opencv.core Point Rect Size])
+    org.opencv.core.Size
+    user=> (def r1 (Rect. p1 p2))
+    #'user/r1
+    user=> r1
+    #<Rect {0, 0, 100x100}>
+    user=> (class r1)
+    org.opencv.core.Rect
+    user=> (instance? org.opencv.core.Rect r1)
+    true
+    user=> (Size. 100 100)
+    #<Size 100x100>
+    user=> (def sq-100 (Size. 100 100))
+    #'user/sq-100
+    user=> (class sq-100)
+    org.opencv.core.Size
+    user=> (instance? org.opencv.core.Size sq-100)
+    true
+
+Obviously you can call methods on instances as well.
+
+.. code:: clojure
+
+    user=> (.area r1)
+    10000.0
+    user=> (.area sq-100)
+    10000.0
+
+Or modify the value of a member field.
+
+.. code:: clojure
+
+    user=> (set! (.x p1) 10)
+    10
+    user=> p1
+    #<Point {10.0, 0.0}>
+    user=> (set! (.width sq-100) 10)
+    10
+    user=> (set! (.height sq-100) 10)
+    10
+    user=> (.area sq-100)
+    100.0
+
+If you find yourself not remembering a OpenCV class behavior, the
+REPL gives you the opportunity to easily search the corresponding
+javadoc documention:
+
+.. code:: clojure
+
+    user=> (javadoc Rect)
+    "http://www.google.com/search?btnI=I%27m%20Feeling%20Lucky&q=allinurl:org/opencv/core/Rect.html"
+
+Mimic the OpenCV Java Tutorial Sample in the REPL
+-------------------------------------------------
+
+Let's now try to port to Clojure the `opencv java tutorial sample <http://docs.opencv.org/2.4.4-beta/doc/tutorials/introduction/desktop_java/java_dev_intro.html>`_.
+Instead of writing it in a source file we're going to evaluate it at the
+REPL.
+
+Following is the original Java source code of the cited sample.
+
+.. code:: java
+
+    import org.opencv.core.Mat;
+    import org.opencv.core.CvType;
+    import org.opencv.core.Scalar;
+
+    class SimpleSample {
+
+      static{ System.loadLibrary("opencv_java244"); }
+
+      public static void main(String[] args) {
+        Mat m = new Mat(5, 10, CvType.CV_8UC1, new Scalar(0));
+        System.out.println("OpenCV Mat: " + m);
+        Mat mr1 = m.row(1);
+        mr1.setTo(new Scalar(1));
+        Mat mc5 = m.col(5);
+        mc5.setTo(new Scalar(5));
+        System.out.println("OpenCV Mat data:\n" + m.dump());
+      }
+
+    }
+
+Add injections to the project
+-----------------------------
+
+Before start coding, we'd like to eliminate the boring need of
+interactively loading the native opencv lib any time we start a new REPL
+to interact with it.
+
+First, stop the REPL by evaluating the ``(exit)`` expression at the REPL
+prompt.
+
+.. code:: clojure
+
+    user=> (exit)
+    Bye for now!
+
+Then open your ``project.clj`` file and edit it as follows:
+
+.. code:: clojure
+
+    (defproject simple-sample "0.1.0-SNAPSHOT"
+      ...
+      :injections [(clojure.lang.RT/loadLibrary org.opencv.core.Core/NATIVE_LIBRARY_NAME)])
+
+Here we're saying to load the opencv native lib anytime we run the REPL
+in such a way that we have not anymore to remember to manually do it.
+
+Rerun the ``lein repl`` task
+
+.. code:: bash
+
+    lein repl
+    nREPL server started on port 51645 on host 127.0.0.1
+    REPL-y 0.3.0
+    Clojure 1.5.1
+        Docs: (doc function-name-here)
+              (find-doc "part-of-name-here")
+      Source: (source function-name-here)
+     Javadoc: (javadoc java-object-or-class-here)
+        Exit: Control+D or (exit) or (quit)
+     Results: Stored in vars *1, *2, *3, an exception in *e
+
+    user=>
+
+Import the interested OpenCV java interfaces.
+
+.. code:: clojure
+
+    user=> (import '[org.opencv.core Mat CvType Scalar])
+    org.opencv.core.Scalar
+
+We're going to mimic almost verbatim the original OpenCV java tutorial
+to:
+
+-  create a 5x10 matrix with all its elements intialized to 0
+-  change the value of every element of the second row to 1
+-  change the value of every element of the 6th column to 5
+-  print the content of the obtained matrix
+
+.. code:: clojure
+
+    user=> (def m (Mat. 5 10 CvType/CV_8UC1 (Scalar. 0 0)))
+    #'user/m
+    user=> (def mr1 (.row m 1))
+    #'user/mr1
+    user=> (.setTo mr1 (Scalar. 1 0))
+    #<Mat Mat [ 1*10*CV_8UC1, isCont=true, isSubmat=true, nativeObj=0x7fc9dac49880, dataAddr=0x7fc9d9c98d5a ]>
+    user=> (def mc5 (.col m 5))
+    #'user/mc5
+    user=> (.setTo mc5 (Scalar. 5 0))
+    #<Mat Mat [ 5*1*CV_8UC1, isCont=false, isSubmat=true, nativeObj=0x7fc9d9c995a0, dataAddr=0x7fc9d9c98d55 ]>
+    user=> (println (.dump m))
+    [0, 0, 0, 0, 0, 5, 0, 0, 0, 0;
+      1, 1, 1, 1, 1, 5, 1, 1, 1, 1;
+      0, 0, 0, 0, 0, 5, 0, 0, 0, 0;
+      0, 0, 0, 0, 0, 5, 0, 0, 0, 0;
+      0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
+    nil
+
+If you are accustomed to a functional language all those abused and
+mutating nouns are going to irritate your preference for verbs. Even
+if the CLJ interop syntax is very handy and complete, there is still
+an impedance mismatch between any OOP language and any FP language
+(bein Scala a mixed paradigms programming language).
+
+To exit the REPL type ``(exit)``, ``ctr-D`` or ``(quit)`` at the REPL
+prompt.
+
+.. code:: clojure
+
+    user=> (exit)
+    Bye for now!
+
+Interactively load and blur an image
+------------------------------------
+
+In the next sample you will learn how to interactively load and blur and
+image from the REPL by using the following OpenCV methods:
+
+-  the ``imread`` static method from the ``Highgui`` class to read an
+   image from a file
+-  the ``imwrite`` static method from the ``Highgui`` class to write an
+   image to a file
+-  the ``GaussianBlur`` static method from the ``Imgproc`` class to
+   apply to blur the original image
+
+We're also going to use the ``Mat`` class which is returned from the
+``imread`` method and accpeted as the main argument to both the
+``GaussianBlur`` and the ``imwrite`` methods.
+
+Add an image to the project
+---------------------------
+
+First we want to add an image file to a newly create directory for
+storing static resources of the project.
+
+.. image:: images/lena.png
+   :alt: Original Image
+   :align: center
+
+.. code:: bash
+
+    mkdir -p resources/images
+    cp ~/opt/opencv/doc/tutorials/introduction/desktop_java/images/lena.png resource/images/
+
+Read the image
+--------------
+
+Now launch the REPL as usual and start by importing all the OpenCV
+classes we're going to use:
+
+.. code:: clojure
+
+    lein repl
+    nREPL server started on port 50624 on host 127.0.0.1
+    REPL-y 0.3.0
+    Clojure 1.5.1
+        Docs: (doc function-name-here)
+              (find-doc "part-of-name-here")
+      Source: (source function-name-here)
+     Javadoc: (javadoc java-object-or-class-here)
+        Exit: Control+D or (exit) or (quit)
+     Results: Stored in vars *1, *2, *3, an exception in *e
+
+    user=> (import '[org.opencv.core Mat Size CvType]
+                   '[org.opencv.highgui Highgui]
+                   '[org.opencv.imgproc Imgproc])
+    org.opencv.imgproc.Imgproc
+
+Now read the image from the ``resources/images/lena.png`` file.
+
+.. code:: clojure
+
+    user=> (def lena (Highgui/imread "resources/images/lena.png"))
+    #'user/lena
+    user=> lena
+    #<Mat Mat [ 512*512*CV_8UC3, isCont=true, isSubmat=false, nativeObj=0x7f9ab3054c40, dataAddr=0x19fea9010 ]>
+
+As you see, by simply evaluating the ``lena`` symbol we know that
+``lena.png`` is a ``512x512`` matrix of ``CV_8UC3`` elements type. Let's
+create a new ``Mat`` instance of the same dimensions and elements type.
+
+.. code:: clojure
+
+    user=> (def blurred (Mat. 512 512 CvType/CV_8UC3))
+    #'user/blurred
+    user=>
+
+Now apply a ``GaussianBlur`` filter using ``lena`` as the source matrix
+and ``blurred`` as the destination matrix.
+
+.. code:: clojure
+
+    user=> (Imgproc/GaussianBlur lena blurred (Size. 5 5) 3 3)
+    nil
+
+As a last step just save the ``blurred`` matrix in a new image file.
+
+.. code:: clojure
+
+    user=> (Highgui/imwrite "resources/images/blurred.png" blurred)
+    true
+    user=> (exit)
+    Bye for now!
+
+Following is the new blurred image of Lena.
+
+.. image:: images/blurred.png
+   :alt: Blurred Image
+   :align: center
+
+Next Steps
+==========
+
+This tutorial only introduces the very basic environment set up to be
+able to interact with OpenCV in a CLJ REPL.
+
+I recommend any Clojure newbie to read the `Clojure Java Interop chapter <http://clojure.org/java_interop>`_ to get all you need to know
+to interoperate with any plain java lib that has not been wrapped in
+Clojure to make it usable in a more idiomatic and functional way within
+Clojure.
+
+The OpenCV Java API does not wrap the ``highgui`` module
+functionalities depending on ``Qt`` (e.g. ``namedWindow`` and
+``imshow``. If you want to create windows and show images into them
+while interacting with OpenCV from the REPL, at the moment you're left
+at your own. You could use Java Swing to fill the gap.
+
+
+License
+-------
+
+Copyright © 2013 Giacomo (Mimmo) Cosenza aka Magomimmo
+
+Distributed under the BSD 3-clause License, the same of OpenCV.
diff --git a/doc/tutorials/introduction/clojure_dev_intro/images/blurred.png b/doc/tutorials/introduction/clojure_dev_intro/images/blurred.png
new file mode 100644 (file)
index 0000000..c8aeea8
Binary files /dev/null and b/doc/tutorials/introduction/clojure_dev_intro/images/blurred.png differ
diff --git a/doc/tutorials/introduction/clojure_dev_intro/images/lena.png b/doc/tutorials/introduction/clojure_dev_intro/images/lena.png
new file mode 100644 (file)
index 0000000..68342fa
Binary files /dev/null and b/doc/tutorials/introduction/clojure_dev_intro/images/lena.png differ