Эта статья представляет собой краткое руководство по внедрению системы земного покрова на изображениях SAR с использованием сегментации объектов на основе глубокого обучения.

Дистанционное зондирование позволяет измерить влияние человеческой деятельности на окружающую среду. Благодаря дистанционному зондированию можно определять состав почв, классифицировать типы растительности на территории и наносить на карту последствия человеческой деятельности как урбанизации. Для этого необходимо уметь эффективно анализировать изображения для создания, например, карт землепользования, которые представляют собой отображение однородных типов окружающей среды (городские районы, сельскохозяйственные районы, леса и т. Д.) На поверхности земли. Возникшие земли.

Радиообнаружение и дальность, дозорный-1

Радар, благодаря диапазону несущей частоты используемых сигналов, имеет то преимущество, что позволяет проводить наблюдения независимо от условий освещенности и туманности в широком смысле. Более того, эти инструменты позволяли предвидеть перспективы наблюдения более сложных явлений, таких как утечки нефти, оползни и т. Д. Но, несмотря на различные миссии по наблюдению Земли, в ходе которых накопилось много важной информации, изображения, полученные с радара все еще очень редки и представляют собой настоящую проблему семантической интерпретации для тех, кто доступен. Это связано, в частности, со структурной сложностью этих изображений, обусловленной принципами их получения, и с высокой стоимостью доступа к данным. Этот аспект доступа к данным по-прежнему имеет тенденцию улучшаться благодаря проекту Copernicus.

радар с синтезированной апертурой (SAR),

Это электронные устройства, которые могут отображать электромагнитную отражательную способность объектов или окружающей среды с высокой пространственной точностью. Чтобы преодолеть ограничение обычного радара, был реализован принцип открытия синтеза. Это основано на анализе изменения фазы сигнала, отраженного от объекта при изменении положения измерения. Методы обработки сигналов позволяют сфокусировать отклик объекта в двунаправленной плоскости с повышенным разрешением, поэтому на сегодняшний день порядок величины был сначала декаметровым, затем метрическим и дециметрическим. Они широко используются при дистанционном зондировании окружающей природной среды, мониторинге и картировании территорий и видов деятельности.

Обнаружение изменений с помощью изображения SAR

Карта обнаружения изменений по радиолокационным изображениям остается долгой и сложной задачей. Хотя создание такой карты из оптических изображений было прорывом с использованием больших данных, системы на основе радаров не достигли такого же прогресса, вероятно, из-за трудностей, связанных со структурной сложностью этих изображений. разрабатывать и экспериментировать с новыми усовершенствованными цепочками обработки, используя преимущества новых методов, которые стали очевидными, чтобы иметь возможность эффективно использовать этот новый большой поток данных в сочетании с вычислительной мощностью, доступной для обработки изображений, которая также выросли.

статистический инструмент для проектирования и анализа: SAR-DNNClassifier

Многослойный персептрон может аппроксимировать сложные нелинейные функции для обработки больших объемов данных. В рамках нашей работы подход заключается в том, чтобы представить векторизованное изображение, то есть в форме вектора, размерность которого равна количеству пикселей изображения, на входе в глубокую сеть.

Функция оптимизации Адама. Выбор хорошего алгоритма оптимизации для модели может повлиять на хорошие результаты в минутах, часах или днях. Алгоритм оптимизации Адама, вывод и оценка адаптивного момента, является расширением стохастического градиентного спуска для приложений глубокого обучения. Он имеет особенность итеративного обновления весов соединений в сети в соответствии с данными обучения, с одной стороны, и, помимо сохранения суммы предыдущих квадратных градиентов, он также сохраняет предыдущие градиенты (аналогично импульсу ) в экспоненциальном разложении.

Поскольку наша задача является невыпуклой задачей оптимизации, ее применение к Адаму дает следующие преимущества:

  • Просто реализовать
  • Оперативность в расчетах
  • Небольшие требования к памяти
  • инвариантен к масштабированию диагонали градиентов
  • Хорошо адаптирован к важным задачам с точки зрения данных и / или параметров
  • подходит для нестационарных целей
  • подходит для очень шумных или очень редких градиентных задач
  • гиперпараметры имеют интуитивно понятную интерпретацию и обычно требуют небольшой настройки

Программное обеспечение и библиотеки, использованные при реализации

Google Earth Engine

Совместная площадка

Библиотека Tensorflow

[Google Earth Engine:] Как экспортировать данные поездов / испытаний SAR и данные изображений?

Google Earth Engine - это глобальная облачная платформа геопространственной аналитики, которая обеспечивает доступ к огромным вычислительным возможностям Google для изучения множества серьезных социальных проблем, включая вырубку лесов, засуху, стихийные бедствия, продовольственную безопасность, управление водными ресурсами, мониторинг климата и защиту окружающей среды.

Во-первых, подключили вас на земной платформе Google Earth Engine.

1. Выберите изображения из copernicus projet. Чтобы создать однородное подмножество данных Sentinel-1, обычно необходимо фильтровать коллекцию с использованием свойств метаданных.

var imgVV = ee.ImageCollection(‘COPERNICUS/S1_GRD’)        
  .filter(ee.Filter.listContains(‘transmitterReceiverPolarisation’, ‘VV’))
  .filter(ee.Filter.eq(‘instrumentMode’, ‘IW’))
  .map(function(image) {
     var edge = image.lt(-30.0);
     return image;
 });

2. Свойства орбиты

var desc = imgVV.filter(ee.Filter.eq(‘orbitProperties_pass’, ‘DESCENDING’));

3. Сопоставьте функцию с периодом (один год) данных и возьмите медианное значение

var period = ee.Filter.date(‘2018–01–01’, ‘2018–12–31’);
var descChange = ee.Image.cat(desc.filter(period).mean());

4. Чтобы отобразить результат

Map.setCenter(9.69,4.07, 12); //geographical coordinate of the area and the value of the zoom
Map.addLayer(descChange, {bands: [‘VV’,’VH’,’angle’],min: -25, max:5}, ‘MY SAR Mean Desc’, true);

Для изучения необходимо составить описание, соответствующее истине (рис. 2.4).

e.g:
Label  | Description      | color
0         vegetation         green
1         ground             yellow
2         water              sky blue
3         vase               dark blue
4         mangrove_swamp     purple

5. Объединить функции

var newfc = vegetation.merge(ground).merge(water).merge(vase).merge(mangrove_swamp)

6. Данные ПОЕЗДА / ТЕСТА

var bands = [‘VV’,’VH’,’angle’];
var training = descChange.select(bands).sampleRegions({
 collection:newfc,
 properties:[‘landcover’],
 scale:30
}).randomColumn();
//PARTITION OF TRAINING DATA
// Approximately 70% of our training data
var trainingPartition = training.filter(ee.Filter.lt('random', 0.7));
// Approximately 30% of our training data
var testingPartition = training.filter(ee.Filter.gte('random', 0.7));

7. Экспортируйте данные обучения и тестирования в формат TFRecord.

var outputFeatures = Array.from(bands);
outputFeatures.push(‘landcover’);
var link = ‘9a26cef21ab34f6257d0a250882124fc’; //unique ID
var train_desc = ‘tf_trainFinal_’ + link;
var test_desc = ‘tf_testFinal_’ + link;
// choose a) OR b)
//a) Export to cloud Storage
Export.table.toCloudStorage({
  collection: trainingPartition, 
  description: train_desc, 
  bucket: ‘mydir-training-temp’, 
  fileFormat: ‘TFRecord’, 
  selectors: outputFeatures
});
Export.table.toCloudStorage({
  collection: testingPartition, 
  description: test_desc, 
  bucket: ‘mydir-training-temp’, 
  fileFormat: ‘TFRecord’, 
  selectors: outputFeatures
});
//b) Export to Drive
Export.table.toDrive({
 collection: trainingPartition, 
 description: train_desc, 
 fileFormat: ‘TFRecord’, 
 selectors: outputFeatures
});
Export.table.toDrive({
 collection: testingPartition, 
 description: test_desc, 
 fileFormat: ‘TFRecord’, 
 selectors: outputFeatures
});

8. Данные оценки

var evaluation = descChange.select(bands);
var image_desc = 'tf_image_' + link;
// choose a) OR b)
// a)
Export.image.toCloudStorage({
    image: image.select(bands),
    description: image_desc,
    scale: 30,
    fileFormat: 'TFRecord',
    bucket: 'mydir-training-temp', 
    region: exportRegion,
    formatOptions: {
      'patchDimensions': [256, 256],
      maxFileSize: 104857600,
      compressed: true,
    },
});
// b)
Export.image.toDrive({
  image: evaluation,
  description: image_desc,
  scale: 30,
  fileFormat: 'TFRecord',
  region: exportRegion,
  formatOptions: {
    'patchDimensions': [256, 256],
    maxFileSize: 104857600,
    compressed: true,
  },
});

[Совместная платформа:] Как применить Deep network к нашим данным?

1. Настройте среду

Земляной двигатель,

#@install Earth Engine
!pip install earthengine-api
#@Authentication to Earth Engine for connection
import ee
try:
  ee.Initialize()
  print('The Earth Engine package initialized successfully!')
except ee.EEException as e:
  print('The Earth Engine package failed to initialize!')
  !earthengine authenticate
except:
  print("Unexpected error:", sys.exc_info()[0])
  raise

Тензорфлоу,

#@title Import tensorflow library
import tensorflow as tf
#@title Import math library
import math
#@title Test if Tensorflow is working
hello = tf.constant('hello world')
with tf.Session() as sess:
  print(sess.run(hello))
#@title Install the PyDrive library

Гугл драйв,

# This only needs to be done once per notebook
!pip install -U PyDrive
#@title import authentification libraries
from google.colab import auth
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
from oauth2client.client import GoogleCredentials
#@title Authenticate for connection
auth.authenticate_user()
gauth = GoogleAuth()
gauth.credentials = GoogleCredentials.get_application_default()
drive = GoogleDrive(gauth)

2. Проверьте входные данные.

#@title Load training/testing data from Earth Engine exports
# Specify the training file exported from EE.
# If you wish to use your own data, then
# replace the file ID, below, with your own file.
trainFileId = '1Nmmy8yYMoDIv3qah6W1eEZkucoBwhvT-'
trainDownload = drive.CreateFile({'id': trainFileId})
# Create a local file of the specified name.
tfrTrainFile = 'training.tfrecord.gz'
trainDownload.GetContentFile(tfrTrainFile)
print('Successfully downloaded training file?')
print(tf.gfile.Exists(tfrTrainFile))
# Specify the test file.
# If you wish to use your own data, then
# replace the file ID, below, with your own file.
testFileId = '19FuRN6nm_nTU8tbHLdCrSsLShylIklyp'
testDownload = drive.CreateFile({'id': testFileId})
# Creates a local file of the specified name.
tfrTestFile = 'testing.tfrecord.gz'
testDownload.GetContentFile(tfrTestFile)
print('Successfully downloaded testing file?')
print(tf.gfile.Exists(tfrTestFile))
print('Content of the working directory:')
!ls

Проверьте набор данных TFRecord

#@title Inspect the TFRecord dataset
driveDataset = tf.data.TFRecordDataset(tfrTrainFile, compression_type='GZIP')
iterator = driveDataset.make_one_shot_iterator()
foo = iterator.get_next()
with tf.Session() as sess:
  print(sess.run([foo]))

3. Определите структуру данных обучения / тестирования.

#@title Define the structure of the training/testing data
# Names of the features.
bands = ['VV','VH','angle']
label = 'landcover'
featureNames = list(bands)
featureNames.append(label)
print(featureNames)
# Feature columns
columns = [tf.FixedLenFeature(shape=[1], dtype=tf.float32) for k in featureNames]
# Dictionary with names as keys, features as values.
featuresDict = dict(zip(featureNames, columns))
print(featuresDict)

4. Создайте и протестируйте функцию синтаксического анализа.

#@title Make and test a parsing function
def parse_tfrecord(example_proto):
  parsed_features = tf.parse_single_example(example_proto, featuresDict)
  labels = parsed_features.pop(label)
  return parsed_features, tf.cast(labels, tf.int32)
# Map the function over the dataset
parsedDataset = driveDataset.map(parse_tfrecord, num_parallel_calls=5)
print(parsedDataset)
iterator = parsedDataset.make_one_shot_iterator()
foo = iterator.get_next()
print(foo)
with tf.Session() as sess:
  print(sess.run([foo]))

5. ДОПОЛНЕНИЕ ДАННЫХ. Сделайте функции для добавления дополнительных функций.

#@title Make functions to add additional features
# Compute normalized difference of two inputs.  If denomenator is zero, add a small delta.
#a)
def normalizedDifferenceSurfacePolarisation(a, b):
  nd = (a - b)
  return nd
#b)
def normalizedSumSurfacePolarisation(a, b):
  nd = (a + b)
  return nd
#c)
def normalizedDivisonSurfacePolarisation(a, b):
  nd = a / b
  return nd
# Add normalized to the dataset.  Shift the label to zero.
def addFeatures(features, label):
  features['x'] = normalizedDifferenceSurfacePolarisation(features['VV'], features['VH'])
  features['y'] = normalizedSumSurfacePolarisation(features['VV'], features['VH'])
  features['z'] = normalizedDivisonSurfacePolarisation(features['VH'],features['VV'])
  return features, label

6. Модель

#@title Make an input function
def tfrecord_input_fn(fileName, numEpochs=None,shuffle=True,batchSize=None):
  dataset = tf.data.TFRecordDataset(fileName, compression_type='GZIP')
  
  # Map the parsing function over the dataset  
  dataset = dataset.map(parse_tfrecord, num_parallel_calls=5)
  
  # Add additional features.
  dataset = dataset.map(addFeatures)
  
  # Shuffle, batch, and repeat.
  if shuffle:
    dataset = dataset.shuffle(buffer_size=batchSize * 10)
  dataset = dataset.batch(batchSize)
  dataset = dataset.repeat(numEpochs)
  
  # Make a one-shot iterator.
  iterator = dataset.make_one_shot_iterator()
  features, labels = iterator.get_next()
  return features, labels

7. Сделайте и обучите классификатор

#@title Make and train a classifier
#['VV','VH','angle','x','y'..etc] specify the data on which 
# the classifier should train
inputColumns = {
  tf.feature_column.numeric_column(k) for k in ['VV','VH']
}
#Activation function Softmax
activation_fn = tf.nn.softmax
#optimizer function Adam
optimizer = tf.train.AdamOptimizer(1e-4)
#classifier
#specify the n_classes according to the number of labels
#model_dir = the directory in which the model will be save
#save_summary_steps = after number_step the model state will be 
#saved for graph visualization with tensorboard
#[10,10]= deep network architecture
classifier = tf.estimator.DNNClassifier(feature_columns=inputColumns,hidden_unit=[10,10],n_classes=5,model_dir='output_folder',optimizer=optimizer,activation_fn= tf.nn.relu,batch_norm= True,config=tf.estimator.RunConfig().replace(save_summary_steps=10))
classifier.train(input_fn=lambda:tfrecord_input_fn(fileName=tfrTrainFile, numEpochs=10, batchSize=1),steps=10000)
!ls output_folder

TensorBoard для визуализации статуса

#@title TensorBoard for statistic
%load_ext tensorboard.notebook
%tensorboard --logdir output_folde

8. Оцените классификатор.

#@title Evaluate the classifier
accuracy_score = classifier.evaluate(input_fn=lambda: tfrecord_input_fn(fileName=tfrTestFile, numEpochs=1, batchSize=1, shuffle=False))['accuracy']

9. Делайте прогнозы на основе тестовых данных.

#@title Make predictions on the test data
import itertools
# Do the prediction from the trained classifier.
checkPredictions = classifier.predict(input_fn=lambda: tfrecord_input_fn(fileName=tfrTestFile, numEpochs=1, batchSize=1, shuffle=False))
# Make a couple iterators.
iterator1, iterator2 = itertools.tee(checkPredictions, 2) 
#Iterate over the predictions, printing the class_ids and posteriors
for pred_dict in iterator1:
  class_id = pred_dict['class_ids']
  probability = pred_dict['probabilities']
  print(class_id, probability)

10. Найдите экспортированное изображение и файлы JSON на Диске.

#@title Find the exported image and JSON files in Drive
# tf_image_9a26cef21ab34f6257d0a250882124fc is the name of the 
# evaluation data(Earth Engine part 8) that was exported. you will 
# find it in your google drive(it will be different)
file_list = drive.ListFile({
  # You have to know this base filename from wherever you did the 
  # export.
  'q': 'title contains  "tf_image_9a26cef21ab34f6257d0a250882124fc"'}).GetList()
fileNames = []
jsonFile = None
for gDriveFile in file_list:
  title = gDriveFile['title']
  # Download to the notebook server VM.
  gDriveFile.GetContentFile(title)
  # If the filename contains .gz, it's part of the image.
  if (title.find('gz') > 0):
    fileNames.append(gDriveFile['title'])
  if (title.find('json') > 0):
    jsonFile = title
# Make sure the files are in the right order.
fileNames.sort()
# Check the list of filenames to ensure there's nothing
# unintentional in there.
print(fileNames)

11. Сделайте функцию ввода для предсказания.

#@title Make an input function for exported image data
# You have to know the following from your export.
PATCH_WIDTH = 256
PATCH_HEIGHT = 256
PATCH_DIMENSIONS_FLAT = [PATCH_WIDTH * PATCH_HEIGHT, 1]
# Make sure this matches the exported
bands = ['VV', 'VH', 'angle']
# Note that the tensors are in the shape of a patch, 
# one patch for each band.
columns = [tf.FixedLenFeature(shape=PATCH_DIMENSIONS_FLAT, dtype=tf.float32) for k in bands]
featuresDict = dict(zip(bands, columns))
# This function adds NDVI to a feature that doesn't have a label.
def addServerFeatures(features):
  return addFeatures(features, None)[0]
# This input function reads in the TFRecord files exported 
# from an image.
# Note that because the pixels are arranged in patches, 
# we need some additional
# code to reshape the tensors.
def predict_input_fn(fileNames):
  # Note that you can make one dataset from many files 
  # by specifying a list.
  dataset = tf.data.TFRecordDataset(fileNames, compression_type='GZIP')
  def parse_image(example_proto):
    parsed_features = tf.parse_single_example(example_proto, featuresDict)
    return parsed_features
  dataset = dataset.map(parse_image, num_parallel_calls=5)
  
  # Break our long tensors into many littler ones
  dataset = dataset.flat_map(lambda features: tf.data.Dataset.from_tensor_slices(features))
  
  # Add additional features (NDVI).
  dataset = dataset.map(addServerFeatures)
  # Read in batches corresponding to patch size.
  dataset = dataset.batch(PATCH_WIDTH * PATCH_HEIGHT)
  # Make a one-shot iterator.
  iterator = dataset.make_one_shot_iterator()
  return iterator.get_next()

# Do the prediction from the trained classifier.
predictions = classifier.predict(input_fn=lambda: predict_input_fn(fileNames))

12. Экспортируйте модель.

#@title Define output names
# INSERT YOUR USERNAME HERE:
username = 'username'
baseName = 'gs://folder_name/' + username
outputImageFile = baseName + '_predictions.TFRecord'
outputJsonFile = baseName + '_predictions.json'
print('Writing to: ' + outputImageFile)

13. Примените модель к нашему набору данных оценочных изображений.

#@title Make predictions on the image data, write to a file
iter1, iter2 = itertools.tee(predictions, 2)
# Iterate over the predictions, printing the class_ids and posteriors.
# This is just to examine the first prediction.
for pred_dict in iter1:
  print(pred_dict)
  break # OK
# Instantiate the writer.
writer = tf.python_io.TFRecordWriter(outputImageFile)
# Every patch-worth of predictions we'll dump an example 
# into the output
# file with a single feature that holds our predictions. Since are predictions
# are already in the order of the exported data, our patches we create here
# will also be in the right order.
# make sure this(patch) matche the number of labels + 1(probability)
patch = [[], [], [], [],[],[]]
for pred_dict in iter2:
  patch[0].append(pred_dict['class_ids'])
  patch[1].append(pred_dict['probabilities'][0])
  patch[2].append(pred_dict['probabilities'][1])
  patch[3].append(pred_dict['probabilities'][2])
  patch[4].append(pred_dict['probabilities'][3])
  patch[5].append(pred_dict['probabilities'][4])
  
  # Once we've seen a patches-worth of class_ids...
  if (len(patch[0]) == PATCH_WIDTH * PATCH_HEIGHT):
    
    # Create an example
    example = tf.train.Example(
              features=tf.train.Features(feature={
                'prediction': tf.train.Feature(             
                              int64_list=tf.train.Int64List(
                                               value=patch[0])),
                'vegProb': tf.train.Feature(
                              float_list=tf.train.FloatList(
                                                value=patch[1])),
                'groundProb': tf.train.Feature(
                              float_list=tf.train.FloatList(
                                                value=patch[2])),
                'waterProb': tf.train.Feature(
                              float_list=tf.train.FloatList(
                                                value=patch[3])),
                'vase_waterProb': tf.train.Feature(
                              float_list=tf.train.FloatList(
                                                value=patch[4])),
                'mangroveProb': tf.train.Feature(
                              float_list=tf.train.FloatList(
                                                value=patch[5])),
                }
              )
            )
  # Write the example to the file and clear our patch array 
  # so it's ready for
  # another batch of class ids
  writer.write(example.SerializeToString())
  patch = [[], [], [], [],[],[]]
writer.close()

14. Экспортируйте результат (JSON) в облачное хранилище.

#@title Copy the JSON file to a cloud storage bucket
# Copy the JSON file so it has the same base name as the image.
!gsutil cp {jsonFile} {outputJsonFile}
!gsutil ls gs://folder_name

[Colaboratory-to-Earth Engine] Экспорт прогноза в Earth Engine для визуализации

#@title Install the Earth Engine API
!pip install earthengine-api
!earthengine authenticate --quiet
#@title Authentication for Earth Engine
!earthengine authenticate --authorization-code= replace_with_generated_key_here
#@title Get earthengine upload help
!earthengine upload image -h
#@title Upload the classified image to Earth Engine
# Change the filenames to match your personal user folder 
# in Earth Engine.
# replace folder_name with your one
outputAssetID = 'users/folder_name'
!earthengine upload image --asset_id={outputAssetID} {outputImageFile} {outputJsonFile}

Проверить статус приема актива

#@title Check the status of the asset ingestion
import ee
ee.Initialize()
tasks = ee.batch.Task.list()
print(tasks)

Выводы

Надеюсь, вам понравился этот пост. Дайте мне, если понимаете. Надеюсь, теперь вы можете обучить свой собственный SAR-dnnclassifier для обнаружения изменений. Следуйте за мной здесь, на Medium @ghomsiDev или в твиттере @ghomsiDev, чтобы быть в курсе моих работ. Позвольте Наслаждайтесь радиолокационными изображениями

Спасибо за уделенное время!

:)