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 "SIFT/VisualObject.H"
00039 #include "SIFT/ScaleSpace.H"
00040 #include "Image/ColorOps.H"
00041 #include "Image/DrawOps.H"
00042 #include "Image/ShapeOps.H"
00043 #include "Image/Kernels.H"
00044 #include "Image/FilterOps.H"
00045 #include "Image/MathOps.H"
00046 #include "Image/Pixels.H"
00047 #include "Raster/Raster.H"
00048
00049 #include <algorithm>
00050 #include <cmath>
00051 #include <istream>
00052 #include <ostream>
00053
00054 #include <cctype>
00055
00056 namespace
00057 {
00058 bool isInteger(const std::string& s)
00059 {
00060 if (s.length() == 0) return false;
00061
00062 if (s[0] != '-' && !isdigit(s[0])) return false;
00063
00064 for (size_t i = 1; i < s.length(); ++i)
00065 if (!isdigit(s[i])) return false;
00066
00067 return true;
00068 }
00069 }
00070
00071
00072 class lessKP
00073 {
00074 public:
00075 bool operator()(const rutz::shared_ptr<Keypoint>& x,
00076 const rutz::shared_ptr<Keypoint>& y)
00077 { return (*x) < (*y); }
00078 };
00079
00080
00081
00082
00083
00084 template <class ForwardIterator, class StrictWeakOrdering>
00085 bool myIsSorted(ForwardIterator begin, ForwardIterator end,
00086 StrictWeakOrdering comp)
00087 {
00088 if (begin == end) return true;
00089
00090 ForwardIterator next = begin;
00091 ++next;
00092 for (; next != end ; ++begin,++next) if (comp(*next, *begin)) return false;
00093
00094 return true;
00095 }
00096
00097
00098 VisualObject::VisualObject(const std::string& name,
00099 const std::string& imagefname,
00100 const Image< PixRGB<byte> >& image,
00101 const Point2D<int>& salpt,
00102 const std::vector<float>& preattfeatures,
00103 const std::vector< rutz::shared_ptr<Keypoint> >&
00104 keypoints,
00105 const bool useColor,
00106 bool computeKP) :
00107
00108 itsName(name), itsImageFname(imagefname), itsImage(image),
00109 itsKeypoints(keypoints), itsSalPoint(salpt), itsFeatures(preattfeatures),
00110 itsIsSorted(false), itsUseColor(useColor),itsImageLoaded(true)
00111 {
00112 itsObjectSize = image.getDims();
00113 if(computeKP) computeKeypoints();
00114 }
00115
00116
00117 void VisualObject::computeKeypoints()
00118 {
00119
00120 if (itsImage.initialized() && itsKeypoints.empty())
00121 {
00122 LDEBUG("%s: initializing ScaleSpace from %dx%d image...",
00123 itsName.c_str(), itsImage.getWidth(), itsImage.getHeight());
00124
00125
00126 Image<float> lum = luminance(itsImage);
00127
00128
00129
00130 Image<float> rg, by;
00131 if (itsUseColor){
00132 getRGBY(itsImage, rg, by, 25.0F);
00133 rg = interpolate(rg);
00134 by = interpolate(by);
00135 }
00136
00137
00138 lum = interpolate(lum);
00139
00140 const int nums = 3;
00141 const double sigma = 1.6F;
00142 float octscale = 0.5F;
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153 const float blursig = sqrtf(sigma * sigma - 1.0F);
00154 Image<float> kernel = gaussian<float>(1.0F, blursig,
00155 lum.getWidth(), 1.0F);
00156 kernel = kernel / float(sum(kernel));
00157 lum = sepFilter(lum, kernel, kernel, CONV_BOUNDARY_CLEAN);
00158
00159 if (itsUseColor){
00160
00161 rg = sepFilter(rg, kernel, kernel, CONV_BOUNDARY_CLEAN);
00162 by = sepFilter(by, kernel, kernel, CONV_BOUNDARY_CLEAN);
00163 }
00164
00165
00166 int iter = 0; uint numkp = 0;
00167 while (lum.getWidth() > 24 && lum.getHeight() > 24)
00168 {
00169 ImageSet<float> inImg(3);
00170 inImg[ScaleSpace::LUM_CHANNEL] = lum;
00171
00172 if (itsUseColor){
00173 inImg[ScaleSpace::RG_CHANNEL] = rg;
00174 inImg[ScaleSpace::BY_CHANNEL] = by;
00175 }
00176
00177 ScaleSpace ss(inImg, octscale, nums, sigma, itsUseColor);
00178
00179
00180 uint nkp = ss.findKeypoints(itsKeypoints);
00181 LDEBUG("%s: Found %d keypoints in ScaleSpace %d",
00182 itsName.c_str(), nkp, iter);
00183 numkp += nkp;
00184
00185
00186 lum = decXY(ss.getTwoSigmaImage(ScaleSpace::LUM_CHANNEL));
00187
00188 if (itsUseColor){
00189 rg = decXY(ss.getTwoSigmaImage(ScaleSpace::RG_CHANNEL));
00190 by = decXY(ss.getTwoSigmaImage(ScaleSpace::BY_CHANNEL));
00191 }
00192
00193 ++ iter; octscale *= 2.0F;
00194 }
00195
00196 LDEBUG("%s: Found total of %d keypoints over all ScaleSpaces.",
00197 itsName.c_str(), numkp);
00198 }
00199 }
00200
00201
00202 VisualObject::VisualObject(const VisualObject& vo)
00203 {
00204 itsName = vo.itsName; itsImageFname = vo.itsImageFname;
00205 if (vo.itsImage.initialized()) itsImage = vo.itsImage; else itsImage.freeMem();
00206 itsKeypoints = vo.itsKeypoints;
00207 itsFeatures = vo.itsFeatures;
00208 itsIsSorted = vo.itsIsSorted;
00209 }
00210
00211
00212 VisualObject::~VisualObject()
00213 { }
00214
00215
00216 void VisualObject::deleteImageFile() const
00217 {
00218 if (Raster::fileExists(itsImageFname, RASFMT_PNG))
00219 if (unlink(itsImageFname.c_str()) == -1)
00220 PLERROR("Could not delete '%s' -- IGNORING", itsImageFname.c_str());
00221 }
00222
00223
00224 VisualObject& VisualObject::operator=(const VisualObject& vo)
00225 {
00226 itsName = vo.itsName; itsImageFname = vo.itsImageFname;
00227
00228 itsImage.freeMem();
00229 if (vo.itsImage.initialized()) itsImage = vo.itsImage;
00230
00231 itsKeypoints = vo.itsKeypoints;
00232 itsFeatures = vo.itsFeatures;
00233 itsIsSorted = vo.itsIsSorted;
00234
00235 return *this;
00236 }
00237
00238
00239 double VisualObject::getFeatureDistSq(const rutz::shared_ptr<VisualObject>& obj) const
00240 {
00241 ASSERT(itsFeatures.size() == obj->itsFeatures.size());
00242
00243 double distSq = 0.0;
00244 std::vector<float>::const_iterator
00245 src1 = itsFeatures.begin(), stop = itsFeatures.end(),
00246 src2 = obj->itsFeatures.begin();
00247
00248 while (src1 != stop)
00249 {
00250 const double diff = double(*src1++) - double(*src2++);
00251 distSq += diff * diff;
00252 }
00253
00254 return distSq;
00255 }
00256
00257
00258 void VisualObject::sortKeypoints()
00259 {
00260 if (itsIsSorted) return;
00261
00262
00263 std::sort(itsKeypoints.begin(), itsKeypoints.end(), lessKP());
00264 itsIsSorted = true;
00265 }
00266
00267
00268 std::ostream& operator<<(std::ostream& os, const VisualObject& v)
00269 {
00270 os<<v.itsName<<std::endl<<v.itsImageFname<<std::endl;
00271 if (v.itsImageFname != "NULL" && v.itsImageFname != "" && Raster::fileExists(v.itsImageFname, RASFMT_PNG) == false)
00272 {
00273 LINFO("Writing image file: %s", v.itsImageFname.c_str());
00274 Raster::WriteRGB(v.itsImage, v.itsImageFname, RASFMT_PNG);
00275 }
00276
00277 if (v.itsImageFname == "NULL" || v.itsImageFname == "")
00278 os<<v.itsObjectSize.w()<<std::endl<<v.itsObjectSize.h()<<std::endl;
00279
00280 os<<v.itsSalPoint.i<<std::endl<<v.itsSalPoint.j<<std::endl;
00281 const uint featureSize = v.itsFeatures.size();
00282 os<<featureSize<<std::endl;
00283 for (uint i = 0; i < featureSize; i++) os<<v.itsFeatures[i]<<' ';
00284
00285 const uint keySize = v.itsKeypoints.size();
00286 os<<keySize<<std::endl;
00287 for (uint i = 0; i < keySize; i++) os<<*(v.itsKeypoints[i]);
00288
00289 return os;
00290 }
00291
00292
00293 std::istream& operator>>(std::istream& is, VisualObject& v)
00294 {
00295
00296 v.createVisualObject(is, v);
00297 return is;
00298 }
00299
00300
00301 void VisualObject::createVisualObject
00302 (std::istream& is, VisualObject &v, bool loadImage)
00303 {
00304 is >> std::ws;
00305 std::getline(is, v.itsName);
00306 std::getline(is, v.itsImageFname);
00307 v.itsImageLoaded = loadImage;
00308
00309
00310
00311
00312
00313 uint featureSize;
00314 if (v.itsImageFname != "NULL" && v.itsImageFname != "")
00315 {
00316
00317 if (loadImage)
00318 {
00319 LINFO("Opening image file %s", v.itsImageFname.c_str());
00320 v.itsImage = Raster::ReadRGB(v.itsImageFname);
00321 }
00322 }
00323 else
00324 {
00325 LDEBUG("Image file %s not opened", v.itsImageFname.c_str());
00326 v.itsImageFname = std::string("NULL");
00327 int objW = 0, objH = 0;
00328 is>>objW; is>>objH;
00329 LINFO("%d %d", objW, objH);
00330 v.itsObjectSize = Dims(objW, objH);
00331 }
00332 is>>v.itsSalPoint.i;
00333 is>>v.itsSalPoint.j;
00334
00335 is>>featureSize;
00336 v.itsFeatures.clear(); v.itsFeatures.resize(featureSize);
00337 for (uint i = 0; i < featureSize; i++) is>>v.itsFeatures[i];
00338
00339 uint keySize; is>>keySize;
00340 v.itsKeypoints.clear(); v.itsKeypoints.resize(keySize);
00341
00342 std::vector< rutz::shared_ptr<Keypoint> >::iterator
00343 k = v.itsKeypoints.begin(), stop = v.itsKeypoints.end();
00344
00345 while (k != stop)
00346 {
00347 rutz::shared_ptr<Keypoint> newkey(new Keypoint());
00348 is>>(*newkey); *k++ = newkey;
00349 }
00350
00351 v.itsIsSorted =
00352 myIsSorted(v.itsKeypoints.begin(), v.itsKeypoints.end(), lessKP());
00353 }
00354
00355
00356 Image<PixRGB<byte> > VisualObject::
00357 getKeypointImage(const float scale, const float vmag,
00358 const PixRGB<byte> col)
00359 {
00360 std::vector<rutz::shared_ptr<Keypoint> >::const_iterator
00361 k = itsKeypoints.begin(),
00362 stop = itsKeypoints.end();
00363
00364 Image< PixRGB<byte> > image(getImage());
00365 if (scale != 1.0F)
00366 image = rescale(image, int(image.getWidth() * scale),
00367 int(image.getHeight() * scale));
00368
00369 while(k != stop)
00370 {
00371 const float x = (*k)->getX() * scale;
00372 const float y = (*k)->getY() * scale;
00373 const float s = (*k)->getS() * scale * vmag;
00374 const float o = (*k)->getO();
00375
00376 Point2D<int> loc(int(x + 0.5F), int(y + 0.5F));
00377 drawDisk(image, loc, 2, PixRGB<byte>(255,0,0));
00378 if (s > 0.0f) drawLine(image, loc,
00379 Point2D<int>(int(x + s * cosf(o) + 0.5F),
00380 int(y + s * sinf(o) + 0.5F)),
00381 PixRGB<byte>(255, 0, 0));
00382 ++k;
00383 }
00384 return image;
00385 }
00386
00387
00388 Image<PixRGB<byte> > VisualObject::
00389 getKeypointImage2(const float scale, const float vmag,
00390 const PixRGB<byte> col)
00391 {
00392 std::vector<rutz::shared_ptr<Keypoint> >::const_iterator
00393 k = itsKeypoints.begin(),
00394 stop = itsKeypoints.end();
00395
00396 Image< PixRGB<byte> > image(getImage());
00397 if (scale != 1.0F)
00398 image = rescale(image, int(image.getWidth() * scale),
00399 int(image.getHeight() * scale));
00400
00401 while(k != stop)
00402 {
00403 const float x = (*k)->getX() * scale;
00404 const float y = (*k)->getY() * scale;
00405 const float s = (*k)->getS() * scale * vmag;
00406 const float o = (*k)->getO();
00407
00408 Point2D<int> loc(int(x + 0.5F), int(y + 0.5F));
00409 drawDisk(image, loc, 2, PixRGB<byte>(255,0,0));
00410
00411 if (s >= 1.0f)
00412 drawCircle(image, loc, int(s), PixRGB<byte>(255,0,0));
00413 if (s > 0.0f) drawLine(image, loc,
00414 Point2D<int>(int(x + s * cosf(o) + 0.5F),
00415 int(y + s * sinf(o) + 0.5F)),
00416 PixRGB<byte>(255, 0, 0));
00417 ++k;
00418 }
00419 return image;
00420 }
00421
00422
00423 Image<PixRGB<byte> > VisualObject::
00424 getSalAndKeypointImage(const float scale, const float vmag,
00425 const PixRGB<byte> col)
00426 {
00427
00428 Image<PixRGB<byte> > image = getKeypointImage(scale,vmag,col);
00429 Point2D<int> salpt((int)(itsSalPoint.i*scale), (int)(itsSalPoint.j*scale));
00430 drawDisk(image, salpt, 2, PixRGB<byte>(255,255,0));
00431
00432 return image;
00433 }
00434
00435
00436
00437
00438
00439