segenerator.cpp

00001 
00002 /***************************************************************************
00003  *  segenerator.cpp - Class that helps to create some standard structuring
00004  *                    elements
00005  *
00006  *  Created: Wed Jun 07 11:23:03 2006
00007  *  Copyright  2005-2007  Tim Niemueller [www.niemueller.de]
00008  *
00009  ****************************************************************************/
00010 
00011 /*  This program is free software; you can redistribute it and/or modify
00012  *  it under the terms of the GNU General Public License as published by
00013  *  the Free Software Foundation; either version 2 of the License, or
00014  *  (at your option) any later version. A runtime exception applies to
00015  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00016  *
00017  *  This program is distributed in the hope that it will be useful,
00018  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020  *  GNU Library General Public License for more details.
00021  *
00022  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00023  */
00024 
00025 #include <filters/morphology/segenerator.h>
00026 
00027 #include <utils/math/angle.h>
00028 
00029 #include <fvutils/draw/drawer.h>
00030 #include <fvutils/color/colorspaces.h>
00031 #include <fvutils/writers/png.h>
00032 #include <fvutils/writers/fvraw.h>
00033 
00034 #include <cstdlib>
00035 #include <cstring>
00036 
00037 namespace firevision {
00038 #if 0 /* just to make Emacs auto-indent happy */
00039 }
00040 #endif
00041 
00042 /** @class SEGenerator <filters/morphology/segenerator.h>
00043  * Basic generators for structuring elements for morphological filters.
00044  * @author Tim Niemueller
00045  */
00046 
00047 
00048 /** Generate linear structuring element.
00049  * @param width width of structuring element
00050  * @param height height of structuring element
00051  * @param proposed_center_x contains the proposed x coordinate of the anchor
00052  * upon return
00053  * @param proposed_center_y contains the proposed y coordinate of the anchor
00054  * upon return
00055  * @param slope_angle_rad the slope of the line in radians
00056  * @return buffer with linear structuring element. The buffer has been allocated
00057  * using malloc(). Use free() to free the memory after you are done with it.
00058  */
00059 unsigned char *
00060 SEGenerator::linear(unsigned int width, unsigned int height,
00061                     unsigned int *proposed_center_x, unsigned int *proposed_center_y,
00062                     float slope_angle_rad)
00063 {
00064 
00065   // we always start at (0,0) and then calculate the corrensponding
00066   // y of the linear functional
00067   // l: x -> mx + b, where b is 0.
00068   // by tan(slope_angle_rad) = y / x
00069   // => y = x * tan(slope_angle_rad)    with x = width
00070 
00071   if ( height == 0 ) return NULL;
00072   if ( width == 0) return NULL;
00073 
00074   
00075   unsigned char *tmp = (unsigned char *)malloc(colorspace_buffer_size(YUV422_PLANAR, width, height));
00076   memset(tmp, 0, colorspace_buffer_size(YUV422_PLANAR, width, height));
00077   Drawer *d = new Drawer();
00078   d->set_buffer(tmp, width, height);
00079   d->set_color(1, 0, 0);
00080 
00081   float a = fawkes::normalize_mirror_rad( slope_angle_rad );
00082 
00083   if ( (a == M_PI/2) || (a == -M_PI/2) ) {
00084     // It's just a vertical line
00085     // std::cout << "Drawing line from (0,0) -> (0," << height - 1 << ")" << std::endl;
00086     d->draw_line(0, 0, 0, height - 1);
00087   } else {
00088 
00089     // sectors 3 and 4 can be converted to sector 2 and 1 lines
00090     if ( a > M_PI / 2)    a -= M_PI;
00091     if ( a < - M_PI / 2)  a += M_PI;
00092 
00093     int y = (int)roundf(((float)width - 1.f) * tan( a ));
00094 
00095     if ( y < 0) {
00096       // std::cout << "Drawing line from (0,0) -> (" << width - 1 << "," << -y << ")" << std::endl;
00097       d->draw_line( 0, 0, width - 1, -y );
00098     } else {
00099       // std::cout << "Drawing line from (0," << y << ") -> (" << width - 1 << ",0)" << std::endl;
00100       d->draw_line( 0, y, width - 1, 0 );
00101     }
00102   }
00103 
00104   delete d;
00105 
00106   unsigned char *se = (unsigned char *)malloc(width * height);
00107   memcpy(se, tmp, width * height);
00108 
00109   PNGWriter *png = new PNGWriter();
00110   png->set_dimensions( width, height );
00111   png->set_buffer(YUV422_PLANAR, tmp);
00112   png->set_filename("se_test.png");
00113   png->write();
00114   delete png;
00115 
00116   FvRawWriter *fvraw = new FvRawWriter("se_test.raw", width, height, YUV422_PLANAR, tmp);
00117   fvraw->write();
00118   delete fvraw;
00119 
00120   free( tmp );
00121 
00122   if ( (proposed_center_x != NULL) && (proposed_center_y != NULL) ) {
00123     unsigned int min_x = width;
00124     unsigned int max_x = 0;
00125     unsigned int min_y = height;
00126     unsigned int max_y = 0;
00127     for (unsigned int h = 0; h < height; ++h) {
00128       for (unsigned int w = 0; w < width; ++w) {
00129         if ( se[ h * width + w ] != 0 ) {
00130           if ( w < min_x ) min_x = w;
00131           if ( w > max_x ) max_x = w;
00132           if ( h < min_y ) min_y = h;
00133           if ( h > max_y ) max_y = h;
00134         }
00135       }
00136     }
00137 
00138     *proposed_center_x = min_x + (max_x - min_x) / 2;
00139     *proposed_center_y = min_y + (max_y - min_y) / 2;
00140   }
00141 
00142   return se;
00143 }
00144 
00145 
00146 /** Generate square structuring element.
00147  * @param width width of structuring element
00148  * @param height height of structuring element
00149  * @return buffer with square structuring element. The buffer has been allocated
00150  * using malloc(). Use free() to free the memory after you are done with it.
00151  */
00152 unsigned char *
00153 SEGenerator::square(unsigned int width, unsigned int height)
00154 {
00155   unsigned char *se = (unsigned char *)malloc(width * height);
00156   memset(se, 1, width * height);
00157   return se;
00158 }
00159 
00160 
00161 /** Draw structuring element.
00162  * This draws the structuring element to an image buffer.
00163  * @param yuv422planar_buffer image buffer
00164  * @param mask structuring element
00165  * @param width width of structuring element
00166  * @param height height of structuring element
00167  */
00168 void
00169 SEGenerator::drawSE(unsigned char *yuv422planar_buffer, unsigned char *mask, unsigned int width, unsigned int height)
00170 {
00171   memset(yuv422planar_buffer, 128, colorspace_buffer_size(YUV422_PLANAR, width, height) );
00172   for (unsigned int h = 0; h < height; ++h) {
00173     for (unsigned int w = 0; w < width; ++w) {
00174       if ( mask[ h * width + w ] != 0 ) {
00175         yuv422planar_buffer[ h * width + w ] = 255;
00176       }
00177     }
00178   }
00179 }
00180 
00181 
00182 /** Draw structuring element.
00183  * This draws the structuring element to a b/w image buffer.
00184  * @param yuv422planar_buffer image buffer
00185  * @param mask structuring element
00186  * @param width width of structuring element
00187  * @param height height of structuring element
00188  */
00189 void
00190 SEGenerator::drawSEbw(unsigned char *yuv422planar_buffer, unsigned char *mask, unsigned int width, unsigned int height)
00191 {
00192   memset(yuv422planar_buffer, 128, colorspace_buffer_size(YUV422_PLANAR, width, height) );
00193   memset(yuv422planar_buffer, 255, width * height );
00194   for (unsigned int h = 0; h < height; ++h) {
00195     for (unsigned int w = 0; w < width; ++w) {
00196       if ( mask[ h * width + w ] != 0 ) {
00197         yuv422planar_buffer[ h * width + w ] = 0;
00198       }
00199     }
00200   }
00201 }
00202 
00203 } // end namespace firevision