Image analysis, classification and change detection in remote sensing: with algorithms for Python Fourth Edition Canty - Get instant access to the full ebook with detailed content
Image analysis, classification and change detection in remote sensing: with algorithms for Python Fourth Edition Canty - Get instant access to the full ebook with detailed content
com
https://textbookfull.com/product/image-analysis-
classification-and-change-detection-in-remote-sensing-with-
algorithms-for-python-fourth-edition-canty/
OR CLICK HERE
DOWLOAD EBOOK
https://textbookfull.com/product/fuzzy-machine-learning-algorithms-
for-remote-sensing-image-classification-1st-edition-anil-kumar/
textbookfull.com
https://textbookfull.com/product/image-processing-and-gis-for-remote-
sensing-techniques-and-applications-second-edition-liu/
textbookfull.com
https://textbookfull.com/product/multisensor-image-fusion-and-data-
mining-for-environmental-remote-sensing-first-edition-bai/
textbookfull.com
Remote sensing of vegetation. Hyperspectral indices and
image classifications for agriculture and vegetation
Second Edition Huete
https://textbookfull.com/product/remote-sensing-of-vegetation-
hyperspectral-indices-and-image-classifications-for-agriculture-and-
vegetation-second-edition-huete/
textbookfull.com
https://textbookfull.com/product/hyperspectral-imaging-remote-sensing-
physics-sensors-and-algorithms-1st-edition-dimitris-g-manolakis/
textbookfull.com
https://textbookfull.com/product/spatial-analysis-for-radar-remote-
sensing-of-tropical-forests-1st-edition-gianfranco-d-de-grandi/
textbookfull.com
https://textbookfull.com/product/deep-learning-for-remote-sensing-
images-with-open-source-software-1st-edition-remi-cresson/
textbookfull.com
https://textbookfull.com/product/introductory-digital-image-
processing-a-remote-sensing-perspective-john-r-jensen-dr-kalmesh-
lulla/
textbookfull.com
Image Analysis,
Classification, and Change
Detection in Remote
Sensing
With Algorithms for Python
Fourth edition
Image Analysis,
Classification, and Change
Detection in Remote
Sensing
With Algorithms for Python
Fourth edition
This book contains information obtained from authentic and highly regarded sources. Reasonable
efforts have been made to publish reliable data and information, but the author and publisher cannot
assume responsibility for the validity of all materials or the consequences of their use. The authors and
publishers have attempted to trace the copyright holders of all material reproduced in this publication
and apologize to copyright holders if permission to publish in this form has not been obtained. If any
copyright material has not been acknowledged please write and let us know so we may rectify in any
future reprint.
Except as permitted under U.S. Copyright Law, no part of this book may be reprinted, reproduced,
transmitted, or utilized in any form by any electronic, mechanical, or other means, now known or
hereafter invented, including photocopying, microfilming, and recording, or in any information
storage or retrieval system, without written permission from the publishers.
For permission to photocopy or use material electronically from this work, please access
www.copyright.com (http://www.copyright.com/) or contact the Copyright Clearance Center, Inc.
(CCC), 222 Rosewood Drive, Danvers, MA 01923, 978-750-8400. CCC is a not-for-profit organization
that provides licenses and registration for a variety of users. For organizations that have been granted
a photocopy license by the CCC, a separate system of payment has been arranged.
Trademark Notice: Product or corporate names may be trademarks or registered trademarks, and
are used only for identification and explanation without intent to infringe.
2 Image Statistics 31
2.1 Random variables . . . . . . . . . . . . . . . . . . . . . . . . . 31
2.1.1 Discrete random variables . . . . . . . . . . . . . . . . 32
2.1.2 Continuous random variables . . . . . . . . . . . . . . 33
2.1.3 Random vectors . . . . . . . . . . . . . . . . . . . . . 36
2.1.4 The normal distribution . . . . . . . . . . . . . . . . . 39
2.1.5 The gamma distribution and its derivatives . . . . . . 41
2.2 Parameter estimation . . . . . . . . . . . . . . . . . . . . . . . 44
2.2.1 Random samples . . . . . . . . . . . . . . . . . . . . . 44
2.2.2 Sample distributions and interval estimators . . . . . . 47
2.3 Multivariate distributions . . . . . . . . . . . . . . . . . . . . 50
2.3.1 Vector sample functions and the data matrix . . . . . 51
2.3.2 Provisional means . . . . . . . . . . . . . . . . . . . . 53
v
vi Image Analysis, Classification, and Change Detection in Remote Sensing
3 Transformations 83
3.1 The discrete Fourier transform . . . . . . . . . . . . . . . . . 83
3.2 The discrete wavelet transform . . . . . . . . . . . . . . . . . 88
3.2.1 Haar wavelets . . . . . . . . . . . . . . . . . . . . . . . 89
3.2.2 Image compression . . . . . . . . . . . . . . . . . . . . 93
3.2.3 Multiresolution analysis . . . . . . . . . . . . . . . . . 96
3.3 Principal components . . . . . . . . . . . . . . . . . . . . . . 103
3.3.1 Principal components on the GEE . . . . . . . . . . . 105
3.3.2 Image compression and reconstruction . . . . . . . . . 107
3.3.3 Primal solution . . . . . . . . . . . . . . . . . . . . . . 111
3.3.4 Dual solution . . . . . . . . . . . . . . . . . . . . . . . 111
3.4 Minimum noise fraction . . . . . . . . . . . . . . . . . . . . . 112
3.4.1 Additive noise . . . . . . . . . . . . . . . . . . . . . . . 113
3.4.2 Minimum noise fraction via PCA . . . . . . . . . . . . 116
3.5 Spatial correlation . . . . . . . . . . . . . . . . . . . . . . . . 117
3.5.1 Maximum autocorrelation factor . . . . . . . . . . . . 117
3.5.2 Noise estimation . . . . . . . . . . . . . . . . . . . . . 119
3.6 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
C Software 463
C.1 Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 463
C.2 Command line utilities . . . . . . . . . . . . . . . . . . . . . . 464
C.2.1 gdal . . . . . . . . . . . . . . . . . . . . . . . . . . . . 464
C.2.2 earthengine . . . . . . . . . . . . . . . . . . . . . . . . 464
C.2.3 ipcluster . . . . . . . . . . . . . . . . . . . . . . . . . . 465
C.3 Source code . . . . . . . . . . . . . . . . . . . . . . . . . . . . 465
C.4 Python scripts . . . . . . . . . . . . . . . . . . . . . . . . . . 465
C.4.1 adaboost.py . . . . . . . . . . . . . . . . . . . . . . . . 466
C.4.2 atwt.py . . . . . . . . . . . . . . . . . . . . . . . . . . 466
C.4.3 c corr.py . . . . . . . . . . . . . . . . . . . . . . . . . . 467
C.4.4 classify.py . . . . . . . . . . . . . . . . . . . . . . . . . 467
C.4.5 crossvalidate.py . . . . . . . . . . . . . . . . . . . . . . 468
C.4.6 ct.py . . . . . . . . . . . . . . . . . . . . . . . . . . . . 469
C.4.7 dispms.py . . . . . . . . . . . . . . . . . . . . . . . . . 469
C.4.8 dwt.py . . . . . . . . . . . . . . . . . . . . . . . . . . . 470
C.4.9 eeMad.py . . . . . . . . . . . . . . . . . . . . . . . . . 470
C.4.10 eeSar seq.py . . . . . . . . . . . . . . . . . . . . . . . . 471
C.4.11 eeWishart.py . . . . . . . . . . . . . . . . . . . . . . . 471
C.4.12 ekmeans.py . . . . . . . . . . . . . . . . . . . . . . . . 472
C.4.13 em.py . . . . . . . . . . . . . . . . . . . . . . . . . . . 472
C.4.14 enlml.py . . . . . . . . . . . . . . . . . . . . . . . . . . 473
C.4.15 gamma filter.py . . . . . . . . . . . . . . . . . . . . . . 473
C.4.16 hcl.py . . . . . . . . . . . . . . . . . . . . . . . . . . . 474
C.4.17 iMad.py . . . . . . . . . . . . . . . . . . . . . . . . . . 474
C.4.18 iMadmap.py . . . . . . . . . . . . . . . . . . . . . . . . 475
C.4.19 kkmeans.py . . . . . . . . . . . . . . . . . . . . . . . . 475
C.4.20 kmeans.py . . . . . . . . . . . . . . . . . . . . . . . . . 476
C.4.21 kpca.py . . . . . . . . . . . . . . . . . . . . . . . . . . 476
C.4.22 krx.py . . . . . . . . . . . . . . . . . . . . . . . . . . . 477
C.4.23 mcnemar.py . . . . . . . . . . . . . . . . . . . . . . . . 477
C.4.24 meanshift.py . . . . . . . . . . . . . . . . . . . . . . . 477
C.4.25 mmse filter.py . . . . . . . . . . . . . . . . . . . . . . . 478
C.4.26 mnf.py . . . . . . . . . . . . . . . . . . . . . . . . . . . 478
C.4.27 pca.py . . . . . . . . . . . . . . . . . . . . . . . . . . . 478
C.4.28 plr.py . . . . . . . . . . . . . . . . . . . . . . . . . . . 479
C.4.29 radcal.py . . . . . . . . . . . . . . . . . . . . . . . . . 479
C.4.30 readshp.py . . . . . . . . . . . . . . . . . . . . . . . . . 480
C.4.31 registerms.py . . . . . . . . . . . . . . . . . . . . . . . 480
C.4.32 registersar.py . . . . . . . . . . . . . . . . . . . . . . . 481
Contents xi
References 489
Index 501
Preface to the First Edition
This textbook had its beginnings as a set of notes to accompany seminars and
lectures conducted at the Geographical Institute of Bonn University and at its
associated Center for Remote Sensing of Land Cover. Lecture notes typically
continue to be refined and polished over the years until the question inevitably
poses itself: “Why not have them published?” The answer of course is “By all
means, if they contribute something new and useful.”
So what is “new and useful” here? This is a book about remote sensing
image analysis with a distinctly mathematical-algorithmic-computer-oriented
flavor, intended for graduate-level teaching and with, to borrow from the re-
mote sensing jargon, a rather restricted FOV. It does not attempt to match
the wider fields of view of existing texts on the subject, such as Schowengerdt
(1997), Richards (2012), Jensen (2005) and others. However, the topics that
are covered are dealt with in considerable depth, and I believe that this cov-
erage fills an important gap. Many aspects of the analysis of remote sensing
data are quite technical and tend to be intimidating to students with moder-
ate mathematical backgrounds. At the same time, one often witnesses a desire
on the part of students to apply advanced methods and to modify them to
fit their particular research problems. Fulfilling the latter wish, in particular,
requires more than superficial understanding of the material.
The focus of the book is on pixel-oriented analysis of visual/infrared Earth
observation satellite imagery. Among the topics that get the most attention
are the discrete wavelet transform, image fusion, supervised classification with
neural networks, clustering algorithms and statistical change detection meth-
ods. The first two chapters introduce the mathematical and statistical tools
necessary in order to follow later developments. Chapters 3 and 4 deal with
spatial/spectral transformations, convolutions and filtering of multispectral
image arrays. Chapter 5 treats image enhancement and some of the prepro-
cessing steps that precede classification and change detection. Chapters 6 and
7 are concerned, respectively, with supervised and unsupervised land cover
classification. The last chapter is about change detection with heavy emphasis
on the use of canonical correlation analysis. Each of the 8 chapters concludes
with exercises, some of which are small programming projects, intended to
illustrate or justify the foregoing development. Solutions to the exercises are
included in a separate booklet. Appendix A provides some additional mathe-
matical/statistical background and Appendix B develops two efficient training
algorithms for neural networks. Finally, Appendix C describes the installation
and use of the many computer programs introduced in the course of the book.
xiii
xiv Image Analysis, Classification and Change Detection in Remote Sensing
Morton Canty
Preface to the Second Edition
Shortly after the manuscript for the first edition of this book went to the
publisher, ENVI 4.3 appeared along with, among other new features, a support
vector machine classifier. Although my decision not to include the SVM in
the original text was a conscious one (I balked at the thought of writing my
own IDL implementation), this event did point to a rather glaring omission
in a book purporting to be partly about land use/land cover classification.
So, almost immediately, I began to dream of a Revised Second Edition and
to pester CRC Press for a contract. This was happily forthcoming and the
present edition now has a fairly long section on supervised classification with
support vector machines.
The SVM is just one example of so-called kernel methods for nonlinear
data analysis, and I decided to make kernelization one of the themes of the
revised text. The treatment begins with a dual formulation for ridge regression
in Chapter 2 and continues through kernel principal components analysis in
Chapters 3 and 4, support vector machines in Chapter 6, kernel K-means clus-
tering in Chapter 8 and nonlinear change detection in Chapter 9. Other new
topics include entropy and mutual information (Chapter 1), adaptive boosting
(Chapter 7) and image segmentation (Chapter 8). In order to accommodate
the extended material on supervised classification, discussion is now spread
over the two Chapters 6 and 7. The exercises at the end of each chapter have
been extended and re-worked and, as for the first edition, a solutions manual
is provided.
I have written several additional IDL extensions to ENVI to accompany the
new themes, which are available, together with updated versions of previous
programs, for download on the Internet. In order to accelerate some of the
more computationally intensive routines for users with access to CUDA (par-
allel processing on NVIDIA graphics processors), code is included which can
make use of the IDL bindings to CUDA provided by Tech-X Corporation in
their GPULib product:
http://gpulib.txcorp.com
Notwithstanding the revisions, the present edition remains a monograph
on pixel-oriented analysis of intermediate-resolution remote sensing imagery
with emphasis on the development and programming of statistically moti-
vated, data-driven algorithms. Important topics such as object-based feature
analysis (for high-resolution imagery), or the physics of the radiation/surface
interaction (for example, in connection with hyperspectral sensing) are only
xv
xvi Image Analysis, Classification and Change Detection in Remote Sensing
touched upon briefly, and the huge field of radar remote sensing is left out
completely. Nevertheless, I hope that the in-depth focus on the topics covered
will continue to be of use both to practitioners as well as to teachers.
I would like to express my appreciation to Peter Reinartz and the German
Aerospace Center for permission to use the traffic scene images in Chapter 9
and to NASA’s Land Processes Distributed Active Archive Center for free and
uncomplicated access to archived ASTER imagery. Thanks also go to Peter
Messmer and Michael Galloy, Tech-X Corp., for their prompt responses to my
many cries for help with GPULib. I am especially grateful to my colleagues
Harry Vereecken and Allan Nielsen, the former for generously providing me
with the environment and resources needed to complete this book, the latter
for the continuing inspiration of our friendship and long-time collaboration.
Morton Canty
Preface to the Third Edition
A main incentive for me to write a third edition of this book stemmed from my
increasing enthusiasm for the Python programming language. I began to see
the advantage of illustrating the many image processing algorithms covered
in earlier editions of the text not only in the powerful and convenient, but
not inexpensive, ENVI/IDL world, but also on a widely available open source
platform. Python, together with the NumPy and Scipy packages, can hold its
own with any commercial array processing software system. Furthermore, the
Geospatial Data Abstraction Library (GDAL) and its Python wrappers allow
for great versatility and convenience in reading, writing and manipulating dif-
ferent image formats. This was enough to get me going on a revised textbook,
one which I hope will have appeal beyond the ENVI/IDL community.
Another incentive for a new edition was hinted at in the preface to the
previous edition, namely the lack of any discussion of the vast and increas-
ingly important field of radar remote sensing. Obviously this would be a topic
for (at least) a whole new book, so I have included material only on a very
special aspect of particular interest to me, namely multivariate statistical clas-
sification and change detection algorithms applied to polarimetric synthetic
aperture radar (polSAR) data. Up until recently, not many researchers or
practitioners have had access to this kind of data. However with the advent of
several spaceborne polarimetric SAR instruments such as the Japanese ALOS,
the Canadian Radarsat-2, the German TerraSAR-X and the Italian COSMO-
SkyMed missions, the situation has greatly improved. Chapters 5, 7 and 9
now include treatments of speckle filtering, image co-registration, supervised
classification and multivariate change detection with multi-look polSAR data.
The software associated with the present edition includes, along with the
ENVI/IDL extensions, Python scripts for all of the main processing, classifi-
cation and change detection algorithms. In addition, many examples discussed
in the text are illustrated with Python scripts as well as in IDL. The Appen-
dices C and D separately document the installation and use of the ENVI/IDL
and Python code. For readers who wish to use the Eclipse/Pydev development
environment (something which I highly recommend), the Python scripts are
provided in the form of a Pydev project.
What is missing in the Python world, of course, is the slick GUI provided
by ENVI. I have made no attempt to mimic an ENVI graphical environment
in Python, and the scripts provided content themselves with reading imagery
from, and writing results to, the file system. A rudimentary command line
script for RGB displays of multispectral band combinations in different his-
xvii
xviiiImage Analysis, Classification and Change Detection in Remote Sensing
Morton Canty
Preface to the Fourth Edition
The fourth revision marks the completion of a transition, begun in the pre-
ceding edition, from ENVI/IDL to the Python language for implementing the
algorithms discussed in the text. It was with some hesitation that I abandoned
the comfort and convenience of the powerful ENVI/IDL environment and ven-
tured into the raw world of open source. But it has become apparent that open
source software is the future for scientific computing in general and for geo-
spatial analysis in particular. The popularity of R, JavaScript or Python in
the remote sensing community, the potential of machine learning software
such as TensorFlow for object recognition, the Python and JavaScript APIs
to the wonderful Google Earth Engine, the many open source mapping plat-
forms and servers like Mapbox, OpenLayers, Leaflet or the OpenStreetMap
project, the elegance of Jupyter notebooks for interactive and collaborative
development, the power of container technology like Docker for painless distri-
bution of scientific software, all of the advantages of these languages, tools and
platforms are freely available and under continual development by a gigantic
community of software engineers, both commercial and voluntary.
So I have jumped off the fence and onto the open source bandwagon in order
to ensure that the computer code used in the present version of the book will
be not only in line with the current trend, but also accessible to anyone,
student or scientist, with a computer and an Internet connection. Each of the
nine chapters of the text is now accompanied by its own Jupyter notebook
illustrating all, or almost all, of the concepts and algorithms presented in that
chapter. The Python scripts are uniformly command-line oriented so as to be
able to be started easily from within a notebook input cell. All of the software
is packaged into a single Docker container which, when run on the user’s
machine, serves the Jupyter notebooks to his or her favorite web browser.
The necessary packages and modules, including the Google Earth Engine and
TensorFlow APIs, are already built into the container so that there is no need
to install anything at all, apart from the Docker engine. This is of course great
for the reader, and for me it means no longer worrying about 32-bit vs. 64-
bit Windows vs. Linux vs. MacOS, or who has what pre-installed version of
which Python package. The container is pulled from DockerHub automatically
when run for the first time, and the source software can be cloned/forked from
GitHub. The details are all given in an appendix.
Had I approached this revision just a couple of years ago, I would have had
some misgivings about retaining the long and rigorous descriptions of neural
network training algorithms in Chapter 6 and Appendix B. Neural network
xix
xx Image Analysis, Classification and Change Detection in Remote Sensing
land cover classifiers had until recently gone somewhat out of fashion, giv-
ing way to random forests, support vector machines and the like. However,
given the present artificial intelligence craze, the mathematical detail in the
text should help to provide a solid background for anyone interested in un-
derstanding and exploiting deep learning techniques.
Like the earlier editions, this is not a text on programming or on the in-
tricacies of the various packages, tools and APIs referred to in the text. As
a solid introduction to scientific computing with Python, I would still recom-
mend Langtangen (2009) and, for TensorFlow, the book by Géron (2017). I
expect that I’m not alone in hoping for a good textbook on the Google Earth
Engine API. Fortunately the on-line documentation is excellent.
Apart from taking advantage of many of these exciting advances in open
source computing, the revised text continues to concentrate on an in-depth
treatment of pixel-oriented, data-driven, statistical methods for remote sens-
ing image processing and interpretation. The choice of topics and algorithms
is by no means all-encompassing and reflects strongly the author’s personal in-
terests and experience. Those topics chosen, however, are presented in depth
and from first principles. Chapters 1 and 2 on linear algebra and statistics
continue to be pretty much essential for an understanding of the rest of the
material. Especially new in the present edition is the discussion of an ele-
gant sequential change detection method for polarimetric synthetic aperture
radar imagery developed by Knut Conradsen and his colleagues at the Danish
Technical University. It has been a pleasure for me to be involved in its imple-
mentation, both in “conventional” Python and for the Google Earth Engine
Python and JavaScript APIs.
I would like to thank my editor Irma Shagla Britton at CRC Press for
waking me up to the idea of a fourth edition, and to give a big thank you to
the friendly, competent and infinitely patient GEE development team.
Morton Canty
Author Biography
Morton John Canty, now semi-retired, was a senior research scientist in the
Institute for Bio- and Geosciences at the Jülich Research Center in Germany.
He received his PhD in Nuclear Physics in
1969 at the University of Manitoba, Canada
and, after post-doctoral positions in Bonn,
Groningen and Marburg, began work in Jülich
in 1979. There, his principal interests have
been the development of statistical and game-
theoretical models for the verification of inter-
national treaties and the use of remote sensing
data for monitoring global treaty compliance.
He has served on numerous advisory bodies to
the German Federal Government and to the
International Atomic Energy Agency in Vi-
enna and was a coordinator within the Euro-
pean Network of Excellence on Global Mon-
itoring for Security and Stability, funded by
the European Commission. Morton Canty is the author of three monographs
in the German language: on the subject of non-linear dynamics (Chaos und
Systeme, Vieweg, 1995), neural networks for classification of remote sensing
data (Fernerkundung mit neuronalen Netzen, Expert, 1999) and algorithmic
game theory (Konfliktlösungen mit Mathematica, Springer 2000). The lat-
ter text has appeared in a revised English version (Resolving Conflicts with
Mathematica, Academic Press, 2003). He is co-author of a monograph on
mathematical methods for treaty verification (Compliance Quantified, Cam-
bridge University Press, 1996). He has published many papers on the sub-
jects of experimental nuclear physics, nuclear safeguards, applied game theory
and remote sensing and has lectured on nonlinear dynamical growth models
and remote sensing digital image analysis at Universities in Bonn, Berlin,
Freiberg/Saxony and Rome.
xxi
1
Images, Arrays, and Matrices
There are many Earth observation satellite-based sensors, both active and
passive, currently in orbit or planned for the near future. Representative of
these, we describe briefly the multispectral ASTER system (Abrams et al.,
1999) and the TerraSAR-X synthetic aperture radar satellite (Pitz and Miller,
2010). See Jensen (2018), Richards (2012) and Mather and Koch (2010) for
overviews of remote sensing satellite platforms.
The Advanced Spaceborne Thermal Emission and Reflectance Radiometer
(ASTER) instrument was launched in December 1999 on the Terra space-
craft. It is being used to obtain detailed maps of land surface temperature,
reflectance and elevation and consists of sensors to measure reflected solar
radiance and thermal emission in three spectral intervals:
• VNIR: Visible and near-infrared bands 1, 2, 3N, and 3B, in the spectral
region between 0.52 and 0.86 µm (four arrays of charge-coupled detectors
(CCDs) in pushbroom scanning mode).
• SWIR: Short wavelength infrared bands 4 to 9 in the region between
1.60 and 2.43 µm (six cooled PtSi-Si Schottky barrier arrays, pushbroom
scanning).
• TIR: Thermal infrared bands 10 to 14 covering a spectral range from 8.13
to 11.65 µm (cooled HgCdTe detector arrays, whiskbroom scanning).
The altitude of the spacecraft is 705 km. The across- and in-track ground
sample distances (GSDs), i.e., the detector widths projected through the sys-
tem optics onto the Earth’s surface, are 15 m (VNIR), 30 m (SWIR) and
90 m (TIR).∗ The telescope associated with the 3B sensors is back-looking at
an angle of 27.6o to provide, together with the 3N sensors, along-track stereo
image pairs. In addition, the VNIR camera can be rotated from straight down
(nadir) to ± 24o across-track. The SWIR and TIR instrument mirrors can be
pointed to ± 8.5o across-track. Like most platforms in this ground resolution
category, the orbit is near polar, sun-synchronous. Quantization levels are 8
bits for VNIR and SWIR and 12 bits for TIR. The sensor systems have an
∗ At the time of writing, both the VNIR and TIR systems are still producing good data.
1
2 Images, Arrays, and Matrices
FIGURE 1.1
ASTER color composite image (1000 × 1000 pixels) of VNIR bands 1 (blue),
2 (green), and 3N (red) over the town of Jülich in Germany, acquired on May
1, 2007. The bright areas are open cast coal mines.
average duty cycle of 8% per orbit (about 650 scenes per day, each 60×60 km2
in area) with revisit times between 4 and 16 days.
Figure 1.1 shows a spatial/spectral subset of an ASTER scene. The image is
a UTM (Universal Transverse Mercator) projection oriented along the satel-
lite path (rotated approximately 16.4o from north) and orthorectified using a
digital terrain model generated from the stereo bands.
Unlike passive multi- and hyperspectral imaging sensors, which measure
reflected solar energy or the Earth’s thermal radiation, synthetic aperture
radar (SAR) airborne and satellite platforms supply their own microwave
radiation source, allowing observations which are independent of time of day
3
FIGURE 1.2
A 5000×5000-pixel spatial subset of the HH polarimetric band of a TerraSAR-
X quad polarimetric image acquired over the Rhine River, Germany, in so-
called Stripmap mode. The data are slant-range, single-look, complex. The
gray-scale values correspond to the magnitudes of the complex pixel values.
where c is the number of pixel columns (also called samples) and r is the
number of pixel rows (or lines). The index k denotes the spectral band, of
which there are N in all. For data at an early processing stage a pixel may be
stored as a digital number (DN), often in a single byte so that 0 ≤ gk ≤ 255.
This is the case for the ASTER VNIR and SWIR bands at processing level L1A
(unprocessed reconstructed instrument data), whereas the L1A TIR data are
quantized to 12 bits (as unsigned integers) and thus stored as digital numbers
from 0 to 212 − 1 = 4095. Processed image data may of course be stored in
byte, integer or floating point format and can have negative or even complex
values.
The gray-scale values in the various bands encode measurements of the
radiance L∆λ (x, y) in wavelength interval ∆λ due to sunlight reflected from
some point (x, y) on the Earth’s surface, or due to thermal emission from
that surface, and focused by the instrument’s optical system along the array
of sensors. Ignoring all absorption and scattering effects of the intervening
atmosphere, the at-sensor radiance available for measurement from reflected
sunlight from a horizontal, Lambertian surface, i.e., a surface which scatters
reflected radiation uniformly in all directions, is given by
The units are [W/(m2 · sr · µm)], E∆λ is the average spectral solar irradiance
in the spectral band ∆λ, θz is the solar zenith angle, R∆λ (x, y) is the surface
reflectance at coordinates (x, y), a number between 0 and 1, and π accounts
for the upper hemisphere of solid angle. The conversion between DN and
at-sensor radiance is determined by the sensor calibration as measured (and
maintained) by the satellite image provider. For example, for ASTER VNIR
and SWIR L1A data,
∗ GeoTIFF is an open source specification and refers to TIFF files which have geographic
(or cartographic) data embedded as tags within the file. The geographic data can be used
to position the image in the correct location and geometry on the screen of a geographic
information display.
6 Images, Arrays, and Matrices
Listing 1.1 is a simple and fairly self-explanatory Python script which reads
a multispectral image into a Python/NumPy array in BSQ interleave format
with the aid of GDAL (the Geospatial Data Abstraction Library) and then
displays a spectral band using the matplotlib.pyplot package. The script
takes two arguments, the image filename and the band number to be displayed
and is run from the command prompt in Windows or from a console window
on Unix-like systems with the command python ex1 1.py *args. In the Unix
case, the “shebang” #! in the first line allows it to be run simply by typing
the filename, assuming the path to the env utility is /usr/bin/env. In this
book we will prefer to work almost exclusively from within Jupyter notebooks,
where the script can be executed with the so-called line magic %run without
Another Random Document on
Scribd Without Any Related Topics
trouve la preuve dans la biographie authentique
de Galien qui habitait alors cette ville[133].
Frappé d’une insurmontable terreur, il partit
secrètement pour la Campanie. Mais ne s’y
croyant pas assez en sûreté, il s’embarqua à
Brindes pour Pergame, ce qui donne à penser
qu’il n’y avait plus trace d’épidémie dans l’Asie
Mineure. Vers la fin de cette année ou au
commencement de la suivante (169), il fut
mandé par les empereurs, revint à Rome et alla
les rejoindre à Aquilée. Il est vraisemblable que
l’épidémie s’était sensiblement affaiblie,
puisqu’on ne ralentit pas les préparatifs d’une
grande expédition. Mais au moment où l’on
était plein d’espoir, survint une grande
recrudescence à laquelle l’agglomération des
troupes ne fut probablement pas étrangère. Les
deux souverains quittèrent précipitamment
Aquilée; et, pendant le retour, Lucius Vérus
mourut subitement d’un coup de sang, selon les
uns, par le poison, d’après les autres. Cette
indécision des historiens, assez indifférente en
elle-même, prouve qu’il ne succomba pas à
l’épidémie régnante.
Peu de temps après, Marc-Aurèle prit le
commandement de l’armée, et comme l’entrée
en campagne ne fut point ajournée, il est à
croire que la maladie avait cessé d’inspirer des
craintes. Mais son terme définitif devait se faire
longtemps attendre. Galien atteste
formellement qu’elle n’était pas éteinte à
l’époque où il rédigeait le Ve livre de sa
Thérapeutique. Il y exprime, en effet, le vœu de
la voir prendre bientôt fin[134]. Or, on sait que
Galien était déjà avancé en âge lorsqu’il
composa cet ouvrage, où il cite plusieurs de ses
écrits antérieurs[135]. On ne se trompe donc pas
en évaluant approximativement à quinze ans la
durée entière de la peste Antonine, que Galien
distingue des autres maladies populaires dont il
a l’occasion de parler, en l’appelant la longue
peste, pestis diuturna.
Julius Capitolinus a noté un détail des
derniers moments de Marc-Aurèle qui pourrait
avoir sa valeur dans cette question de
chronologie. «Le septième jour, dit-il, s’étant
senti plus mal, il ne voulut recevoir que son fils,
qu’il congédia aussitôt, dans la crainte de lui
communiquer sa maladie[136].»
La préoccupation du mourant et les termes
qui l’expriment font assez justement supposer à
M. Hecker que l’empereur se savait atteint de la
peste, dont il n’ignorait pas la transmissibilité.
Je suis d’autant plus disposé à adopter cette
version, qu’elle n’est contredite par aucun
document. A ce compte, il y aurait encore eu
des cas de peste en 180, année de la mort de
Marc-Aurèle.
Les historiens qui ont consigné dans leurs
chroniques le récit de ce funèbre épisode, ont
laissé prudemment à l’écart la question
médicale. Mais on compte se refaire de leur
silence auprès de Galien, qui a saisi, sans
doute, avec empressement l’occasion d’ajouter
à son œuvre un beau travail de plus. L’épreuve
dément bientôt cette espérance.
Galien, qui affecte un grand dédain
scientifique pour la description de Thucydide, et
qui aurait dû montrer comment il fallait s’y
prendre pour faire mieux, a reculé devant les
chances du parallèle[137].
Comprend-on qu’un écrivain aussi fécond,
dont la prolixité filandreuse se donne si souvent
carrière sur une foule de sujets sans
importance, au risque de lasser la patience du
lecteur le plus résolu, se soit borné, sur un fait
aussi grave, à quelques indications éparses,
dont on regrette doublement l’obscurité et la
concision[138]!
Alléguera-t-on la manière d’observer des
anciens? Mais cette excuse banale tombe
devant les descriptions nosographiquement
irréprochables qui ne sont pas rares dans leurs
livres et sont restées des modèles.
Disons-le sans détour, quoi qu’il en coûte: le
motif de l’inexplicable réserve de Galien n’est
pas de ceux que la science avoue. Il faut s’en
prendre tout simplement à l’effroi qu’inspirait
une maladie épidémique et contagieuse, contre
laquelle il n’y avait de recours assuré que dans
la fuite. A cette époque d’abaissement moral, la
fibre du devoir médical restait insensible. Les
nobles engagements du serment d’Hippocrate
ne trouvaient plus d’écho. Affronter la mort
pour soigner des malades était acte de dupe.
De nos jours ce lâche égoïsme serait justiciable
de l’opinion publique. Au temps de Galien, il
avait passé dans les mœurs, et le médecin de
l’empereur donnait lui-même l’exemple. Comme
le dit avec esprit M. Hecker: au lieu d’observer
et de traiter des pestiférés, au péril de sa vie,
Galien aimait mieux s’isoler dans son paisible
laboratoire pour y préparer sa merveilleuse
thériaque d’Andromaque, destinée à calmer les
souffrances des souverains et des grands de
l’empire[139].
Cédant peut-être à un remords secret, il se
vante d’avoir soigné d’innombrables malades
(μυριους), sans s’apercevoir que cette
hyperbole, fût-elle même l’expression de la
vérité, aggravait le reproche qu’il avait encouru
pour avoir traité avec tant d’indifférence, la
plume à la main, un fait médical aussi
mémorable[140].
Il n’en faut pas moins reconnaître que les
renseignements qu’il nous a transmis, tout
incomplets qu’ils sont, ont d’autant plus de prix
qu’on ne les trouve que dans ses écrits, qu’ils
nous viennent d’un témoin oculaire, et que ce
témoin est Galien[141].
Voici donc le tableau symptomatique de la
peste Antonine, tel que nous avons pu le
reconstruire en rapprochant, non sans difficulté,
tous les fragments disséminés dans les œuvres
les plus disparates du médecin de Rome.
Au contact, le corps des malades ne
paraissait pas plus chaud que dans l’état
naturel; mais ils ressentaient une ardeur
intérieure intolérable[142]. La peau n’était pas
jaune, mais un peu rouge et livide. A un
moment donné, elle se couvrait d’une éruption
dont Galien a parfaitement spécifié les
caractères. Chez le plus grand nombre, elle
occupait toute la surface du corps, sous la
forme de pustules qui s’ulcéraient et se
recouvraient d’une croûte (εφελκις des Grecs)
[143]
. Quand cette croûte se détachait, elle
laissait une cicatrice solide. Dans des cas plus
rares, l’éruption était «rude et psorique»
(aspera et scabiosa), c’est-à-dire composée de
papules qui se terminaient par une sorte de
desquamation[144].
Cet exanthème spécial ne peut être
confondu avec aucun de ceux que nous
connaissons. Il diffère totalement des éruptions
pétéchiales et miliaires qui accompagnent si
souvent les pyrexies épidémiques de notre
temps et notamment la peste d’Orient. On ne
les voit jamais en effet s’ulcérer, se revêtir d’une
croûte et laisser des cicatrices. Si nous y
retrouvons quelque analogie avec la pustulation
variolique, nous constatons aussi des
dissemblances notables. Le champ est donc
largement ouvert aux conjectures. Pour nous
guider dans la détermination de ce diagnostic
différentiel, nous aurions pu tirer d’utiles
éclaircissements du rapprochement et de la
comparaison d’un certain nombre de faits. Mais
j’ai annoncé bien des lacunes, et Galien qui
avait, à l’entendre, recueilli tant d’observations,
a trouvé bon de ne nous en donner qu’une
seule.
Il s’agit d’un jeune homme qui eut, le
neuvième jour, le corps entier couvert d’ulcères.
Trois jours après, les cicatrices étaient faites, et
le malade se sentit assez bien pour s’embarquer
et aller achever sa guérison, par l’usage du lait,
dans un site renommé pour sa salubrité[145].
D’après le nombre de jours assignés par
l’auteur à la formation de l’éruption et des
cicatrices, il paraîtrait que cette maladie
rappelait par la succession régulière de ses
périodes et leur durée prévue, les fièvres
éruptives de la nosologie moderne. Mais il ne
nous est pas permis d’aller au delà de cette
similitude extérieure.
Les pustules étaient noires et leur passage à
l’ulcération était le fait le plus commun, sans
toutefois être constant.
Dans certains cas, il n’y avait ni croûtes, ni
cicatrices consécutives, et on ne voyait se
détacher qu’une simple pellicule. D’où il résulte
que l’éruption affectait la forme de pustules ou
de vésicules. Les premières, profondément
implantées dans le derme, laissaient des
marques après elles. Les autres, plus
superficielles, soulevaient simplement
l’épiderme et il n’en restait pas de traces. Dans
les cas où il se formait des cicatrices, elles
étaient complètes en deux ou trois jours,
témoin l’observation qu’on vient de lire.
Lorsque l’exanthème était «sec» c’est-à-dire
papuleux, la desquamation s’effectuait dans le
même temps; ce qu’il était facile de vérifier sur
les sujets dont la peau était semée de pustules
et de papules entremêlées.
La couleur noire de l’éruption et l’odeur
repoussante exhalée par les malades étaient
l’expression de l’état malin et putride dont on
ne pouvait méconnaître la redoutable
association.
Il est heureux que Galien n’ait pas abrégé le
signalement de cet exanthème qui est un des
traits les plus originaux de la peste Antonine et
lui imprime un cachet d’individualité morbide,
que nous retrouverons d’ailleurs dans
l’ensemble de ses autres caractères.
Les malades accusaient une invincible
aversion pour les aliments. Tourmentés par une
soif dévorante, ils demandaient à grands cris
des boissons froides[146].
Le trouble des facultés intellectuelles prenait
diverses formes. Certains malades éprouvaient
comme des absences pendant lesquelles ils
n’avaient pas conscience d’eux-mêmes et ne
reconnaissaient pas leur entourage[147]. D’autres
étaient pris d’un délire furieux, suivi d’un état
comateux ou léthargique. Dans ce cas, le
pronostic était alarmant. On comptait aussi
parmi les symptômes de funeste augure, les
inflammations viscérales; les évacuations
diarrhéiques colliquatives; la gangrène qui
dévorait jusques à l’os les parties en contact
avec les excrétions putrides dont le lit était
imprégné.
Du côté de l’appareil respiratoire, on
observait une toux sèche plus ou moins intense
avec timbre rauque de la voix, signe évident de
la phlegmasie de la muqueuse laryngo-
bronchique.
Le jeune homme dont nous avons déjà dit
un mot, se mit à tousser le jour même où sa
peau fut entièrement couverte d’ulcères. Le
lendemain il fut pris tout à coup d’une quinte
violente qui provoqua l’expulsion d’une croûte
semblable à celles de l’éruption cutanée. Le
sujet s’était plaint d’éprouver, dans la région
latérale du cou, sur le trajet de la trachée-
artère, une sensation douloureuse, signe
probable de la formation d’un ulcère interne.
Galien avait exploré attentivement la bouche et
l’arrière-gorge, et n’y avait découvert aucun
indice de travail ulcératif. La déglutition des
solides et des liquides s’opérait sans la moindre
gêne. Le corps étranger, rejeté par le patient,
n’était pas ce que nous appellerions aujourd’hui
un produit diphthéritique. Il provenait des
pustules propagées sur la muqueuse des voies
aériennes, comme on le voit si souvent dans la
variole. Galien reconnut aussitôt une croûte
détachée de l’ulcération laryngienne, pareille à
celles qui recouvraient la peau. Il eut occasion,
s’il faut l’en croire, de vérifier le même
phénomène chez d’autres sujets dont la maladie
eut également une heureuse fin. (Ad
postremum similiter alii.)
Pour préciser le véritable siége de la douleur
accusée par le sujet, et s’assurer qu’elle ne
dépendait pas d’une lésion gutturale ou
œsophagienne, Galien avait eu recours à un
singulier expédient. Il avait prescrit une mixture
de vinaigre et de moutarde, et comme le
contact de cette matière irritante le long de
l’œsophage n’avait éveillé aucun sentiment
douloureux, il avait acquis la certitude que
l’ulcération était établie sur la muqueuse
trachéale[148].
Le diagnostic pouvait être porté dès
l’invasion, lorsque les yeux étaient enflammés,
et que la cavité buccale, la langue et l’arrière-
gorge offraient une teinte rouge sui generis
dont Galien a caractérisé d’un mot la valeur
séméiotique en l’appelant pestilentielle[149]. A
première vue, les personnes étrangères à la
médecine reconnaissaient la maladie. Cette
coloration, que l’auteur compare à celle «de
l’érysipèle ou de l’herpès» n’était pas le résultat
d’un état phlegmasique local, puisque la
déglutition était facile et indolente. Elle
annonçait seulement un haut degré
d’inflammation dans la muqueuse intestinale.
On n’observa que chez un certain nombre de
malades des vomissements de matières jaunes
plus ou moins foncées; mais il y eut chez tous
des déjections alvines de même couleur, qui
devenaient plus tard noirâtres par leur mélange
avec le sang. Cette couleur n’apparaissait
jamais à l’invasion ou dans la période
d’augment, mais toujours vers le déclin ou aux
approches de la mort; parfois vers le septième
jour; le plus souvent au neuvième; plus
rarement au onzième[150]. Dans quelques cas,
ces évacuations diarrhéiques parurent
salutaires; mais généralement elles furent du
plus fâcheux augure. Elles emportèrent le plus
grand nombre des malades en épuisant leurs
forces.
La survenance des gangrènes locales était
aussi des plus graves, sans cependant interdire
tout espoir. Galien avait vu les orteils (extremos
pedes) se séparer spontanément après leur
mortification. Plusieurs malades, qui avaient
survécu à cette mutilation, ne pouvaient, dit-il,
assurer leur marche qu’à l’aide d’un bâton, sur
lequel ils étaient même obligés de s’appuyer
fortement[151].
Notre auteur qui s’était tant occupé du
pouls, nous apprend qu’il restait souvent normal
pendant le cours de la maladie, et que les
malheureux chez lesquels il conserva ce
caractère, périrent tous. Circonstance bien faite,
ajoute-t-il, pour donner le change même aux
praticiens les plus expérimentés[152].
A côté de ces faits, il faut placer ceux où il
avait vu l’urine différer à peine de l’état
naturel[153].
Ces deux phénomènes congénères
n’appartenaient pas en propre à la peste
Antonine. Ils ne s’y rattachaient éventuellement
qu’à titre de maladie maligne où
«l’affaiblissement des forces radicales fait cesser
les synergies et les sympathies les plus
ordinaires des organes[154].» Galien vérifiait une
fois de plus le célèbre aphorisme de son maître:
«Pulsus bonus, urina bona, æger moritur.»
Notons enfin, que la maladie pouvait se
prolonger et prendre la marche chronique.
Après quelques alternatives de rémission et de
redoublement, dont la durée était très-variable
suivant les individus, la fièvre hectique
s’allumait, et le patient succombait dans le
dernier degré de la consomption.
Nous possédons, en ce moment, des
données suffisantes pour répondre à cette
question: Qu’est-ce que la peste Antonine?
En additionnant successivement ses
symptômes d’après les indications de Galien,
nous avons vu se dessiner peu à peu une
individualité morbide dont le signalement
complet a fini par reproduire, trait pour trait,
l’image frappante de la peste d’Athènes.
Que le lecteur qui a bien voulu me suivre,
prenne la peine de confronter les deux
descriptions, et j’espère qu’il partagera ma
conviction très-arrêtée sur l’identité des deux
maladies.
Ardeur inflammatoire des yeux; rougeur sui
generis de la cavité buccale et de la langue;
aversion pour les aliments; soif inextinguible;
température extérieure normale, contrastant
avec la sensation d’un embrasement intérieur;
coloration de la peau rougeâtre et livide; toux
violente et timbre rauque de la voix, signes de
phlegmasie laryngo-bronchique; horrible fétidité
de l’haleine; éruption générale de pustules
suivies d’ulcérations; inflammation de la
muqueuse intestinale; vomissements de
matières bilieuses; diarrhée colliquative de
même nature épuisant les forces; gangrènes
partielles et séparation spontanée des organes
mortifiés; troubles variés des facultés
intellectuelles; délire tranquille ou furieux;
terminaison funeste du septième au neuvième
jour. Enfin, dans des cas moins aigus,
dégénérescence de la maladie en fièvre
hectique mortelle, après des oscillations plus ou
moins prolongées.
Tous les symptômes que je viens d’énumérer
se retrouvent dans le tableau tracé par
Thucydide et dans celui que nous sommes
parvenus à recomposer d’après Galien. Deux
affections morbides qui ont cette expression
commune, ne peuvent évidemment être
séparées l’une de l’autre.
Si Galien, au lieu de critiquer son illustre
devancier, avait imité son exemple, nous
n’aurions eu qu’à rapprocher les deux récits
pour que leur conclusion légitime surgît d’elle-
même.
Mais il a mieux aimé proposer à ses lecteurs
futurs une sorte d’hiéroglyphe nosographique
dont il a fallu retrouver les signes, confusément
éparpillés dans son œuvre immense, et comme
égarés dans des digressions théoriques, au
milieu desquelles il n’est pas toujours facile de
se reconnaître. C’est ainsi que je m’explique le
silence, l’indécision ou le laconisme des
loïmographes modernes à l’égard de la peste
Antonine. Ils ont trouvé commode de répéter,
les uns après les autres, qu’une grande maladie
épidémique avait désolé le monde sous le règne
de Marc-Aurèle; que Galien, son contemporain,
en avait été témoin et qu’il en avait eu
grand’peur. Cela dit, ils se croient quittes, de
très-bonne foi, envers leurs lecteurs, et n’ont
pas l’air de se douter qu’on puisse être plus
exigeant.
Il y avait donc une lacune à remplir dans
l’histoire ancienne des grandes épidémies.
L’entreprise a tenté deux médecins allemands
dont l’érudition et l’expérience étaient une
garantie de succès[155]. J’ai eu l’avantage de
venir après eux, et j’ai mis la main sur quelques
passages de Galien qu’ils n’avaient pas indiqués.
Quelle que soit ma profonde estime pour les
travaux de Fodéré et d’Ozanam, je ne pouvais
méconnaître qu’en présence de la peste
Antonine, ils ne s’étaient pas tenus à la hauteur
du sujet; et j’aurais été sans excuse si je leur
avais laissé le dernier mot, lorsqu’il y avait tant
à dire[156].
Quant à ma conclusion, c’est celle de Galien
lui-même qui, frappé de ce qu’il voyait, a
reconnu formellement que cette maladie
pestilentielle avait le même aspect que celle
dont Thucydide avait écrit la relation: «... In
magnâ hâc peste cujus eadem facies fuit atque
ejus qua Thucydidis memoria grassabatur[157].»
Galien revient sur cette idée en plusieurs
endroits. Les médecins d’Athènes n’avaient pu
dissimuler leur étonnement devant ce fléau
inconnu qui prenait possession de la pathologie
humaine. Il n’en fut plus de même lors de
l’apparition de la peste Antonine. Comme
homme, Galien fut terrifié; comme médecin, il
n’éprouva pas la moindre surprise. Il n’eut qu’à
relire le récit de Thucydide pour s’assurer qu’il
assistait au retour d’une ancienne maladie, et
que ce ne serait probablement pas le dernier.
Pour compléter cette étude, je crois devoir
examiner quelques particularités signalées par
Galien qui pourraient fournir matière à
discussion si je ne les mettais dans leur vrai
jour.
On ne m’opposera pas sans doute que les
deux descriptions, envisagées dans leur
ensemble, diffèrent sur certains points. Ces
divergences sont inévitables, et on les
retrouverait, à coup sûr, dans les récits de deux
médecins également attentifs et instruits qui
auraient observé simultanément la même
épidémie et raconteraient ce qu’ils ont vu. Mais
on sait que, quelle que soit la mobilité protéique
du tableau symptomatique d’une épidémie en
cours d’évolution, le type morbide qui la
représente garde son relief personnel au milieu
des épiphénomènes et des complications qui
viennent se grouper autour de lui. Deux
maladies qui portent cette estampille sont donc
nosologiquement identiques. A cet égard, je
crois ma conclusion parfaitement conforme aux
principes.
J’ai à répondre à un argument plus sérieux
qui exige quelques explications.
Galien donne clairement à entendre, dans
plus d’un passage, que l’éruption fut souvent
critique, et jugea heureusement la maladie[158].
Elle se montra, en effet, chez la plupart des
sujets qui guérirent, tandis qu’elle manqua
entièrement ou fut incomplète chez ceux qui
succombèrent ou dont la maladie fut le plus
grave. Thucydide ne fait aucune allusion à cette
circonstance qui valait bien la peine d’être
notée.
Entre le silence de l’un et l’affirmation de
l’autre, où se trouve la vérité? Je me range sans
balancer du côté de Galien, et voici mes raisons.
Thucydide n’était pas médecin, et la fermeté
de l’homme de guerre ne pouvait lui tenir lieu
des connaissances spéciales indispensables
pour pénétrer le sens des phénomènes
morbides qu’il observait.
Galien rachetait par son expérience pratique
sa défaillance morale; et sa théorie favorite,
dont on ne peut blâmer que l’exagération, le
ramenait à l’idée d’un effort conservateur, qui
pouvait avoir une issue heureuse.
Our website is not just a platform for buying books, but a bridge
connecting readers to the timeless values of culture and wisdom. With
an elegant, user-friendly interface and an intelligent search system,
we are committed to providing a quick and convenient shopping
experience. Additionally, our special promotions and home delivery
services ensure that you save time and fully enjoy the joy of reading.
textbookfull.com