Эх сурвалжийг харах

Merge branch 'master' of dbv.inf-cv.uni-jena.de:nice/nice-core

Johannes Ruehle 11 жил өмнө
parent
commit
7dbc1aa616

+ 223 - 216
core/iceconversion/image_convertice.h

@@ -26,248 +26,255 @@
 namespace NICE
 {
 
-    /**
-     * For internal use.
-     */
-    inline unsigned char invert255(unsigned char value, bool invert)
+  /**
+   * For internal use.
+   */
+  inline unsigned char invert255(unsigned char value, bool invert)
+                                 {
+    if (invert)
     {
-        if (invert)
-        {
-            return 255 - value;
-        }
-        else
-        {
-            return value;
-        }
+      return 255 - value;
     }
-
-    /**
-     * Create a new \c NICE::Image from an \c ice::Image.
-     * @param source The source image.
-     * @param invertImage Invert the image? Note: ICE works with inverted images.
-     * @param memoryLayout The memory layout for the new \c NICE::Image.
-     * @return The new \c NICE::Image (ownership given away!)
-     */
-    inline NICE::Image*
-    createGrayImage(const ice::Image& source,
-                    bool invertImage = true,
-                    NICE::GrayColorImageCommonImplementation::MemoryLayout memoryLayout
-                    = NICE::GrayColorImageCommonImplementation::ippAlignment)
+    else
     {
-        // auto_ptr for exception safety
-        auto_ptr<Image>
-        result(new Image(source->xsize, source->ysize, memoryLayout));
-
-        for (int y = 0; y < source->ysize; y++)
+      return value;
+    }
+  }
+
+  /**
+   * Create a new \c NICE::Image from an \c ice::Image.
+   * @param source The source image.
+   * @param invertImage Invert the image? Note: ICE works with inverted images.
+   * @param memoryLayout The memory layout for the new \c NICE::Image.
+   * @return The new \c NICE::Image (ownership given away!)
+   */
+  inline NICE::Image*
+  createGrayImage(const ice::Image& source,
+                  bool invertImage = true,
+                  NICE::GrayColorImageCommonImplementation::MemoryLayout memoryLayout
+                  = NICE::GrayColorImageCommonImplementation::ippAlignment)
+                  {
+    // auto_ptr for exception safety
+    auto_ptr< Image >
+    result(new Image(source->xsize, source->ysize, memoryLayout));
+
+    for (int y = 0; y < source->ysize; y++)
         {
-            Image::Pixel* cursor = result->getPixelPointerY(y);
-
-            for (int x = 0; x < source->xsize; x++)
-            {
-                // FIXME GetVal_nocheck ?!
-                *cursor = invert255(GetVal(source, x, y), invertImage);
-                cursor++;
-            }
-        }
-
-        return result.release();
+      Image::Pixel* cursor = result->getPixelPointerY(y);
+
+      for (int x = 0; x < source->xsize; x++)
+          {
+        // FIXME GetVal_nocheck ?!
+        *cursor = invert255(GetVal(source, x, y), invertImage);
+        cursor++;
+      }
     }
 
-    /**
-     * Copy an ice::Image to a NICE::Image
-     * @param source The source image
-     * @param dst The destination image
-     * @param invertImage Invert the image? Note: ICE works with inverted images.
-     *
-     */
-    inline void
-    copyGrayImage(const ice::Image& source,
-                  NICE::Image& dst,
-                  bool invertImage = true)
-    {
-        dst.resize(source->xsize, source->ysize);
-        for (int y = 0; y < source->ysize; y++)
+    return result.release();
+  }
+
+  /**
+   * Copy an ice::Image to a NICE::Image
+   * @param source The source image
+   * @param dst The destination image
+   * @param invertImage Invert the image? Note: ICE works with inverted images.
+   *
+   */
+  inline void
+  copyGrayImage(const ice::Image& source,
+                NICE::Image& dst,
+                bool invertImage = true)
+                {
+    dst.resize(source->xsize, source->ysize);
+    for (int y = 0; y < source->ysize; y++)
         {
-            Image::Pixel* cursor = dst.getPixelPointerY(y);
-            for (int x = 0; x < source->xsize; x++)
-            {
-                *cursor = invert255(GetVal(source, x, y), invertImage);
-                cursor++;
-            }
-        }
+      Image::Pixel* cursor = dst.getPixelPointerY(y);
+      for (int x = 0; x < source->xsize; x++)
+          {
+        *cursor = invert255(GetVal(source, x, y), invertImage);
+        cursor++;
+      }
     }
-
-
-    /**
-     * Create a new \c ice::Image from an \c NICE::Image.
-     * @param source The source image.
-     * @param invertImage Invert the image? Note: ICE works with inverted images.
-     * @return The new \c ice::Image (ownership given away!)
-     */
-    inline ice::Image createIceImage(const NICE::Image& source,
-                                     bool invertImage = true)
-    {
-        ice::Image result = ice::NewImg(source.width(), source.height(), 255);
-
-        for (int y = 0; y < source.height(); y++)
+  }
+
+  /**
+   * Create a new \c ice::Image from an \c NICE::Image.
+   * @param source The source image.
+   * @param invertImage Invert the image? Note: ICE works with inverted images.
+   * @return The new \c ice::Image (ownership given away!)
+   */
+  inline ice::Image createIceImage(const NICE::Image& source,
+                                   bool invertImage = true)
+                                   {
+    ice::Image result = ice::NewImg(source.width(), source.height(), 255);
+
+    for (int y = 0; y < source.height(); y++)
         {
-            const Image::Pixel* cursor = source.getPixelPointerY(y);
-
-            for (int x = 0; x < source.width(); x++)
-            {
-                // FIXME PutVal_nocheck ?!
-                PutVal(result, x, y, invert255(*cursor, invertImage));
-                cursor++;
-            }
-        }
-
-        return result;
+      const Image::Pixel* cursor = source.getPixelPointerY(y);
+
+      for (int x = 0; x < source.width(); x++)
+          {
+        // FIXME PutVal_nocheck ?!
+        PutVal(result, x, y, invert255(*cursor, invertImage));
+        cursor++;
+      }
     }
 
-    /**
-     * Create a new \c NICE::ColorImage from an \c ice::ImageRGB.
-     * @param source The source image.
-     * @param invertImage Invert the image? Note: ICE works with inverted images.
-     * @param memoryLayout The memory layout for the new \c NICE::ColorImage.
-     * @return The new \c NICE::ColorImage (ownership given away!)
-     */
-    inline NICE::ColorImage*
-    createColorImage(const ice::ImageRGB& source,
-                     bool invertImage = true,
-                     NICE::GrayColorImageCommonImplementation::MemoryLayout memoryLayout
-                     = NICE::GrayColorImageCommonImplementation::ippAlignment)
-    {
-        // auto_ptr for exception safety
-        auto_ptr<ColorImage>
-        //result(new ColorImage(source.xsize(), source.ysize(), memoryLayout));
-        result(new ColorImage(source.RedImage()->xsize,
-                              source.RedImage()->ysize,
-                              memoryLayout));
-
-        for (int y = 0; y < source.RedImage()->ysize; y++)
+    return result;
+  }
+
+  /**
+   * Create a new \c NICE::ColorImage from an \c ice::ImageRGB.
+   * @param source The source image.
+   * @param invertImage Invert the image? Note: ICE works with inverted images.
+   * @param memoryLayout The memory layout for the new \c NICE::ColorImage.
+   * @return The new \c NICE::ColorImage (ownership given away!)
+   */
+  inline NICE::ColorImage*
+  createColorImage(const ice::ColorImage &source,  // const ice::ImageRGB& source,
+                   bool invertImage = true,
+                   NICE::GrayColorImageCommonImplementation::MemoryLayout memoryLayout
+                   = NICE::GrayColorImageCommonImplementation::ippAlignment)
+                   {
+    // auto_ptr for exception safety
+    auto_ptr< ColorImage >
+    //result(new ColorImage(source.xsize(), source.ysize(), memoryLayout));
+    result(new ColorImage(source.redImage()->xsize,
+                          source.redImage()->ysize,
+                          memoryLayout));
+
+    for (int y = 0; y < source.redImage()->ysize; y++)
         {
-            ColorImage::Pixel* cursor = result->getPixelPointerY(y);
-
-            for (int x = 0; x < source.RedImage()->xsize; x++)
-            {
-                // FIXME GetVal_nocheck ?!
-                *cursor = invert255(GetVal(source.RedImage(), x, y), invertImage);
-                cursor++;
-                *cursor = invert255(GetVal(source.GreenImage(), x, y), invertImage);
-                cursor++;
-                *cursor = invert255(GetVal(source.BlueImage(), x, y), invertImage);
-                cursor++;
-            }
-        }
-
-        return result.release();
+      ColorImage::Pixel* cursor = result->getPixelPointerY(y);
+
+      for (int x = 0; x < source.redImage()->xsize; x++)
+          {
+        // FIXME GetVal_nocheck ?!
+        *cursor = invert255(GetVal(source.redImage(), x, y), invertImage);
+        cursor++;
+        *cursor = invert255(GetVal(source.greenImage(), x, y), invertImage);
+        cursor++;
+        *cursor = invert255(GetVal(source.blueImage(), x, y), invertImage);
+        cursor++;
+      }
     }
 
-    /**
-     * Create a new \c ice::ImageRGB from an \c NICE::ColorImage.
-     * @param source The source image.
-     * @param invertImage Invert the image? Note: ICE works with inverted images.
-     * @return The new \c ice::ImageRGB (ownership given away!)
-     */
-    inline ice::ImageRGB* createIceImageRGB(const NICE::ColorImage& source,
+    return result.release();
+  }
+
+  /**
+   * Create a new \c ice::ImageRGB from an \c NICE::ColorImage.
+   * @param source The source image.
+   * @param invertImage Invert the image? Note: ICE works with inverted images.
+   * @return The new \c ice::ImageRGB (ownership given away!)
+   */
+  inline ice::ColorImage* createIceImageRGB(const ice::ColorImage &source,  // const NICE::ColorImage& source,
                                             bool invertImage = true)
-    {
-        ice::ImageRGB* result = new ice::ImageRGB(source.width(), source.height());
+                                            {
+    ice::ColorImage* result = new ice::ColorImage();
+    result->create(source.xsize, source.ysize, source.maxval);
 
-        for (int y = 0; y < source.height(); y++)
+    for (int y = 0; y < source.ysize; y++)
         {
-            const Image::Pixel* cursor = source.getPixelPointerY(y);
-
-            for (int x = 0; x < source.width(); x++)
-            {
-                PutVal(result->RedImage(), x, y, invert255(*cursor, invertImage));
-                cursor++;
-                PutVal(result->GreenImage(), x, y, invert255(*cursor, invertImage));
-                cursor++;
-                PutVal(result->BlueImage(), x, y, invert255(*cursor, invertImage));
-                cursor++;
-            }
-        }
-
-        return result;
+//            const Image::Pixel* cursor = source.getPixelPointerY(y);
+
+      for (int x = 0; x < source.xsize; x++)
+          {
+//                PutVal(result->redImage(), x, y, invert255(*cursor, invertImage));
+//                cursor++;
+//                PutVal(result->greenImage(), x, y, invert255(*cursor, invertImage));
+//                cursor++;
+//                PutVal(result->blueImage(), x, y, invert255(*cursor, invertImage));
+//                cursor++;
+
+        ice::ColorValue valSrc = source.getPixel(x, y);
+        ice::ColorValue valDst(invert255(valSrc.red, invertImage),
+                             invert255(valSrc.green, invertImage),
+                             invert255(valSrc.blue, invertImage));
+        source.setPixel(x, y, valDst);
+      }
     }
 
-    /**
-     * Create a new \c NICE::FloatImage from an \c ice::ImageD.
-     * @param source The source FloatImage.
-     * @param memoryLayout The memory layout for the new \c NICE::FloatImage.
-     * @return The new \c NICE::FloatImage (ownership given away!)
-     */
-    inline NICE::FloatImage*
-    createFloatImage(const ice::ImageD& source
-                     )
-    {
-        // auto_ptr for exception safety
-        auto_ptr<FloatImage>
-        result(new FloatImage(source->xsize, source->ysize));
-
-        for (int y = 0; y < source->ysize; y++)
+    return result;
+  }
+
+  /**
+   * Create a new \c NICE::FloatImage from an \c ice::ImageD.
+   * @param source The source FloatImage.
+   * @param memoryLayout The memory layout for the new \c NICE::FloatImage.
+   * @return The new \c NICE::FloatImage (ownership given away!)
+   */
+  template<class T>
+  inline NICE::FloatImage*
+  createFloatImage(const ice::ImageF< T >& source)
+                   {
+    // auto_ptr for exception safety
+    auto_ptr< FloatImage >
+    result(new FloatImage(source->xsize, source->ysize));
+
+    for (int y = 0; y < source->ysize; y++)
         {
-            FloatImage::Pixel* cursor = result->getPixelPointerY(y);
-
-            for (int x = 0; x < source->xsize; x++)
-            {
-                // FIXME GetVal_nocheck ?!
-                *cursor = GetValD(source, x, y);
-                cursor++;
-            }
-        }
-
-        return result.release();
+      FloatImage::Pixel* cursor = result->getPixelPointerY(y);
+
+      for (int x = 0; x < source->xsize; x++)
+          {
+        // FIXME GetVal_nocheck ?!
+        *cursor = GetValD(source, x, y);
+        cursor++;
+      }
     }
 
-    /**
-     * Copy an ice::ImageD to a NICE::FloatImage
-     * @param source The source FloatImage
-     * @param dst The destination FloatImage
-     */
-    inline void
-    copyFloatImage(const ice::ImageD& source,
-                   NICE::FloatImage& dst)
-    {
-        dst.resize(source->xsize, source->ysize);
-        for (int y = 0; y < source->ysize; y++)
+    return result.release();
+  }
+
+  /**
+   * Copy an ice::ImageD to a NICE::FloatImage
+   * @param source The source FloatImage
+   * @param dst The destination FloatImage
+   */
+  inline void
+  copyFloatImage(const ice::ImageD& source,
+                 NICE::FloatImage& dst)
+                 {
+    dst.resize(source.xsize, source.ysize);
+    for (int y = 0; y < source.ysize; y++)
         {
-            FloatImage::Pixel* cursor = dst.getPixelPointerY(y);
-            for (int x = 0; x < source->xsize; x++)
-            {
-                *cursor = GetValD(source, x, y);
-                cursor++;
-            }
-        }
+      FloatImage::Pixel* cursor = dst.getPixelPointerY(y);
+      for (int x = 0; x < source.xsize; x++)
+          {
+        *cursor = GetValD(source, x, y);
+        cursor++;
+      }
     }
-
-
-    /**
-     * Create a new \c ice::ImageD from an \c NICE::FloatImage.
-     * @param source The source FloatImage.
-     * @return The new \c ice::ImageD (ownership given away!)
-     */
-    inline ice::ImageD createIceImageD(const NICE::FloatImage& source
-                                      )
-    {
-        ice::ImageD result = ice::NewImgD(source.width(), source.height());
-
-        for (int y = 0; y < source.height(); y++)
+  }
+
+  /**
+   * Create a new \c ice::ImageD from an \c NICE::FloatImage.
+   * @param source The source FloatImage.
+   * @return The new \c ice::ImageD (ownership given away!)
+   */
+  inline ice::ImageD createIceImageD(const NICE::FloatImage& source
+                                     )
+                                     {
+    ice::ImageD result = ice::NewImgD(source.width(), source.height());
+
+    for (int y = 0; y < source.height(); y++)
         {
-            const FloatImage::Pixel* cursor = source.getPixelPointerY(y);
-
-            for (int x = 0; x < source.width(); x++)
-            {
-                // FIXME PutVal_nocheck ?!
-                PutValD(result, x, y, *cursor);
-                cursor++;
-            }
-        }
-
-        return result;
+      const FloatImage::Pixel* cursor = source.getPixelPointerY(y);
+
+      for (int x = 0; x < source.width(); x++)
+          {
+        // FIXME PutVal_nocheck ?!
+        PutValD(result, x, y, *cursor);
+        cursor++;
+      }
     }
 
-}; // namespace
+    return result;
+  }
+
+}
+;
+// namespace
 
 #endif /* _CONVERTICE_IMAGE_H */

+ 1 - 1
core/optimization/gradientBased/OptimizationProblemFirst.h

@@ -34,7 +34,7 @@ class OptimizationProblemFirst : private NonCopyable {
 public:
   //! Default constructor
   inline OptimizationProblemFirst(unsigned int dimension)
-      : m_gradientCache(dimension) {
+      : m_gradientCache(dimension, 0), m_positionCache(dimension,0) {
     init();
   }
 

+ 14 - 0
core/tutorial/doc/01_imageio.md

@@ -139,3 +139,17 @@ return 0;
 
 Remember that _ImageFile_ objects are just containers for a file's location
 and only open the file when you call methods that require reading or writing.
+
+## Running the sample
+
+_Command line:_
+
+```bash
+./01_imageio ../../nice-core/core/tutorial/samples/peppers_color.ppm /tmp/output.ppm
+```
+
+_Output:_
+
+```
+Source image dimensions: 512 x 512 (3 channels, 8 bpp)
+```

+ 8 - 0
core/tutorial/doc/02_grayscale.md

@@ -151,3 +151,11 @@ NICE::ImageFile dest_image(output_path);
 dest_image.writer(&image);
 return 0;
 ```
+
+## Running the sample
+
+_Command line:_
+
+```bash
+./02_grayscale ../../nice-core/core/tutorial/samples/peppers_gray.pgm /tmp/output.ppm
+```

+ 9 - 1
core/tutorial/doc/03_color.md

@@ -123,4 +123,12 @@ After this is done, we write __pseudo_image__ to disk so we can look at it:
 NICE::ImageFile dest_image(output_path);
 dest_image.writer(&pseudo_image);
 return 0;
-```
+```
+
+## Running the sample
+
+_Command line:_
+
+```bash
+./03_color ../../nice-core/core/tutorial/samples/peppers_gray.pgm /tmp/output.ppm
+```

+ 10 - 1
core/tutorial/doc/04_filter.md

@@ -84,4 +84,13 @@ You need to call two methods in this case:
 
 ```c++
 NICE::Filter::filterX(image, kernel, result);
-NICE::Filter::filterY(image, kernel, result);
+NICE::Filter::filterY(image, kernel, result);
+```
+
+## Running the sample
+
+_Command line:_
+
+```bash
+./04_filter ../../nice-core/core/tutorial/samples/peppers_color.ppm /tmp/output.pgm
+```

+ 34 - 0
core/tutorial/doc/06_algebra.md

@@ -55,3 +55,37 @@ NICE::VectorT<double> eigenvals = NICE::eigenvalues(matrix);
 NICE::VectorT<double> my_own_vector(3);
 NICE::eigenvalues(matrix, my_own_vector);
 ```
+
+## Running the sample
+
+_Command line:_
+
+```bash
+./05_matio ../../nice-core/core/tutorial/samples/simple.mat MyMatrix
+```
+
+_Output:_
+
+```
+Loading matrix "MyMatrix"...
+Dimensions: 4 x 4
+1       2       3       4
+4       5       6       7
+2       3       4       5
+2       9       8       1
+Vt:
+-0.266556       -0.584949       -0.621772       -0.447418
+-0.188645       0.497147        0.204551        -0.821837
+0.925622        0.0646203       -0.282292       -0.243639
+-0.191273       0.637577        -0.701334       0.255031
+U:
+-0.285172       -0.294773       -0.738967       -0.534522
+-0.607906       -0.440949       0.603809        -0.267261
+-0.39275        -0.343498       -0.291375       0.801784
+-0.62839        0.775037        -0.0666614      -1.08901e-16
+S:
+17.8539 0       0       0
+0       6.33725 0       0
+0       0       1.03735 0
+0       0       0       2.17065e-16
+```

+ 161 - 0
core/tutorial/doc/07_optimization.md

@@ -0,0 +1,161 @@
+# Tutorial 07 - Optimization Problems
+NICE can solve different kinds of optimization problems using different
+algorithms in a modular fashion.
+
+Some standard problems are already defined in NICE-core, including:
+* Solving linear systems
+* Approximating bilinear products
+
+See the relevant doxygen documentation for more information on these.
+
+This tutorial will show you how to implement your own, non-standard
+optimization problems in a way that is compatible with NICE.
+
+The sample problem is a simple one: find the minimum of the quadratic
+function _f(x)=ax^2 +bx+c_.
+The values are read from the command line.
+
+We start by implementing the problem as a subclass of
+_OptimizationProblemFirst_.
+The "first" stands for first-order, meaning that the objective function is
+differentiable.
+
+The class provides us with helper functions and manages the state of the
+optimization.
+The member variable __parameters__ holds the current position in parameter
+space.
+
+Two functions must be implemented: __computeObjective__ and
+__computeGradient__.
+There also has to be a constructor that explicitly calls the
+_OptimizationProblemFirst_ constructor because it needs to know the
+dimensionality of the problem.
+
+## Includes
+The sample program needs some STL includes for I/O and to convert the command
+line parameters to floating-point values.
+We use the integrated _FirstOrderRasmussen_ solver in this example:
+
+```c++
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <core/vector/VectorT.h>
+#include <core/optimization/gradientBased/OptimizationProblemFirst.h>
+#include <core/optimization/gradientBased/FirstOrderRasmussen.h>
+```
+
+## The _QuadraticOptimizationProblem_ class
+Our _QuadraticOptimizationProblem_ class has member variables for each of the
+parameters. Everything else is managed by the base class.
+
+The constructor initializes the member variables and class the base constructor
+with the parameter "1", because this is a one-dimensional problem.
+
+```c++
+class QuadraticOptimizationProblem : public NICE::OptimizationProblemFirst {
+private:
+	double a, b, c;
+
+public:
+	QuadraticOptimizationProblem(double a, double b, double c) :
+		OptimizationProblemFirst(1),
+		a(a), b(b), c(c) { }
+```
+
+Because we want to find the minimum of the quadratic function f(x), the
+objective function is the same.
+The __parameters__ function returs the current state (position) of the
+optimization process.
+
+```c++
+double computeObjective() {
+	double x = parameters()(0);	
+	return a * x * x + b * x + c;
+}
+```
+
+The gradient function is just as simple.
+It gets called with a const reference to a _Vector_ that matches the
+dimensionality of the problem.
+We write the value of the derivative f'(x) = 2ax+b into the _Vector_:
+
+```c++
+void computeGradient(NICE::Vector& newGradient) {
+	double x = parameters()(0);	
+	double dx_dy = 2.0 * a * x + b;
+	newGradient(0) = dx_dy;
+}
+```
+
+## The program
+First, a small utility function to convert the command line arguments:
+
+```c++
+double convert_param(const std::string& s) {
+	double r;
+	if(!(std::istringstream(s) >> r)) {
+		return 0;
+	}
+	return r;
+}
+```
+
+Now, the main function.
+We start by counting the argmuments and converting them if there are enough
+of them.
+They are the displayed for verification:
+
+```c++
+int main(int argc, char** argv) {
+	// Check if enough parameters were supplied
+	if (argc < 4) {
+		std::cout << "USAGE: " << argv[0] << " <a> <b> <c>\n";
+		return -1;
+	}
+
+	// Convert the arguments
+	double param_a = convert_param(argv[1]);
+	double param_b = convert_param(argv[2]);
+	double param_c = convert_param(argv[3]);
+	std::cout << "Optimizing function f(x) = " << param_a << " x^2 + ";
+	std::cout << param_b << " x + " << param_c << "\n";
+```
+
+Solving the problem is very simple and done in three lines:
+
+```c++
+QuadraticOptimizationProblem problem(param_a, param_b, param_c);
+NICE::FirstOrderRasmussen solver;
+solver.optimizeFirst(problem);
+```
+
+The solution is part of the problem's state and can be accessed by calling the
+__position__ method:
+
+```c++
+double x_min = problem.position()(0);
+std::cout << "Solution: " << x_min << "\n";
+```
+
+## Running the sample
+
+_Command line:_
+
+```bash
+./06_optimization 4.3 5 2.3
+```
+
+_Output:_
+
+```
+Optimizing function f(x) = 4.3 x^2 + 5 x + 2.3
+FirstOrderRasmussen: initial value of the objective function is 2.3
+Iteration 1 / 100  objective function = 2.3
+FirstOrderRasmussen: new objective value 0.846598
+Iteration 3 / 100  objective function = 0.846598
+FirstOrderRasmussen: new objective value 0.846512
+Iteration 7 / 100  objective function = 0.846512
+FirstOrderRasmussen: low gradient 7.72715e-14 < 1e-05 = epsilonG
+Solution: -0.581395
+```

+ 2 - 1
core/tutorial/doc/samples.md

@@ -8,7 +8,8 @@ The following sample programs are available:
 | 02 | Program that optimizes the contrast of a grayscale image|
 | 03 | Program that colorizes a grayscale image using pseudocolors|
 | 04 | Program that applies a motion blur effect to an image using a linear filter|
-| 05 | Program that loads a Matlab file to showcase algebra functions|
+| 05 / 06 | Program that loads a Matlab file to showcase algebra functions|
+| 07 | Program that minimizes a given quadratic function |
 
 # Sample images for sample code
 NICE-core supports PPM and PGM images out of the box without any additional

+ 80 - 0
core/tutorial/progs/06_optimization.cpp

@@ -0,0 +1,80 @@
+/*
+ * Tutorial 07 - Optimization Problmes
+ * Sample Implementation
+ *
+ * @file 06_optimization.cpp
+ * @brief Sample implementation for tutorial 07
+ * @date 28.04.2014
+ * @author Clemens-A. Brust
+ */
+
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <core/vector/VectorT.h>
+#include <core/optimization/gradientBased/OptimizationProblemFirst.h>
+#include <core/optimization/gradientBased/FirstOrderRasmussen.h>
+
+class QuadraticOptimizationProblem : public NICE::OptimizationProblemFirst {
+private:
+	double a, b, c;
+
+public:
+	QuadraticOptimizationProblem(double a, double b, double c) :
+		OptimizationProblemFirst(1),
+		a(a), b(b), c(c) { }
+
+	double computeObjective() {
+		double x = parameters()(0);	
+		return a * x * x + b * x + c;
+	}
+	
+	void computeGradient(NICE::Vector& newGradient) {
+		double x = parameters()(0);	
+		double dx_dy = 2.0 * a * x + b;
+		newGradient(0) = dx_dy;
+	}
+};
+
+
+/*
+ * Parameter conversion
+ */
+double convert_param(const std::string& s) {
+	double r;
+	if(!(std::istringstream(s) >> r)) {
+		return 0;
+	}
+	return r;
+}
+
+
+/*
+ * Entry point
+ */
+int main(int argc, char** argv) {
+	// Check if enough parameters were supplied
+	if (argc < 4) {
+		std::cout << "USAGE: " << argv[0] << " <a> <b> <c>\n";
+		return -1;
+	}
+
+	// Convert the arguments
+	double param_a = convert_param(argv[1]);
+	double param_b = convert_param(argv[2]);
+	double param_c = convert_param(argv[3]);
+	
+	std::cout << "Optimizing function f(x) = " << param_a << " x^2 + ";
+	std::cout << param_b << " x + " << param_c << "\n";
+
+	// Instantiate and solve the problem
+	QuadraticOptimizationProblem problem(param_a, param_b, param_c);
+	NICE::FirstOrderRasmussen solver;
+	solver.optimizeFirst(problem);
+
+	// Display the solution
+	double x_min = problem.position()(0);
+	std::cout << "Solution: " << x_min << "\n";
+
+	return 0;
+}