Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

LinkedChainList.C

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------+
00002  | Library QgarLib, graphics analysis and recognition                  |
00003  | Copyright (C) 2002  Qgar Project, LORIA                             |
00004  |                                                                     |
00005  | This library is free software; you can redistribute it and/or       |
00006  | modify it under the terms of the GNU Lesser General Public          |
00007  | License version 2.1, as published by the Free Software Foundation.  |
00008  |                                                                     |
00009  | This library is distributed in the hope that it will be useful,     |
00010  | but WITHOUT ANY WARRANTY; without even the implied warranty of      |
00011  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                |
00012  | See the GNU Lesser General Public License for more details.         |
00013  |                                                                     |
00014  | The GNU Lesser General Public License is included in the file       |
00015  | LICENSE.LGPL, in the root directory of the Qgar packaging. See      |
00016  | http://www.gnu.org/licenses/lgpl.html for the terms of the licence. |
00017  | To receive a paper copy, write to the Free Software Foundation,     |
00018  | Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.       |
00019  |                                                                     |
00020  | Contact Project Qgar for any information:                           |
00021  |   LORIA - équipe Qgar                                               |
00022  |   B.P. 239, 54506 Vandoeuvre-lès-Nancy Cedex, France                |
00023  |   email: qgar-contact@loria.fr                                      |
00024  |   http://www.qgar.org/                                              |
00025  *---------------------------------------------------------------------*/
00026 
00027 
00028 /**
00029  * @file  LinkedChainList.C
00030  * @brief Implementation of class qgar::LinkedChainList.
00031  *
00032  *        See file LinkedChainList.H for the interface.
00033  *
00034  * @author <a href="mailto:qgar-develop@loria.fr?subject=Qgar fwd Karl Tombre">Karl Tombre</a>
00035  * @date   July 3,  2001  16:14
00036  * @since  Qgar 1.0
00037  */
00038 
00039 
00040 
00041 // STD
00042 #include <string>
00043 // STL
00044 #include <algorithm>
00045 #include <cstdlib>
00046 // QGAR
00047 #include <qgarlib/GenPointChain.H>
00048 #include <qgarlib/LabeledSkeletonImage.H>
00049 #include <qgarlib/LinkedChainList.H>
00050 #include <qgarlib/QgarErrorDeveloper.H>
00051 
00052 
00053 
00054 using namespace std;
00055 
00056 
00057 namespace qgar
00058 {
00059 
00060 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00061 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00062 // L O C A L    D A T A
00063 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00064 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00065 
00066 
00067 // The mark
00068 const unsigned char LINKEDCHAINLIST_MARK = 2;
00069 
00070 // For the checking
00071 static int LINKEDCHAINLIST_MINL = 0;
00072 
00073 
00074 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00075 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00076 // L O C A L    I N L I N E S
00077 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00078 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00079 
00080 // Is this dangerous?
00081 // Do comparisons always return 1 or 0?
00082 
00083 int
00084 LINKEDCHAINLIST_connect4(unsigned char* p, int w)
00085 {
00086   return   (*(p - w) == 255)
00087          + (*(p + w) == 255)
00088          + (*(p - 1) == 255)
00089          + (*(p + 1) == 255);
00090 }
00091 
00092 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00093 
00094 int
00095 LINKEDCHAINLIST_connect4M(unsigned char* p, int w)
00096 {
00097   return   (*(p - w) == LINKEDCHAINLIST_MARK)
00098          + (*(p + w) == LINKEDCHAINLIST_MARK)
00099          + (*(p - 1) == LINKEDCHAINLIST_MARK)
00100          + (*(p + 1) == LINKEDCHAINLIST_MARK);
00101 }
00102 
00103 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00104 
00105 int
00106 LINKEDCHAINLIST_connect8(unsigned char* p, int w)
00107 {
00108   return   (*(p - w - 1) == 255)
00109          + (*(p - w + 1) == 255)
00110          + (*(p + w - 1) == 255)
00111          + (*(p + w + 1) == 255);
00112 }
00113 
00114 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00115 
00116 int
00117 LINKEDCHAINLIST_connect8M(unsigned char* p, int w)
00118 {
00119   return   (*(p - w - 1) == LINKEDCHAINLIST_MARK)
00120          + (*(p - w + 1) == LINKEDCHAINLIST_MARK)
00121          + (*(p + w - 1) == LINKEDCHAINLIST_MARK)
00122          + (*(p + w + 1) == LINKEDCHAINLIST_MARK);
00123 }
00124 
00125 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00126 
00127 Point
00128 LINKEDCHAINLIST_neigh(unsigned char* p, int l, int c, int w)
00129 {
00130   int x = c;
00131   int y = l;
00132 
00133   if (*(p + 1) == 255)
00134     {
00135       x += 1;
00136     }
00137   else if (*(p + w) == 255)
00138     {
00139       y += 1;
00140     }
00141   else if (*(p - 1) == 255)
00142     {
00143       x -= 1;
00144     }
00145   else if (*(p - w) == 255)
00146     {
00147       y -= 1;
00148     }
00149   else if (*(p + w + 1) == 255)
00150     {
00151       x += 1;
00152       y += 1;
00153     }
00154   else if (*(p + w - 1) == 255)
00155     {
00156       x -= 1;
00157       y += 1;
00158     }
00159   else if (*(p - w - 1) == 255)
00160     {
00161       x -= 1;
00162       y -= 1;
00163     }
00164   else if (*(p - w + 1) == 255)
00165     {
00166       x += 1;
00167       y -= 1;
00168     }
00169   //  else
00170   //    {
00171   //      // do nothing
00172   //    }
00173 
00174   return Point(x,y);
00175 }
00176 
00177 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00178 
00179 // Get any non null neighbor
00180 
00181 Point
00182 LINKEDCHAINLIST_neighPlus(unsigned char* p, int l, int c, int w)
00183 {
00184   int x = c;
00185   int y = l;
00186 
00187   if (*(p + 1) != 0)
00188     {
00189       x += 1;
00190     }
00191   else if (*(p + w) != 0)
00192     {
00193       y += 1;
00194     }
00195   else if (*(p - 1) != 0)
00196     {
00197       x -= 1;
00198     }
00199   else if (*(p - w) != 0)
00200     {
00201       y -= 1;
00202     }
00203   else if (*(p + w + 1) != 0)
00204     {
00205       x += 1;
00206       y += 1;
00207     }
00208   else if (*(p + w - 1) != 0)
00209     {
00210       x -= 1;
00211       y += 1;
00212     }
00213   else if (*(p - w - 1) != 0)
00214     {
00215       x -= 1;
00216       y -= 1;
00217     }
00218   else if (*(p - w + 1) != 0)
00219     {
00220       x += 1;
00221       y -= 1;
00222     }
00223   //  else
00224   //    {
00225   //      // do nothing
00226   //    }
00227 
00228   return Point(x,y);
00229 }
00230 
00231 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00232 
00233 Point
00234 LINKEDCHAINLIST_neigh4(unsigned char* p, int l, int c, int w)
00235 {
00236   int x = c;
00237   int y = l;
00238 
00239   if (*(p + 1) == 255)
00240     {
00241       x += 1;
00242     }
00243   else if (*(p + w) == 255)
00244     {
00245       y += 1;
00246     }
00247   else if (*(p - 1) == 255)
00248     {
00249       x -= 1;
00250     }
00251   else if (*(p - w) == 255)
00252     {
00253       y -= 1;
00254     }
00255   //  else
00256   //    {
00257   //      // do nothing
00258   //    }
00259 
00260   return Point(x,y);
00261 }
00262 
00263 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00264 
00265 Point
00266 LINKEDCHAINLIST_neigh8(unsigned char* p, int l, int c, int w)
00267 {
00268   int x = c;
00269   int y = l;
00270 
00271   if (*(p + w + 1) == 255)
00272     {
00273       x += 1;
00274       y += 1;
00275     }
00276   else if (*(p + w - 1) == 255)
00277     {
00278       x -= 1;
00279       y += 1;
00280     }
00281   else if (*(p - w - 1) == 255)
00282     {
00283       x -= 1;
00284       y -= 1;
00285     }
00286   else if (*(p - w + 1) == 255)
00287     {
00288       x += 1;
00289       y -= 1;
00290     }
00291   //  else
00292   //    {
00293   //      // do nothing
00294   //    }
00295 
00296   return Point(x,y);
00297 }
00298 
00299 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00300 
00301 Point
00302 LINKEDCHAINLIST_neighM(unsigned char* p, int l, int c, int w)
00303 {
00304   int x = c;
00305   int y = l;
00306 
00307   if (*(p + 1) == LINKEDCHAINLIST_MARK)
00308     {
00309       x += 1;
00310     }
00311   else if (*(p + w) == LINKEDCHAINLIST_MARK)
00312     {
00313       y += 1;
00314     }
00315   else if (*(p - 1) == LINKEDCHAINLIST_MARK)
00316     {
00317       x -= 1;
00318     }
00319   else if (*(p - w) == LINKEDCHAINLIST_MARK)
00320     {
00321       y -= 1;
00322     }
00323   else if (*(p + w + 1) == LINKEDCHAINLIST_MARK)
00324     {
00325       x += 1;
00326       y += 1;
00327     }
00328   else if (*(p + w - 1) == LINKEDCHAINLIST_MARK)
00329     {
00330       x -= 1;
00331       y += 1;
00332     }
00333   else if (*(p - w - 1) == LINKEDCHAINLIST_MARK)
00334     {
00335       x -= 1;
00336       y -= 1;
00337     }
00338   else if (*(p - w + 1) == LINKEDCHAINLIST_MARK)
00339     {
00340       x += 1;
00341       y -= 1;
00342     }
00343   //  else
00344   //    {
00345   //      // do nothing
00346   //    }
00347 
00348   return Point(x,y);
00349 }
00350 
00351 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00352 
00353 Point
00354 LINKEDCHAINLIST_neigh4M(unsigned char* p, int l, int c, int w)
00355 {
00356   int x = c;
00357   int y = l;
00358 
00359   if (*(p + 1) == LINKEDCHAINLIST_MARK)
00360     {
00361       x += 1;
00362     }
00363   else if (*(p + w) == LINKEDCHAINLIST_MARK)
00364     {
00365       y += 1;
00366     }
00367   else if (*(p - 1) == LINKEDCHAINLIST_MARK)
00368     {
00369       x -= 1;
00370     }
00371   else if (*(p - w) == LINKEDCHAINLIST_MARK)
00372     {
00373       y -= 1;
00374     }
00375   //  else
00376   //    {
00377   //      // do nothing
00378   //    }
00379 
00380   return Point(x,y);
00381 }
00382 
00383 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00384 
00385 Point
00386 LINKEDCHAINLIST_neigh8M(unsigned char* p, int l, int c, int w)
00387 {
00388   int x = c;
00389   int y = l;
00390 
00391   if (*(p + w + 1) == LINKEDCHAINLIST_MARK)
00392     {
00393       x += 1;
00394       y += 1;
00395     }
00396   else if (*(p + w - 1) == LINKEDCHAINLIST_MARK)
00397     {
00398       x -= 1;
00399       y += 1;
00400     }
00401   else if (*(p - w - 1) == LINKEDCHAINLIST_MARK)
00402     {
00403       x -= 1;
00404       y -= 1;
00405     }
00406   else if (*(p - w + 1) == LINKEDCHAINLIST_MARK)
00407     {
00408       x += 1;
00409       y -= 1;
00410     }
00411   //  else
00412   //    {
00413   //      // do nothing
00414   //    }
00415 
00416   return Point(x,y);
00417 }
00418 
00419 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00420 
00421 void
00422 LINKEDCHAINLIST_markNeigh(unsigned char* p, int w, int c4, int c8)
00423 {
00424   if (c4 != 0 && c8 == 0)   // Only 4-neighbors: mark 4-neighbors
00425   {
00426 
00427     if (*(p + 1) != 0)
00428       {
00429         *(p + 1) = LINKEDCHAINLIST_MARK;
00430       }
00431 
00432     if (*(p + w) != 0)
00433       {
00434         *(p + w) = LINKEDCHAINLIST_MARK;
00435       }
00436 
00437     if (*(p - 1) != 0)
00438       {
00439         *(p - 1) = LINKEDCHAINLIST_MARK;
00440       }
00441 
00442     if (*(p - w) != 0)
00443       {
00444         *(p - w) = LINKEDCHAINLIST_MARK;
00445       }
00446   }
00447   else if (c4 == 0 && c8 != 0) // Only 8-neighbors: mark 8-neighbors
00448   {
00449 
00450     if (*(p + w + 1) != 0)
00451       {
00452         *(p + w + 1) = LINKEDCHAINLIST_MARK;
00453       }
00454 
00455     if (*(p + w - 1) != 0)
00456       {
00457         *(p + w - 1) = LINKEDCHAINLIST_MARK;
00458       }
00459 
00460     if (*(p - w - 1) != 0)
00461       {
00462         *(p - w - 1) = LINKEDCHAINLIST_MARK;
00463       }
00464 
00465     if (*(p - w + 1) != 0)
00466       {
00467         *(p - w + 1) = LINKEDCHAINLIST_MARK;
00468       }
00469   }
00470   else // there are both 4- and 8-neighbors
00471   {
00472     // mark 4-neighbors
00473 
00474     if (*(p + 1) != 0)
00475       {
00476         *(p + 1) = LINKEDCHAINLIST_MARK;
00477       }
00478 
00479     if (*(p + w) != 0)
00480       {
00481         *(p + w) = LINKEDCHAINLIST_MARK;
00482       }
00483 
00484     if (*(p - 1) != 0)
00485       {
00486         *(p - 1) = LINKEDCHAINLIST_MARK;
00487       }
00488 
00489     if (*(p - w) != 0)
00490       {
00491         *(p - w) = LINKEDCHAINLIST_MARK;
00492       }
00493 
00494     // and mark others which have no connected path
00495     if ((*(p + w + 1) != 0) && (*(p + 1) == 0) && (*(p + w) == 0))
00496       {
00497         *(p + w + 1) = LINKEDCHAINLIST_MARK;
00498       }
00499 
00500     if ((*(p + w - 1) != 0) && (*(p + w) == 0) && (*(p - 1) == 0))
00501       {
00502         *(p + w - 1) = LINKEDCHAINLIST_MARK;
00503       }
00504 
00505     if ((*(p - w - 1) != 0) && (*(p - 1) == 0) && (*(p - w) == 0))
00506       {
00507         *(p - w - 1) = LINKEDCHAINLIST_MARK;
00508       }
00509 
00510     if ((*(p - w + 1) != 0) && (*(p - w) == 0) && (*(p + 1) == 0))
00511       {
00512         *(p - w + 1) = LINKEDCHAINLIST_MARK;
00513       }
00514   }
00515 }
00516 
00517 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00518 
00519 int
00520 LINKEDCHAINLIST_degree(unsigned char* p, int w)
00521 {
00522   int d = 0;
00523 
00524   if((*(p-1)) != 0)
00525     {
00526       ++d;
00527     }
00528 
00529   if((*(p-w-1)) != 0)
00530     {
00531       ++d;
00532     }
00533 
00534   if((*(p-w)) != 0)
00535     {
00536       ++d;
00537     }
00538 
00539   if((*(p-w+1)) != 0)
00540     {
00541       ++d;
00542     }
00543 
00544   if((*(p+1)) != 0)
00545     {
00546       ++d;
00547     }
00548 
00549   if((*(p+w+1)) != 0)
00550     {
00551       ++d;
00552     }
00553 
00554   if((*(p+w)) != 0)
00555     {
00556       ++d;
00557     }
00558 
00559   if((*(p+w-1)) != 0)
00560     {
00561       ++d;
00562     }
00563 
00564   return d;
00565 }
00566 
00567 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00568 
00569 void
00570 LINKEDCHAINLIST_loadBinNeigh(unsigned char* p, unsigned char* n, int w)
00571 {
00572   *n = *p ? 1 : 0;
00573   ++n;
00574   *n = *(p-1) ? 1 : 0;
00575   ++n;
00576   *n = *(p - w - 1) ? 1 : 0;
00577   ++n;
00578   *n = *(p - w) ? 1 : 0;
00579   ++n;
00580   *n = *(p - w + 1) ? 1 : 0;
00581   ++n;
00582   *n = *(p + 1) ? 1 : 0;
00583   ++n;
00584   *n = *(p + w + 1) ? 1 : 0;
00585   ++n;
00586   *n = *(p + w) ? 1 : 0;
00587   ++n;
00588   *n = *(p + w - 1) ? 1 : 0;
00589   ++n;
00590   *n = *(p - 1) ? 1 : 0;  // n[9] == n[1]
00591 }
00592 
00593 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00594 
00595 int
00596 LINKEDCHAINLIST_crossNb(unsigned char* n, int w)
00597 {
00598   int x4=0;
00599 
00600   for(int k = 1 ; k <= 8 ; ++k)
00601     {
00602       x4 += std::abs(n[k + 1] - n[k]);
00603     }
00604 
00605   x4 /= 2;
00606 
00607   return x4;
00608 }
00609 
00610 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00611 
00612 // To check if a chain is OK
00613 
00614 static bool
00615 LINKEDCHAINLIST_tooSmall(PointChain& xChain)
00616 {
00617   return (xChain.size() < LINKEDCHAINLIST_MINL);
00618 }
00619 
00620 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00621 
00622 // Are two points neighbors?
00623 
00624 bool
00625 LINKEDCHAINLIST_areNeigh(Point p1, Point p2)
00626 {
00627   return    (std::fabs((double)p1.x() - p2.x()) <= 1)
00628             && (std::fabs((double)p1.y() - p2.y()) <= 1);
00629 }
00630 
00631 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00632 
00633 // Can two chains merge?
00634 
00635 int
00636 LINKEDCHAINLIST_canMerge(PointChain& ch1, PointChain& ch2)
00637 {
00638   return    LINKEDCHAINLIST_areNeigh(ch1.back(),  ch2.front())
00639          || LINKEDCHAINLIST_areNeigh(ch1.front(), ch2.back())
00640          || LINKEDCHAINLIST_areNeigh(ch1.front(), ch2.front())
00641          || LINKEDCHAINLIST_areNeigh(ch1.back(),  ch2.back());
00642 }
00643 
00644 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00645 
00646 void
00647 LINKEDCHAINLIST_mergeChains(PointChain& ch1, PointChain& ch2)
00648 {
00649   if (LINKEDCHAINLIST_areNeigh(ch1.front(), ch2.front()))
00650     {
00651       ch1.reverse();
00652     }
00653   else if (LINKEDCHAINLIST_areNeigh(ch1.back(), ch2.back()))
00654     {
00655       ch1.reverse();
00656     }
00657 
00658   if (LINKEDCHAINLIST_areNeigh(ch1.back(), ch2.front()))
00659     {
00660       (ch1.pointList()).insert(ch1.pointList().end(),
00661                                ch2.pointList().begin(),
00662                                ch2.pointList().end());
00663     }
00664 
00665   // add ch2 after ch1
00666   else if (LINKEDCHAINLIST_areNeigh(ch1.front(), ch2.back()))
00667     {
00668       (ch1.pointList()).insert(ch1.pointList().begin(),
00669                                ch2.pointList().begin(),
00670                                ch2.pointList().end());
00671     }
00672 
00673   //  // add ch2 before ch1
00674   //  else
00675   //
00676   //    ;
00677 }
00678 
00679 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00680 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00681 // E N D    O F    L O C A L S
00682 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00683 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00684 
00685 
00686 
00687 
00688 // -------------------------------------------------------------------
00689 // -------------------------------------------------------------------
00690 // C O N S T R U C T O R S
00691 // -------------------------------------------------------------------
00692 // -------------------------------------------------------------------
00693 
00694 
00695 // BUILD FROM GIVEN BINARY IMAGE
00696 
00697 LinkedChainList::LinkedChainList(const BinaryImage& img,
00698                                  unsigned int minChainLength,
00699                                  unsigned int minCycleLength)
00700 
00701   : _minChainLength(minChainLength),
00702     _minCycleLength(minCycleLength)
00703 
00704 {
00705   // Let us first create a work image with pixel values
00706   GreyLevelImage wkImg(img);
00707 
00708   // Set the static global variable
00709   LINKEDCHAINLIST_MINL = minChainLength;
00710 
00711   // Get hold of the pixmap and of height and length
00712   GreyLevelImage::value_type* pixmap = wkImg.pPixMap();
00713   int width = img.width();
00714   int height = img.height();
00715 
00716   // Set borders to zero
00717   GreyLevelImage::value_type* p = pixmap;
00718   for (int i = 0; i < width ; ++i)
00719     {
00720       *p = 0;
00721       ++p;
00722     }
00723 
00724   p = pixmap;
00725   for (int i = 0 ; i < height ; ++i, p += width)
00726     {
00727       *p = 0;
00728     }
00729 
00730   p = pixmap + width - 1;
00731   for (int i = 0 ; i < height ; ++i, p += width)
00732     {
00733       *p = 0;
00734     }
00735 
00736   p = pixmap + (height - 1) * width;
00737   for (int i = 0 ; i < width ; ++i)
00738     {
00739       *p = 0;
00740       ++p;
00741     }
00742 
00743   int i;
00744   // Process the whole image
00745   for (i = 1, p = pixmap + width + 1 ; i < (height - 1) ; ++i, p += 2)
00746     for (int j = 1 ; j < (width - 1) ; ++j, ++p)
00747       if (*p != 0)  // contour point
00748         {
00749           int c4 = LINKEDCHAINLIST_connect4(p, width);
00750           int c8 = LINKEDCHAINLIST_connect8(p, width);
00751 
00752           if ((c4 == 0) && (c8 == 0))
00753             {
00754               // Isolated point: delete it
00755               *p = 0;
00756             }
00757           else if ((c4 + c8) == 1)
00758             {
00759               // Single choice: create a chain and follow it
00760               PointChain* ch1 = new PointChain;
00761               ch1 = aChain(ch1, i, j, wkImg);
00762 
00763               if (ch1 != 0)
00764                 {
00765                   if (ch1->size() < _minChainLength)
00766                     {
00767                       delete ch1;
00768                     }
00769                   else
00770                     {
00771                       push_back(*ch1);   // add to list
00772                     }
00773                 }
00774             }
00775           else
00776             {
00777               // All other cases
00778               // Create a first chain
00779               PointChain* ch1 = new PointChain;
00780               // Build a first chain
00781               ch1 = aChain(ch1, i, j, wkImg);
00782               // And if there are still neighbors, build other chains and
00783               // merge
00784 
00785               if ((LINKEDCHAINLIST_connect4(p, width) +
00786                    LINKEDCHAINLIST_connect8(p, width)) != 0)
00787                 {
00788                   // get a neighbor
00789                   Point v = LINKEDCHAINLIST_neigh(p, i, j, width);
00790                   PointChain* ch2 = new PointChain;
00791                   ch2 = aChain(ch2, v.y(), v.x(), wkImg); // chain
00792 
00793                   if ((ch1 != 0) && (ch2 != 0) && LINKEDCHAINLIST_canMerge(*ch1, *ch2))
00794                     {
00795                       LINKEDCHAINLIST_mergeChains(*ch1, *ch2);
00796                       delete ch2;
00797                     }
00798                   else if (ch2 != 0)
00799                     {
00800                       if(ch2->size() < _minChainLength)
00801                         {
00802                           delete ch2;
00803                         }
00804                       else
00805                         {
00806                           push_back(*ch2);   // add to list
00807                         }
00808                     }
00809                 }
00810 
00811               if (ch1 != 0)
00812                 {
00813                   if(ch1->size() < _minChainLength)
00814                     {
00815                       delete ch1;
00816                     }
00817                   else
00818                     {
00819                       push_back(*ch1);   // add to list
00820                     }
00821                 }
00822             }
00823 
00824         }
00825 }
00826 
00827 
00828 // -------------------------------------------------------------------
00829 
00830 
00831 // CONSTRUCT FROM A LABELED SKELETON
00832 
00833 LinkedChainList::LinkedChainList(const LabeledSkeletonImage& skel)
00834 
00835   throw(QgarErrorDeveloper)
00836 
00837   : _minChainLength(0),
00838     _minCycleLength(0)
00839 
00840 {
00841   // Let us first create a work image with pixel values
00842   GreyLevelImage wkImg(skel);
00843 
00844   // Get hold of the pixmap and of height and length
00845   GreyLevelImage::value_type* pixmap = wkImg.pPixMap();
00846   int width = skel.width();
00847   int height = skel.height();
00848 
00849   int i = 0;
00850   GreyLevelImage::value_type* p = pixmap;
00851 
00852   GreyLevelImage::value_type n[10];
00853   // Mark all points of degree different from 2
00854   // or of degree equal to 2, but with special configuration
00855 
00856   for (i = 1, p = pixmap + width + 1 ; i < height - 1 ; ++i, p += 2)
00857     for (int j = 1 ; j < width - 1 ; ++j, ++p)
00858       if (*p != 0)  // we are on a skeleton point
00859       {
00860         LINKEDCHAINLIST_loadBinNeigh(p, n, width);
00861 
00862         if (((*(p-width) != 0) && (*(p-width+1) != 0) && (*(p+1) != 0)) ||
00863             ((*(p+1) != 0) && (*(p+width+1) != 0) && (*(p+width) != 0)) ||
00864             ((*(p+width) != 0) && (*(p+width-1) != 0) && (*(p-1) != 0)) ||
00865             ((*(p-1) != 0) && (*(p-width-1) != 0) && (*(p-width) != 0)))
00866           {
00867             *p = LINKEDCHAINLIST_MARK;  // special square configuration
00868           }
00869         else if (LINKEDCHAINLIST_crossNb(n, width) == 2)
00870           {
00871             *p = 255;
00872           }
00873         else
00874           {
00875             *p = LINKEDCHAINLIST_MARK;
00876           }
00877       }
00878 
00879   int encore = 1;
00880   // Now, go through image and chain
00881 
00882   while (encore)
00883   {
00884     for (i = 1, p = pixmap + width + 1 ; i < height - 1 ; ++i, p += 2)
00885       for (int j = 1 ; j < width - 1 ; ++j, ++p)
00886         if (*p == LINKEDCHAINLIST_MARK)  // marked point
00887         {
00888           int d = LINKEDCHAINLIST_degree(p, width);
00889 
00890           if (d == 0)
00891             // Isolated point: delete it
00892             *p = 0;
00893           else // there are points to follow
00894           {
00895             // Create the starting point for all the chains
00896             Point fPoint(j, i);
00897             // Get all its non-null neighbors and mark them as potential
00898             // points to follow by decrementing their value by 1
00899             list<Point> pList;
00900 
00901             if(*(p+1) != 0)
00902             {
00903               Point aPoint = fPoint;
00904               aPoint.translate(1, 0);
00905               pList.push_back(aPoint);
00906               *(p+1) -= 1;
00907             }
00908 
00909             if(*(p+width) != 0)
00910             {
00911               Point aPoint = fPoint;
00912               aPoint.translate(0, 1);
00913               pList.push_back(aPoint);
00914               *(p+width) -= 1;
00915             }
00916 
00917             if(*(p-1) != 0)
00918             {
00919               Point aPoint = fPoint;
00920               aPoint.translate(-1, 0);
00921               pList.push_back(aPoint);
00922               *(p-1) -= 1;
00923             }
00924 
00925             if(*(p-width) != 0)
00926             {
00927               Point aPoint = fPoint;
00928               aPoint.translate(0, -1);
00929               pList.push_back(aPoint);
00930               *(p-width) -= 1;
00931             }
00932 
00933             if(*(p+width+1) != 0 && *(p+1) == 0 && *(p+width) == 0)
00934             {
00935               Point aPoint = fPoint;
00936               aPoint.translate(1, 1);
00937               pList.push_back(aPoint);
00938               *(p+width+1) -= 1;
00939             }
00940 
00941             if(*(p+width-1) != 0 && *(p+width) == 0 && *(p-1) == 0)
00942             {
00943               Point aPoint = fPoint;
00944               aPoint.translate(-1, 1);
00945               pList.push_back(aPoint);
00946               *(p+width-1) -= 1;
00947             }
00948 
00949             if(*(p-width-1) !=0 && *(p-1) == 0 && *(p-width) == 0)
00950             {
00951               Point aPoint = fPoint;
00952               aPoint.translate(-1, -1);
00953               pList.push_back(aPoint);
00954               *(p-width-1) -= 1;
00955             }
00956 
00957             if(*(p-width+1) != 0 && *(p-width) == 0 && *(p+1) == 0)
00958             {
00959               Point aPoint = fPoint;
00960               aPoint.translate(1, -1);
00961               pList.push_back(aPoint);
00962               *(p-width+1) -= 1;
00963             }
00964 
00965             list<Point>::iterator myIter = pList.begin();
00966 
00967             while (myIter != pList.end())
00968             {
00969               Point cPoint = fPoint;
00970               // create a chain
00971               PointChain* ch = new PointChain;
00972               ch->push_back(cPoint); // put the first point in chain
00973               // temporarily delete start point so that we do not fall
00974               // back to it prematurely
00975               *p = 0;
00976               // put the second point in the chain
00977               cPoint = *myIter;
00978               ch->push_back(cPoint);
00979               GreyLevelImage::value_type* pp = pixmap + cPoint.y() * width + cPoint.x();
00980               // If we had removed it at a previous step (loop)
00981               // forget the whole thing
00982 
00983               if (*pp == 0)
00984               {
00985                 delete ch;
00986                 ++myIter;
00987                 continue;
00988               }
00989 
00990               // Increment it again
00991               *pp += 1;
00992 
00993               int continueChain = 1;
00994 
00995               if (*pp == LINKEDCHAINLIST_MARK)
00996                 continueChain = 0;
00997               else
00998                 *pp = 0;
00999 
01000               while (continueChain)
01001               {
01002                 int checkLoop = 0;
01003                 // try to get a non marked 4-neighbor
01004                 Point nPoint = LINKEDCHAINLIST_neigh4(pp, cPoint.y(), cPoint.x(), width);
01005 
01006                 if (nPoint == cPoint)
01007                 { // If I did not find a non-marked 4-neighbor
01008                   // try to get a marked 4-neighbor
01009                   nPoint = LINKEDCHAINLIST_neigh4M(pp, cPoint.y(), cPoint.x(), width);
01010 
01011                   if (nPoint == cPoint)
01012                   {
01013                     // If no marked 4-neighbor, look for a
01014                     // non-marked 8-neighbor
01015                     nPoint = LINKEDCHAINLIST_neigh8(pp, cPoint.y(),
01016                                                     cPoint.x(), width);
01017 
01018                     if (nPoint == cPoint)
01019                     {
01020                       // no non-marked, look for marked 8 neighbor
01021                       nPoint = LINKEDCHAINLIST_neigh8M(pp,
01022                                                        cPoint.y(),
01023                                                        cPoint.x(),
01024                                                        width);
01025 
01026                       if (nPoint == cPoint)
01027                         // Nothing found
01028                       {
01029                         // get a neighbor (mark decremented)
01030                         nPoint = LINKEDCHAINLIST_neighPlus(pp, cPoint.y(), cPoint.x(), width);
01031 
01032                         if (nPoint == cPoint)
01033                           {
01034                             // Nothing found
01035                             throw QgarErrorDeveloper(__FILE__, __LINE__,
01036                                                      "qgar::LinkedChainList::LinkedChainList(const qgar::LabeledSkeletonImage&)",
01037                                                      "Strange things happen: See Karl!");
01038                           }
01039                         else
01040                           checkLoop = 1;
01041 
01042                         continueChain = 0;
01043                       }
01044                       else
01045                         continueChain = 0;
01046                     }
01047                   }
01048                   else
01049                     continueChain = 0; // we have a marked 4-neighbor
01050                 }
01051 
01052                 // update current point
01053                 cPoint = nPoint;
01054 
01055                 // add to chain
01056                 ch->push_back(cPoint);
01057 
01058                 // update pointer
01059                 pp = pixmap + cPoint.y() * width + cPoint.x();
01060 
01061                 // if we were on a continuation pixel, delete it
01062                 if (continueChain)
01063                   *pp = 0;
01064                 else if (checkLoop)
01065                 {
01066                   // We came back to the beginning
01067                   // If we are on a marked point, we must stop
01068                   // it not we can loop
01069 
01070                   if (*pp != (LINKEDCHAINLIST_MARK - 1))
01071                   {
01072                     // add first point to chain again (loop)
01073                     ch->push_back(fPoint);
01074                     // and set point to zero
01075                     *pp = 0;
01076                   }
01077                 }
01078               }
01079 
01080               // We have ended the chaining.
01081               push_back(*ch);   // add to list
01082 
01083               // restore mark on current pixel
01084               *p = LINKEDCHAINLIST_MARK;
01085 
01086               // get next point to follow
01087               ++myIter;
01088             }
01089 
01090             // At end, set point to 0 as it is completely processed
01091             *p = 0;
01092           }
01093 
01094         }
01095 
01096     // OK: Do we have perfect loops?
01097     encore = 0;
01098 
01099     for (i = 1, p = pixmap + width + 1 ;
01100          (encore == 0) && (i < height - 1) ;
01101          ++i, p += 2)
01102       {
01103         for (int j = 1 ; j < width - 1 ; ++j, ++p)
01104           {
01105             if (*p != 0)  // we are on a skeleton point
01106               {
01107                 *p = LINKEDCHAINLIST_MARK;
01108                 encore = 1;
01109                 break;
01110               }
01111           }
01112       }
01113   }
01114 
01115 }
01116 
01117 
01118 // -------------------------------------------------------------------
01119 
01120 
01121 // BUILD WITH GIVEN MINIMAL LENGTH PARAMETERS
01122 //
01123 // For temporary use!
01124 
01125 LinkedChainList::LinkedChainList(unsigned int minChainLength,
01126                                  unsigned int minCycleLength)
01127 
01128     : _minChainLength(minChainLength),
01129       _minCycleLength(minCycleLength)
01130 
01131   {
01132     // VOID
01133   }
01134 
01135 
01136 // -------------------------------------------------------------------
01137 // -------------------------------------------------------------------
01138 // D E S T R U C T O R
01139 // -------------------------------------------------------------------
01140 // -------------------------------------------------------------------
01141 
01142 
01143 // VIRTUAL DESTRUCTOR
01144 LinkedChainList::~LinkedChainList()
01145 {
01146   erase(begin(), end());
01147 }
01148 
01149 
01150 // -------------------------------------------------------------------
01151 // -------------------------------------------------------------------
01152 // P R I V A T E   A U X I L I A R Y   F U N C T I O N S
01153 // -------------------------------------------------------------------
01154 // -------------------------------------------------------------------
01155 
01156 
01157 // RECURSIVE FUNCTION FOR CHAINING
01158 
01159 PointChain*
01160 LinkedChainList::aChain(PointChain* ch,
01161                         int l,
01162                         int c,
01163                         GreyLevelImage& wkImg)
01164 {
01165   // Get hold of the pixmap and of height and length
01166   GreyLevelImage::value_type* pixmap = wkImg.pPixMap();
01167   int width = wkImg.width();
01168 
01169   // Possible list of temporary chain
01170   LinkedChainList tmpList(_minChainLength, _minCycleLength);
01171 
01172   // Add current point to the chain
01173   Point cPoint(c, l);
01174   ch->push_back(cPoint);
01175 
01176   // Set the point to zero
01177   GreyLevelImage::value_type* p = pixmap + l * width + c;
01178   *p = 0;
01179   int c4 = LINKEDCHAINLIST_connect4(p, width);
01180   int c8 = LINKEDCHAINLIST_connect8(p, width);
01181 
01182   if ((c4 == 0) && (c8 == 0))
01183   {
01184     // if there is a cycle, insert last point
01185 
01186     if ((ch->size() >= _minCycleLength) &&
01187         (LINKEDCHAINLIST_connect4M(p, width) == 1) &&
01188         (LINKEDCHAINLIST_connect8M(p, width) == 0))
01189     {
01190       Point v = LINKEDCHAINLIST_neigh4M(p, l, c, width); // get marked neighbor
01191       ch->push_back(v);
01192       *(pixmap + v.y() * width + v.x()) = 0; // set to zero
01193     }
01194     else if ((ch->size() >= _minCycleLength) &&
01195              (LINKEDCHAINLIST_connect8M(p, width) == 1) &&
01196              (LINKEDCHAINLIST_connect4M(p, width) == 0))
01197     {
01198       Point v = LINKEDCHAINLIST_neigh8M(p, l, c, width); // get marked neighbor
01199       ch->push_back(v);
01200       *(pixmap + v.y() * width + v.x()) = 0; // set to zero
01201     }
01202 
01203     return ch;
01204   }
01205 
01206   else if ((c4 + c8) == 1)  // only one choice to continue
01207   {
01208     Point v = LINKEDCHAINLIST_neigh(p, l, c, width);  // get continuation
01209     // recursion
01210     return aChain(ch, v.y(), v.x(), wkImg);
01211   }
01212   else // in all other cases
01213   {
01214     LINKEDCHAINLIST_markNeigh(p, width, c4, c8);    // mark the neighbors
01215 
01216     while (LINKEDCHAINLIST_connect4M(p, width) +
01217            LINKEDCHAINLIST_connect8M(p, width) != 0)
01218     {
01219       // As long as there are unprocessed neighbors
01220       // create chains and add them to a temporary list
01221       Point v = LINKEDCHAINLIST_neighM(p, l, c, width);  // get a marked neighbor
01222       PointChain* tmpch = new PointChain;
01223       tmpch = aChain(tmpch, v.y(), v.x(), wkImg);
01224 
01225       if (tmpch != 0)
01226         tmpList.push_back(*tmpch);
01227     }
01228 
01229     // Remove from tmpList too small chains
01230     LinkedChainList::iterator newend =
01231       std::remove_if(tmpList.begin(), tmpList.end(), LINKEDCHAINLIST_tooSmall);
01232 
01233     //  remove_if(tmpList.begin(), tmpList.end(), LINKEDCHAINLIST_tooSmall);
01234     tmpList.erase(newend, tmpList.end());
01235 
01236     // if there is a single remaining chain, see if we can merge with ch
01237     if (tmpList.size() == 1 && LINKEDCHAINLIST_canMerge(*ch, tmpList.front()))
01238     {
01239       PointChain tmpChain = tmpList.front(); // get chain
01240       tmpList.pop_front();   // remove it from list
01241 
01242       // Merge them
01243       LINKEDCHAINLIST_mergeChains(*ch, tmpChain);
01244 
01245       // return
01246       return ch;
01247     }
01248     else if (tmpList.size() > 1 && ch->size() == 1) // ch is a single point
01249     {
01250       LinkedChainList::iterator tmpIter = tmpList.begin();
01251 
01252       while (tmpIter != tmpList.end())
01253         if ((*tmpIter).size() > 0 &&
01254             LINKEDCHAINLIST_canMerge(*ch, *tmpIter))
01255         {
01256           LINKEDCHAINLIST_mergeChains(*tmpIter, *ch);
01257           delete ch;
01258           ch = 0;
01259           break;
01260         }
01261         else
01262           {
01263             ++tmpIter;
01264           }
01265     }
01266 
01267     // Add to global list all remaining chains in tmpList
01268     insert(end(),tmpList.begin(),tmpList.end());
01269 
01270     return ch;
01271   }
01272 }
01273 
01274 
01275 // -------------------------------------------------------------------
01276 
01277 } // namespace qgar