* apps/camera-process/process.cc (process): Here.
(min_rgb_comp): New functor.
* apps/camera-process/camprocess.cc: Set the size of the captured
image to 640x480 pixels.
---
milena/ChangeLog | 9 +++
milena/apps/camera-process/camprocess.cc | 4 +
milena/apps/camera-process/process.cc | 105 ++++++++++++++++++++++--------
3 files changed, 90 insertions(+), 28 deletions(-)
diff --git a/milena/ChangeLog b/milena/ChangeLog
index 77113b3..14b8ce1 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,3 +1,12 @@
+2012-09-27 Roland Levillain <roland(a)lrde.epita.fr>
+
+ Make apps/camera-process/process detect large, white objects.
+
+ * apps/camera-process/process.cc (process): Here.
+ (min_rgb_comp): New functor.
+ * apps/camera-process/camprocess.cc: Set the size of the captured
+ image to 640x480 pixels.
+
2012-09-25 Roland Levillain <roland(a)lrde.epita.fr>
New app: camera stream processing (using OpenCV for capture).
diff --git a/milena/apps/camera-process/camprocess.cc
b/milena/apps/camera-process/camprocess.cc
index 2a10fa6..f815d72 100644
--- a/milena/apps/camera-process/camprocess.cc
+++ b/milena/apps/camera-process/camprocess.cc
@@ -51,6 +51,10 @@ int main()
exit(1);
}
+ // Set the size of the captured image.
+ cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, 640);
+ cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, 480);
+
// Create a GUI window.
cvNamedWindow("Window", CV_WINDOW_AUTOSIZE);
diff --git a/milena/apps/camera-process/process.cc
b/milena/apps/camera-process/process.cc
index 8cf2446..d76405f 100644
--- a/milena/apps/camera-process/process.cc
+++ b/milena/apps/camera-process/process.cc
@@ -26,13 +26,43 @@
#include <mln/core/image/image2d.hh>
#include <mln/opt/at.hh>
+#include <mln/core/image/vmorph/fun_image.hh>
+#include <mln/core/image/dmorph/image_if.hh>
+
#include <mln/value/int_u8.hh>
#include <mln/value/rgb8.hh>
-#include <mln/fun/v2v/rgb_to_int_u.hh>
+#include <mln/literal/colors.hh>
+#include <mln/literal/black.hh>
+#include <mln/literal/white.hh>
+
+#include <mln/math/min.hh>
+
+#include <mln/pw/all.hh>
+
+#include <mln/core/alias/neighb2d.hh>
+#include <mln/core/alias/window2d.hh>
+
+#include <mln/morpho/dilation.hh>
+#include <mln/morpho/gradient.hh>
+#include <mln/morpho/opening/area.hh>
#include "process.hh"
+// FIXME: Move this into the library.
+/// Functor returning the minimal component of an mln::value::rgb<n> value.
+template <unsigned n>
+struct min_rgb_comp : mln::Function_v2v< min_rgb_comp<n> >
+{
+ typedef mln::value::int_u<n> result;
+
+ result operator()(const mln::value::rgb<n>& c) const
+ {
+ return mln::math::min(mln::math::min(c.red(), c.green()), c.blue());
+ }
+};
+
+
/* FIXME: Hide OpenCV-Milena conversion operations; or better, wrap
the `Iplimage' data structure in a Milena image so that it can be
processed directly. */
@@ -40,32 +70,51 @@
void process(IplImage* cv_ima)
{
using namespace mln;
+ using mln::value::int_u8;
+ using mln::value::rgb8;
+
+ char* data = cv_ima->imageData;
+ int height = cv_ima->height;
+ int width = cv_ima->width;
+ int widthstep = cv_ima->widthStep;
+ int nchannels = cv_ima->nChannels;
+
+ // Convert `cv_ima' into a Milena image.
+ image2d<rgb8> mln_ima(height, width);
+ for (int row = 0; row < height; ++row)
+ for (int col = 0; col < width; ++col)
+ for (int chan = 0; chan < nchannels; ++chan)
+ opt::at(mln_ima, row, col).comp(chan) =
+ (unsigned char) data[row * widthstep + col * nchannels + chan];
+
+ // Detect white objects having a minimal area.
+ image2d<bool> bin;
+ initialize(bin, mln_ima);
+ data::fill(bin, false);
+ int_u8 threshold = 160;
+ data::fill((bin | (pw::value(min_rgb_comp<8>() << mln_ima)
+ >= pw::cst(threshold))).rw(),
+ true);
+ // For a lack of a better characterization.
+ unsigned area = 15000;
+ image2d<bool> objects = morpho::opening::area(bin, c4(), area);
+ // Find contours.
+ image2d<bool> outline = morpho::gradient_external(objects, win_c4p());
+ // Enlarge them.
+ image2d<bool> contours = morpho::dilation(outline, win_c4p());
+
+ // Alter the original OpenCV image `cv_ima'.
+ for (int row = 0; row < height; ++row)
+ for (int col = 0; col < width; ++col)
+ if (char(opt::at(contours, row, col)))
+ {
+ /* Paint the pixel in red.
- // Convert `cv_ima' into a Milena image...
- image2d<value::rgb8> mln_ima(cv_ima->height, cv_ima->width);
- for (int row = 0; row < cv_ima->height; ++row)
- for (int col = 0; col < cv_ima->width; ++col)
- for (int chan = 0; chan < cv_ima->nChannels; ++chan)
- {
- opt::at(mln_ima, row, col).comp(chan) =
- (unsigned char) cv_ima->imageData[row * cv_ima->widthStep
- + col * cv_ima->nChannels
- + chan];
- }
-
- // ...do something with it...
- mln_piter_(image2d<value::rgb8>) p(mln_ima.domain());
- for_all(p)
- convert::from_to(fun::v2v::rgb_to_int_u<8>()(mln_ima(p)), mln_ima(p));
-
- // ...and paste `mln_ima' back into the OpenCV image `cv_ima'.
- for (int row = 0; row < cv_ima->height; ++row)
- for (int col = 0; col < cv_ima->width; ++col)
- for (int chan = 0; chan < cv_ima->nChannels; ++chan)
- {
- cv_ima->imageData[row * cv_ima->widthStep
- + col * cv_ima->nChannels
- + chan] =
- (char) opt::at(mln_ima, row, col).comp(chan);
- }
+ In the initial test environment, the frame was encoded
+ as a BGR image. */
+ int pos = row * widthstep + col * nchannels;
+ data[pos + 0] = mln_min(int_u8); // Channel 0: Blue.
+ data[pos + 1] = mln_min(int_u8); // Channel 1: Green.
+ data[pos + 2] = mln_max(int_u8); // Channel 2: Red.
+ }
}
--
1.7.2.5