src/qvdta/qvcontour.cpp

Go to the documentation of this file.
00001 /*
00002  *      Copyright (C) 2007. PARP Research Group.
00003  *      <http://perception.inf.um.es>
00004  *      University of Murcia, Spain.
00005  *
00006  *      This file is part of the QVision library.
00007  *
00008  *      QVision is free software: you can redistribute it and/or modify
00009  *      it under the terms of the GNU Lesser General Public License as
00010  *      published by the Free Software Foundation, version 3 of the License.
00011  *
00012  *      QVision is distributed in the hope that it will be useful,
00013  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *      GNU Lesser General Public License for more details.
00016  *
00017  *      You should have received a copy of the GNU Lesser General Public
00018  *      License along with QVision. If not, see <http://www.gnu.org/licenses/>.
00019  */
00020 
00024 
00025 #include <qvdta/qvcontour.h>
00026 
00027 namespace qvdta
00028 {
00029 // Direction-número            Y
00030 //      NE-7    N-0     NW-1    |
00031 //      E-6     *       W-2     v
00032 //      SE-5    S-4     SW-3
00033 // X -->
00034 //                              N       NO      O       SO      S       SE      E       NE
00035 const char      coorX[8] = {    0,      1,      1,      1,      0,      -1,     -1,     -1 };
00036 const char      coorY[8] = {    -1,     -1,     0,      1,      1,      1,      0,      -1 };
00037 
00038 // Auxiliar function for border extraction. It gets a border point, and the direction where there is one of the outside of the connected-set pixels.
00039 QVPolyline getContourThresholdFromBorderPoint(const QVImage<uChar> &image, const int startPointX, const int startPointY, const uChar threshold)
00040         {
00041         //std::cout << "xx"<< std::endl;
00042         QVPolyline lista;
00043 
00044         //std::cout << "xx 1"<< std::endl;
00045         lista.loop = true;
00046         lista.append(QPoint(startPointX, startPointY));
00047 
00048         QVIMAGE_INIT_READ(uChar,image);
00049         QRect roi = image.getROI();
00050 
00051         //std::cout << "xx 2"<< std::endl;
00052         Q_ASSERT_X(roi.contains(startPointX, startPointY), "getContourThresholdFromBorderPoint", "start point out of image ROI");
00053         Q_ASSERT_X(QVIMAGE_PIXEL(image, startPointX, startPointY, 0) >= threshold, "getContourThresholdFromBorderPoint", "start point is not contained in a connected set");
00054 
00055         //std::cout << "xx 3" << std::endl;
00056 
00057         // Comprobamos tanto que no tenemos un píxel interior, como que no tenemos un píxel solitario.
00058         // De paso buscamos una dirección en la que haya un píxel vacío (que no pertenezca a un conjunto).
00059         uChar searchDir = 128, numOuterPixels = 0;
00060         for (int i = 0; i<8; i++)
00061                 {
00062                 int x =  startPointX +coorX[i], y =  startPointY +coorY[i];
00063                 if (!roi.contains(x, y))
00064                         {
00065                         numOuterPixels++;
00066                         searchDir = i;
00067                         }
00068                 else if (QVIMAGE_PIXEL(image, x, y,0) < threshold)
00069                         {
00070                         numOuterPixels++;
00071                         searchDir = i;
00072                         }
00073                 }
00074 
00075         // Caso de que se haya proporcionado un píxel interior, assert
00076         Q_ASSERT_X(searchDir < 8, "getContourThresholdFromBorderPoint", "start point is inside the set, not in the border");
00077 
00078         // Caso de que se haya proporcionado un píxel solitario, devolvermos ese pixeĺ sólo:
00079         if (numOuterPixels == 8)
00080                 return lista;
00081 
00082         //std::cout << "xx 4" << std::endl;
00083 
00084         // Recorremos cada punto del contorno, insertándolo en la lista de puntos.
00085         int sumSearchDir = 0, actualPointX = startPointX, actualPointY = startPointY;
00086         while (true)
00087                 {
00088                 // We search for the next point belonging to the contour.
00089                 uChar d;
00090                 int     nextPointX, nextPointY;
00091                 for (d = 0; d < 8; d++)
00092                         {
00093                         searchDir = (searchDir+1)%8;
00094                         nextPointX = actualPointX + coorX[searchDir];
00095                         nextPointY = actualPointY + coorY[searchDir];
00096                         if (roi.contains(nextPointX, nextPointY))
00097                                 if ( (QVIMAGE_PIXEL(image, nextPointX, nextPointY,0) >= threshold) )
00098                                         break;
00099                         }
00100 
00101                 sumSearchDir += d - 3;
00102 
00103                 actualPointX = nextPointX;
00104                 actualPointY = nextPointY;
00105 
00106                 if ( QVIMAGE_PIXEL(image, actualPointX, actualPointY,0) < threshold )
00107                         break;
00108 
00109                 if ( startPointX == actualPointX && startPointY == actualPointY)
00110                         break;
00111 
00112                 lista.append(QPoint(actualPointX, actualPointY));
00113                 //std::cout << " 4" << actualPointX << ", " << actualPointY << std::endl;
00114                 searchDir = searchDir + 4;
00115                 }
00116 
00117         //std::cout << " 4" << std::endl;
00118 
00119         lista.direction = (sumSearchDir >= 0);
00120         lista.dir = sumSearchDir;
00121 
00122         //std::cout << " end" << std::endl;
00123         return lista;
00124         }
00125 
00126 QVPolyline getContourThreshold(const QVImage<uChar> &image, const QPoint startPoint, const uChar threshold)
00127         {
00128         // TODO: esto tiene que arreglarse.
00129         //QVIMAGE_INIT_READ(uChar,image);
00130         //QRect roi = image.getROI();
00131 
00132         int     startPointX = startPoint.x(), startPointY = startPoint.y();
00133 
00134         //Q_ASSERT_X(roi.contains(startPointX, startPointY), "getContourThreshold", "start point out of image ROI");
00135         //Q_ASSERT_X(QVIMAGE_PIXEL(image, startPointX, startPointY, 0) >= threshold, "getContourThreshold", "start point is not contained in a connected set");
00136 
00137         // Buscamos un punto alrededor del inicial, en sentido de las agujas de reloj, que NO
00138         // pertenezca al contorno. (debe de existir, si el que use la clase se asegura de
00139         // crearla con un punto adecuado).
00140         /*uChar searchDir;
00141         for (searchDir = 0; searchDir<8; searchDir++)
00142                 {
00143                 int     startX = startPoint.x() + coorX[searchDir],
00144                         startY = startPoint.y() + coorY[searchDir];
00145 
00146                 if (!roi.contains(startX, startY))
00147                         break;
00148 
00149                 if ( !(QVIMAGE_PIXEL(image, startX, startY,0) >= threshold) )
00150                         break;
00151                 }
00152 
00153         searchDir = (searchDir+4)%8;*/
00154 
00155         return getContourThresholdFromBorderPoint(image, startPointX, startPointY, threshold);
00156         }
00157 
00158 QList<QVPolyline> getContoursThreshold(const QVImage <uChar> &image, const uChar threshold)
00159         {
00160         //std::cout << "in" << std::endl;
00161         qDebug() << "getPolylinesThreshold()";
00162         QVImage<uChar> mask(image.getCols()+1, image.getRows()+1);
00163         qvipp::Set(mask,0);
00164         //std::cout << "in 1" << std::endl;
00165         QVIMAGE_INIT_READ(uChar,image);
00166         QVIMAGE_INIT_WRITE(uChar,mask);
00167 
00168         QRect roi = image.getROI();
00169 
00170         QList<QVPolyline> polylineList;
00171         //std::cout << "in 2" << std::endl;
00172         // Recorremos la imagen buscando píxeles que correspondan a algún grupo
00173         for (int row = roi.y(); row < roi.y() + roi.height(); row++)
00174                 for (int col = roi.x(); col < roi.y() + roi.width(); col++)
00175                         {
00176                         // En cada paso siempre que encontremos un píxel que pertenezca a algún conjunto conexo, pertenecerá a su contorno.
00177                         if (QVIMAGE_PIXEL(image, col, row,0) >= threshold)
00178                                 {
00179                                 //std::cout << "\tloop start " << col << ", " << row << std::endl;
00180 
00181                                 // si no están marcados, obtenemos el contorno al que pertenecen.
00182                                 if ( !QVIMAGE_PIXEL(mask, col, row,0) )
00183                                         {
00184                                         //std::cout << "\tZ" << std::endl;
00185                                         QVPolyline lista = getContourThresholdFromBorderPoint(image, col, row, threshold);
00186                                         //std::cout << "\tA" << std::endl;
00187                                         draw(mask, lista, true, true);
00188                                         //std::cout << "\tB" << std::endl;
00189                                         polylineList.append(lista);
00190                                         //std::cout << "\tC" << std::endl;
00191                                         }
00192                                 //std::cout << "\tloop 1" << std::endl;
00193 
00194                                 // Nos aseguramos de que el siguiente píxel pertenezca al contorno.
00195                                 while (roi.contains(col+1, row))
00196                                         {
00197                                         if ( QVIMAGE_PIXEL(image, col+1, row,0) < threshold )
00198                                                 break;
00199                                         col++;
00200                                         }
00201                                 //std::cout << "\tloop 2" << std::endl;
00202 
00203                                 // esto es por si tenemos un contorno interno, puede ser que no se procese correctamente. Nos aseguramos.
00204                                 if ( !QVIMAGE_PIXEL(mask, col, row,0) )
00205                                         {
00206                                         QVPolyline lista = getContourThresholdFromBorderPoint(image, col, row, threshold);
00207                                         draw(mask, lista, true, true);
00208                                         polylineList.append(lista);
00209                                         }
00210                                 //std::cout << "\tloop end" << std::endl;
00211                                 }
00212 
00213                         }
00214         //std::cout << "in 3" << std::endl;
00215         qDebug() << "getPolylinesThreshold():"<< polylineList.size() << "contours obtained";
00216         qDebug() << "getPolylinesThreshold() <~ return";
00217         return polylineList;
00218         }
00219 }

Generated on Fri Dec 7 12:20:59 2007 for QVision by  doxygen 1.5.3