Statistics
| Revision:

root / org.gvsig.toolbox / trunk / org.gvsig.toolbox / org.gvsig.toolbox.algorithm / src / main / java / es / unex / sextante / imageAnalysis / vectorizeTrees / VectorizeTreesAlgorithm.java @ 59

History | View | Annotate | Download (17 KB)

1
package es.unex.sextante.imageAnalysis.vectorizeTrees;
2

    
3
import java.awt.Point;
4
import java.awt.geom.Point2D;
5
import java.awt.geom.Rectangle2D;
6
import java.util.ArrayList;
7
import java.util.Arrays;
8

    
9
import com.vividsolutions.jts.geom.Coordinate;
10
import com.vividsolutions.jts.geom.Envelope;
11
import com.vividsolutions.jts.geom.Geometry;
12
import com.vividsolutions.jts.geom.GeometryFactory;
13

    
14
import es.unex.sextante.additionalInfo.AdditionalInfoMultipleInput;
15
import es.unex.sextante.additionalInfo.AdditionalInfoNumericalValue;
16
import es.unex.sextante.additionalInfo.AdditionalInfoVectorLayer;
17
import es.unex.sextante.core.AnalysisExtent;
18
import es.unex.sextante.core.GeoAlgorithm;
19
import es.unex.sextante.core.Sextante;
20
import es.unex.sextante.dataObjects.IFeature;
21
import es.unex.sextante.dataObjects.IFeatureIterator;
22
import es.unex.sextante.dataObjects.IRasterLayer;
23
import es.unex.sextante.dataObjects.IVectorLayer;
24
import es.unex.sextante.exceptions.GeoAlgorithmExecutionException;
25
import es.unex.sextante.exceptions.IteratorException;
26
import es.unex.sextante.exceptions.RepeatedParameterNameException;
27
import es.unex.sextante.math.simpleStats.SimpleStats;
28
import es.unex.sextante.outputs.OutputVectorLayer;
29
import es.unex.sextante.parameters.RasterLayerAndBand;
30
import es.unex.sextante.rasterWrappers.GridCell;
31

    
32
public class VectorizeTreesAlgorithm
33
         extends
34
            GeoAlgorithm {
35

    
36
   private final static int   m_iOffsetX[]       = { 0, 1, 1, 1, 0, -1, -1, -1 };
37
   private final static int   m_iOffsetY[]       = { 1, 1, 0, -1, -1, -1, 0, 1 };
38

    
39
   public static final String INPUT              = "INPUT";
40
   public static final String POLYGONS           = "POLYGONS";
41
   public static final String TOLERANCE_SPECTRAL = "TOLERANCE_SPECTRAL";
42
   public static final String TOLERANCE_SIZE     = "TOLERANCE_SIZE";
43
   public static final String MINSIZE            = "MINSIZE";
44
   public static final String MAXSIZE            = "MAXSIZE";
45
   public static final String TREES              = "TREES";
46

    
47
   private static final int   ANALIZED           = 2;
48

    
49
   private int                m_iMinX, m_iMinY;
50
   private IRasterLayer[]     m_Window;
51
   private IRasterLayer       m_BinaryImage;
52
   private ArrayList          m_Bands;
53
   private IVectorLayer       m_Polygons;
54
   private ArrayList          m_Stats;
55
   private SimpleStats        m_SizeStats;
56
   private IVectorLayer       m_Trees;
57
   private ArrayList          m_TreesArray;
58
   private double             m_dTolerance;
59
   private double             m_dToleranceSize;
60
   private double             m_dMinSize;
61
   private double             m_dMaxSize;
62
   private GeometryFactory    m_GeometryFactory;
63
   private int                m_iBand[];
64

    
65

    
66
   @Override
67
   public void defineCharacteristics() {
68

    
69
      setName(Sextante.getText("Detect_and_vectorize_individual_trees"));
70
      setGroup(Sextante.getText("Image_processing"));
71
      setUserCanDefineAnalysisExtent(true);
72

    
73
      try {
74
         m_Parameters.addMultipleInput(INPUT, Sextante.getText("Bands"), AdditionalInfoMultipleInput.DATA_TYPE_BAND, true);
75
         m_Parameters.addInputVectorLayer(POLYGONS, Sextante.getText("Sample_trees"),
76
                  AdditionalInfoVectorLayer.SHAPE_TYPE_POLYGON, true);
77
         m_Parameters.addNumericalValue(TOLERANCE_SPECTRAL, Sextante.getText("Tolerance"),
78
                  AdditionalInfoNumericalValue.NUMERICAL_VALUE_DOUBLE, 1, 0, Double.MAX_VALUE);
79
         m_Parameters.addNumericalValue(TOLERANCE_SIZE, Sextante.getText("Tolerance_[size]"),
80
                  AdditionalInfoNumericalValue.NUMERICAL_VALUE_DOUBLE, 1, 0, Double.MAX_VALUE);
81
         //                        m_Parameters.addNumericalValue(MINSIZE,
82
         //                                                                                    Sextante.getText( "Tamano_min"),
83
         //                                                                                    AdditionalInfoNumericalValue.NUMERICAL_VALUE_DOUBLE,
84
         //                                                                                    0,0, Double.MAX_VALUE);
85
         //                        m_Parameters.addNumericalValue(MAXSIZE,
86
         //                                                                                        Sextante.getText( "Tamano_max"),
87
         //                                                                                        AdditionalInfoNumericalValue.NUMERICAL_VALUE_DOUBLE,
88
         //                                                                                        100,0, Double.MAX_VALUE);
89
         addOutputVectorLayer(TREES, Sextante.getText("Trees"), OutputVectorLayer.SHAPE_TYPE_POINT);
90
      }
91
      catch (final RepeatedParameterNameException e) {
92
         Sextante.addErrorToLog(e);
93
      }
94

    
95
   }
96

    
97

    
98
   @Override
99
   public boolean processAlgorithm() throws GeoAlgorithmExecutionException {
100

    
101
      int i;
102

    
103
      m_GeometryFactory = new GeometryFactory();
104

    
105
      m_Bands = m_Parameters.getParameterValueAsArrayList(INPUT);
106
      m_Polygons = m_Parameters.getParameterValueAsVectorLayer(POLYGONS);
107
      m_dTolerance = m_Parameters.getParameterValueAsDouble(TOLERANCE_SPECTRAL);
108
      m_dToleranceSize = m_Parameters.getParameterValueAsDouble(TOLERANCE_SIZE);
109
      //                m_dMinSize = m_Parameters.getParameterValueAsDouble(MINSIZE);
110
      //                m_dMaxSize = m_Parameters.getParameterValueAsDouble(MAXSIZE);
111

    
112
      m_TreesArray = new ArrayList();
113

    
114
      m_Trees = getNewVectorLayer(TREES, Sextante.getText("Trees"), IVectorLayer.SHAPE_TYPE_POINT, new Class[] { Integer.class,
115
               Double.class, Double.class },
116
               new String[] { "ID", Sextante.getText("Superficie"), Sextante.getText("coef_forma") });
117

    
118
      m_SizeStats = new SimpleStats();
119

    
120
      getClassInformation();
121

    
122
      m_BinaryImage = this.getTempRasterLayer(IRasterLayer.RASTER_DATA_TYPE_BYTE, m_AnalysisExtent, 1);
123
      m_BinaryImage.setNoDataValue(0.);
124

    
125
      for (i = 0; i < m_Window.length; i++) {
126
         m_Window[i].setWindowExtent(m_AnalysisExtent);
127
      }
128

    
129
      doParalellpiped();
130
      detectAndVectorizeTrees();
131

    
132
      //addOutputObject("out", "out", null, m_BinaryImage);
133

    
134
      return !m_Task.isCanceled();
135

    
136

    
137
   }
138

    
139

    
140
   private void detectAndVectorizeTrees() {
141

    
142
      int x, y;
143
      int iNX, iNY;
144
      double dValue;
145

    
146
      iNX = m_BinaryImage.getWindowGridExtent().getNX();
147
      iNY = m_BinaryImage.getWindowGridExtent().getNY();
148

    
149
      setProgressText(Sextante.getText("Vectorizing"));
150
      for (y = 0; (y < iNY) && setProgress(y, iNY); y++) {
151
         for (x = 0; x < iNX; x++) {
152
            dValue = m_BinaryImage.getCellValueAsDouble(x, y);
153
            if (!m_BinaryImage.isNoDataValue(dValue) && (dValue != ANALIZED)) {
154
               detectTree(x, y);
155
            }
156
         }
157
      }
158

    
159
      vectorize();
160

    
161
   }
162

    
163

    
164
   private void detectTree(int x,
165
                           int y) {
166

    
167
      int x2, y2;
168
      int iPt;
169
      int n;
170
      int iCells = 0;
171
      int xMax = Integer.MIN_VALUE;
172
      int yMax = Integer.MIN_VALUE;
173
      int xMin = Integer.MAX_VALUE;
174
      int yMin = Integer.MAX_VALUE;
175
      double xCenter, yCenter;
176
      double dValue;
177
      ArrayList centralPoints = new ArrayList();
178
      ArrayList adjPoints = new ArrayList();
179
      Point point;
180

    
181
      xMin = Math.min(xMin, x);
182
      yMin = Math.min(yMin, y);
183
      xMax = Math.max(xMax, x);
184
      yMax = Math.max(yMax, y);
185
      iCells++;
186

    
187
      centralPoints.add(new Point(x, y));
188
      //m_BinaryImage.setNoData(x,y);
189
      m_BinaryImage.setCellValue(x, y, ANALIZED);
190
      while (centralPoints.size() != 0) {
191
         for (iPt = 0; iPt < centralPoints.size(); iPt++) {
192
            point = (Point) centralPoints.get(iPt);
193
            x = point.x;
194
            y = point.y;
195
            for (n = 0; n < 8; n++) {
196
               x2 = x + m_iOffsetX[n];
197
               y2 = y + m_iOffsetY[n];
198
               dValue = m_BinaryImage.getCellValueAsDouble(x2, y2);
199
               if (!m_BinaryImage.isNoDataValue(dValue) && (dValue != ANALIZED)) {
200
                  //m_BinaryImage.setNoData(x2,y2);
201
                  m_BinaryImage.setCellValue(x2, y2, ANALIZED);
202
                  adjPoints.add(new Point(x2, y2));
203
                  xMin = Math.min(xMin, x2);
204
                  yMin = Math.min(yMin, y2);
205
                  xMax = Math.max(xMax, x2);
206
                  yMax = Math.max(yMax, y2);
207
                  iCells++;
208
               }
209
            }
210
         }
211

    
212
         centralPoints = adjPoints;
213
         adjPoints = new ArrayList();
214

    
215
         if (m_Task.isCanceled()) {
216
            return;
217
         }
218

    
219
      }
220

    
221
      if (Math.abs(iCells - m_SizeStats.getMean()) < m_SizeStats.getStdDev() * m_dToleranceSize) {
222
         final Tree tree = new Tree();
223
         final GridCell cellMin = new GridCell(xMin, yMin, 0);
224
         final GridCell cellMax = new GridCell(xMax, yMax, 0);
225
         final Point2D ptMin = m_AnalysisExtent.getWorldCoordsFromGridCoords(cellMin);
226
         final Point2D ptMax = m_AnalysisExtent.getWorldCoordsFromGridCoords(cellMax);
227
         xCenter = (ptMax.getX() + ptMin.getX()) / 2.;
228
         yCenter = (ptMax.getY() + ptMin.getY()) / 2.;
229

    
230
         tree.center = new Point2D.Double(xCenter, yCenter);
231
         tree.dArea = iCells;
232
         tree.dPerimeter = ((xMax - xMin + 1) * (yMax - yMin + 1));
233
         m_TreesArray.add(tree);
234
      }
235

    
236
   }
237

    
238

    
239
   private void vectorize() {
240

    
241
      int iTree = 1;
242
      Tree tree;
243

    
244
      for (int i = 0; i < m_TreesArray.size(); i++) {
245
         tree = (Tree) m_TreesArray.get(i);
246
         final Object[] value = new Object[3];
247
         value[0] = new Integer(iTree);
248
         value[1] = new Double(tree.dArea);
249
         value[2] = new Double(tree.getAreaPerimeterRatio());
250
         final com.vividsolutions.jts.geom.Point pt = m_GeometryFactory.createPoint(new Coordinate(tree.center.getX(),
251
                  tree.center.getY()));
252
         m_Trees.addFeature(pt, value);
253
         iTree++;
254
      }
255

    
256
   }
257

    
258

    
259
   private void getClassInformation() {
260

    
261
      int i;
262
      final RasterLayerAndBand band;
263
      m_Stats = new ArrayList();
264

    
265
      m_Window = new IRasterLayer[m_Bands.size()];
266
      m_iBand = new int[m_Bands.size()];
267
      for (i = 0; i < m_Bands.size(); i++) {
268
         final RasterLayerAndBand rab = (RasterLayerAndBand) m_Bands.get(i);
269
         m_iBand[i] = rab.getBand();
270
         m_Window[i] = rab.getRasterLayer();
271
         final AnalysisExtent extent = getAdjustedGridExtent(i);
272
         m_Stats.add(new SimpleStats());
273
         m_Window[i].setWindowExtent(extent);
274
      }
275

    
276
      setProgressText(Sextante.getText("Calculating_spectral_signatures"));
277
      i = 0;
278
      final int iShapeCount = m_Polygons.getShapesCount();
279
      final IFeatureIterator featureIter = m_Polygons.iterator();
280
      while (featureIter.hasNext() && setProgress(i, iShapeCount)) {
281
         IFeature feature;
282
         try {
283
            feature = featureIter.next();
284
            final Geometry geometry = feature.getGeometry();
285
            doPolygon(geometry);
286
         }
287
         catch (final IteratorException e) {
288
            //we ignore wrong features
289
         }
290

    
291
      }
292
      featureIter.close();
293

    
294
   }
295

    
296

    
297
   private void doPolygon(final Geometry geom) {
298

    
299
      for (int i = 0; i < geom.getNumGeometries(); i++) {
300
         final Geometry part = geom.getGeometryN(i);
301
         doPolygonPart(part);
302
      }
303

    
304
   }
305

    
306

    
307
   private void doPolygonPart(final Geometry geom) {
308

    
309
      boolean bFill;
310
      boolean bCrossing[];
311
      int iNX, iNY;
312
      int i;
313
      int x, y, ix, xStart, xStop;
314
      int iSize = 0;
315
      int iPoint;
316
      double yPos;
317
      double dValue;
318
      AnalysisExtent ge;
319
      SimpleStats substats;
320
      Coordinate pLeft, pRight, pa, pb, p;
321

    
322
      final Envelope extent = geom.getEnvelopeInternal();
323

    
324
      final Coordinate[] points = geom.getCoordinates();
325

    
326
      for (i = 0; i < m_Window.length; i++) {
327
         p = new Coordinate();
328
         substats = (SimpleStats) m_Stats.get(i);
329
         ge = m_Window[i].getWindowGridExtent();
330
         iNX = ge.getNX();
331
         iNY = ge.getNY();
332
         bCrossing = new boolean[iNX];
333

    
334
         xStart = (int) ((extent.getMinX() - ge.getXMin()) / ge.getCellSize()) - 1;
335
         if (xStart < 0) {
336
            xStart = 0;
337
         }
338

    
339
         xStop = (int) ((extent.getMaxX() - ge.getXMin()) / ge.getCellSize()) + 1;
340
         if (xStop >= iNX) {
341
            xStop = iNX - 1;
342
         }
343

    
344
         for (y = 0, yPos = ge.getYMax(); y < iNY; y++, yPos -= ge.getCellSize()) {
345
            if ((yPos >= extent.getMinY()) && (yPos <= extent.getMaxY())) {
346
               Arrays.fill(bCrossing, false);
347
               pLeft = new Coordinate(ge.getXMin() - 1.0, yPos);
348
               pRight = new Coordinate(ge.getXMax() + 1.0, yPos);
349

    
350
               pb = points[points.length - 1];
351

    
352
               for (iPoint = 0; iPoint < points.length; iPoint++) {
353
                  pa = pb;
354
                  pb = points[iPoint];
355

    
356
                  if ((((pa.y <= yPos) && (yPos < pb.y)) || ((pa.y > yPos) && (yPos >= pb.y)))) {
357
                     getCrossing(p, pa, pb, pLeft, pRight);
358

    
359
                     ix = (int) ((p.x - ge.getXMin()) / ge.getCellSize() + 1.0);
360

    
361
                     if (ix < 0) {
362
                        ix = 0;
363
                     }
364
                     else if (ix >= iNX) {
365
                        ix = iNX - 1;
366
                     }
367

    
368
                     bCrossing[ix] = !bCrossing[ix];
369
                  }
370
               }
371

    
372
               for (x = xStart, bFill = false; x <= xStop; x++) {
373
                  if (bCrossing[x]) {
374
                     bFill = !bFill;
375
                  }
376
                  if (bFill) {
377
                     iSize++;
378
                     dValue = m_Window[i].getCellValueAsDouble(x /*+ m_iMinX - 1*/, y /*+ m_iMinY - 1*/, m_iBand[i]);
379
                     if (!m_Window[i].isNoDataValue(dValue)) {
380
                        substats.addValue(dValue);
381
                     }
382
                  }
383
               }
384
            }
385
         }
386

    
387
         if (i == 0) {
388
            m_SizeStats.addValue(iSize);
389
         }
390
      }
391

    
392

    
393
   }
394

    
395

    
396
   private boolean getCrossing(final Coordinate crossing,
397
                               final Coordinate a1,
398
                               final Coordinate a2,
399
                               final Coordinate b1,
400
                               final Coordinate b2) {
401

    
402
      double lambda, div, a_dx, a_dy, b_dx, b_dy;
403

    
404
      a_dx = a2.x - a1.x;
405
      a_dy = a2.y - a1.y;
406

    
407
      b_dx = b2.x - b1.x;
408
      b_dy = b2.y - b1.y;
409

    
410
      if ((div = a_dx * b_dy - b_dx * a_dy) != 0.0) {
411
         lambda = ((b1.x - a1.x) * b_dy - b_dx * (b1.y - a1.y)) / div;
412

    
413
         crossing.x = a1.x + lambda * a_dx;
414
         crossing.y = a1.y + lambda * a_dy;
415

    
416
         return true;
417

    
418
      }
419

    
420
      return false;
421

    
422
   }
423

    
424

    
425
   private AnalysisExtent getAdjustedGridExtent(final int iLayer) {
426

    
427
      double iMaxX, iMaxY;
428
      double dMinX, dMinY;
429
      double dMinX2, dMinY2, dMaxX2, dMaxY2;
430
      double dCellSize;
431
      final AnalysisExtent ge = new AnalysisExtent();
432

    
433
      final Rectangle2D rect = m_Polygons.getFullExtent();
434
      dMinX = m_Window[iLayer].getLayerGridExtent().getXMin();
435
      dMinY = m_Window[iLayer].getLayerGridExtent().getYMin();
436
      dCellSize = m_Window[iLayer].getLayerGridExtent().getCellSize();
437

    
438
      m_iMinX = (int) Math.floor((rect.getMinX() - dMinX) / dCellSize);
439
      iMaxX = Math.ceil((rect.getMaxX() - dMinX) / dCellSize);
440
      m_iMinY = (int) Math.floor((rect.getMinY() - dMinY) / dCellSize);
441
      iMaxY = Math.ceil((rect.getMaxY() - dMinY) / dCellSize);
442

    
443
      dMinX2 = dMinX + m_iMinX * dCellSize;
444
      dMinY2 = dMinY + m_iMinY * dCellSize;
445
      dMaxX2 = dMinX + iMaxX * dCellSize;
446
      dMaxY2 = dMinY + iMaxY * dCellSize;
447

    
448
      ge.setCellSize(dCellSize);
449
      ge.setXRange(dMinX2, dMaxX2, true);
450
      ge.setYRange(dMinY2, dMaxY2, true);
451

    
452
      return ge;
453

    
454
   }
455

    
456

    
457
   private boolean doParalellpiped() {
458

    
459
      boolean bIsInParalellpiped;
460
      int iNX, iNY;
461
      int x, y;
462
      int iGrid;
463
      final double dMean[] = new double[m_Window.length];
464
      final double dStdDev[] = new double[m_Window.length];
465
      double dValue;
466
      SimpleStats substats;
467

    
468
      iNX = m_BinaryImage.getWindowGridExtent().getNX();
469
      iNY = m_BinaryImage.getWindowGridExtent().getNY();
470

    
471
      for (iGrid = 0; iGrid < m_Window.length; iGrid++) {
472
         substats = ((SimpleStats) m_Stats.get(iGrid));
473
         dMean[iGrid] = substats.getMean();
474
         dStdDev[iGrid] = Math.sqrt(substats.getVariance());
475
      }
476

    
477
      setProgressText(Sextante.getText("Classifying"));
478
      for (y = 0; (y < iNY) && setProgress(y, iNY); y++) {
479
         for (x = 0; x < iNX; x++) {
480
            bIsInParalellpiped = true;
481
            for (iGrid = 0; iGrid < m_Window.length; iGrid++) {
482
               dValue = m_Window[iGrid].getCellValueAsDouble(x, y, m_iBand[iGrid]);
483
               if (!m_Window[iGrid].isNoDataValue(dValue)) {
484
                  if (Math.abs(dValue - dMean[iGrid]) > dStdDev[iGrid] * m_dTolerance) {
485
                     bIsInParalellpiped = false;
486
                     break;
487
                  }
488
               }
489
               else {
490
                  bIsInParalellpiped = false;
491
                  break;
492
               }
493
            }
494

    
495
            if (bIsInParalellpiped) {
496
               m_BinaryImage.setCellValue(x, y, 1);
497
            }
498
            else {
499
               m_BinaryImage.setNoData(x, y);
500
            }
501
         }
502
      }
503

    
504
      return true;
505

    
506
   }
507

    
508
}