00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include "Channels/ObjDetChannel.H"
00039 #include "Image/DrawOps.H"
00040 #include "Image/Kernels.H"
00041 #include "Image/MathOps.H"
00042 #include "Image/ShapeOps.H"
00043 #include "Image/Transforms.H"
00044 #include "Channels/ChannelOpts.H"
00045 #include "Component/ModelOptionDef.H"
00046 #include "Component/GlobalOpts.H"
00047
00048 static const ModelOptionDef OPT_CascadeFilePath =
00049 { MODOPT_ARG_STRING, "Cascade file path", &MOC_CHANNEL, OPTEXP_CORE,
00050 "Name of directory containing the description of a trained cascade classifier."
00051 "Used in making faces salient or any other object. ",
00052 "cascade-file", '\0', "<filename>.xml",
00053
00054 "/usr/share/opencv/haarcascades/haarcascade_frontalface_alt2.xml"};
00055
00056 ObjDetChannel::ObjDetChannel(OptionManager& mgr, const std::string & descrName,
00057 const std::string& tagName) :
00058 ChannelBase(mgr, descrName, tagName, FACE),
00059 itsMap(),
00060 itsLevelSpec(&OPT_LevelSpec, this),
00061 itsCascadeFile(&OPT_CascadeFilePath, this),
00062 itsNormType(&OPT_MaxNormType, this),
00063 itsOutputRangeMin(&OPT_ChannelOutputRangeMin, this),
00064 itsOutputRangeMax(&OPT_ChannelOutputRangeMax, this),
00065 itsUseRandom(&OPT_UseRandom, this),
00066 itsNormalizeOutput("SingleChannelNormalizeOutput", this, false)
00067 {
00068
00069 #ifdef HAVE_OPENCV
00070 cascade = (CvHaarClassifierCascade*)cvLoad( itsCascadeFile.getVal().c_str(), 0, 0, 0 );
00071
00072 if( !cascade )
00073 LFATAL("ERROR: Could not load classifier cascade (%s)\n", itsCascadeFile.getVal().c_str() );
00074 storage = cvCreateMemStorage(0);
00075 #else
00076 LFATAL("OpenCV is needed for ObjDet channel");
00077 #endif
00078
00079
00080 }
00081
00082
00083 ObjDetChannel::~ObjDetChannel()
00084 { }
00085
00086
00087 bool ObjDetChannel::outputAvailable() const
00088 { return itsMap.initialized(); }
00089
00090
00091 uint ObjDetChannel::numSubmaps() const
00092 {
00093 return 1;
00094 }
00095
00096
00097 Dims ObjDetChannel::getMapDims() const
00098 {
00099 if (!this->hasInput())
00100 LFATAL("Oops! I haven't received any input yet");
00101
00102 const Dims indims = this->getInputDims();
00103
00104 return Dims(indims.w() >> itsLevelSpec.getVal().mapLevel(),
00105 indims.h() >> itsLevelSpec.getVal().mapLevel());
00106
00107 }
00108
00109
00110 void ObjDetChannel::getFeatures(const Point2D<int>& locn,
00111 std::vector<float>& mean) const
00112 {
00113 if (!this->outputAvailable())
00114 { CLDEBUG("I have no input yet -- RETURNING ZEROS"); mean.push_back(0.0F); return; }
00115
00116
00117
00118
00119
00120 const Dims indims = this->getInputDims();
00121 mean.push_back(itsMap.getValInterpScaled(locn, indims));
00122 }
00123
00124
00125 void ObjDetChannel::getFeaturesBatch(std::vector<Point2D<int>*> *locn,
00126 std::vector<std::vector<float> > *mean,
00127 int *count) const
00128 {
00129 if (!this->outputAvailable())
00130 {
00131 CLDEBUG("I have no input yet -- RETURNING ZEROS");
00132 std::vector<std::vector<float> >::iterator imean = mean->begin();
00133 for (int i = 0; i < *count; i++, ++imean) imean->push_back(0.0);
00134 return;
00135 }
00136
00137
00138
00139
00140
00141 const Dims indims = this->getInputDims();
00142
00143 std::vector<Point2D<int>*>::iterator ilocn = locn->begin();
00144 std::vector<std::vector<float> >::iterator imean = mean->begin();
00145
00146 for (int i = 0; i < *count; ++i, ++ilocn, ++imean)
00147 imean->push_back(itsMap.getValInterpScaled(**ilocn, indims));
00148 }
00149
00150
00151 void ObjDetChannel::doInput(const InputFrame& inframe)
00152 {
00153 ASSERT(inframe.grayFloat().initialized());
00154 Image<byte> lum = inframe.grayFloat();
00155
00156 #ifdef HAVE_OPENCV
00157 const double scale = 1.3;
00158 IplImage* small_img =
00159 cvCreateImage(cvSize(cvRound(lum.getWidth() / scale), cvRound(lum.getHeight() / scale)), 8, 1 );
00160
00161 cvResize(img2ipl(lum), small_img, CV_INTER_LINEAR);
00162 cvEqualizeHist(small_img, small_img);
00163 cvClearMemStorage(storage);
00164
00165 if (cascade)
00166 {
00167 double t = double(cvGetTickCount());
00168 CvSeq* objects = cvHaarDetectObjects(small_img, cascade, storage,
00169 1.1, 2, 0,
00170 cvSize(30, 30));
00171 t = double(cvGetTickCount()) - t;
00172 LDEBUG( "detection time = %gms", t / (double(cvGetTickFrequency())*1000.0));
00173
00174 itsMap = Image<float>(lum.getDims(), ZEROS);
00175 for (int i = 0; i < (objects ? objects->total : 0); ++i )
00176 {
00177 CvRect* r = (CvRect*)cvGetSeqElem(objects, i);
00178
00179 Rectangle objRect(Point2D<int>(int(r->x*scale), int(r->y*scale)),
00180 Dims(int(r->width*scale), int(r->height*scale)));
00181
00182 const Point2D<int> objCenter = Point2D<int>(objRect.topLeft().i + objRect.width()/2,
00183 objRect.topLeft().j + objRect.height()/2);
00184
00185 Image<float> objBlob =
00186 gaussianBlobUnnormalized<float>(lum.getDims(), objCenter,
00187 float(objRect.width())/2, float(objRect.height())/2);
00188
00189 itsMap += objBlob;
00190 }
00191 }
00192
00193 inplaceRectify(itsMap);
00194 itsMap = rescale(itsMap, this->getMapDims());
00195
00196
00197 inplaceNormalize(itsMap, 0.0F, 255.0F);
00198 if (itsUseRandom.getVal()) inplaceAddBGnoise(itsMap, 255.0F);
00199
00200
00201 if (itsNormalizeOutput.getVal())
00202 {
00203 LDEBUG("%s: Normalizing output: %s(%f .. %f)", tagName().c_str(),
00204 maxNormTypeName(itsNormType.getVal()), itsOutputRangeMin.getVal(),
00205 itsOutputRangeMax.getVal());
00206
00207 itsMap = maxNormalize(itsMap, itsOutputRangeMin.getVal(),
00208 itsOutputRangeMax.getVal(), itsNormType.getVal());
00209 }
00210
00211 cvReleaseImage(&small_img);
00212 #endif
00213 }
00214
00215
00216 Image<float> ObjDetChannel::getSubmap(const uint index) const
00217 {
00218 if (index != 0)
00219 LFATAL("got submap index = %u, but I have only one submap", index);
00220
00221 return itsMap;
00222 }
00223
00224
00225 std::string ObjDetChannel::getSubmapName(const uint index) const
00226 {
00227 return "ObjDet";
00228 }
00229
00230
00231 std::string ObjDetChannel::getSubmapNameShort(const uint index) const
00232 {
00233 return "ObjDet";
00234 }
00235
00236
00237
00238 Image<float> ObjDetChannel::getOutput()
00239 { return itsMap; }
00240
00241
00242
00243
00244
00245
00246