imageprocessors.h

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2005 by Robot Group Leipzig                             *
00003  *    martius@informatik.uni-leipzig.de                                    *
00004  *    der@informatik.uni-leipzig.de                                        *
00005  *                                                                         *
00006  *   This program is free software; you can redistribute it and/or modify  *
00007  *   it under the terms of the GNU General Public License as published by  *
00008  *   the Free Software Foundation; either version 2 of the License, or     *
00009  *   (at your option) any later version.                                   *
00010  *                                                                         *
00011  *   This program is distributed in the hope that it will be useful,       *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00014  *   GNU General Public License for more details.                          *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU General Public License     *
00017  *   along with this program; if not, write to the                         *
00018  *   Free Software Foundation, Inc.,                                       *
00019  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00020  *                                                                         *
00021  *   DESCRIPTION                                                           *
00022  *   A collection of simple image processing filters/processors            *
00023  *   that can be plugged into a camera                                     *
00024  *
00025  *******************************************`********************************/
00026 #ifndef __IMAGEPROCESSORS
00027 #define __IMAGEPROCESSORS
00028 
00029 #include "imageprocessor.h"
00030 
00031 #include <selforg/stl_adds.h>
00032 
00033 #define MIN3(x,y,z) x<y ? (x<z ? x : z) : (y<z ? y : z)
00034 #define MAX3(x,y,z) x>y ? (x>z ? x : z) : (y>z ? y : z)
00035 
00036 namespace lpzrobots {
00037 
00038   /** Standard image processor - convenience class for 1 to 1 image processing. 
00039       The last image of the stack is the source (output of last processor).
00040       Simpler to implement than ImageProcessor.
00041       @param show whether do display the resulting image on the screen
00042       @param scale how to scale the display
00043       @see ImageProcessor
00044    */
00045   struct StdImageProcessor : public ImageProcessor {
00046     StdImageProcessor(bool show, float scale) {
00047       _dest.show  = show;
00048       _dest.scale = scale;
00049     };
00050     virtual ~StdImageProcessor() {
00051     };
00052 
00053     /// overload this function and initialise the dest.img and the dest.name 
00054     virtual void initDestImage(Camera::CameraImage& dest, const Camera::CameraImage& src) = 0;
00055     
00056     /// overload this function and do processing here
00057     virtual void process(const osg::Image* src, osg::Image* dest) = 0;
00058 
00059     /*   substituded generic interface */
00060     virtual Camera::CameraImage init(const Camera::CameraImages& imgs){
00061       assert(imgs.size()>0);
00062       _src = imgs.back();
00063       // printf("source picture: %s, %i x %i\n",src.name.c_str(), src.img->s(), src.img->t());
00064       _dest.img = new osg::Image;
00065       initDestImage(_dest, _src);
00066       return _dest;
00067     }
00068         
00069     virtual void process(){
00070       process(_src.img, _dest.img);
00071       _dest.img->dirty();         
00072     }
00073     
00074   protected:
00075     Camera::CameraImage _dest;
00076     Camera::CameraImage _src;    
00077   };
00078 
00079 
00080 
00081   /// black and white image @see StdImageProcessor
00082   struct BWImageProcessor : public StdImageProcessor {
00083     enum ChannelMask {Red = 1, Green = 2, Blue = 4, Hue = 1, Saturation = 2, Value = 4};
00084 
00085     /// @param channelmask which channels to consider, @see BWImageProcessor::ChannelMask
00086     BWImageProcessor(bool show, float scale, char channelmask = 7)
00087       : StdImageProcessor(show,scale), channelmask(channelmask) {}    
00088 
00089     virtual ~BWImageProcessor() {}
00090     
00091     virtual void initDestImage(Camera::CameraImage& dest, const Camera::CameraImage& src){
00092       dest.img->allocateImage(src.img->s(), src.img->t(), 1, GL_LUMINANCE, GL_UNSIGNED_BYTE);    
00093       dest.name  = "bw(" + src.name + ")"; 
00094       red   = (channelmask & 1);
00095       green = (channelmask & 2);
00096       blue  = (channelmask & 4);
00097       numchannels = red+green+blue;
00098       printf("BWImageProcessor: Select: Red %i, Green %i, Blue %i : numchannels %i\n", 
00099              red, green, blue,numchannels);
00100       if(numchannels==0) numchannels=1; // avoid division by 0
00101     }
00102     
00103     virtual void process(const osg::Image* src, osg::Image* dest){      
00104       assert(src && src->getPixelFormat()==GL_RGB && src->getDataType()==GL_UNSIGNED_BYTE);
00105       for(int r=0; r < src->t(); ++r) {
00106         const unsigned char* sdata = src->data(0, r);
00107         unsigned char* ddata = dest->data(0, r);
00108         for(int c=0; c < src->s(); ++c) {
00109           (*ddata) =  (*(sdata)*red + *(sdata+1)*green + *(sdata+2)*blue)/numchannels;
00110           sdata+=3;
00111           ddata++;
00112         }
00113       }
00114     }
00115     bool red, green, blue;
00116     char numchannels;
00117     char channelmask;
00118   };
00119 
00120   /** converts the image to a HSV coded image @see StdImageProcessor.
00121       If this image is shown the h,s,v is displayed by r,g,b!
00122       The h (hue) values are @see HSVColors
00123   */
00124 
00125   struct HSVImgProc : public StdImageProcessor {
00126     enum Colors {Red=0, Yellow=30, Green=60, Cyan=90, 
00127                  Blue=120, Magenta=150, Red2=180, Gray=255, Span=30};
00128 
00129     HSVImgProc(bool show, float scale)
00130       : StdImageProcessor(show,scale) {
00131     }
00132 
00133     virtual ~HSVImgProc() {}
00134     
00135     virtual void initDestImage(Camera::CameraImage& dest, const Camera::CameraImage& src){
00136       dest.img->allocateImage(src.img->s(), src.img->t(), 1, GL_RGB, GL_UNSIGNED_BYTE);    
00137       dest.name  = "hsv(" + src.name + ")";
00138     }
00139     
00140     virtual void process(const osg::Image* src, osg::Image* dest){      
00141       assert(src && src->getPixelFormat()==GL_RGB && src->getDataType()==GL_UNSIGNED_BYTE);
00142       for(int r=0; r < src->t(); ++r) {
00143         const unsigned char* sdata = src->data(0, r);
00144         unsigned char* ddata = dest->data(0, r);
00145         for(int c=0; c < src->s(); ++c) {
00146           RGBtoHSV(*(sdata),*(sdata+1),*(sdata+2),
00147                    (*ddata), *(ddata+1), *(ddata+2));
00148           sdata+=3;
00149           ddata+=3;
00150         }
00151       }
00152     }
00153 
00154     /** converts RGB to HSV color model;
00155         r,g,b values are from 0 to 255;
00156         h = [0,180]+255, s = [0,255], v = [0,255];
00157         h is the standard hue value/2 (since 360 cannot be represented) 
00158         and 255 if undefined (gray)
00159     */
00160     void RGBtoHSV( unsigned char r, unsigned char g, unsigned char b, 
00161                    unsigned char& h, unsigned char& s, unsigned char& v ) {
00162       unsigned char min, max;
00163       float delta;
00164       float hue;
00165       min = MIN3( r, g, b );
00166       max = MAX3( r, g, b );
00167       v = max;                               // v
00168       delta = max - min;
00169       if( max != 0 ){
00170         s = 255.0*delta / max;               // s
00171       }
00172       if( max == 0 || delta == 0){
00173         // r = g = b                         // s = 0, h is undefined
00174         s = 0;        
00175         h = 255;
00176         return;
00177       }
00178 
00179       if( r == max )
00180         hue = float( g - b ) / delta;        // between yellow & magenta
00181       else if( g == max )
00182         hue = 2.0 + float( b - r ) / delta;     // between cyan & yellow
00183       else
00184         hue = 4.0 + float( r - g ) / delta;     // between magenta & cyan
00185       hue *=30; // this is 60 in full range 
00186       if( hue < 0 )
00187         hue += 180;
00188       h = int(hue);
00189     }
00190   };
00191 
00192 
00193   /** filters for a specific color (requires HSV, so use HSVImgProc before) 
00194       @param minhue minimal hue value to pass through @see HSVImgProc::Colors
00195       @param maxhue maximal hue value to pass through @see HSVImgProc::Colors
00196       @param satThreshold minimal saturation required to be considered as a color
00197       @param valThreshold minimal "value" required to be considered as a color
00198       @see HSVImgProc
00199       @see StdImageProcessor
00200   */
00201   struct ColorFilterImgProc : public StdImageProcessor {
00202     ColorFilterImgProc(bool show, float scale, int minhue, int maxhue, 
00203                        int sat_threshold=100, int val_threshold=50)
00204       : StdImageProcessor(show,scale), 
00205         minhue(minhue), maxhue(maxhue), sat_threshold(sat_threshold), val_threshold(val_threshold) {
00206     }
00207     
00208     virtual ~ColorFilterImgProc() {}
00209     
00210     virtual void initDestImage(Camera::CameraImage& dest, const Camera::CameraImage& src){
00211       dest.img->allocateImage(src.img->s(), src.img->t(), 1, GL_LUMINANCE, GL_UNSIGNED_BYTE);    
00212           //      dest.img->allocateImage(16, 1, 1, GL_LUMINANCE, GL_UNSIGNED_BYTE);    
00213       dest.name  = "spots(" + src.name + ")"; 
00214     }
00215     
00216     virtual void process(const osg::Image* src, osg::Image* dest){      
00217       // actually we need HSV but there is no coding for it
00218       assert(src && src->getPixelFormat()==GL_RGB && src->getDataType()==GL_UNSIGNED_BYTE);
00219       for(int r=0; r < src->t(); ++r) {
00220         const unsigned char* sdata = src->data(0, r);
00221         unsigned char* ddata = dest->data(0, r);
00222         for(int c=0; c < src->s(); ++c) {
00223           if(*(sdata) >= minhue && *(sdata) < maxhue 
00224              && *(sdata+1) > sat_threshold && *(sdata+2) > val_threshold){
00225             (*ddata) = *(sdata+2);
00226           } else{
00227             (*ddata) = 0;
00228           }
00229           sdata+=3;
00230           ddata++;
00231         }
00232       }
00233     }
00234     int minhue;
00235     int maxhue;
00236     int sat_threshold;
00237     int val_threshold;
00238   };
00239 
00240 
00241 
00242   /** creates a lightsensitive sensorline. It requires a black and white source, 
00243       e.g. provided by BWImageProcessor, ColorFilterImgProc
00244       @param num number of segments of the sensor line
00245       @param factor factor for average pixel value (rescaling)
00246       @see StdImageProcessor
00247   */
00248   struct LineImgProc : public StdImageProcessor {
00249     LineImgProc(bool show, float scale, int num, double factor = 20.0)
00250       : StdImageProcessor(show,scale), num(num), factor(factor) {
00251     }
00252     
00253     virtual ~LineImgProc() {}
00254     
00255     virtual void initDestImage(Camera::CameraImage& dest, const Camera::CameraImage& src){
00256       dest.img->allocateImage(num, 1, 1, GL_LUMINANCE, GL_UNSIGNED_BYTE);    
00257       dest.name  = "line(" + src.name + ")"; 
00258     }
00259     
00260     virtual void process(const osg::Image* src, osg::Image* dest){      
00261       // actually we need HSV but there is no coding for it
00262       assert(src && src->getPixelFormat()==GL_LUMINANCE  && src->getDataType()==GL_UNSIGNED_BYTE);
00263 
00264       int w = src->s();
00265       int h = src->t();
00266       int size = w/num; // size of one segment
00267       int numpixel_per_segm = size*h;
00268       int segmentvalue;
00269       unsigned char* destdata = dest->data();
00270       for(int k=0; k<num; k++){
00271         int sum = 0;
00272         for(int j=0; j<h; j++){
00273           const unsigned char* pixel = src->data(k*size, j);
00274           for(int i=0; i< size; i++){
00275             sum += *pixel;
00276             pixel++;
00277           }
00278         }
00279         segmentvalue = (double)sum*factor/(double)numpixel_per_segm; 
00280         destdata[k] = std::min(segmentvalue,255);
00281       }      
00282     }
00283     int num;
00284     double factor;
00285   };
00286 
00287   /** time average of image @see StdImageProcessor.
00288   */
00289 
00290   struct AvgImgProc : public StdImageProcessor {
00291 
00292     /// @param time length of averageing (time=1: no averaging)
00293     AvgImgProc(bool show, float scale, int time)
00294       : StdImageProcessor(show,scale), time(time) {
00295       if(time<1) time =1;
00296       factor = 1.0/(float)time;
00297     }
00298 
00299     virtual ~AvgImgProc() {}
00300     
00301     virtual void initDestImage(Camera::CameraImage& dest, const Camera::CameraImage& src){
00302       assert(src.img && src.img->getDataType()==GL_UNSIGNED_BYTE);
00303       dest.img->allocateImage(src.img->s(), src.img->t(), 1, src.img->getPixelFormat(), 
00304                               GL_UNSIGNED_BYTE);    
00305       dest.name  = "avg(" + std::itos(time) +  "," + src.name + ")";
00306     }
00307     
00308     virtual void process(const osg::Image* src, osg::Image* dest){            
00309       for(int r=0; r < src->t(); ++r) {
00310         const unsigned char* sdata = src->data(0, r);
00311         unsigned char* ddata = dest->data(0, r);
00312         for(unsigned int c=0; c < src->getRowSizeInBytes(); ++c) {
00313           *ddata =  ((float)*sdata)*factor + ((float)*ddata)*(1-factor);
00314           sdata++;
00315           ddata++;
00316         }
00317       }
00318     }
00319     
00320     int time; 
00321     float factor;
00322   };
00323 
00324       
00325 //   /** Testing code
00326 //   */
00327 //   struct TestLineImgProc : public StdImageProcessor {
00328 //     TestLineImgProc(bool show, float scale, int num)
00329 //       : StdImageProcessor(show,scale), num(num) {
00330 //     }
00331     
00332 //     virtual ~TestLineImgProc() {}
00333     
00334 //     virtual void initDestImage(Camera::CameraImage& dest, const Camera::CameraImage& src){
00335 //       dest.img->allocateImage(src.img->s(), src.img->t(), 1, GL_LUMINANCE, GL_UNSIGNED_BYTE);    
00336 //       dest.name  = "testline(" + src.name + ")"; 
00337 //     }
00338     
00339 //     virtual void process(const osg::Image* src, osg::Image* dest){      
00340 //       // actually we need HSV but there is no coding for it
00341 //       assert(src && src->getPixelFormat()==GL_LUMINANCE  && src->getDataType()==GL_UNSIGNED_BYTE);
00342 
00343 //       int w = src->s();
00344 //       int h = src->t();
00345 //       int size = w/num; // size of one segment
00346 //       int numpixel_per_segm = size*h;
00347 //       for(int k=0; k<num; k++){
00348 //         int sum = 0;
00349 //         for(int j=0; j<h; j++){
00350 //           const unsigned char* pixel = src->data(k*size, j);
00351 //           unsigned char* destdata = dest->data(k*size, j);
00352 //           for(int i=0; i< size; i++){
00353 //             *destdata= (k*111+*pixel)%256;
00354 //             pixel++;
00355 //             destdata++;
00356 //           }
00357 //         }
00358 //       }      
00359 //     }
00360 //     int num;
00361 //   };
00362 
00363 
00364 
00365 
00366 }
00367 
00368 #endif
Generated on Fri Nov 4 10:59:38 2011 for Robot Simulator of the Robotics Group for Self-Organization of Control by  doxygen 1.6.3