Fawkes API  Fawkes Development Version
sobel.cpp
00001 
00002 /***************************************************************************
00003  *  sobel.cpp - Implementation of a Sobel filter
00004  *
00005  *  Created: Thu May 12 13:20:43 2005
00006  *  Copyright  2005-2012  Tim Niemueller [www.niemueller.de]
00007  ****************************************************************************/
00008 
00009 /*  This program is free software; you can redistribute it and/or modify
00010  *  it under the terms of the GNU General Public License as published by
00011  *  the Free Software Foundation; either version 2 of the License, or
00012  *  (at your option) any later version. A runtime exception applies to
00013  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00014  *
00015  *  This program is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU Library General Public License for more details.
00019  *
00020  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00021  */
00022 
00023 #include <fvfilters/sobel.h>
00024 
00025 #include <core/exception.h>
00026 
00027 #ifdef HAVE_IPP
00028 #  include <ippi.h>
00029 #elif defined(HAVE_OPENCV)
00030 #  include <cv.h>
00031 #else
00032 #  error "Neither IPP nor OpenCV available"
00033 #endif
00034 
00035 
00036 namespace firevision {
00037 #if 0 /* just to make Emacs auto-indent happy */
00038 }
00039 #endif
00040 
00041 /** @class FilterSobel <fvfilters/sobel.h>
00042  * Sobel filter.
00043  * @author Tim Niemueller
00044  */
00045 
00046 /** Constructor.
00047  * @param ori edge orientation
00048  */
00049 FilterSobel::FilterSobel(orientation_t ori)
00050   : Filter("FilterSobel")
00051 {
00052 }
00053 
00054 
00055 /** Generate a sobel kernel for the given orientation.
00056  * @param k matrix for the kernel of size 3x3, contains three
00057  * lines concatenated into an one dimensional array.
00058  * @param ori requested orientation of the filter
00059  */
00060 static inline void
00061 generate_kernel(
00062 #ifdef HAVE_IPP
00063                 int *k,
00064 #else
00065                 float *k,
00066 #endif
00067                 orientation_t ori)
00068 {
00069   // k is the kernel
00070   switch (ori) {
00071   case ORI_DEG_0:
00072   case ORI_DEG_360:
00073     k[0] =  1;    k[1] =  2;    k[2] =  1;
00074     k[3] =  0;    k[4] =  0;    k[5] =  0;
00075     k[6] = -1;    k[7] = -2;    k[8] = -1;
00076     break;
00077   case ORI_DEG_45:
00078     k[0] =  2;    k[1] =  1;    k[2] =  0;
00079     k[3] =  1;    k[4] =  0;    k[5] = -1;
00080     k[6] =  0;    k[7] = -1;    k[8] = -2;
00081     break;
00082   case ORI_DEG_90:
00083     k[0] =  1;    k[1] =  0;    k[2] = -1;
00084     k[3] =  2;    k[4] =  0;    k[5] = -2;
00085     k[6] =  1;    k[7] =  0;    k[8] = -1;
00086     break;
00087   case ORI_DEG_135:
00088     k[0] =  0;    k[1] = -1;    k[2] = -2;
00089     k[3] =  1;    k[4] =  0;    k[5] = -1;
00090     k[6] =  2;    k[7] =  1;    k[8] =  0;
00091     break;
00092   case ORI_DEG_180:
00093     k[0] = -1;    k[1] = -2;    k[2] = -1;
00094     k[3] =  0;    k[4] =  0;    k[5] =  0;
00095     k[6] =  1;    k[7] =  2;    k[8] =  1;
00096     break;
00097   case ORI_DEG_225:
00098     k[0] = -2;    k[1] = -1;    k[2] =  0;
00099     k[3] = -1;    k[4] =  0;    k[5] =  1;
00100     k[6] =  0;    k[7] =  1;    k[8] =  2;
00101     break;
00102   case ORI_DEG_270:
00103     k[0] = -1;    k[1] =  0;    k[2] =  1;
00104     k[3] = -2;    k[4] =  0;    k[5] =  2;
00105     k[6] = -1;    k[7] =  0;    k[8] =  1;
00106     break;
00107   case ORI_DEG_315:
00108     k[0] =  0;    k[1] =  1;    k[2] =  2;
00109     k[3] = -1;    k[4] =  0;    k[5] =  1;
00110     k[6] = -2;    k[7] = -1;    k[8] =  0;
00111     break;
00112   default:
00113     throw fawkes::Exception("Cannot generate Sobel kernel for the given orientation");
00114     break;
00115   }
00116 }
00117 
00118 void
00119 FilterSobel::apply()
00120 {
00121   shrink_region(src_roi[0], 3);
00122   shrink_region(dst_roi, 3);
00123 
00124 #if defined(HAVE_IPP)
00125   IppiSize size;
00126   size.width = src_roi[0]->width;
00127   size.height = src_roi[0]->height;
00128 
00129   IppStatus status;
00130 
00131   if (ori[0] == ORI_HORIZONTAL) {
00132     //                                    base + number of bytes to line y              + pixel bytes
00133     status = ippiFilterSobelHoriz_8u_C1R( src[0] + (src_roi[0]->start.y * src_roi[0]->line_step) + (src_roi[0]->start.x * src_roi[0]->pixel_step), src_roi[0]->line_step,
00134                                           dst + (dst_roi->start.y * dst_roi->line_step) + (dst_roi->start.x * dst_roi->pixel_step), dst_roi->line_step,
00135                                           size );
00136   } else if (ori[0] == ORI_VERTICAL) {
00137     status = ippiFilterSobelHoriz_8u_C1R( src[0] + (src_roi[0]->start.y * src_roi[0]->line_step) + (src_roi[0]->start.x * src_roi[0]->pixel_step), src_roi[0]->line_step,
00138                                           dst + (dst_roi->start.y * dst_roi->line_step) + (dst_roi->start.x * dst_roi->pixel_step), dst_roi->line_step,
00139                                           size );
00140 
00141   } else if ( (ori[0] == ORI_DEG_0) ||
00142               (ori[0] == ORI_DEG_45) ||
00143               (ori[0] == ORI_DEG_90) ||
00144               (ori[0] == ORI_DEG_135) ||
00145               (ori[0] == ORI_DEG_180) ||
00146               (ori[0] == ORI_DEG_225) ||
00147               (ori[0] == ORI_DEG_270) ||
00148               (ori[0] == ORI_DEG_315) ||
00149               (ori[0] == ORI_DEG_360)
00150               ) {
00151 
00152     Ipp32s kernel[9];
00153     generate_kernel(kernel, ori[0]);
00154 
00155     IppiSize kernel_size;
00156     kernel_size.width = kernel_size.height = 3;
00157 
00158     IppiPoint anchor;
00159     anchor.x = anchor.y = 1;
00160 
00161     status = ippiFilter_8u_C1R( src[0] + (src_roi[0]->start.y * src_roi[0]->line_step) + (src_roi[0]->start.x * src_roi[0]->pixel_step), src_roi[0]->line_step,
00162                                 dst + (dst_roi->start.y * dst_roi->line_step) + (dst_roi->start.x * dst_roi->pixel_step), dst_roi->line_step,
00163                                 size,
00164                                 kernel, kernel_size,
00165                                 anchor,
00166                                 /* divisor */ 1 );
00167     
00168   } else {
00169     // cout << "FilterSobel: Unsupported direction" << endl;
00170     status = ippStsNullPtrErr;
00171   }
00172 
00173   if ( status != ippStsNoErr ) {
00174     throw fawkes::Exception("Sobel filter failed with %i", status);
00175   }
00176 #elif defined(HAVE_OPENCV)
00177   cv::Mat srcm(src_roi[0]->height, src_roi[0]->width, CV_8UC1,
00178                src[0] +
00179                  (src_roi[0]->start.y * src_roi[0]->line_step) +
00180                  (src_roi[0]->start.x * src_roi[0]->pixel_step),
00181                src_roi[0]->line_step);
00182 
00183   if (dst == NULL) { dst = src[0]; dst_roi = src_roi[0]; }
00184 
00185   cv::Mat dstm(dst_roi->height, dst_roi->width, CV_8UC1,
00186                dst +
00187                  (dst_roi->start.y * dst_roi->line_step) +
00188                  (dst_roi->start.x * dst_roi->pixel_step),
00189                dst_roi->line_step);
00190 
00191   if (ori[0] == ORI_HORIZONTAL) {
00192     if ((dst == NULL) || (dst == src[0])) {
00193       throw fawkes::Exception("OpenCV-based Sobel filter cannot be in-place");
00194     }
00195 
00196     cv::Sobel(srcm, dstm, /* ddepth */ -1, /* xorder */ 1, /* yorder */ 0,
00197               /* ksize */ 3, /* scale */ 1);
00198   } else if (ori[0] == ORI_VERTICAL) {
00199     if ((dst == NULL) || (dst == src[0])) {
00200       throw fawkes::Exception("OpenCV-based Sobel filter cannot be in-place");
00201     }
00202 
00203     cv::Sobel(srcm, dstm, /* ddepth */ -1, /* xorder */ 0, /* yorder */ 1,
00204               /* ksize */ 3, /* scale */ 1);
00205   } else if ( (ori[0] == ORI_DEG_0) ||
00206               (ori[0] == ORI_DEG_45) ||
00207               (ori[0] == ORI_DEG_90) ||
00208               (ori[0] == ORI_DEG_135) ||
00209               (ori[0] == ORI_DEG_180) ||
00210               (ori[0] == ORI_DEG_225) ||
00211               (ori[0] == ORI_DEG_270) ||
00212               (ori[0] == ORI_DEG_315) ||
00213               (ori[0] == ORI_DEG_360)
00214               )
00215   {
00216     cv::Mat kernel(3, 3, CV_32F);
00217     generate_kernel((float *)kernel.ptr(), ori[0]);
00218  
00219     cv::filter2D(srcm, dstm, /* ddepth */ -1, kernel, cv::Point(1, 1));
00220   } else {
00221     throw fawkes::Exception("Unknown filter sobel orientation");
00222 
00223   }
00224 #endif
00225 
00226 }
00227 
00228 } // end namespace firevision