Categories
Linux Sói's Tutorials

Install Microsoft Office 2010 on Kubuntu Linux

Requirements

WINEPREFIX=”$HOME/prefix32″ WINEARCH=win32 wine wineboot

We’ll install MSOffice using the PlayOnLinux wizard. Additionally, MSOffice requires samba and winbind to properly work.

So, if not installed, install them:

sudo apt-get install playonlinux samba winbind

Of course, you’ll need the MSOffice installer files (either DVD/folder files), in the 32 bits version. Even if you’re under Ubuntu 64, we’ll use a 32 bits wine installation.

Then open POL (PlayOnLinux) from command line (playonlinux &) or using Dash.

Pre Install

In the POL window menu, go to Tools > Manage Wine versions and install Wine 2.13. Versions below it will crash after click on a document hyperlink. Versions above it will not properly handle the launcher icon (due missing WM_CLASS when window is maximized).

Install

In the POL window, click on Install at top (the one with a plus sign).

1. PlayOnLinux Install menu

At the Install window, at the bottom, select Office and make sure Commercial (at top) is marked.

Now select Microsoft Office 2010 and click on Install.

2. Welcome to PlayOnLinux Installation Wizard

Nothing to do here other then click on the Next button.

3. Please Choose an Installation Method

Now it’s up to you: select DVD or file installation according your MSOffice installation.

Then click on Next.

Browse the files or the DVD: the goal here is select the MSOffice setup.exe, from the 32 bits version.

Now, after click on Next: you’ll see a sequence of PlayOnLinux installation windows, configuring the new Windows virtual drive, installing components, etc.

4. The MSOffice Install Wizard

Automatically the MSOffice installer will be displayed.

Install the MSOffice as on Windows: agree with EULA, select install type, etc.

In the last Install window, click on Close in the MSOffice installer: you’ll see a PlayOnLinux window still running some additional configurations.

Then, a successful message: click on Next and the install window will be closed.

Now you can close PlayOnLinux.

Post Install

1. Desktop Files

Current PlayOnLinux Office2010 script already creates the above shortchuts.

But in case you deleted them or want to fix something…

Now let’s create some .desktop files to provide better integration into Ubuntu: you can associate typical MSOffice files, like .docx to Word; at Dash, type winword to run Word, etc.

Open a text editor (like gedit, nano or vim) and create 3 files under ~/.local/share/applications, with the following names and contents.

Please, replace /home/<user> (at the Icon line) by your home folder path:

  • Word.desktop

#!/usr/bin/env xdg-open

[Desktop Entry]

Version=1.0

Type=Application

Categories=Office;WordProcessor;

StartupWMClass=WINWORD.EXE

Name=Microsoft Office Word 2010

Comment=winword

Exec=env XMODIFIERS=” playonlinux –run “Microsoft Word 2010” %F

Icon=/home/<user>/.PlayOnLinux/icones/full_size/Microsoft Word 2010

  • Excel.desktop

#!/usr/bin/env xdg-open

[Desktop Entry]

Version=1.0

Type=Application

Categories=Office;Spreadsheet;

StartupWMClass=EXCEL.EXE

Name=Microsoft Office Excel 2010

Comment=excel

Exec=env XMODIFIERS=” playonlinux –run “Microsoft Excel 2010” %F

Icon=/home/<user>/.PlayOnLinux/icones/full_size/Microsoft Excel 2010

  • PowerPoint.desktop

#!/usr/bin/env xdg-open

[Desktop Entry]

Version=1.0

Type=Application

Categories=Office;Presentation;

Terminal=false

StartupWMClass=POWERPNT.EXE

Name=Microsoft Office PowerPoint 2010

Comment=powerpnt

Exec=env XMODIFIERS=” playonlinux –run “Microsoft Powerpoint 2010” %F

Icon=/home/<user>/.PlayOnLinux/icones/full_size/Microsoft Powerpoint 2010

  • OneNote.desktop

#!/usr/bin/env xdg-open

[Desktop Entry]

Version=1.0

Type=Application

Categories=Office;Documentation;

Terminal=false

StartupWMClass=ONENOTE.EXE

Name=Microsoft Office OneNote 2010

Comment=onenote

Exec=env XMODIFIERS=” playonlinux –run “Microsoft OneNote 2010” %F

Icon=/home/<user>/.PlayOnLinux/icones/full_size/Microsoft OneNote 2010

After create those 4 files, open a terminal (Ctrl+Alt+T) and run this command to refresh the Dash entries:

sudo update-desktop-database

One clarification: the env XMODIFIERS=” command in the Exec line is to prevent wine to change keyboard behavior (sometimes while using wine the keyboard uses a different layout, so accents will not work properly, etc).

2. Printers

If you have a printer properly configured under Ubuntu, probably it’ll be automatically available to MSOffice under wine.

If not, we can make it available. Basically, your printer must be installed using cups. No problem if the printer is installed using other softwares/drivers, but to get it available for wine, it must be installed under cups too.

If cups package is not installed, install it:

sudo apt-get install cups

Then, open http://localhost:631/ and add your printer.

After configure it, print a test page using the related printer in Printers from System Settings.

Now, make sure you have this file: /etc/printcap. If it’s not present, create it this way:

ln -sf /var/run/cups/printcap /etc/printcap

Reboot wine: open PlayOnLinux, click Configure, select Office2010, click on Wine tab and click on Windows reboot button.

3. Fix Alternate between Excel windows

When you open 2 files in Excel, and click on Excel icon in the launcher by the second time to see opened files (Expose), you’ll see a weird behavior: one window properly rendered, and the second with just a single icon.

To fix this, open Excel, then File > Options > Advanced > General and check Ignore other applications that use Dyanamic Data Exchange (DDE).

Then, to alternate between Excel files, on Excel click on View tab and then click on Alternate Windows

https://gist.github.com/soiqualang/9576ebed46701d327ad3e26461e16916

Một số lỗi:

Please install winbind (or samba, on Arch Linux) before installing

key

https://minhtan.com.vn/office-2010-full-crack/

J3TQC-KF4KK-HWQW7-P6J73-9WR93

W3BTX-H6BW7-Q6DFW-BXFFY-8RVJP

DX4MW-PB7F4-YR4WT-BV3MM-4YV79

BDD3G-XM7FB-BD2HM-YK63V-VQFDK

6D739-9F4F2-BKKV8-YCHRF-PWR8B

W3G79-KFKR2-M9C86-JG748-G8373

4C9PX-DH3G9-D424D-FGGKF-PRWH3

BDD3G-XM7FB-BD2HM-YK63V-VQFDK

6QFDX-PYH2G-PPYFD-C7RJM-BBKQ8

HXJQ4-VT6T8-7YPRK-R2HQG-CYPPY

6R7J3-K4CB9-PG7BR-TVDBG-YPGBD

4DDJ8-DM67D-GJPT2-32H93-9MMWK

]]>
Categories
Công nghệ

[ML] Vọc phân loại ảnh với kỹ thuật Transfer Learning

Kỹ thuật Transfer Learning là gì thì mình xin dẫn lại lời của anh Duy Luân như sau:

Bình thường khi bạn train từ đầu các model (mô hình, mà mình thích dùng chữ model hơn) nhận diện hình ảnh, bạn sẽ cần rất nhiều sức mạnh từ máy tính. Nếu không có GPU khủng, nói chung là cấu hình mạnh thì sẽ mất rất nhiều thời gian. Chưa kể việc bạn phải viết từ đầu cũng là một thứ không chắc là hay trừ khi bạn cần phải tối ưu nó một cách cụ thể.
Thế nên người ta mới nghĩ tới Transfer Learning, nó là kĩ thuật giúp rút ngắn thời gian (và sức mạnh máy tính) cần thiết để train model bằng cách sử dụng một model nền có sẵn, tạm gọi là model được train gần hoàn chỉnh, sau đó train thêm chút xíu nữa bằng data của riêng bạn để có thể phân loại theo ý bạn muốn. Việc này giống như có ai đó đào móng, dựng cốt thép bê tông sẵn cho bạn rồi, bạn chỉ việc lên xây cái nhà theo ý thích của mình là được.
Bài hướng dẫn mình xem trên Google sử dụng ImageNet 122 làm nền. Đây là một database cực lớn về phân loại hình ảnh đã được Google phát triển một thời gian. Nó đã được train sẵn với 20 nghìn loại (category) hình ảnh khác nhau, chúng ta chỉ cần tận dụng nó thêm một bước nữa để áp category mà bạn muốn vào là được (thay vì chỉ dùng category do Google cung cấp).
Tất nhiên, việc bạn xài một giải pháp có sẵn sẽ không bao giờ có thể tốt như việc bạn từ làm từ đầu, model cũng thế. Nhưng không phải lúc nào bạn cũng cần tới mức phức tạp như vậy, đôi khi chỉ cần việc nó chạy là ngon lắm rồi, và tình huống của mình là như thế đấy. Độ chính xác tầm 70-80% là đã cực kì hiệu quả và giúp cho user của mình nhiều lắm rồi.
Kiểu transfer learning này cũng cho phép bạn train vài nghìn tấm ảnh bằng chính laptop của mình, ngay cả khi nó không có GPU rời. Cho nhu cầu cơ bản và để học, tìm hiểu thì quá tuyệt vời.


https://forum.machinelearningcoban.com/t/viet-engine-phan-loai-hinh-anh-bang-neural-network-mot-cach-de-dang-python-tensorflow/2522

Bắt đầu thôi

Ở đây mình dùng Google Colab

]]>
Categories
Google Earth Engine Tài liệu Viễn thám

[GEE 8] Xây dựng bản đồ sử dụng đất sử dụng mẫu thời gian Landuse map from temporal signature

Xây dựng bản đồ sử dụng đất sử dụng mẫu thời gian

Landuse map from temporal signature

templuse

Một ví dụ bản đồ hiện trạng sử dụng đất từ ảnh lưu trữ Landsat

  1. Nhập Import tập hợp ảnh Landsat 5, 7 và 8 ImageCollections.
imports

2. Xác định khoảng thời gian cần quan tâm.

// Định nghĩa khoảng thời gianvar startyear = 2006;var endyear = 2016; // Đặt lịch theo định dạng ngày tháng:var startdate = ee.Date.fromYMD(startyear,1,1);var enddate = ee.Date.fromYMD(endyear,12,31)

3. Import một fusion table (file vector) của khu vực nghiên cứu mà bạn quan tâm.

// Lưu vực song Cảvar Ca = ee.FeatureCollection(‘ft:1ILFPzWUf4dL_tKNY0Rd3EhGtRQoLfzmk_00i9xC3’);

4. Lựa chọn ImageCollections dựa trên thời gian và khu vực quan tâm.

// Lọc ảnh theo thòi gian chụp và vùng  baovar l5images = l5.filterDate(startdate,enddate).filterBounds( Ca);var l7images = l7.filterDate(startdate,enddate).filterBounds( Ca);var l8images = l8.filterDate(startdate,enddate).filterBounds( Ca);

5. Bao gồm cả hàm để loại bỏ mây

// Xác định ngưỡng mâyvar cloud_thresh = 40; // Hàmvar cloudfunction = function(image){  //use add the cloud likelihood band to the image  var CloudScore = ee.Algorithms.Landsat.simpleCloudScore(image);  //isolate the cloud likelihood band  var quality = CloudScore.select(‘cloud’);  //get pixels above the threshold  var cloud01 = quality.gt(cloud_thresh);  //create a mask from high likelihood pixels  var cloudmask = image.mask().and(cloud01.not());  //mask those pixels from the image  return image.updateMask(cloudmask);};

6. Chạy hàm loại bỏ mây cho tất cả các ảnh trong tập hợp ảnh được lựa chọn

// mask all clouds in the image collectionl5images = l5images.map(cloudfunction);l7images = l7images.map(cloudfunction);l8images = l8images.map(cloudfunction);

7. Chọn band Red và NIR (cận hồng ngoại).

// Select the red and NIR bandsl5images = l5images.select([“B4″,”B3”]);l7images = l7images.select([“B4″,”B3”]);l8images = l8images.select([“B5″,”B4”]);

8. Tính NDVI cho tất cả các ảnh.

// calculate ndvi from landsat 8function l8ndvi(img) {  var ndvi = img.normalizedDifference([‘B5’, ‘B4’]).rename(‘NDVI’);  return img.addBands(ndvi);} // calculate ndvi from landsat 5 & 7function l57ndvi(img) {  var ndvi = img.normalizedDifference([‘B4’, ‘B3’]).rename(‘NDVI’);  return img.addBands(ndvi);} // calculate ndwi for each image in imagecollectionvar l5ndvi = l5images.map(l57ndvi);var l7ndvi = l7images.map(l57ndvi);var l8ndvi = l8images.map(l8ndvi);

9. Gộp tất cả các ảnh vào một bộ sưu tập ảnh.

// combine all data in single image collectionvar allcollection =  ee.ImageCollection((l5ndvi.merge(l7ndvi)).merge(l8ndvi));

10. Tính trung bình (Mean) NDVI cho từng tháng.

// create list for yearsvar months = ee.List.sequence(1,12); // calculate the ndvi for each monthvar monthlyNDVI =  ee.ImageCollection.fromImages(  months.map(function(m){  var w = allcollection.select(“NDVI”).filter(ee.Filter.calendarRange(m, m, ‘month’))           .mean();  return w.set(‘year’, 2000)           .set(‘month’, m)           .set(‘date’, ee.Date.fromYMD(2000,m,1))           .set(‘system:time_start’,ee.Date.fromYMD(2000,m,1)) }).flatten());

11. Hiển thị ảnh Mean NDVI của tập hợp ảnh đã chọn  

// the vizualization settingsvar ndvi_viz = {min:0.0, max:0.70, palette:”ffe60a,dfffd1,277005″}; // add map to canvasMap.addLayer(monthlyNDVI.select(“NDVI”).mean().clip(Ca),ndvi_viz ,”ndvi”)

Bây giờ chúng ta sẽ vẽ các mẫu thời gian (temporal signature)

12. Dùng công cụ vẽ Select the polygon drawing tool.

poly1

13. Vẽ một vùng mẫu cho các lớp sử dụng đất cần quan tâm

poly2

14. Đặt tên cho vùng mẫu. Lựa chọn tập hợp đối tượng có cùng đặc điểm và đặt cho nó cùng 1 giá trị = 0

.

poly3

15. Lặp lại công việc này đối với các lớp khác bằng cách tạo ra new layer. Đảm bảo rằng các lớp khác nhau có giá trị khác nhau

16. Gộp các lớp khác nhau thành 1 tập hợp mẫu

// merge into one feature collectionvarmergedtable = rice //0.merge(urban)               //1.merge(water)               //2.merge(richforest)          //3.merge(annualcrops)         //4.merge(secondaryforest)     //5

17. Hiển thị mẫu thời gian dưới dạng đồ thị

17// Predefine the chart titles.var title = {  title: ‘landuseclass’,  hAxis: {title: ‘Time’},  vAxis: {title: ‘ndvi’},}; // create chartvar chart = ui.Chart.image.seriesByRegion(monthlyNDVI,                                          mergedtable,                                           ee.Reducer.mean(),                                           ‘NDVI’,                                           30,                                           ‘system:time_start’,                                           ‘class’).setOptions(title); print(chart);
mychart.jpg

Bây giờ chúng ta cần đưa thêm vào 12 ảnh (ảnh của mỗi tháng) coi như là một band ảnh của một tập hợp ảnh mới. việc này có thể thực hiện nhờ đoạn code dưới đây.

18. Copy và paste đoạn code này vào Code Editor

// Create a list with monthsvarmonthnames = [“jan”,”feb”,”mar”,”apr”,”may”,”jun”,”jul”,”aug”,”sep”,”oct”,”nov”,”dec”] // make a list of from the imagecollectionvarmyNDVIlist = monthlyNDVI.select(“NDVI”).toList(12); // create a new image from the month JanuaryvarmyCollection = ee.Image(myNDVIlist.get(0)).rename(“jan”); // add the image of each month as band to the imagefor (vari = 1; i<myNDVIlist.length().getInfo(); i++) {  varmymap = ee.Image(myNDVIlist.get(i)).rename(monthnames[i]);  myCollection = myCollection.addBands(mymap);}

19. Sử dụng đoạn code dưới đây để phân loại ảnh.

// set training image collection

varTrainingImage = myCollection;

// define training features

vartrainingFeatures = mergedtable;

// define predicion bands

varpredictionBands = myCollection.bandNames();

// set training classifier

var classifierTraining = TrainingImage.select(predictionBands).sampleRegions({collection: trainingFeatures, properties: [‘class’], scale: 30 });

// set classifier

var classifier = ee.Classifier.svm()

                 .train({features:classifierTraining, classProperty:’class’, inputProperties: predictionBands});

// classify

var classified = TrainingImage.select(predictionBands).classify(classifier);

// add the result to the Map

Map.addLayer(classified.clip(Ca), {min: 0, max: 5,

palette: [‘f0ff00′,’616343′,’2f00ff’,’125610′,’a93e9f’,’b8fbc0′]},’landuse classification’

]]>
Categories
Google Earth Engine Tài liệu Viễn thám

[GEE 6] Lab 6: Biến đổi ảnh và các chỉ số quang phổ

Lab 6: Biến đổi ảnh và các chỉ số quang phổ

Mục đích :  Mục đích của bài tập này là giúp bạn biết them về các chỉ số quang phổ, có thể được sử dụng để làm nổi bật đặc tính của các đối tượng mà chúng ta quan tâm trên ảnh viễn thám. Các bạn sẽ được giới thiệu các phương pháp để tạo các chỉ số về thực vật, nước, tuyết, bề mặt trống và bề mặt đã bị đốt cháy.

  1. Các chỉ số quang phổ

Các chỉ số quang phổ được xây dựng dựa trên phổ phản xạ khác nhau của các loại lớp phủ bề mặt. Các chỉ số được thiết kế để khai thác những sự khác biệt để làm nổi bật các loại đất cụ thể. Hãy tìm hiểu đồ thị về phản xạ phổ của các đối tượng bề mặt khác nhau trong đồ thị dưới đây.

Quan sát cho thấy các loại lớp phủ phản xạ khác nhau tại một hoặc nhiều bước sóng. Ví dụ đường cong phản xạ của thực vật (xanh) có hệ số phản xạ tương đối cao trong khoảng cận hồng ngoại (NIR), do năng lượng bức xạ tán xạ bởi các tế bào trong lá cây (Bowker et al. 1985). Bên cạnh đó. thực vật có phản xạ thấp trong dải màu đỏ, nơi năng lượng bức xạ được hấp thụ bởi chất diệp lục. Những quan sát này thúc đẩy việc xây dựng các chỉ số thực vật, ví dụ:

  1. NDVI.  

Chỉ số chuẩn hóa khác biệt về thực vật – The Normalized Difference Vegetation Index (NDVI) có lịch sử lâu đời trong viễn thám.  Công thức đặc trưng là

NDVI = (NIR – red) / (NIR + red)

Với kênh cận hồng ngoại và đỏ thể hiện phản xạ, tán xạ hoặc giá trị số cụ thể tại mỗi bước sóng cụ thể. Thực hiện chỉ số này trong GEE sẽ sử dụng phương pháp normalizedDifference(). Trước hết lấy một ảnh tại khu vực quan tâm bằng cách vẽ một điểm (Point), đặt tên điểm và nhập từ tập hợp ảnh Landsat8 TOA như là

Được gọi là landsat8 và sắp xếp tập hợp ảnh theo dữ liệu metadata về mây che phủ:

var image = ee.Image(landsat8

    .filterBounds(point)

    .filterDate(‘2015-06-01’, ‘2015-09-01’)

    .sort(‘CLOUD_COVER’)

    .first());

var trueColor = {bands: [‘B4’, ‘B3’, ‘B2’], min: 0, max: 0.3};

Map.addLayer(image, trueColor, ‘image’);

Công thức tính toán NDVI là dòng lệnh dưới đây:

var ndvi = image.normalizedDifference([‘B5’, ‘B4’]);

Hiển thị ảnh NDVI với bảng màu (có thể thay đổi)

var vegPalette = [‘red’, ‘blue’, ‘yellow’, ‘green’];

Map.addLayer(ndvi, {min: -1, max: 1, palette: vegPalette}, ‘NDVI’);

Sử dụng Inspector để kiểm tra các giá trị pixel trong các khu vực có thực vật và không có thực vật phủ.

  1. EVI.  

Chỉ số thực vật tăng cường (EVI) được thiết kế để giảm thiểu hiệu ứng bão hoà và các yếu tố nền của chỉ số NDVI (Huete et al. 2002). Vì nó không phải là một chỉ số khác biệt chuẩn, nó được tính toán theo biểu thức:

var evi = image.expression(

    ‘2.5 * ((NIR – RED) / (NIR + 6 * RED – 7.5 * BLUE + 1))’, {

      ‘NIR’: image.select(‘B5’),

      ‘RED’: image.select(‘B4’),

      ‘BLUE’: image.select(‘B2’)

});

Quan sát các kênh ảnh  được tham chiếu với sự giúp đỡ của một đối tượng sau khi được tính toán theo biểu thức image.expression().  

Hiển thị ảnh EVI:

Map.addLayer(evi, {min: -1, max: 1, palette: vegPalette}, ‘EVI’);

SO sánh kết quả của EVI và  NDVI. Bạn thấy có điểm khác biệt gi?

  1. NDWI.  

Chỉ số chuẩn hóa khác biệt về nước (NDWI) được phát triển bởi Gao (1996) là chỉ số về lượng thực vật và nước :

NDWI = (NIR – SWIR) / (NIR + SWIR)

Tính chỉ số NDWI trong GEE với công thức:

var ndwi = image.normalizedDifference([‘B5’, ‘B6’]);

Và hiển thị :

var waterPalette = [‘red’, ‘yellow’, ‘green’, ‘blue’];

Map.addLayer(ndwi, {min: -0.5, max: 1, palette: waterPalette}, ‘NDWI’);

Lưu ý rằng đây không phải là việc thực hiện chính xác NDWI, theo OLI spectral response, vì OLI không có kênh ảnh theo bước sóng đúng (1.26 𝛍m).

  1. NDWBI.  

Hai chỉ số NDWI khác nhau đã được phát minh một cách độc lập vào năm 1996. Để phân biệt, công thức NDWBI – chuẩn khác biệt về các bề  mặt nước là chỉ số được mô tả trong McFeeters (1996)

NDWBI = (green – NIR) / (green + NIR)

Giống như trên, thực hiện công thức NDWBI theo hàm normalizedDifference() và hiển thị kết quả:

var ndwi = image.normalizedDifference([‘B3’, ‘B5’]);

Map.addLayer(ndwi, {min: -1, max: 0.5, palette: waterPalette}, ‘NDWBI’);

So sánh kết quả NDWIvà NDWBI.  Bạn thấy có khác biệt gì ?

  1. NDBI.  

Chỉ số Chuẩn khác biệt về bề mặt trống Normalized Difference Bare Index (NDBI) được phát triển bởi  Zha et al. (2003)  để giúp đánh giá sự khác biệt ở khu vực đô thị:

NDBI = (SWIR – NIR) / (SWIR + NIR)

Lưu ý rằng chỉ số NDBI là chỉ số đảo của NDWI. Tính NDBI và hiển thị với bảng màu tùy chọn:

var ndbi = image.normalizedDifference([‘B6’, ‘B5’]);

var barePalette = waterPalette.slice().reverse();

Map.addLayer(ndbi, {min: -1, max: 0.5, palette: barePalette}, ‘NDBI’);

(Check this reference to demystify the palette reversal).

  1. BAI.  

Chỉ số cháy (BAI) được phát triển bởi Chuvieco et al. (2002) để hỗ trợ trong việc mô tả những khu vực bị cháy và đánh giá mức độ nghiêm trọng của đám cháy. Nó được dựa trên khoảng cách phản xạ phổ của than. Để kiểm tra chỉ số cháy, tải một hình ảnh từ đám cháy ở Sierra Nevadas năm 2013:

var burnImage = ee.Image(landsat8

    .filterBounds(ee.Geometry.Point(-120.083, 37.850))

    .filterDate(‘2013-08-17’, ‘2013-09-27’)

    .sort(‘CLOUD_COVER’)

    .first());

Map.addLayer(burnImage, trueColor, ‘burn image’);

Khi kiểm tra kỹ lưỡng theo hiển thị màu thực của bức ảnh này, bạn có thể chỉ ra các vị trí có đám cháy? Nếu không công thức BAI có thể giúp. Giống như EVI, chí số BAI được tính trên GEE như sau

:

var bai = burnImage.expression(

    ‘1.0 / ((0.1 – RED)**2 + (0.06 – NIR)**2)’, {

      ‘NIR’: burnImage.select(‘B5’),

      ‘RED’: burnImage.select(‘B4’),

});

Hiển thị kết quả. Khu vực bị cháy sẽ hiển thị ró ràng hơn trên ảnh kết quả BAI

var burnPalette = [‘green’, ‘blue’, ‘yellow’, ‘red’];

Map.addLayer(bai, {min: 0, max: 400, palette: burnPalette}, ‘BAI’);

  1. NBRT.  

Tỉ số chuẩn hóa nhiệt (NBRT) được phát triển dựa trên ý tưởng rằng bế mặt đất bị đốt cháy sẽ phản xạ thấp ở kênh cận hồng ngoại (ít thực vật), phản xạ cao ở kênh SWIR (tro), và độ sáng cao với nhiệt độ (Holden et al. 2005). Không giống như các chỉ số khác, một pixel có chỉ só NBRT thấp hơn có nghĩa là bị cháy nhiều hơn. Thực hiện NBRT với biểu thức:

var nbrt = burnImage.expression(

  ‘(NIR – 0.0001 * SWIR * Temp) / (NIR + 0.0001 * SWIR * Temp)’, {

    ‘NIR’: burnImage.select(‘B5’),

    ‘SWIR’: burnImage.select(‘B7’),

    ‘Temp’: burnImage.select(‘B11’)

});

Hiển thị kết quả và đảo ngược tý lệ :

Map.addLayer(nbrt, {min: 1, max: 0.9, palette: burnPalette}, ‘NBRT’);

Sự khác biệt trong chỉ số này, trước và sau khi cháy có thể được sử dụng để xác định các khu vực cháy nghiêm trọng (see van Wagtendonk et al. 2004).

  1. NDSI.  

Chỉ số chuẩn về tuyết (NDSI) được thiết kế để ước lượng số lượng pixel có tuyết phủ

 (Riggs et al. 1994):

NDSI = (green – SWIR) / (green + SWIR)

Trước hết, tìm một cảnh ảnh có tuyết để kiểm tra chí số:

var snowImage = ee.Image(landsat8

    .filterBounds(ee.Geometry.Point(-120.0421, 39.1002))

    .filterDate(‘2013-11-01’, ‘2014-05-01’)

    .sort(‘CLOUD_COVER’)

    .first());

Map.addLayer(snowImage, trueColor, ‘snow image’);

Tính và hiển thị kết quả NDSI trên GEE:

var ndsi = snowImage.normalizedDifference([‘B3’, ‘B6’]);

var snowPalette = [‘red’, ‘green’, ‘blue’, ‘white’];

Map.addLayer(ndsi, {min: -0.5, max: 0.5, palette: snowPalette}, ‘NDSI’);

  1. Chuyển đổi tuyến tính

Phép biến đổi tuyến tính là sự kết hợp tuyến tính của các giá trị pixel đầu vào. Đây có thể là kết quả của một loạt các chiến lược khác nhau, nhưng một chủ đề chung là pixel đang được coi là một dãy các giá trị của các kênh ảnh.

  1. Tasseled cap (TC).

Dựa trên những quan sát về đất nông nghiệp phản xạ trong khoảng phổ giữa cận hồng ngoại và đỏ, Kauth và Thomas (1976) đã phát minh ra cách luân chuyển theo form

p1 = RTp0

 Với p0 là vector px1 điểm ảnh gốc (một tập hợp các giá trị p được coi như một mảng các giá trị), p1 là pixel xoay và R là một cơ sở trực chuẩn của không gian mới (do đó RT là nghịch đảo của nó). Kauth và Thomas tìm thấy R bằng cách xác định trục đầu tiên của không gian chuyển đổi để song song với đường phản xạ của đất trong biểu đồ dưới đây, sau đó sử dụng phương pháp Gram-Schmidt để tìm các vectơ cơ sở khác.

Giả sử R là một biến. một chiều để tiến hành xoay trục trong GEE là với các mảng (array) này. Cụ thể, tạo một mảng của hệ số TC

var coefficients = ee.Array([

  [0.3037, 0.2793, 0.4743, 0.5585, 0.5082, 0.1863],

  [-0.2848, -0.2435, -0.5436, 0.7243, 0.0840, -0.1800],

  [0.1509, 0.1973, 0.3279, 0.3406, -0.7112, -0.4572],

  [-0.8242, 0.0849, 0.4392, -0.0580, 0.2012, -0.2768],

  [-0.3280, 0.0549, 0.1075, 0.1855, -0.4357, 0.8085],

  [0.1084, -0.9022, 0.4120, 0.0573, -0.0251, 0.0238]

]);

Các hệ số ở trên là hệ số của vệ tinh ảnh Landsat TM sensor, tìm một ảnh ít mây. Trước hết tìm ‘landsat 5 toa’, sau đó Import ‘USGS Landsat 5 TOA Reflectance (Orthorectified)’.  Đặt tên ảnh mới nhập landsat5, sau đó lọc lựa chọn ảnh và sắp xếp theo mức độ mây che phủ:

var tcImage = ee.Image(landsat5

    .filterBounds(point)

    .filterDate(‘2008-06-01’, ‘2008-09-01’)

    .sort(‘CLOUD_COVER’)

    .first());

Để thực hiện phép nhân ma trận, lầu tiên chuyển đổi ảnh ban đầu từ một ảnh nhiều kênh phổ trở thành ảnh 1 kênh với các dãy giá trị, trong đó mỗi pixel chứa một mảng giá trị số:

var bands = [‘B1’, ‘B2’, ‘B3’, ‘B4’, ‘B5’, ‘B7’];

// Make an Array Image, with a 1-D Array per pixel.

var arrayImage1D = tcImage.select(bands).toArray();

// Make an Array Image with a 2-D Array per pixel, 6×1.

var arrayImage2D = arrayImage1D.toArray(1);

Thực hiện nhân ma trận, và chuyển đổi trở về ảnh đa kênh phổ:

var componentsImage = ee.Image(coefficients)

  .matrixMultiply(arrayImage2D)

  // Get rid of the extra dimensions.

  .arrayProject([0])

  // Get a multi-band image with TC-named bands.

  .arrayFlatten(

    [[‘brightness’, ‘greenness’, ‘wetness’, ‘fourth’, ‘fifth’, ‘sixth’]]);

Cuối cùng, hiển thị kết quả:

var vizParams = {

  bands: [‘brightness’, ‘greenness’, ‘wetness’],

  min: -0.1, max: [0.5, 0.1, 0.1]

};

Map.addLayer(componentsImage, vizParams, ‘TC components’);

]]>
Categories
Google Earth Engine Tài liệu Viễn thám

[GEE 5] Bài 5: Ảnh số và xử lý ảnh

Bài 5: Ảnh số và xử lý ảnh

Mục đích: Mục đích của bài thực hành này là giới thiệu những khái niệm cơ bản về xử lý ảnh.  Bạn sẽ được tìm hiểu các hàm giúp nâng cao chất lượng ảnh như smoothing/làm mịn, sharpening/làm sắc nét, edge detection/dò biên ảnh, morphological processing/xử lý hình thái học, texture analysis/phân tích kết cấu ảnh, resampling/thay đổi độ phân giải và reprojection/nắn ảnh.  Sau khi hoàn thành bài thực hành, bạn sẽ có thể xác định các công cụ xử lý ảnh phù hợp để trích xuất thông tin bạn cần trong quá trình phân tích ảnh.

  1. Ảnh Số Là Gì?

Ảnh số, còn được gọi là raster, là một tập hợp các pixel (Besag 1986).  Mỗi pixel có một vị trí, được tính trong theo trục của một hệ tọa độ nhất định (coordinate reference system – CRS), cụ thể là một hệ tọa độ địa lý.  Một hệ tọa độ trong Earth Engine gắn liền với một phép chiếu, phép chiếu là cách biểu thị mặt cong của trái đất lên một mặt phẳng bản đồ dựa trên một gốc tọa độ.

Ví dụ:

  1. Tạo một điểm/point sử dụng geometry drawing tools (công cụ vẽ đối tượng hình học) để xác định vùng nghiên cứu của bạn. Đặt tên cho điểm/point đó.
  1. Đưa ảnh Sentinel vào bằng công cụ tìm kiếm với từ khóa ‘Sentinel’ và chọn tập dữ liệu raster ‘Sentinel 2’. Đặt tên cho ảnh Sentinel vừa được đưa vào.  
  1. Chon một ảnh Sentinel gần đây, bao phủ toàn bộ khu vực nghiên cứu của bạn, xem và kiểm tra ảnh.

// Get a single NAIP image over the area of interest.

var image = ee.Image(Sentinel

    .filterBounds(point)

    .sort(‘CLOUDY_PIXEL_PERCENTAGE’, true)

    .first());

//subset by the bands. Here we chose NIR, red and green

var bands = [‘B8′,’B4′,’B3’];

image = image.select(bands);    

// Print the image to the console.

print(‘Inspect the image object:’, image);

// Display the image with the default visualization.

Map.centerObject(point, 14);

Map.addLayer(image, {min:1300, max:3000}, ‘Original image’);

  1. Mở rộng phần thông tin về đối tượng ảnh vừa được in trong console.  Mở rộng phần thuộc tính của các band/kênh phổ và một trong các band/kênh phổ (ví dụ band số 0).  Chú ý rằng phép chuyển hệ trục tọa độ được lưu trong thuộc tính của crs_transform và hệ trục tọa độ được lưu trong thuộc tính crs, tham khảo EPSG code. Bạn có thể học thêm về EPSG code tại the spatialreference.org site.  Phép chuyển hệ trục tọa độ được liệt kê như sau: [m00, m01, m02, m10, m11, m12] trong phần chú giải của tài liệu tham khảo này.
  1. Truy nhập những dữ liệu này theo thứ tự sử dụng hàm .projection():

// Display the projection of band 0.

print(‘Inspect the projection of band 0:’, image.select(0).projection());

  1. Chú ý rằng phép chiếu có thể khác nhau với từng band, do đó việc kiểm tra phép chiếu cho từng band ảnh là rất cần thiết.  (Nếu bạn gọi .projection() cho từng ảnh hoặc cho những đối tượng mà phép chiếu các band khác nhau, bạn sẽ nhận được báo lỗi.)  Tìm hiểu ghi chú của ee.Projection để biết thêm về các hàm thường được dùng cho đối tượng Projection.  (Để tìm hiểu thêm về các phép chiếu, thử công cụ này.)
  1. Hiển Thị Ảnh Số

Chúng ta đã học về cách mà mỗi ảnh lưu trữ dữ liệu pixel trong mỗi band/kênh ảnh với các giá trị số (DNs) và các các pixel được sắp xếp theo không gian. Khi bạn đưa ảnh vào cửa sổ hiển thị, Earth Engine thực hiện hiển thị ảnh qua việc nhận diện phép chiếu và đặt tất cả các pixel vào đúng vị trí của nó theo không gian.  Truy nhiên, bạn cần định rõ biên độ của DNs để hiển thị một ảnh 16-bit (ví dụ các thông số hiển thị min và max).  Định rõ min và max áp dụng công thức sau (trong đó DN’ là giá trị hiển thị):

DN’ = (DN – min) * 65536 / (max – min)

  1. Để áp dụng hiệu chỉnh gamma (gamma correction) (DN’ = DN𝛾), sử dụng:

// Display gamma stretches of the input image.

Map.addLayer(image.visualize({gamma: 0.5}), { min:1300, max:3000}, ‘gamma = 0.5’);

Map.addLayer(image.visualize({gamma: 1.5}), { min:1300, max:3000}, ‘gamma = 1.5’);

  1. Chú ý rằng gamma được đưa ra như một đối số/argument cho image.visualize() vì vậy bạn có thể click vào ảnh để xem sự khác nhau trong các giá trị pixel (hãy thử!). Bạn cũng có thể định rõ gamma, min và max để đạt được các hiển thị đặc trưng khác.
  1. (Không bắt buộc)   Để áp dụng phương pháp  histogram equalization (cân bằng histogram), sử dụng hàm sldStyle() 

// Define a RasterSymbolizer element with ‘_enhance_’ for a placeholder.

var histogram_sld =

  ‘<RasterSymbolizer>’ +

    ‘<ContrastEnhancement><Histogram/></ContrastEnhancement>’ +

    ‘<ChannelSelection>’ +

      ‘<RedChannel>’ +

        ‘<SourceChannelName>B8</SourceChannelName>’ +

      ‘</RedChannel>’ +

      ‘<GreenChannel>’ +

        ‘<SourceChannelName>B4</SourceChannelName>’ +

      ‘</GreenChannel>’ +

      ‘<BlueChannel>’ +

        ‘<SourceChannelName>B3</SourceChannelName>’ +

      ‘</BlueChannel>’ +

    ‘</ChannelSelection>’ +

  ‘</RasterSymbolizer>’;

// Display the image with a histogram equalization stretch.

Map.addLayer(image.sldStyle(histogram_sld), {}, ‘Equalized’);

  1. Hàm sldStyle() method yêu cầu các thống kê của ảnh phải được thực hiện trong phạm vi một vùng (để xác định biểu đồ histogram).
  1. Lọc Tuyến Tính

Trong ngữ cảnh hiện tại, lọc tuyến tính/linear filtering (hay convolution (tích chập) là sự kết hợp tuyến tính của các giá trị pixel trong một vùng lân cận. Vùng lân cận được xác định bằng một kernel (cửa sổ lọc/ma trận lọc), trong đó các trọng số/weight của cửa sổ lọc/ma trận lọc quyết định các hệ số/coefficient của liên kết tuyến tính.  (Trong bài thực hành này, các thuật ngữ kernel/cửa sổ lọc và filter/lọc là một)  Lọc một ảnh có thể hữu ích cho việc trích xuất thông tin ảnh tại tần số không gian/spatial frequencies khác nhau. Do đó, bộ lọc làm mịn ảnh/smoothing filter được gọi là lọc tần số thấp/low-pass filters (dữ liệu đi qua cửa sổ lọc với tuần số thấp) và lọc edge detection filter/dò biên ảnh được gọi là lọc số suất cao/high-pass filter.  Để dùng các bộ lọc trong Earth Engine sử dụng image.convolve() với đối số/argument ee.Kernel.

  1. Smoothing/Làm mịn.  Smoothing/làm mịn có nghĩa là nhân chập ảnh với cửa sổ lọc smoothing.
  1. Một phép lọc smoothing đơn giản là một cửa sổ lọc hình vuông có cùng trọng số mà tổng của bằng 1.  Nhân chập với cửa sổ lọc này, mỗi pixel sẽ có một giá trị mới bằng giá trị trung bình của các pixel lân cận nằm trong cửa sổ lọc.  In một cửa sổ lọc hình vuông với cùng một trọng số (đôi khi còn được gọi là “pillbox” hay “boxcar” filter):

// Print a uniform kernel to see its weights.

print(‘A uniform kernel:’, ee.Kernel.square(2));

Mở rộng phần thông tin về đối tượng cửa sổ lọc/kernel tại console để xem các trọng số. Cửa sổ lọc này được định nghĩa bằng số lượng pixel nằm trong cửa sổ lọc (hay nói cách khác kích thước cửa sổ lọc có đơn vị là ‘pixel’).  Một cửa sổ lọc với kích thước theo mét nghĩa là kích thước của cửa sổ lọc đó đã được điều chỉnh từ pixel, do đó bạn không thể thấy được trọng số của nó, nhưng nó lại linh động hơn khi phải làm việc với các ảnh đầu vào ở tỷ lệ khác nhau. Trong phần sau, sử dụng các cửa sổ lọc với kích thước được định nghĩa theo mét (bỏ qua bước kiểm tra trọng số).

  1.  Định nghĩa một cửa sổ lọc có kích thước 20 mét (Tương ứng với bao nhiêu pixel của ảnh Sentinel?  Convolve/Nhân chập ảnh với cửa sổ lọc đó và so sánh ảnh đầu vào và ảnh sau khi đã được làm mịn/smooth)

// Define a square, uniform kernel.

var uniformKernel = ee.Kernel.square({

  radius: 20,

  units: ‘meters’,

});

// Filter the image by convolving with the smoothing filter.

var smoothed = image.convolve(uniformKernel);

Map.addLayer(smoothed, { min: 1123, max: 2069}, ‘smoothed image’);

  1. Để ảnh được mịn hơn, thử thay đổi kích thước của vùng lân cận bằng cách tăng kích thước pixel.
  1. Cửa sổ lọc Gaussian (lọc nhiễu) cũng có thể được sử dụng để làm mịn ảnh.  Lọc với cửa sổ lọc Gaussian bằng cách tính trung bình lượng giá của các pixel lân cận. Ví dụ như:

// Print a Gaussian kernel to see its weights.

print(‘A Gaussian kernel:’, ee.Kernel.gaussian(2));

// Define a square Gaussian kernel:

var gaussianKernel = ee.Kernel.gaussian({

  radius: 20,

  units: ‘meters’,

});

// Filter the image by convolving with the Gaussian filter.

var gaussian = image.convolve(gaussianKernel);

Map.addLayer(gaussian, {min: 1123, max: 2069}, ‘Gaussian smoothed image’);

  1. Edge detection/Dò biên ảnh.  Nhân chập với cửa sổ lọc dò biên ảnh/edge-detection kernel để tìm những biến đổi trong DNs, thường được phát hiện ở mép của các đối tượng trong ảnh dữ liệu.
  1. Cửa sổ lọc dò biên ảnh cổ điển là ma trận Laplacian.  Xem kỹ trọng số trong của sổ lọc và ảnh kết quả sau khi nhân chập với cửa sổ Laplacian:

// Define a Laplacian filter.

var laplacianKernel = ee.Kernel.laplacian8();

// Print the kernel to see its weights.

print(laplacianKernel);

// Filter the image by convolving with the Laplacian filter.

var edges = image.convolve(laplacianKernel)

                     .reproject(‘EPSG:32647’, null, 10);

Map.addLayer(edges, {min: 1123, max: 2069}, ‘Laplacian filtered image’);

  1. (bỏ qua  reproject().  Nó sẽ được giải thích trong phần 6.)
  2. Các cửa sổ lọc dò biên ảnh khác gồm có SobelPrewitt và Roberts.  Tìm hiểu thêm về các phương pháp dò biên ảnh khác trong Earth Engine.
  1. (Không bắt buộc)  Lọc theo đạo hàm Gradients.  Gradient ảnh là sự thay đổi giá trị pixel theo không gian (tương tự như tạo slope/dốc cho DEM).  
  1. Trong Earth Engine, dùng image.gradient() để tính gradient/độ dốc của các band/kênh phổ trong ảnh.  Ví dụ, gradient/độ dóc của kênh phổ hồng ngoại NIR chỉ thị sự biến đổi về thực vật:

// Compute the image gradient in the X and Y directions.

var xyGrad = image.select(‘B8’).gradient();

// Compute the magnitude of the gradient.

var gradient = xyGrad.select(‘x’).pow(2)

          .add(xyGrad.select(‘y’).pow(2)).sqrt()

    .reproject(‘EPSG: 32647’, null, 10);

// Compute the direction of the gradient.

var direction = xyGrad.select(‘y’).atan2(xyGrad.select(‘x’))

.reproject(‘EPSG:32647’, null, 10);

// Display the results.

Map.addLayer(direction, {min: -3, max: 3, format: ‘png’}, ‘direction’);

Map.addLayer(gradient, {min: -10, max: 50, format: ‘png’}, ‘gradient’);

  1. (Bỏ qua reproject() sẽ được giải thích trong 6.)
  2. Để hiểu sâu hơn về gradients/độ dốc trong ảnh đa phổ, đọc Di Zenzo (1986).
  1. (Không bắt buộc)  Tăng cường độ sắc nét/Sharpening.  Tăng cường độ sắc nét của ảnh hay edge enhancement (lọc tăng cường biên), có liên quan đến đạo hàm bậc hai của ảnh.  Cụ thể, mô phỏng lại quan điểm về Hiệu ứng ảo ảnh Mach bands trong phản xạ quang học của mắt người bằng cách cộng ảnh với đạo hàm bậc hai của nó.  
  1. Môt ứng dụng của ý tưởng này là nhân chập ảnh với một toán tử Laplace của một hàm Gauss (Laplacian-of-a-Gaussian) hoặc lọc Difference-of-Gaussians (Hàm sai khác DoG)  (đọc Schowengerdt 2007 để biết thêm chi tiết), và đưa nó vào ảnh đầu vào:

// Define a “fat” Gaussian kernel.

var fat = ee.Kernel.gaussian({

  radius: 30,

  sigma: 3,

  magnitude: -1,

  units: ‘meters’

});

// Define a “skinny” Gaussian kernel.

var skinny = ee.Kernel.gaussian({

  radius: 30,

  sigma: 0.5,

  units: ‘meters’

});

// Compute a difference-of-Gaussians (DOG) kernel.

var dog = fat.add(skinny);

// Add the DoG filtered image to the original image.

var sharpened = image.add(image.convolve(dog));

Map.addLayer(sharpened, {min: 1123, max: 2069}, ‘Edges enhanced’);

  1. Các khái niệm liên quan gồm có spectral inversion (nghịch đảo phổ) từ xử lý ảnh số và unsharp masking (mặt nạ không sắc nét) (Burger and Burge 2008).
  1. Xóa Script/Tập Lệnh
  2. Tạo một đối tượng dạng Điểm/Point  bằng  geometry drawing tools (công cụ vẽ vật thể hình học) để xác định vùng nghiên cứu của (chú ý, phải nằm trong Hoa Kỳ).  Đặt tên cho điểm/point đó.
  1. Đưa ảnh NAIP vào bằng cách thanh công cụ tìm kiếm với từ khóa ‘naip’ và chọn tập dữ liệu raster ‘NAIP: National Agriculture Imagery Program’ raster dataset.  Đặt tên cho ảnh naip.  
  1. Lấy một ảnh NAIP gần đây bao phủ toàn bộ khu vực nghiên cứu của bạn và xem kỹ nó:

// Get a single NAIP image over the area of interest.

var image = ee.Image(naip

   .filterBounds(point)

   .sort(‘system:time_start’, false)

   .first());

// Print the image to the console.

print(‘Inspect the image object:’, image);

// Display the image with the default visualization.

Map.centerObject(point, 18);

Map.addLayer(image, {}, ‘Original image’);

// Define a square, uniform kernel.

var uniformKernel = ee.Kernel.square({

  radius: 20,

  units: ‘meters’,

});

  1. Lọc Phi Tuyến Tính

Các ví dụ nhân chập/convolution vừa được giới thiệu được thực hiện như những tổ hợp tuyến tính của các giá trị pixel tại một vùng lân cận (lọc theo đạo hàm gradient cần thêm một vài bước, nhưng không đáng bận tâm).  Các hàm phi tuyến tính/Non-linear functions được áp dụng cho vùng lân cận cũng rất hữu ích.  Sử dụng những hàm này cho ảnh trong Earth Engine thông qua reduceNeighborhood().  

  1. Median/Lọc Trung vị.  Lọc trung vị/median filter rất hiệu quả để giảm độ nhiễu của ảnh.  Cụ thể, giả dụ rằng các pixel bất kỳ trong ảnh của bạn bị vỡ màu do những giá trị cao hoặc thấp hơn bình thường gây ra nhiễu.  Lọc ảnh với lọc trung bình/mean filter (như trong phần 3.a.i) có thể gây ra các pixel bị ảnh hưởng bởi nhiễu.  Để tránh điều đó, làm mịn ảnh với lọc trung vị  (sử dụng lại cửa sổ lọc đồng nhất 5×5 như ở trên):

var median = image.reduceNeighborhood({

 reducer: ee.Reducer.median(),

 kernel: uniformKernel

});

Map.addLayer(median, {min: 0, max: 255}, ‘Median’);

  1. Mode/Lọc mode.   Đối với các bản đồ phân loại, các phương pháp lọc trung vị/median hoặc lọc trung bình/mean thường ít có ý nghĩa để tập hợp dữ liệu định danh (nominal data).  Trong những trường hợp này, sử dụng mode (giá trị xuất hiện nhiều nhất) của vùng lân cận để có được giá trị xuất hiện thường xuyên nhất.
  1. Với mục đích giới thiệu, thử tạo một bản đồ phân loại bằng cách đặt ngưỡng giới hạn cho kênh phổ cận hồng ngoại NIR.  Với hai lớp kết quả được gán nhãn là 1 và 0:

// Create and display a simple two-class image.

var veg = image.select(‘N’).gt(200);

// Display the two-class (binary) result.

var binaryVis = {min: 0, max: 1, palette: [‘black’, ‘green’]};

Map.addLayer(veg, binaryVis, ‘veg’);

  1. Tính giá trị mode trong cửa sổ lọc kích thước 5×5:

// Compute the mode in each 5×5 neighborhood and display the result.

var mode = veg.reduceNeighborhood({

 reducer: ee.Reducer.mode(),

 kernel: uniformKernel

});

Map.addLayer(mode, binaryVis, ‘mode’);

  1. So sánh hình dạng của các patch (khoanh vi, mảng rời rạc) trong ảnh  mode  và ảnh nguyên gốc veg.  Chú ý hình dạng của các patch để thấy hiệu ứng làm mịn mà mode thực hiện.
  1. Morphological processing/Xử lý hình thái học.  Ý tưởng về xử lý ảnh theo hình thái học gắn liền với khái niệm về các đối tượng trong ảnh.  Ví dụ, giả định rằng các patch của giá trị 1 trong ảnh veg từ phần thực hành trên trên đại diện cho các patch/mảng rời rạc của lớp thực vật.
  1. Phép giãn ảnh/Dilation (max).  Nếu sự phân bố patch thấp hơn thực tế phân bố của thực vật, hoặc có chứa các holes/khe trống, phép lọc max có để được dùng để giãn tăng cường các vùng thực vật

// Dilate by takaing the max in each 5×5 neighborhood.

var max = veg.reduceNeighborhood({

 reducer: ee.Reducer.max(),

 kernel: uniformKernel

});

Map.addLayer(max, binaryVis, ‘max’);

  1. Thử tăng độ giãn bằng cách tăng kích thước của cửa sổ lọc (tăng radius) hoặc áp dụng reduceNeighborhood() nhiều lần.
  1. Phép co ảnh/Erosion (min).  Trái ngược với phép giãn ảnh là co ảnh, để giảm kích thước của các patch/mảng rời rạc:

// Erode by takaing the min in each 5×5 neighborhood.

var min = veg.reduceNeighborhood({

 reducer: ee.Reducer.min(),

 kernel: uniformKernel

});

Map.addLayer(min, binaryVis, ‘min’);

  1. Kiểm tra kết quả và so sánh với ảnh đầu vào. Chú ý rằng hình dạng của cửa sổ lọc có ảnh hưởng đển hình dáng của các patch đã được giảm kích (tương tự với phép giãn ảnh).  Tìm hiểu thêm về những ảnh hưởng này bằng cách thử thay đổi hình dạng của cửa sổ lọc.  Cũng như phép giãn ảnh, chú ý rằng bạn có thể tăng độ co hơn bằng cách tăng kích thước của cửa sổ lọc hoặc lặp quy trình lại nhiều lần.
  1. Mở/Opening.  Để “mở” các “khe trống” có thể xuất hiện tại các patch/mảng rời rạc, thực hiện phép co ảnh trước, sau đó là giãn ảnh. Quy trình này được gọi là  Mở/opening.  Thử bằng cách thực hiện phép giãn ảnh từ một ảnh đã qua phép co ảnh:

// Perform an opening by dilating the eroded image.

var opened = min.reduceNeighborhood({

 reducer: ee.Reducer.max(),

 kernel: uniformKernel

});

Map.addLayer(opened, binaryVis, ‘opened’);

  1. Đóng/Closing.  Trái ngược với opening là Đóng/cosing, hoặc phép giãn ảnh được thực hiện trước, sau đó là phép giãn ảnh.  Dùng để  “đóng” các “khe trống” có thể xuất hiện trong các patch/mảng rời rạc trong ảnh đầu vào:

// Perform a closing by eroding the dilated image.

var closed = max.reduceNeighborhood({

 reducer: ee.Reducer.min(),

 kernel: uniformKernel

});

Map.addLayer(closed, binaryVis, ‘closed’);

  1. Kiểm tra kỹ sự khác biện giữa mỗi phép xử lý hình thái học và đầu vào veg.  Điều chỉnh các toán tử hình thái học/toán tử morphological này bằng cách thay đổi kích thước và hình dạng của cửa sổ lọc (trong trường hợp này còn được gọi là phần tử cấu truc, do tác động của nó đến hình thái đối tượng trong kết quả đầu ra), hoặc lặp đi lặp lại các quy trình.
  2. Cấu trúc ảnh/Texture

Kết cấu được định nghĩa như phép đo sự phân tán của DN trong khu vực lân cận. Có nhiều cách để   tính toán kết cẩu trong Earth Engine.

  1. Độ Lệch Chuẩn/Standard Deviation (SD).  Độ lệch chuẩn đo độ phân tán của DN trong vùng lân cận. Một vùng lân cận không có kết cấu là vùng chỉ có một giá trị DN, SD=0. Tính độ lệnh chủa trong vùng lân cận cho ảnh NAIP với:

// Define a big neighborhood with a 7-meter radius kernel.

var bigKernel = ee.Kernel.square({

 radius: 7,

 units: ‘meters’

});

// Compute SD in a neighborhood.

var sd = image.reduceNeighborhood({

 reducer: ee.Reducer.stdDev(),

 kernel: bigKernel

});

Map.addLayer(sd, {min: 0, max: 70}, ‘SD’);

  1. Entropy.  Cho những ảnh đầu vào rời rạc, bạn có thể tính entropy cho vùng lân cận, trong đó entropy được xem như một chỉ số thể hiện tính đa dạng của DN diversity trong vùng lân cận:

// Compute entropy in a neighborhood.

var entropy = image.entropy(bigKernel);

Map.addLayer(entropy, {min: 1, max: 5}, ‘entropy’);

  1. (Không bắt buộc)  Ma trận đồng nhất mức xám độ /Gray-level co-occurrence matrices (GLCM).  GLCM được tính bằng cách tạo một ma trận cỡ MxM cho một ảnh với M các giá trị có thể của DN, sau đó thực hiện nhập i,j bằng tần suất mà DN=i liền kề với DN=j.  Có rất nhiều thông số về kết cấu ảnh có thể thu được từ ma trận đó, trong đó có độ tương phản:

// Use the GLCM to compute a large number of texture measures.

var glcmTexture = image.glcmTexture(7);

// Display the ‘contrast’ results for the red, green and blue bands.

var contrastVis = {

 bands: [‘R_contrast’, ‘G_contrast’, ‘B_contrast’],

 min: 40,

 max: 2000

};

Map.addLayer(glcmTexture, contrastVis, ‘contrast’);

  1. (Không bắt buộc)  Thống kê không gian/Spatial statistics.  Hai phương pháp kết cấu sử dụng thống kê không gian bao gồm Local Moran’s I và Local Geary’s C (Anselin 1995).  Tính local Geary’s C với ảnh NAIP đầu vào, sử dụng:

// Create a list of weights for a 9×9 kernel.

var list = [1, 1, 1, 1, 1, 1, 1, 1, 1];

// The center of the kernel is zero.

var centerList = [1, 1, 1, 1, 0, 1, 1, 1, 1];

// Assemble a list of lists: the 9×9 kernel weights as a 2-D matrix.

var lists = [list, list, list, list, centerList, list, list, list, list];

// Create the kernel from the weights.

// Non-zero weights represent the spatial neighborhood.

var kernel = ee.Kernel.fixed(9, 9, lists, -4, -4, false);

// Use the max among bands as the input.

var maxBands = image.reduce(ee.Reducer.max());

// Convert the neighborhood into multiple bands.

var neighs = maxBands.neighborhoodToBands(kernel);

// Compute local Geary’s C, a measure of spatial association.

var gearys = maxBands.subtract(neighs).pow(2).reduce(ee.Reducer.sum())

            .divide(Math.pow(9, 2));

Map.addLayer(gearys, {min: 20, max: 2500}, “Geary’s C”);

  1. Thay Đổi Độ Phân Giải và Nắn Ảnh

Earth Engine đã nỗ lực để có thể thực hiện toàn bộ các chức năng liên quan đến lưới chiếu và tỷ lệ do vậy mà bạn không cần phải thực hiện chúng. Tuy nhiên, trong nhiều trường hợp mà việc hiểu về lưới chiếu là rất quan trọng để có được kết quả bạn muốn. Đây là lúc để làm tìm hiểu về hàm reproject() trong các ví dụ trước.  Earth Engine yêu cầu thông tin đầu vào cho việc thực hiện lưới chiếu và tỷ lệ trong kết quả đầu ra.  Bản đồ được sử dụng trong phần thực hành có lưới chiếu Mercator .  Tỷ lệ/Scale được xác định từ độ phóng của cửa sổ bản đồ.  Khi bạn thêm dữ liệu vào cửa sổ bản đồ, Earth Engine sẽ nắn lại các dữ liệu đầu vào này theo lưới chiếu Mercator, thay đổi độ phân giải (sử dụng nearest neighbor) để điều chỉnh độ phân giải pixel phù hợp với mức độ phóng to thu nhỏ của cửa sổ bản đồ, sau đó thực hiện các thao tác với ảnh đã được nắn chỉnh và thay đổi độ phân giải. Trong những ví dụ trước, khi chúng ta gọi reproject() nghĩa là đã ra lệnh cho thao tác trên được thực hiện các tính toán tại độ phân giải của ảnh đầu vào là: 1 meter.

  1. Chạy lại code edge detection/dò biên ảnh cùng với nắn ảnh và không cùng với nắn ảnh (Tạo chú giải/comment lên toàn bộ phần gọi  Map.addLayer() trừ phần nguyên gốc ban đầu):

// Zoom all the way in.

Map.centerObject(point, 21);

// Display edges computed on a reprojected image.

Map.addLayer(image.convolve(laplacianKernel), {min: 0, max: 255},

   ‘Edges with little screen pixels’);

// Display edges computed on the image at native resolution.

Map.addLayer(edges, {min: 0, max: 255},

   ‘Edges with 1 meter pixels’);

  1. Điều xảy ra ở đây đó là phép chiếu được xác định trong reproject() được đẩy lùi lại gần với đầu vào, bắt tất cả các quá trình tính toán thực hiện trên phép chiếu đó.  Nếu bạn không định rõ, các tính toán sẽ được thực hiện theo lưới chiếu và tỷ lệ của bản đồ (Mercator) theo độ phân giải màn hình.
  1. Bạn có thể điều khiển thay đổi độ phân giải của Earth Engine tại đầu vào với resample().  Theo mặc định, tất cả thay đổi độ phân giải được thực hiện với nearest neighbor.  Để thay đổi, gọi resample() cho đầu vào.  So sánh ảnh đầu vào, được thay đổi theo độ phân giải màn hình và với phương pháp resampling  bilinear và bicubic:

// Resample the image with bilinear instead of nearest neighbor.

var bilinearResampled = image.resample(‘bilinear’);

Map.addLayer(bilinearResampled, {}, ‘input image, bilinear resampling’);

// Resample the image with bicubic instead of nearest neighbor.

var bicubicResampled = image.resample(‘bicubic’);

Map.addLayer(bicubicResampled, {}, ‘input image, bicubic resampling’);

  1. Thử phóng to thu nhỏ, so sánh với ảnh đầu vào được resample với nearest neighbor (ví dụ không goi resample() cho đầu vào).
  1. Bạn ít khi phải dùng  reproject()  resample().  Không nên dùng reproject() hoặc resample() nếu không cần thiết.  Chúng được đưa ra trong bài học này chỉ với mục đích giới thiệu.
]]>
Categories
Google Earth Engine Tài liệu Viễn thám

[GEE 4] Bài Tập 4: Xuất Dữ Liệu


Bài Tập 4: Xuất Dữ Liệu

Mục Lục

Phần 1: Tải ảnh bạn muốn xuất thông tin        2

Phần 2: (không bắt buộc) Tạo biểu đồ/histogram        2

Phần 3: Xuất Dữ Liệu        2

Phần 4: Truy Xuất Video        6

Phần 5: (không bắt buộc) Các Đối Tượng và Hàm khác        7

Phần 1: Tải ảnh bạn muốn xuất thông tin

Trong bài tập về xuất dữ liệu này, chúng ta sẽ sử dụng tập dữ liệu: Độ Cao Tán Cây (Canopy Height) 2005 trích xuất từ dữ liệu lidar đo trên máy bay/airborn lidar – Geoscience Laser Altimeter System (GLAS) và dữ liệu không gian địa lý.

  1. Copy và paste những dòng lệnh sau vào cửa sổ code editor. Click Run để tìm hiểu tập dữ liệu.

var CanopyHeight = ee.Image(“NASA/JPL/global_forest_canopy_height_2005”);

Map.addLayer(CanopyHeight, 

  {min: 0, max: 36, palette: [‘FFFFFF’, ’00FF00′]},

  ‘canopy height’);

Map.setCenter(100.096435546875, 13.966054081318301, 8);

  1. Tiếp theo, sử dụng công cụ draw để vẽ một vùng/polygon nhỏ đại diện cho vùng mà bạn muốn trích xuất thông tin về độ cao tán cây. Tham khảo bài tập 3, Phần 2 nếu bạn cần ôn lại cách số hóa một đối tượng hình học/geometry. Hãy nhớ rằng: vùng càng nhỏ thì thời gian tải càng nhanh.

Phần 2: (không bắt buộc) Tạo biểu đồ/histogram

  1. Script/tập lệnh dưới đây giúp tạo một biểu đồ độ cao tán cây cho toàn bộ khu vực nghiên cứu mà bạn vừa số hóa. Copy và paste tập lệnh này vào cửa sổ code editor để biết được/investigate khoảng độ cao của tán cây trong khu vực nghiên cứu của mình.

// Generate the histogram data.  

var CanopyHeightHistogram = Chart.image.histogram(CanopyHeight, geometry);

CanopyHeightHistogram = CanopyHeightHistogram.setOptions({

  title: ‘Histogram of Canopy Height’

});

print(CanopyHeightHistogram);

Phần 3: Xuất Dữ Liệu

Xuất dữ liệu được thực hiện với Code Editor thông qua các hàm export/xuất, những hàm này gồm nhiều lựa chọn để xuất các dữ liệu dạng ảnh/image, bảng/table, và video. Bạn sẽ tập trung vào hàm  Export.image.toDrive() để tải tập dữ liệu ảnh. Bạn cũng có thể xuất tập ảnh của mình về máy tính cá nhân hoặc lưu tại Google Cloud.

Các hàm export gồm các đối số/argument tùy chọn giúp bạn có thể kiểm soát một số đặc tính quan trọng trong kết quả xuất dữ liệu cuối cùng của mình, ví dụ như độ phân giải/resolution và lưới chiếu/projection.

  1. Xem Chỉ Dẫn Về Hàm Export.image.toDrive()
  2. Dưới tab Docstìm đến  mở chỉ dẫn của hàm Export.image.toDrive(), nằm trong nhóm Export. Đọc kỹ những chỉ dẫn này.
  3. Tạo một tác vụ xuất dữ liệu/export task
  4. Thêm những dòng lệnh sau đây xuống dưới cùng phần script/tập lệnh bạn đang làm việc. Những dòng lệnh này sẽ tạo ra một tác vụ/task trong tab task mà bạn có thể sử dụng để xuất ảnh mình muốn. Xuất các ảnh và lưu tại Google Drive của bạn. Tham khảo hộp ghi chú phía dưới đây để hiểu thêm về các tham số cần được xác định.

//Export the image

Export.image(CanopyHeight, “MyFirstExport”,

      {maxPixels: 1e13,

        region: geometry,

        crs:  ‘EPSG:32647’,

        scale: 1000});

Ghi chú – Trong ví dụ này, bạn đã xác định một vài đối số tùy chọn được nhận diện bởi Export.image(). Mặc dù hàm này bao gồm các tham số tùy chọn (không bắt buộc), nhưng làm quen với những tham số này rất hữu ích cho bạn:

 maxPixels – Tham số này giới hạn số lượng pixels trong ảnh được truy xuất. Theo mặc định/default, giá trị này là 100,000,000 pixel. Bạn có thể gán cho thông số này một giá trị lớn hơn hoặc nhỏ hơn giới hạn mặc định/defaul. “1e13” hay 10 mũ 13 (1013) và là số lượng pixel lớn nhât mà bạn có thể xuất trong GEE.

region – Theo mặc định, dữ liệu được xuất có phạm vi bằng độ rộng cửa sổ view của Code Editor tuy nhiên bạn cũng có thể dùng một đối tượng hình học để thay đổi phạm vi xuất kết quả.

crs – Là hệ tọa độ của ảnh kết quả. Tham số này được xác định bằng code EPSG. Bạn có thể tra cứu các code EPSG code cho hệ tọa độ mà bạn muốn sử dụng tại http://spatialreference.org.

scale – Là độ phân giải tính theo mét (m) của mỗi pixel. Độ phân giải của dữ liệu độ cao tán cây là 30 arc-seconds/giây góc hoặc tương đương với 1 kilomet (km)

  1. Xuất ảnh vào Google Drive với export task

Ghi chú về Google Drive: Google Drive là nơi lưu trữ tạm thời cho bất kỳ dữ liệu nào mà bạn tải về. Để chia sẻ với những người khác, bạn nên sử dụng các giải pháp liên kết/corporate solutions, như email hoặc CloudVault

  1. Chạy/Run tập lệnh mà chúng ta vừa copy vào GEE. Sau đó, tab Tasks phía trên bên phải của Code Editor sẽ được được tô đậm.
Highlighted tasks tab
  1. Click vào tab Tasks. Sau đó click vào nút Run màu xanh biển (như hình dưới) để dữ liệu được xuất tại Google Drive của bạn.
Run your first export.
  1. Đọc kỹ thông tin tại cửa sổ Initiate export vừa xuất hiện (dưới đây). Sau đó click Run để bắt đầu.

Ghi chú: Chức năng/Task này sẽ được xuất kết quả đến Google Drive trong Google Account của bạn. Đó là ảnh GeoTiff có độ phân giải 1000 mét với tên là  MyFirstExport.

  1. Sau khi click Run ở phía dưới cùng cửa sổ Initiate export để bắt đầu xuất dữ liệu, màn hình của bạn sẽ báo hiệu quá trình xuất dữ liệu đang được thực hiện. Task/tác vụ phía dưới tab Task của Code Editor có biểu tượng GEE quay tròn ngay bên cạnh. Sẽ mất một khoảng thời gian nhất định để task này được thực hiện. Khi quy trình hoàn thành, biểu tượng quay tròn sẽ biến mất và tên của task sẽ chuyển thành màu xanh lục. Kiểm tra xem task trên màn hình của bạn đã chuyển sang xanh.
task bar before and after exporting data

Ghi chú: Nếu bạn thử xuất cảnh ảnh Landsat mà không giới hạn/sub-set ảnh trước để có các band/phổ ảnh mà mình muốn, bạn sẽ nhận được thông báo lỗi.

mismatched data type error message

Đó là bởi vì các band/kênh phổ của ảnh Lansdat không đều được lưu dưới cùng một dạng dữ liệu. Phần lớn các band/kênh phổ ở dạng 32 bit float (float 32), nhưng BQA lại ở dạng unsigned 16 bit integer (UInt16). Bạn có thể tra cứu dạng dữ liệu của mỗi band/kênh phổ bằng hàm print (như hình dưới đây). Bạn có thể truy xuất 10 band/kênh phổ ảnh đầu tiên trước hoặc chuyển band không cùng định dạng, BQA, về cùng dạng dữ liệu với các band khác (UInt16 thành float32).

screenshot of inspector output
  1. Đọc kết quả
  2. Khi quá trình xuất/export hoàn thành, mở Google Drive của bạn sử dụng link dưới đây:
https://drive.google.com/drive/my-drive
  1. Locate/Lưu những ảnh mới, có thể gọi tên tương tự như MyFirstExport-0000000000-0000000000.tif, tại Google Drive của bạn.
  2. Không bắt buộc – Tải một trong những ảnh và xem ảnh bằng phần mềm GIS mà bạn muốn (ví dụ, ArcMap hoặc QGIS).

Ghi chú – Một khi cả hai tổ hợp ảnh Landsat của bạn được lưu xuất thành công vào Google Drive, bạn có thể tải và xem lại chúng bằng các phần mềm GIS mà bạn muốn. Thời gian lưu xuất có thể thay đổi tùy thuộc vào độ lớn dữ liệu của bạn cũng như thời gian trong ngày và những gì mà những người dùng khác đang thực hiện trên Google Earth Engine.

Ghi Chú Về Quản Lý Dữ Liệu Trong Google Drive – Sau khi bạn đã tải dữ liệu từ Google Drive, bạn có thể nghĩ tới việc xóa chúng khỏi Google Drive để tiết kiệm bộ nhớ (phụ thuộc vào sức chứa của tài khoản của bạn).

Removing files from Google Drive

Sau khi bạn chuyển dữ liệu đến thùng rác của Google Drive, bạn hãy vào thùng rác và làm trống để bộ nhớ được xóa hoàn toàn.

Emptying Google Drive Trash
  1. Lưu sript/tập lệnh đã hoàn thành vào tài khoản GEE của bạn
  1. Click vào nút Save trong cửa sổ Code editor.
  2. Nhập một tên mới hoặc giữ nguyên tên mặc định và click nút okay.

Ghi chú – Ví dụ trên tập trung vào một task/tác vụ mà sẽ được lưu xuất vào Google Drive trong tài khoản Google của bạn. Mỗi lần tải sẽ có một ảnh GeoTiff có độ phân giải 30 mét. Với Palawan, mỗi vùng tổ hợp được truy xuất có độ lớn khoảng 370 MB. Đảm bảo rằng bạn có khoảng trống trong Google Drive! Nếu cần có thể xóa và làm trống thùng rác để có thêm bộ nới

Phần 4: Xuất Video

  1. Tập chỉnh sửa một script/tập lệnh
  1. Đọc kỹ dòng code dưới đây và chạy để xem dòng code này thực hiện gì. Sử dụng những gì bạn đã học cho tới bây giờ.
  2. Chỉnh sửa nó để lưu xuất một video của những ảnh Landsat cho khu vực nghiên cứu của bạn tại vùng Mekong

// Video demo

var geometry = /* color: d63000 */ee.Geometry.Polygon(

        [[[-112.07496643066406, 40.91892834534881],

          [-111.83326721191406, 40.918409488474005],

          [-111.83326721191406, 41.06767190734072],

          [-112.07290649414062, 41.06818959082366]]]);

// load Landsat 5 imagery

var collection = ee.ImageCollection(‘LT5_L1T_TOA’)

  // Wasatch Front

  .filterMetadata(‘WRS_PATH’, ‘equals’, 38)

  .filterMetadata(‘WRS_ROW’, ‘equals’, 32)

  // filter cloudy scenes

  .filterMetadata(‘CLOUD_COVER’, ‘less_than’, 10)

  // 20 years

  .filterDate(‘1984-01-01’,‘2012-12-30’)

  // need to have 3-band imagery

  .select([‘B7’, ‘B4’, ‘B3’])

  // need to make it 8-bit

  .map(function(image) {

    return image.multiply(512).uint8();

  });

Map.centerObject(geometry, 10);

Map.addLayer(ee.Image(collection.first()));

// Export (change dimensions or scale for higher quality)

Export.video(collection, ‘example_video’, {

  dimensions: ‘720’,

  framesPerSecond: 12,

  region: JSON.stringify(geometry.getInfo())});

Phần 5: (không bắt buộc) Các Đối Tượng và Hàm khác

  1. Những đối tượng Phía máy khách/Client side (đối tượng trong JavaScrips) và phía máy chủ/server side (đối tượng trong Earth Engine)

Những cấu trúc dữ liệu cơ bản khác của Earth Engine bao gồm ee.Dictionary, ee.List, ee.Array, ee.Date, ee.Number và ee.String. Rất nhiều trong số chúng có một bản sao tương tự trong JavaScript. Tuy nhiên, nếu bạn tạo một đối tượng JavaScript thay cho một đối tượng Earth Engine, bất kỳ một thao tác nào với đối tượng này đều sẽ được thực hiện tại máy khách/client side, trình duyệt web của bạn, sử dụng CPU máy tính của bạn. Tốt hơn là (trong phần lớn các trường hợp) sử dụng các đối tượng Earth Engine như vậy chúng sẽ được thực hiện trên máy chủ/server side (ví dụ, trên CPU của Google cloud). Các đối tượng Earth Engine (ví dụ ee.List) cũng tương tác một cách hiệu quả hơn với các đối tượng Earth Engine khác (ví dụ ee.ImageCollection). Trình duyệt của bạn, ví dụ, Chrome, không hiểu gì về các đối tượng Earth Engine trong script của bạn nếu bạn không yêu cầu thông tin cụ thể về chúng. Hàm print() hoặc Map.addLayer() yêu cầu khởi động (các mạch khởi động của máy tính) chuyển thông tin từ  máy chủ của Google đến Code Editor rồi trình duyệt web của bạn.

  1. Đối tượng ee.Number và một số hàm hữu ích

ee.Number là một đối tượng số học trong Earth Engine, đi kèm với một tập hợp các hàm liên quan, ví dụ hàm tính toán/arithmetic. Bạn sẽ tìm hiểu một phần của các hàm này, chúng rất hữu ích cho bạn trong tương lai khi làm việc với Earth Engine.

  1. Xóa script/tập lệnh của bạn. 
clear script.
  1. Tạo một đối tượng số học trong Earth Engine. Copy và paste những dòng lệnh dưới đây vào trình duyệt của bạn. Chạy những dòng lệnh này và kiểm tra kết quả.

var myNum = ee.Number(10.4) ;

print(myNum);

  1. Bạn có thể làm tròn giá trị số học thành một số nguyên dương/whole number, một số nguyên/integer, bằng cách gõ .round ngay sau tên của biến chứa số này. Thêm dòng code dưới đây và chạy nó. Kiểm tra kết quả.

var round_myNum = myNum.round();

print(round_myNum);

  1. Tham khảo bảng dưới đây để tìm hiểu một số hàm được dựng sẵn mà bạn có thể dùng cho đối tượng ee.Number. Tham khảo cột Cú Pháp Ví Dụ nếu cần thiết. Chú ý: Các biến, a và b, là một biến có giá trị số học trong Earth Engine.
Hàm        Chức Năng        Cú Pháp Mẫu
a.max(b);Tìm giá trị lớn nhất của hai số, a và b.var a= ee.Number(5.01);var  b= ee.Number(9); print(a.max(b));//prints: 9
a.min(b);Tìm giá trị nhỏ nhất của hai số, a và b.var a= ee.Number(5.01);var  b= ee.Number(9); print(a.min(b));//prints: 5.01
a.int();Đưa giá trị số đầu vào về dạng số nguyên, a signed 32-bit integer.var  a= ee.Number(5.01); print(a.int());//prints: 5
a.sqrt();Tính căn bậc hai của một số (trong trường hợp này là a).var  a= ee.Number(9); print(a.sqrt());//prints: 3
a.log();Tính logarit tự nhiên của một số (trong trường hợp này là a).var  a= ee.Number(5.01); print(a.log());//prints: 1.611…
  1. Đối tượng ee.String và một số hàm hữu ích

Chuỗi là một tập hợp các kí tự, và một ví dụ của string là từ “blue band”. Bạn sẽ tìm hiểu một phần các hàm thường được sử dụng và thuộc tính string trong Earth Engine.

  1. Xóa script của bạn. 
clear script.
  1. Tạo một đối tượng string Earth Engine. Copy và paste tập lệnh dưới đây vào trình duyệt của bạn. Chạy/Execute các dòng lệnh này và kiểm tra kết quả.

var StringVar = ee.String(“NDVI is a vegetation index”);
print(StringVar); 

  1. Bạn có thể tìm độ dài của string bằng cách gõ .length() ngay sau tên của biến string. Đưa vào và chạy dòng code dưới đây. Kiểm tra kết quả.

print(StringVar.length()); 

// returns how many characters the string contains

  1. Tham khảo bảng dưới đây để tìm hiểu một số hàm được dựng sẵn mà bạn có thể sử dụng với đối tượng ee.String. Tham khảo cột Cú Pháp ví dụ nếu cần thiết. Chú ý: biến, StringVar, là một biến chứa chuỗi ký tự/string trong Earth Engine.
Phương PhápChức năngCú Pháp Ví Dụ
StringVar.toUpperCase();Chuyển chuỗi ký tự/string thành chữ in hoa.var StringVar = ee.String(‘NDVI is a vegetation index’); print(StringVar.toUpperCase());// prints: NDVI IS A VEGETATION INDEX
StringVar.toLowerCase();Chuyển chuỗi ký tự/string thành chữ in thường.var StringVar = ee.String(‘NDVI is a vegetation index’); print(StringVar.toLowerCase());// prints: ndvi is a vegetation index
StringVar.split();Phân tách chuỗi ký tự/string dựa vào dấu cách (hoặc với bất kỳ tham số đầu vào nào).var StringVar = ee.String(‘NDVI is a vegetation index’); print(StringVar.split(‘ ‘)); // prints: [“NDVI”,”is”,”a”,”vegetation”,”index”]
StringVar.index();Tìm vị trí của ký tự đầu tiên trong chuỗi ký tự bạn quan tâm. Giá trị -1 sẽ xuất hiện nếu chuỗi ký tự bạn muốn tìm không   nằm trong câu/cụm từ. Nhớ rằng, hàm sẽ đếm bắt đầu từ 0, không phải 1. Chú ý Index được dùng để phân biệt vị trí các chuỗi ký tự.var StringVar = ee.String(‘NDVI is a vegetation index’); print(StringVar.index(‘vegetation’)); // prints: 10
StringVar.slice();Chia chuỗi ký tự tại vị trí nhất định.var StringVar = ee.String(‘NDVI is a vegetation index’); print(StringVar.slice(10,20));//  prints: vegetation
  1. Đối tượng ee.Date và một số hàm hữu ích

Cũng giống như chuỗi ký tự/strings and số học/numbers, JavaScript cũng có các đối tượng ngày/date, Date(); tuy nhiên GEE lại có đối tượng date/ngày riêng, ee.Date(), nó được thiết kế cho môi trường làm việc của GEE. Tốt hơn là sử dụng đối tượng ee.Date() khi tương tác với ảnh và tập ảnh. GEE cũng có các đối tượng liên quan, ee.DateRange(), giúp làm việc với các tập hợp. Các đối tượng date/ngày của GEE thể hiện một thời điểm nhất định về thời gian và lưu trữ như một giá trị thời gian, độ chính xác tới một phần nghìn giây bắt đầu từ 1 tháng 1, 1970 UTC.

Tại sao là 1 tháng 1, 1970? Đó là ‘thời gian tham chiếu’. Trong JavaScript, đối tượng ngày/Date được lưu trữ chính xác đến một phần nghin giây từ ngày này. Đó là một cách chung để biểu diễn ngày trong giới lập trình.

  1.  Xóa script của bạn. 
clear script.
  1. Đưa vào/Insert và chạy/execute dòng code dưới đây để thiết lập hai biến, startYear và startJulian (ngày của năm).

var startYear = 2015;

print (startYear);

var startJulian= 31;

print(startJulian);

  1. Bây giờ thêm dòng code dưới đây và chạy/execute. Dòng đầu tiên tạo ra ngày 1 Tháng 1, 2015, năm 2015 được khai báo cho biến startYear, tiếp theo, từ ngày đó tiến thêm 31 ngày bạn sẽ có startJulian day là 1 tháng 2, 2015. Xem kết quả từ câu lệnh print trong console. startDate được in dưới dạng yy-mm-dd hh:mm:ss (năm-tháng-ngày giờ-phút-giây). Nếu bạn mở rộng “Date” trong cửa sổ console bạn sẽ thấy giá trị của nó trong tham chiếu thời gian (1422748800000) mặc dù console hiển thị chúng dưới định dạng chúng ta có thể đọc được.

var startDate = ee.Date.fromYMD(ee.Number(startYear),1,1)

                       .advance(startJulian,‘day’);

print(startDate);

  1. Bây giờ thêm và chạy code dưới đây. Dòng đầu tiên thiết lập một biến collection (tập hợp) mới. Dòng thứ 2 tạo một danh sách (list) từ khoảng ngày (date range) của tập hợp (collection’s date range). Dòng thứ 3 chuyển khoảng ngày (date range) thành một đối tượng ee.DateRange. Xem kết quả trong cửa sổ console sau khi lệnh print được thực hiện.

var collection = ee.ImageCollection(‘COPERNICUS/S1_GRD’);

var dates = ee.List(collection.get(‘date_range’));

var dateRange = ee.DateRange(dates.get(0), dates.get(1));

print(‘Date range: ‘, dateRange);

  1. Các đối tượng ee.List và một số hàm hữu ích

Một danh sách theo thứ tự của các giá trị, chúng có thể là các đối tượng số học/numeric hoặc chuỗi/string. Đối tượng danh sách/list của Earth Engine có các thuộc tính và hàm riêng. Bạn sẽ tìm hiểu một phần của những hàm này, chúng sẽ rất hữu dụng khi bạn làm việc với ảnh trong Earth Engine.

  1. Trước tiên Xóa script của bạn. 
clear script.
  1. Tạo một ee.List, và bạn có thể tìm hiểu một số hàm ee.List. Thêm/Insert vày chạy/ execute dòng code dưới đây. Kiểm tra kết quả.

var myList = ee.List([10, 20, 50, 40, 130]);

print(myList);

  1. Bạn có thể tìm được độ dài của danh sách/list bằng cách gõ .length() ngay sau tên của list. Thêm và chạy/execute dòng code dưới đây. Kiểm tra kết quả đã được in.

print(myList.length());

  1. Tham khảo bảng dưới đây để tìm hiểu một số hàm dựng sẵn mà bạn có thể sử dụng cho đối tượng ee.List. Tham khảo cột Cú Pháp Mẫu nếu cần thiết. Chú ý: biến, myList, đại diện cho các biến chứa danh sách/list trong Earth Engine.
HàmChức năngCú Pháp Mẫu
myList.reverse()Đảo thứ tự danh sách/listvar myList= ee.List([9, 12, 5]);print(myList.reverse());//prints: [5, 12, 9]
myList.length()Đặt độ dài cho danh sách/listvar myList= ee.List([9, 12, 5]);print(myList.length());//prints: 3
myList.sort()Sắp xếp list/danh sách theo thứ tựvar myList= ee.List([9, 12, 5]);print(myList.sort());//prints: [5, 9, 12]
  1. ee.Dictionaries

Nhiều giá trị tham số tùy chọn sử dụng trong các hàm làm việc với ảnh mà bạn đã được học được lưu trữ tại đối tượng dictionary của Earth Engine, ví dụ như các thông số hiển thị cho Map.addLayer(). Metadata/Siêu dữ liệu cũng được lưu trong một Earth Engine dictionary. Cú pháp được sử dụng để tạo ra một dictionary là: một khóa, theo sau là giá trị, ngăn cách bởi dấu hai chấm, và đóng bằng dấu ngoặc cong }.

  1. Xóa script của bạn. 
clear script.
  1. Tạo một ee.DictionaryThêm và chạy dòng code dưới đây. Tìm hiểu đầu ra với ba lệnh in khác nhau:
  1. In đối tượng sampleDict,
  2. In với get.Info(), và
  3. In sau khi chuyển chúng thành một chuỗi/string).

var optionalparams = {

vis_param1: [1, 2, 3],

vis_param2: [‘B1’, ‘B4’, ‘B2’]};

var sampleDict = ee.Dictionary(optionalparams);

print(sampleDict);

print(sampleDict.getInfo());

print(sampleDict.toString());

  1. Bạn có thể tra cứu những khóa/key bạn dã sử dụng hàm .keys()Thêm code dưới đây, ngay phía dưới dòng lệnh dictionary. Click Run và kiểm tra kết quả.

print(sampleDict.keys());

  1. Bạn cũng có thể loại ra các giá trị của một khóa/key, dựa vào một chỉ số/index. Thêm dòng code dưới đây vào phần cuối cùng của script/tập lệnh của bạn và chạy. Sau đó kiểm tra kết quả.

print(sampleDict.keys().get(0));

  1. Bạn cũng có thể tra cứu các giá trị trong các khóa/key. Thêm dòng code dưới đây vào phần cuối cùng trong script của bạn và chạy. Sau đó kiểm tra kết quả.

print(sampleDict.values());

  1. Cuối cùng, gọi các giá trị cho một khóa/key sử dụng hàm .get(). Thêm/Add code dưới đây vào phía cuối script của bạn và chạy. Sau đó kiểm tra kết quả. Chú ý, bạn có thấy sự khác biệt giữa .get() và .getInfo() từ bước 1 của phần này?

print(sampleDict.get(‘vis_param1’));

Bài Tập 4: Xuất Dữ Liệu  
]]>
Categories
Công nghệ Google Earth Engine Tài liệu Viễn thám

[GEE 3] Bài tập 3: Viết các Hàm Theo Nhu Cầu Sử dụng và Làm Việc Với Tập Ảnh

Bài tập 3: Viết các Hàm Theo Nhu Cầu Sử dụng và Làm Việc Với Tập Ảnh

image collection

Giới Thiệu

Code Editor cho phép người dùng thực hiện  được tất cả các chức năng của Earth Engine, tuy nhiên, cần có hiểu biết cơ bản về lập trình và JavaScript. Trong bài tập này, chúng ta sẽ tiếp tục học về ngôn ngữ lập trình Java và các khái niệm mới về dữ liệu không gian trong Earth Engine. Bạn sẽ tiếp tục những gì được học ở bài tập 2 về đối tượng ảnh; tuy nhiên trong bài học này bạn sẽ tập trung nhiều hơn vào các tập hợp hoặc chồng lớp của các đối tượng ảnh có tính chất tương tự. Trong bài học này, bạn sẽ tập trung vào các khái niệm cơ bản và phương pháp liên quan đến các tập hợp ảnh trong Earth Engine. Đây là hướng dẫn giúp người sử dụng có thể viết được các sript đơn giản trong JavaScript.

Mục Tiêu

  • Tập viết và chạy code trong Earth Engine Code Editor để truy nhập vào tập hợp dữ liệu ảnh, lọc theo thời gian (theo ngày) và không gian (ví dụ như khu vực nghiên cứu của bạn), thao tác với các đối tượng hình học, và tìm hiểu một số phương pháp xử lý ảnh

Yêu cầu tài liệu

  • Một tài khoản Google Earth Engine
  • Gợi ý: Cài đặt Google Chrome vào máy tính của bạn

Mục Lục

Phần 1: Làm việc với tập ảnh        3

Phần 2: Lọc Tập Ảnh Theo Không Gian        4

Phần 3: Lọc Tập Ảnh Theo Thời Gian        7

Phần 4: Tìm hiểu các hàm xử lý ảnh        8

Phần 5: Giới Thiệu về Reducers        8

Phần 6: Nhập Môn Về Hàm        9

Phần 7: Tạo hàm lọc bỏ mây (cloud mask)        13

Phần 8: Các Hàm Thao Tác Với Tập Hợp Ảnh        15

Phần 1: Làm việc với tập hợp ảnh

Một tập hợp ảnh là một nhóm các ảnh cùng loại trong Earth Engine. Ví dụ như, tất cả ảnh Landsat 8 trong GEE là một tập hợp ảnh

Trong Code Editor, bạn có thể làm việc với toàn bộ tập hợp ảnh ở một dạng nhất định, hoặc bạn có thể sử dụng các bộ lọc để tạo ra một tập ảnh cụ thể (ví dụ như để thể hiện khu vực nhiên cứu của bạn hoặc cho một khoảng thời gian cụ thể). Đọc thêm tại https://developers.google.com/earth-engine/ic_info

  1. Mở một Script mới
  2. Mở trang web Code Editor trong Google Chrome
https://code.earthengine.google.com/
  1. Click vào biểu tượng đầu mũi tên cạnh nút Reset và chọn Clear script.
clear script button.
  1. Tạo một tập hợp đối tượng ảnh Landsat
  2. Tạo một tập hợp các ảnh Landsat 8 có sẵn bằng cách gõ hoặc copy/paste dòng code sau vào code editor

// Get a collection.

var L8_collection = ee.ImageCollection(‘LANDSAT/LC8_L1T_TOA’);

  1. Tiếp theo chúng ta sẽ hiển thih nó trên cửa sổ bản đồ, copy code dưới đây và paste vào code editor. Sau đó click Run để thực hiện toàn bộ các dòng lệnh.

Map.addLayer(L8_collection, { min:0.05, max: 0.8, bands: ‘B6, B5, B4’ }, ‘Landsat Collection’);

Map.setCenter(100.56, 13.94, 7);

  1. Bạn thấy gì trên cửa sổ bản đồ? Tập ảnh gồm nhiều ảnh, nhưng không phải tất cả đều được hiện lên. Khi chúng ta sử dụng hàm Map.addLayer để đưa một tập ảnh vào cửa sổ bản đồ, theo mặc định/default chỉ các pixel mới nhất sẽ được hiển thị
  2.  (Không bắt buộc) Nếu bạn thêm vào dòng lệnh print/in, bạn có thể xác định có bao nhiêu ảnh ở trong tập hợp. Copy và paste dòng sau vào dưới phần script của mình

print(L8_collection);

  1. Tuy nhiên, vì tập ảnh của chúng ta tương đối lớn, chúng ta nhận được báo lỗi trên Console “Collection query aborted after accumulating the metadata for over 5,000 elements”. Có nghĩa là yêu cầu in tập ảnh không thực hiện được khi gom toàn bộ siêu dữ liệu của hơn 5,000 đối tượng ảnh. Chúng ta sẽ lọc tập ảnh theo không gian hoặc thời gan và tìm cách khác để có số lượng ảnh phù hợp trong tập ảnh cần cho việc sử dụng.
Console Display, query abort message
  1. Comment out (//) lên trước lệnh print/inChúng ta sẽ trở lại sau

// print(L8_collection);

Phần 2: Lọc Tập Ảnh Theo ranh giới Không Gian

  1. Vẽ một đối tượng hình học tạo ranh giới không gian để lọc tập ảnh

Đối tượng hình học (Geometry) là một dạng đối tượng không gian địa lý khác trong Earth Engine. Để tải các shapefile hoặc các file vector khác, bạn cần sử dụng Fusion Tables, sẽ được học trong bài tập 4. Bạn có thể vẽ nhanh một đường/line hoặc một vùng/polygon bằng tay hoặc các điểm/point để tạo một đối tượng hình học.

  1. Phía góc trên bên trái của cửa sổ bản đồ/map window, có một số nút chức năng bạn có thể sử dụng để vẽ các đối tượng hình học. Các nút này bao gồm một biểu tượng bàn tay nhỏ (để di chuyển xung quanh ảnh), một biểu tượng giọt lệ ngược, một biểu tượng đường, và một biểu tượng vùng. Click vào biểu tượng vùng/ polygon.
image of the polygon drawing tool.
  1. Công cụ này cho phép bạn vẽ một đối tượng hình học thể hiện vùng nghiên cứu của mình. Click vào cửa sổ bản đồ để tạo một vùng/polygon xung quanh khu vực nghiên cứu của bạn (ví dụ, xung quanh Hà Nội hoặc nơi ở của bạn). Nhớ rằng, bạn có thể tắt/ mở ảnh Landsat để nhìn các lớp phía dưới. Click đúp để đóng kín vùng/polygon.
  2. Sau khi bạn có một vùng/polygon kín, sẽ xuất hiện một bản ghi trên code editor về vùng/polygon vừa được tạo ra. Chú ý mũi tên đỏ và phần khung màu đỏ trong hình dưới đây.
example of a digitized geometry

Chú ý thấy một thuật ngữ JavaScript quen thuộc? Đúng vậy, chúng ta đã sử dụng biến var khá nhiều lần. Trong trường hợp này, chúng ta thấy var được theo sau bằng các từ khác, đối tượng hình học, được viết bằng màu tím. Đây chính là bản ghi (record) chúng ta vừa tạo ra trong trên cửa sổ bản đồ phía dưới. Chúng ta có thể sử dụng nó trong sript của mình bằng cách gọi geometry. Hoặc chúng ta có thể đặt lại tên cho phù hợp hơn để thuận tiện làm việc với tên biến đó

  1. Click vào từ geometry. Thay geometry bằng StudyArea.
rename the geometry
  1. Click vào biểu tượng đầu mũi tên cạnh dòng var StudyArea để xem thông tin của đối tượng hình học chúng ta vừa tạo ra (Xem hình trên)
  1. Bạn có thể làm hiện code vừa tạo bằng cách click vào box/hộp màu xanh lam cạnh dòng Import. Code này có thể đươc copy và paste vào script của bạn.
  2. Nếu bạn lướt/hover qua dòng var StudyArea, một biểu tượng thùng rác xuất hiện ở bên tráiBạn có thể sử dụng để xóa bản ghi thao tác vừa rồi
  3. Lọc tập ảnh bằng đối tượng hình học
  4. Bây giờ chúng ta đã sẵn sàng để lọc tập ảnh, L8_collection. Trở lại với cửa sổ code, copy dòng dưới đây và paste vào code editor. Hãy chắc chắn bạn copy chúng xuống ngay dưới dòng lệnh tạo tập ảnh L8_collection.

// Filter to scenes that intersect your boundary

var L8_StudyArea = L8_collection.filterBounds(StudyArea);

  1. Thay đổi biến trong câu lệnh Map.addlayer thành L8_StudyArea (như dòng lệnh phía sau đây). Đưa nó xuống dưới dòng lệnh tạo biến L8_StudyArea.
  2.  Thay đổi dòng lệnh Map.setCenter thành map.centerObject và cập nhật các tham số đầu vào. Câu lệnh này sẽ giúp dịch chuyển trung tâm của cửa sổ bản đồ về đối tượng hình học chúng ta vừa tạo (ví dụ phía dưới). Chuyển nó xuống dưới dòng lệnh tạo biến L8_StudyArea.

Map.addLayer(L8_StudyArea,

  { min:0.05, max: 0.8, bands: ‘B6, B5, B4’},‘Landsat 8 in study region’);

Map.centerObject(StudyArea, 7);

  1. Click Run. Bây giờ tập ảnh sẽ lọc vả chỉ chọn những ảnh giao với vùng/polygon mà bạn đã tạo.
  2.  ((Không bắt buộc) Chỉnh sửa lệnh print để in chi tiết của tập ảnh mớiL8_StudyArea (đảm bảo để lệnh này ngay dưới lệnh tạo biến the L8_StudyArea). Khi lệnh hoàn thành, kết quả có 486 thành phần/element trong tập ảnh của tôi (Số lượng ảnh của bạn có thể khác phụ thuộc vào kích thước của đối tượng hình học mà bạn đã số hóa)

print(L8_StudyArea);

print message displays in console: 486 images (elements) are present in the image collection that has been filtered by the study area.
  1. Chúng ta cũng có thể sử dụng phương pháp định kích thước của tập ảnh để xác định bao nhiêu ảnh sẽ có trong tập ảnh của bạn. Copy dòng lệnh sau và paste chúng xuỗng dưới script của bạn và. Run script

// Get the number of images.

var count = L8_StudyArea.size();

print(‘Count of L8_StudyArea: ‘, count);

  1. (Không bắt buộc, tìm hiểu các dạng dữ liệu và hàm khác để có cùng câu tr lời với phương pháp đếm/count tập ảnh): Có cách khác để có được số lượng ảnh, mặc dù phức tạp hơn một chút. Chúng ta có thể sử dụng hàm length()  trong  lists/arrays. Trước tiên, chúng ta cần chuyển tập ảnh thành một List/Danh sách. Copy dòng lệnh sau và paste chúng dưới sript của bạn. Run sript.
  2. Đọc trên Console, hàm nào tốn nhiều thời gian để thực hiện hơn

// Convert the collection to a list and get the number of images.

var listL8_SA = L8_StudyArea.toList(1500);

print(“number of images”, listL8_SA.length());

Phần 3: Lọc Tập Ảnh Theo Thời Gian

  1. Tạo tập ảnh với giới hạn theo ngày
  1. Tiếp theo thêm một dòng lệnh giúp lọc ảnh theo thời gian, sử dụng hàm filterDate() (xem ví dụ dưới đây). filterDate() cho phép bạn định rõ ngày bắt đầu và kết thúc như các tham số đầu vào để giảm kích thước của tập ảnh và đạt được mục tiêu dự án của mình. Dòng code mới đưa phép lọc vào tập dữ liệu, L8_StudyArea, dựa vào ngày mà các ảnh được thu nhận
  2. Sau đó, thêm lệnh count/đếm và print/in để xem có bao nhiêu ảnh trong tập ảnh mới
  3. Chúng ta đã có script hoàn chỉnh phía dưới. Chỉnh sửa sript của bạn cho đúng và Click Run   

// Get a collection.

var L8_collection = ee.ImageCollection(‘LANDSAT/LC8_L1T_TOA’);

// Filter to scenes that intersect your boundary

var L8_StudyArea = L8_collection.filterBounds(StudyArea);

// Filter to scenes for a given time period

var L8_SA_2015 = L8_StudyArea.filterDate(‘2015-01-01’, ‘2015-12-31’);

Map.addLayer(L8_SA_2015,

  { min:0.05, max: 0.8, bands: ‘B6, B5, B4’ });

Map.centerObject(StudyArea, 7);

// Get the number of images.

var count = L8_StudyArea.size();

print(‘Count of L8_StudyArea: ‘, count);

// Get the number of images.

var count15 = L8_SA_2015.size();

print(‘Count of L8_SA-2015: ‘, count15);

  1. (Không bắt buộc) Dưới đây là một số lệnh bổ sung giúp bạn có thể tìm hiểu tập ảnh của mình. Các lệnh này nằm trong phần hướng dẫn sử dụng
https://developers.google.com/earth-engine/ic_info

// Get statistics for a property of the images in the collection.

var sunStats = L8_StudyArea.aggregate_stats(‘SUN_ELEVATION’);

print(‘Sun elevation statistics: ‘, sunStats);

// Sort by a cloud cover property, get the least cloudy image.

var LoCloudimage = ee.Image(L8_StudyArea.sort(‘CLOUD_COVER’).first());

print(‘Least cloudy image: ‘, LoCloudimage);

// Limit the collection to the 10 most recent images.

var recent = L8_StudyArea.sort(‘system:time_start’, false).limit(10);

print(‘Recent images: ‘, recent);

Phần 4: Tìm hiểu các hàm xử lý ảnh

Một tập hợp đầy đủ các công cụ sẵn có trong Code Editor để phân tích và xử lý tập ảnh.

Phần 5: Giới Thiệu về Reducers

  1. Phép thu nhỏ tập ảnh, giá trị median/trung bình của pixel

Phần này tập trung vào một hàm dạng khác khi xử lý  dữ liệu trong 1 tập ảnh, reducer/phép thu nhỏ. Các phép thu nhỏ/Reducer để giảm kích thước của tập ảnh bằng các phép toán thống kê đơn giản, ví dụ giá trị trung bình của pixel. Kết quả đầu ra sẽ là một đối tượng ảnh (một lớp raster) thể hiện được một số đặc tính của toàn bộ tập ảnh. Để biết thêm về reducer, đọc hướng dẫn sử dụng tại đây:

https://developers.google.com/earth-engine/reducers_image_collection.
  1. Trước tiên để đơn giản hóa sript/tập lệnh mà bạn đang làm việc. sửa/Modify script trong Code Editor cho giống với hình dưới đây (hoặc bắt đầu với cửa số script mới (empty) và copy toàn độ dòng lệnh dưới vào code editor- nhưng nhớ vẽ lại vùng nghiên cứu của mình). Sau đó Run script/tập lệnh

// Get a collection.

var L8_collection = ee.ImageCollection(‘LANDSAT/LC8_L1T_TOA’);

// Filter to scenes that intersect your boundary

var L8_StudyArea = L8_collection.filterBounds(StudyArea);

// Filter to scenes for a given time period

var L8_SA_2015 = L8_StudyArea.filterDate(‘2015-01-01’, ‘2015-12-31’);

print(L8_SA_2015, ‘L8_SA_2015’);

  1. Bây giờ thêm một số lệnh để tạo hoặc hiển thị một tổ hợp ảnh giá trị trung bình / median composite, sử dụng hàm thu nhỏ tập ảnh median(). Lệnh sẽ giúp tạo  1 layer ảnh Image (một ảnh đơn) biểu diễn giá trị median của tất cả các ảnh trong tập ảnh đã được lọc.

//reduce to median value per pixel

var median_L8_2015 = L8_SA_2015.median();

print(median_L8_2015, ‘median_L8_2015’);

//add layers

Map.addLayer(median_L8_2015,

  { min:0.05, max: 0.8, bands: ‘B6, B5, B4’});

Map.centerObject(StudyArea, 7);

  1. Kiểm tra kết quả, chú ý những điểm sau: :
  1. Nhìn vào kết quả sau khi thực hiện lệnh Print/in. Bạn thấy có sự khác biệt gì giữa L8_SA_2015 và median_L8_2015? Gợi ý: một là tập hợp ảnh, còn một là đối tượng ảnh (một raster layer duy nhất)
  2. Bạn có thể cho hiển thị vùng nghiên cứu của mình bằng cách chọn vào ô/box vuông nhỏ trong thanh công cụ Geometry Imports phía trên bên trái của cửa sổ bản đồ (như hình sau)
  3. Tổ hợp ảnh chỉ bao gồm các hàng cột các cảnh ảnh Landsat giao với vùng nghiên cứu của bạn (phóng to để xem toàn bộ)
  4. Ảnh cũng tương đối ít mây do chúng ta đang xem giá trị trung tuyến /median pixel của toàn bài tập ảnh. Bạn còn thấy mây không?

Kể cả khi sử dụng phép thu nhỏ tập ảnh với median/median reducer, vẫn có thể còn một số pixel trông giống như mây. Tốt nhất cần loại bỏ mây ở mỗi ảnh trong toàn bộ tập ảnh trước khi chạy median reducer. Để được  như vậy, chúng ta cần học thêm về các hàm để làm việc với toàn bộ tập ảnh

  1. Lưu sript/tập lệnh, đặt tên là ‘Ex 3 Image Collection Part 5’. Bạn sẽ quay lại bài tập này sau

Phần 6: Nhập Môn Về các Hàm

Khi bạn phát triển code, các câu lệnh có thể bắt đầu trở nên khá dài. Để code được sắp xếp trật tự và để tạo thêm nhiều code có hiệu quả cao khi sử dụng, bạn có thể tận dụng lại các code mình đã thiết lập từ trước. Bạn hãy chia nhỏ code thành các phần, tách riêng các phần này, đặt tên để có thể sử dụng khi bạn cầu sau này. Các hàm là là phần nhỏ hơn của code. Ví dụ, chúng ta có một hàm để lấy dữ liệu mà mình quan tâm, một hàm để phân tích tích dữ liệu, và một hàm để xuất dữ liệu. Chúng ta cần chia nhỏ code thành 3 phần- mỗi phần tương ứng với một hàm.

Các hàm cũng rất hữu dụng khi chúng ta có một loạt lệnh mà bạn muốn sử dụng lại nhiều lần trong tập code. Ví dụ, có thể ta muốn tính mean của dữ liệu hoặc NDVI của tập raster, chúng ta có thể tạo một hàm mà có thể sử dụng/gọi lại, hơn là phải viết mới từ đầu

  1. Cấu trúc

Đây là cách các hàm được thiết lập :

  1. Code/Mã Lệnh: Bạn lấy code mình muốn sử dụng (một dòng lệnh hoặc hàng trăm dòng lệnh), đưa chúng vào trong dấu ngoặc móc {} để biết được hàm bắt đầu và kết thúc ở đâu. Trong ví dụ dưới đây, các dòng chú giải màu xanh lá cây đang nằm trong khối mã lệnh/code block.
  2. functionBắt đầu bằng từ function (ngôn ngữ Javascript), in thường, trước dấu ngoặc cong đầu tiên
  3. name_of_function (tên hàm): sau function là tên mà chúng ta muốn đặt cho hàm/function đó. Chúng ta có thể đặt tên hàm/function theo ý mình, quy luật và gợi ý đặt tên giống như khi đặt tên biến (không bắt đầu bằng chữ số, thể hiện đúng chức năng của hàm…)
  4. Thông số đầu vào (input): Giữa tên hàm và ngoặc móc {} đầu tiên, chúng ta thêm một dấu ngoặc đơn (). Trong phần dấu ngoặc đơn, chúng ta sẽ điền các thông số đầu vào (input) mà người sử dùng muốn cung cấp cho hàm/function, nếu không có, chúng có thể được để trống. Thông số đầu vào là một phần thông tin (Nó có thể được chứa trong một biến) mà được đưa vào hàm khi được gọi. Nếu bạn có nhiều thông số muốn đưa vào hàm, đơn giản ngăn cách chúng bằng dấu phẩy. Ví dụ khi tạo ra hàm tính NDVI của ảnh, chúng ta sẽ đưa vào hàm một ảnh mà chúng ta muốn tính NDVI.
  5. Gọi hàm: một khi bạn đã tạo một hàm, nó sẽ không được thực hiện cho tới khi bạn gọi hàm đó. Để sử dụng hàm trong code của mình, bạn viết tên hàm, tiếp theo là dấu ngoặc đơn, sau đó là điền thông số vào bên trong ngoặc đơn, kết thúc bằng dấu chấm phẩy.

function name_of_function (parameter_1, parameter_2) {

// code to execute

// more code to execute

// …

}

// call the function

name_of_function(input_1, input_2);

Đây là cấu trúc cơ bản của một hàm. Nếu bạn thấy chúng có vẻ hơi phức tạp, đừng lo lắng, bạn sẽ thấy dễ dàng hơn khi tự viết chúng. Sau đây, bạn sẽ thực tập để tạo một hàm đơn giản calculate_sum

Ghi chú: Quy tắc chung là khai báo và định rõ tất cả các hàm trước, sau đó gọi chúng ra trong script. Điều này là không bắt buộc nhưng sẽ code dễ đọc hơn

  1. Tạo hàm để tính tổng số
  1. Mở một cửa sổ làm việc mới bằng cách click/nhấn vào biểu tượng đầu mũi tên cạnh Reset. Sau đó chọn Clear Script.
  2. Xem kỹ phần code bên dưới. Đây là ví dụ về hàm giúp tính tổng hai giá trị

function calculate_Sum (in_value1, in_value2) {

var Sum = ee.Number(in_value1).add(ee.Number(in_value2)); // code that calculates the sum

    print(Sum);

}

// call the function

calculate_Sum(75, 82);

Ghi chú: Cho tới nay, chúng ta đã thực hiện chạy các code theo thứ tự. Các hàm hơi khác nhau ở điểm chúng có thể được định nghĩa ở bất cứ đâu trong chuỗi code, nhưng chỉ thực hiện chạy khi chúng được gọi. Ví dụ dưới đây cũng giống với ví dụ ở trên. Rất nhiều lập trình viên sẽ nhóm tất cả các hàm của họ lại ngay khi bắt đầu một script, tuy nhiên hàm đó chỉ chạy khi được gọi về sau.

  1. Ngay trong hàm vừa tạo, /type hai giá trị khác vào calculate_Sum () để tính tổng và chạy code. Dòng lệnh ví dụ như sau:

calculate_Sum(99, 106);

// copy the call statement (above), below the creation of the function

function calculate_Sum (in_value1, in_value2) {

var Sum = ee.Number(in_value1).add(ee.Number(in_value2)); // code that calculates the sum

    print(Sum);

}

Ghi chú: Nếu bạn thấy quen với lệnh gọi các hàm này, rất tốt! Chúng ta đã dùng các hàm JavaScript trong bài tập này rồi. Một ví dụ là print()

  1. Một khi hàm đã được tạo, bạn có thể gọi hàm bao nhiêu lần bạn muốn. Hãy gọi gàm này một lần nữa với các tham số mới. Lần này tự thêm hai giá trị bạn muốn

calculate_Sum(790, 1.555);

calculate_Sum(133, 765);

  1. Biến toàn cục và biến cục bộ
  2. Làm thế nào khi chúng ta muốn lưu kết quả tính tổng vừa thực hiện như một biến để sử dụng trong mã code sau này, chúng ta có thể thực hiện được không? Chúng ta tạo và định nghĩa một biến gọi là Sum trong hàm. Thử in biến này sau khi gọi hàm để kiểm tra giá trị kết quả. Gõ dòng lệnh tạo hàm sau và chạy script/tập lệnh.

// call the function

calculate_Sum(75, 82);

print(Sum);

  1. Bạn nhận được gì? Bạn sẽ nhận được báo lỗi trên console “Sum is not defined in the global scope”, có nghĩa là Sum không được định nghĩa trong phạm vi toàn cục.
  2. Câu lệnh trên không thực hiện được. Thử lưu nó dưới một định dạng khác. Hãy xóa dòng code bạn vừa thực hiện ở bước vừa rồi. Xem kỹ dòng code dưới đây. Đưa vào script và Chạy/Run code

//call the function and save it as a variable called Sum_test

var Sum_test = calculate_Sum(75, 82);

// Try to call the variable we created in the function,

// outside of the function call

print(Sum_test);

  1. Chuyện gì xảy ra? Chúng ta không còn thấy báo lỗi nữa, tuy nhiên lưu nó dưới dạng một biến lại không thực hiện được. Tôi nhận được một thông báo rằng “a property cannot be read” – Thuộc tính không được xác định
  2. Cho tới bây giờ, chúng ta vẫn chưa thành công để truy nhập vào kết quả của hàm. Đó là bởi vì biến Sum là một biến cục bộ, một biến chỉ tồn tại và khi được nằm trong hàm của nó. Trong JavaScript, bất kỳ var nào được dùng trong một hàm, biến kết quả là một biến cục bộ chỉ có thể truy cập được trong hàm đó.

Thế nào là biến cục bộ? Thế nào là biến toàn cục?

Biến cục bộ là một biến được khai báo trong một hàm. Không giống như biến toàn cục, biến cục bộ chỉ có thể sử dụng dưới hàm mà nó được khai báo.

Các biến được khai báo bên ngoài hàm được gọi là biến toàn cục và có thể đọc được ở bất kì vị trí nào trong script, kể cả trong hay ngoài các hàm. Cho tới nay, tất cả những gì chúng ta được học là về biến toàn cục, mặc dù chúng ta vẫn chưa gọi chúng là biến toàn cục. Một biến toàn cục là biến mà được khai báo bên ngoài của bất kỳ hàm nào. Các biến này có thể sử dụng bất kỳ lúc nào trong code và có thể sử dụng cả bên trong các hàm.

  1. Sử dụng “return” để lưu kết quả của hàm dưới dạng một biến

Làm thế nào để chúng ta có thể chuyển kết quả cục bộ của một hàm thành một biến toàn cục? JavaScript sử dụng câu lệnh “return” để chuyển một giá trị cục bộ về chương trình chính. Bằng cách khai báo một biến toàn cục và định nó tương đương với một phép gọi hàm, chúng ta gán kết quả của hàm cho một biến mà có thể sử dụng ở bất cứ đâu trong script

  1. Đọc kỹ những dòng lệnh sau. Đưa các dòng lệnh này vào code editor script của bạn và click 
    Run

function calculate_Sum (in_value1, in_value2) {

var Sum = ee.Number(in_value1).add(ee.Number(in_value2)); // code that calculates the sum

    print(“Local variable, Sum, = “Sum);

    return Sum; // here we use return

}

// Now call and save the output of the function.

// Save it as a variable, Sum_test.

var Sum_test = calculate_Sum(75, 82);

// Try to call the variable we created in the function, outside of the

// function call

print(“The global variable, Sum_test, = “,Sum_test);

  1. Bạn thấy gì xảy ra? Bây giờ, dòng lệnh đã thực hiện thành công! Tôi thấy giá trị 157 được in ra trong cửa dổ Console của mình 2 lần:
  1. Lần một là một biến cục bộ sau khi kết quả được in ra từ hàm
  2. Lần thứ hai là sau khi gọi hàm print biến toàn bộ mà tôi vừa tạo, Sum_test.

Phần 7: Tạo hàm lọc bỏ mây (cloud mask)

Nhớ lại bài tập 2, bạn đã học về mặt nạ lọc mây (cloud mask). Bây giờ bạn sẽ viết lại thành hàm mà có thể gọi ra bất cứ lúc nào trong script của mình.

  1. Đưa vào câu lệnh lọc bỏ mây (cloud mask) từ bài tập 2
  2. Copy và paste các dòng lệnh sau vào một cửa sổ Code Editor trống. Trông chúng khá quen vì bạn đã làm việc với chúng từ bài tập 2. Chạy script và đảm bảo nó được thực hiện.

// Get an image and display in map window.

var LC8_image = ee.Image(‘LANDSAT/LC8_L1T_TOA/LC81290502013110LGN01’);

//Specify the cloud likelihood threshold –

var cloud_thresh = 40;

//use add the cloud likelihood band to the image

var CloudScore = ee.Algorithms.Landsat.simpleCloudScore(LC8_image);

//isolate the cloud likelihood band

var quality = CloudScore.select(‘cloud’);

//get pixels above the threshold

var cloud01 = quality.gt(cloud_thresh);

//create a mask from high likelihood pixels

var cloudmask = LC8_image.mask().and(cloud01.not());

//mask those pixels from the image

var LC8_imageNoClouds = LC8_image.mask(cloudmask);

//Review the result

addToMap(LC8_imageNoClouds, {bands:[‘B6’,‘B5’,‘B4’],min:0.1, max:0.5},‘Landsat8scene_cloudmasked’);

  1. Bây giờ chỉnh sửa lại để chuyển nó một thành hàm. Đầu tiên, phía trước “use add the cloud likelihood band to the image”, thêm một dòng như sau

var cloudfunction = function(){

  1. Phía trước dòng ghi chú ‘Review the result’, chỉ thêm duy nhất một dấu ngoặc móc }. Phần code của bạn sẽ trông thế này:

 // Get an image and display in map window.

var LC8_image = ee.Image(‘LANDSAT/LC8_L1T_TOA/LC81290502013110LGN01’);

//Specify the cloud likelihood threshold –

var cloud_thresh = 40;

var cloudfunction = function(){

//use add the cloud likelihood band to the image

var CloudScore = ee.Algorithms.Landsat.simpleCloudScore(LC8_image);

//isolate the cloud likelihood band

var quality = CloudScore.select(‘cloud’);

//get pixels above the threshold

var cloud01 = quality.gt(cloud_thresh);

//create a mask from high likelihood pixels

var cloudmask = LC8_image.mask().and(cloud01.not());

//mask those pixels from the image

var LC8_imageNoClouds = LC8_image.mask(cloudmask);

}

//Review the result

addToMap(LC8_imageNoClouds, {bands:[‘B6’,‘B5’,‘B4’],min:0.1, max:0.5},‘Landsat8scene_cloudmasked’);

  1. Tiếp theo bạn cần định rõ tham số đầu vào. Trong ngoặc đơn ở dòng thứ 7 (dòng khai báo hàm: var cloudfunction = function()), thêm từ image
  2. Sau đó thay biến LC8_image  bằng image. Như vậy là có 3 vị trí LC8_image cần được thay thế, xem ví dụ code dưới đây

// Get an image and display in map window.

var LC8_image = ee.Image(‘LANDSAT/LC8_L1T_TOA/LC81290502013110LGN01’);

//Specify the cloud likelihood threshold –

var cloud_thresh = 40;

var cloudfunction = function(image){

//use add the cloud likelihood band to the image

var CloudScore = ee.Algorithms.Landsat.simpleCloudScore(image);

//isolate the cloud likelihood band

var quality = CloudScore.select(‘cloud’);

//get pixels above the threshold

var cloud01 = quality.gt(cloud_thresh);

//create a mask from high likelihood pixels

var cloudmask = image.mask().and(cloud01.not());

//mask those pixels from the image

var LC8_imageNoClouds = image.mask(cloudmask);

}

//Review the result

addToMap(LC8_imageNoClouds, {bands:[‘B6’,‘B5’,‘B4’],min:0.1, max:0.5},‘Landsat8scene_cloudmasked’);

  1. Cuối cùng, chúng ta cần thêm một lệnh return để kết quả, LC8_imageNoClouds là một biến toàn cục mà chúng ta có thể sử dụng bên ngoài hàm. Thay dòng code dưới đây

  //mask those pixels from the image

var LC8_imageNoClouds = LC8_image.mask(cloudmask);

Bằng lệnh return như sau:

return LC8_image.mask(cloudmask);

  1. Bây giờ chúng ra đã sẵn sàng để gọi hàm. Sau khi đóng ngoặc móc } tại vị trí kết thúc cuối hàm, tạo một biến mới tên là LC8_imageNoClouds. Sau đó chạy hàm trên ảnh chúng ta vừa lưu là LC8_image. Xem ví dụ dòng lệnh sau:

var LC8_imageNoClouds = cloudfunction(LC8_image);

  1. Click Run để xem hàm của chúng ta có làm việc không. Tham khảo toàn bộ script dưới đây để đảm bảo những gì bạn viết là đúng

// Get an image and display in map window.

var LC8_image = ee.Image(‘LANDSAT/LC8_L1T_TOA/LC81290502013110LGN01’);

//Specify the cloud likelihood threshold –

var cloud_thresh = 40;

var cloudfunction = function(image){

//use add the cloud likelihood band to the image

var CloudScore = ee.Algorithms.Landsat.simpleCloudScore(image);

//isolate the cloud likelihood band

var quality = CloudScore.select(‘cloud’);

//get pixels above the threshold

var cloud01 = quality.gt(cloud_thresh);

//create a mask from high likelihood pixels

var cloudmask = image.mask().and(cloud01.not());

//mask those pixels from the image

return image.mask(cloudmask);

}

var LC8_imageNoClouds = cloudfunction(LC8_image);

//Review the result

addToMap(LC8_imageNoClouds, {bands:[‘B6’,‘B5’,‘B4’],min:0.1, max:0.5},‘Landsat8scene_cloudmasked’);

  1. Lưu scrip của bạn với tên gọi “Ex3_CloudMaskFunction”.

Phần 8: Các Hàm sử dụng Với Tập Hợp Ảnh

  1. Bây giờ chúng ta biết các hàm của mình đã hoạt động, cùng áp dụng chúng cho tập ảnh mà bạn đã tạo trong nửa đầu bài tập này
  2. Copy hàm lọc mây (cloud mask) như dưới đây.

var cloudfunction = function(image){

//use add the cloud likelihood band to the image

var CloudScore = ee.Algorithms.Landsat.simpleCloudScore(image);

//isolate the cloud likelihood band

var quality = CloudScore.select(‘cloud’);

//get pixels above the threshold

var cloud01 = quality.gt(cloud_thresh);

//create a mask from high likelihood pixels

var cloudmask = image.mask().and(cloud01.not());

//mask those pixels from the image

return image.mask(cloudmask);

}

  1. Sau đó mở script đã được đặt tên là ‘Ex 3 Image Collection Part 5’.
  2. Paste hàm lọc mây và biến cloud_thresh vào script (sau những dòng lệnh tạo tập hợp ảnh lọc mây, nhưng phía trước median reducer). Xem code hoàn chỉnh phía dưới đây

// Get a collection.

var L8_collection = ee.ImageCollection(‘LANDSAT/LC8_L1T_TOA’);

// Filter to scenes that intersect your boundary

var L8_StudyArea = L8_collection.filterBounds(StudyArea);

// Filter to scenes for a given time period

var L8_SA_2015 = L8_StudyArea.filterDate(‘2015-01-01’, ‘2015-12-31’);

print(L8_SA_2015, ‘L8_SA_2015’);

var cloud_thresh = 40;

var cloudfunction = function(image){

//use add the cloud likelihood band to the image

var CloudScore = ee.Algorithms.Landsat.simpleCloudScore(image);

//isolate the cloud likelihood band

var quality = CloudScore.select(‘cloud’);

//get pixels above the threshold

var cloud01 = quality.gt(cloud_thresh);

//create a mask from high likelihood pixels

var cloudmask = image.mask().and(cloud01.not());

//mask those pixels from the image

return image.mask(cloudmask);

};

//reduce to median value per pixel

var median_L8_2015 = L8_SA_2015.median();

print(median_L8_2015, ‘median_L8_2015’);

//add layers

Map.addLayer(median_L8_2015,

  { min:0.05, max: 0.8, bands: ‘B6, B5, B4’}, ‘median_L8_2015 with clouds’);

Map.centerObject(StudyArea, 7);

  1. Bây giờ thêm một lệnh giúp đưa kết quả thực hiện với toàn bộ tập ảnh lên cửa sổ xuất kết quả bản đồ. Sau đó đưa tập ảnh với mây được lọc lên cửa sổ hiển thị. Xem ví dụ về lệnh map dưới đây

var L8_SA_2015NoClouds = L8_SA_2015.map(cloudfunction);

Map.addLayer(ee.Image(L8_SA_2015NoClouds.first()),

  {min:0.05, max: 0.8, bands: ‘B6, B5, B4’}, ‘first image no clouds’);

Map.centerObject(StudyArea, 7);

  1. Thay đổi lệnh median reducer để chạy trên tập ảnh L8_SA_2015NoClouds image mà bạn vừa tạo. Xem ví dụ các code dưới đây.

//reduce to median value per pixel

var median_L8_2015 = L8_SA_2015NoClouds.median();

print(median_L8_2015, ‘median_L8_2015’);

//add layers

Map.addLayer(median_L8_2015,

  {min:0.05, max: 0.8, bands: ‘B6, B5, B4’}, ‘median composite of cloud free images’);

Bài tập 3: Viết các Hàm Theo Nhu Cầu Sử dụng và Làm Việc Với Tập Ảnh  
]]>
Categories
Google Earth Engine Tài liệu Viễn thám

[GEE 2] Bài tập 2: Đối tượng ảnh trong Earth Engine và các hàm

Bài tập 2: Đối tượng ảnh trong Earth Engine và các hàm

Image object in Earth Engine

Giới Thiệu

Code Editor cho phép thực hiện toàn bộ chức năng của Earth Engine, tuy nhiên, cần có hiểu biết cơ bản về lập trình và JavaScript. Trong bài tập này, chúng ta sẽ học về ngôn ngữ JavaScript và một vài khái niệm cơ bản về dữ liệu không gian của Earth Engine. Bài tập này sẽ tập trung vào các đặc tính và phương pháp, các hàm tính toán khi làm việc với các dữ liệu ảnh trong Earth Engine. Bên cạnh đó, bạn cũng sẽ được giới thiệu ngắn gọn về các dạng đối tượng không gian khác trong Earth Engine. Bài tập này sẽ giúp bạn viết một script/tập lệnh đơn giản trong JavaScript. Bạn cũng sẽ được học về Fusion Tables.

Mục Lục

Phần 1: Thiết lập không gian làm việc        2

Phần 2: Tìm Hiểu Các Hàm Xử Lý Ảnh        2

Phần 3: (Không bắt buộc) Truy nhập Metadata / siêu dữ liệu        5

Phần 4: (Đọc thêm) Một Số Khái Niệm Cơ Bản Về Đối Tượng        6

Phần 1: Thiết Lập Không Gian Làm Việc

  1. Mở một script mới
  2. Mở Code Editor trong Google Chrome:
https://code.earthengine.google.com/
  1. Click vào biểu tượng đầu mũi tên bên cạnh nút Reset và chọn Clear script.
clear script button.
  1. Tạo một biến đại diện cho một ảnh Landsat 8
  2. Dùng dòng code dưới đây để tạo một biến đại diện đối tượng  ee.Image cho một ảnh Landsat 8.
  3. Copy và paste dòng code dưới đây vào Code Editor.

// Get an image and display in map window.

var LC8_image = ee.Image(‘LANDSAT/LC8_L1T_TOA/LC81290502013110LGN01’);

Map.addLayer(LC8_image, {min:0.05, max: 0.8, bands: ‘B6, B5, B4’}, “Landsat 8 Scene”);

Map.centerObject(LC8_image, 8);

Phần 2: Tìm Hiểu Các Hàm Xử Lý Ảnh hiện có

Code Editor có sẵn một tập hợp đầy đủ các công cụ phục vụ cho phân tích và xử lý các đối tượng ảnh mà bạn đã và đang làm việc. Những công cụ này ở dưới dạng các hàm của Earth Engine

  1. Tính NDVI cho ảnh Landsat của bạn
  2. Bạn có thể tính Chỉ Số Thực Vật (NDVI) cho ảnh của mình, sử dụng hàm normalizedDifference(). Copy những dòng lệnh dưới đây và paste chúng vào dưới phần sript/tập lệnh của bạn. Click Run. Những dòng lệnh này sẽ tính giá trị NDVI cho ảnh của bạn.

// Create an NDVI image using bands the nir and red bands (5 and 4)

var NDVI = LC8_image.normalizedDifference([‘B5’,‘B4’]);

// Display the NDVI image – Use a grayscale stretch for display

Map.addLayer(NDVI,{min: 0.2, max:0.5, palette: [‘FFFFFF’, ‘339900’]},“NDVI”);   

  1. Tách vùng mây/ Mask coulds
  2. Xóa script/tập lệnh của bạn từ Phần 4A, trừ những dòng dưới đây

// Get the image.

var LC8_image = ee.Image(‘LANDSAT/LC8_L1T_TOA/LC81290502013110LGN01’);

Map.addLayer(LC8_image, {min:0.05, max: 0.8, bands: ‘B6, B5, B4’}, “Landsat 8 Scene”);

Map.centerObject(LC8_image, 8);

  1. Run/Chạy script. Chú ý những vùng mây xuất hiện ở nửa bên phải của ảnh? Tiếp theo bạn sẽ tiến hành việc loại bỏ những vùng mây này ra khỏi ảnh.
  2. Trước tiên, bạn sẽ tạo một biến, cloud_thresh. Biến này sẽ lưu giá trị ngưỡng của vùng mây. Sau khi bạn soạn xong script, bạn có thể dễ dàng thay đổi giá trị của biến này. Thay đổi giá trị và chạy lại script để tìm ra giá trị ngưỡng hợp lý cho vùng mây trong khu vực nghiên cứu

//Specify the cloud likelihood threshold –

var cloud_thresh = 40;

Sau đây, bạn sẽ sử dụng thuật toán trong Earth Engine giúp tính ngưỡng giá trị vùng mây đơn giản bằng cách kết hợp độ sáng, nhiệt đồ và Chỉ số Tuyết NDSI (Normalized Snow Index). Khoảng giá trị của vùng được thể hiện trong khoảng từ 0 đến 100, trong đó giá trị càng lớn thì khả năng pixel đó là mây càng cao. Bạn có thể đọc thêm tại Tab Docs (hoặc tham khảo hình dưới đây)

simple cloud score
  1.  Copy những dòng lệnh dưới đây và paste xuống dưới script của mình. Dòng lệnh này sẽ giúp tạo một lớp raster có giá trị pixel trong khoảng 0-100, các pixel có giá trị cao hơn thì khả năng là mây cao hơn

//use add the cloud likelihood band to the image

var CloudScore = ee.Algorithms.Landsat.simpleCloudScore(LC8_image);

  1. (Không bắt buộc) Thêm lớp raster vừa tạo (CloudScore) vào cửa sổ xuất kết quả bản đồ bằng cách copy những dòng lệnh sau xuống dưới cùng script/tập lệnh của bạn. Click Run
  1. Những giá trị nào được gán cho vùng mây? (Gợi ý: dùng công cụ inspector để xem các giá trị tại các vị trí khác nhau trong ảnh kết quả)
  2. Bạn có thấy sự khác nhau giữa các kết quả của hai dòng lệnh Map.addLayer()? (Gợi ý: sử dụng tab inspector và tắt bật các lớp/layer để so sánh)
  3. Sau khi bạn kiểm tra xong raster CloudScore raster, remove/xóa (hoặc viết ghi chú lên trước) những dòng code này trong sript/tập lệnh của mình.

// Add the cloud image to the map.

// This will add the first three layers

Map.addLayer(CloudScore,{}, ‘Cloud Likelihood, all bands’);

// but you are interested in the cloud layer.

// you can specify the band you would like displayed in the input

// parameters of the Map.addLayer statement:

Map.addLayer(CloudScore,{bands:‘cloud’}, ‘Cloud Likelihood’);

  1. Raster sau khi được tạo ra từ hàm ee.Algorithms.Landsat.simpleCloudScore() là một ảnh có 13 band, trong đó: 12 band  là của ảnh Landsat và band mới thứ 13 – giá trị của mỗi pixel thể hiện khả năng pixel đó có thể là mây hoặc không (cloud score/likelihood). Bạn cần tách biệt band này để lọc mây/mask cho ảnh Landsat. Copy dòng lệnh dưới đây và paste xuống dưới cùng phần sript của bạn. Dòng lệnh này giúp định nghĩa band ‘mây’/’clound band’ thành một biến gọi là quality.

//isolate the cloud likelihood band

var quality = CloudScore.select(‘cloud’);

  1. Copy những dòng lệnh dưới đây và paste xuống dưới cùng phần script của bạn. Trong những dòng lệnh này có sử dụng hàm gt() để tạo ra một raster nhị phân/binary raster gán cho mỗi pixel một giá trị:
  1.  Giá trị sẽ là 1 nếu biến quality (khả năng thuộc vùng mây/cloud likelihood) lớn hơn ngưỡng giá trị của mây;
  2. Giá trị sẽ là 0 nếu biến quality (khả năng thuộc vùng mây/cloud likelihood) nhỏ hơn ngưỡng giá trị của mây

//get pixels above the threshold

var cloud01 = quality.gt(cloud_thresh);

//Add the image to the map.

Map.addLayer(cloud01,{}, ‘Cloud Mask step 1’);

  1. Run/Chạy code và kiểm tra các giá trị ở các vị trí khác nhau trên kết quả (gợi ý: sử dụng công cụ inspector)
  2. Copy dòng lệnh dưới đây và paste xuống phía dưới cùng script của bạn
  1.  Sử dụng hàm mask()  để loại bỏ các giá trị có khả năng là mây cao (giá trị cloud likelihood cao) khỏi ảnh Landsat. Hàm mask() loại bỏ các pixel trong ảnh Landsat mà pixel tương ứng trong ảnh (cloud01) có giá trị 0.
  2. Nhớ rằng, trong ảnh cloud01, các pixel có thể là mây có giá trị 1, không phải 0. Vì vậy cần có hàm not(). Hàm này quay lại 0 nếu tham số đầu vào khác 0, và là 1 cho các giá trị khác.
  3. Để trống thông số đầu vào của hàm mask () và dùng hàm and() để liên kết với hàm not()  tạo ra một mặt nạ lọc mây là sự kết hợp từ ảnh Landsat và ảnh cloud01. Run/ code và kiểm tra kết quả

//create a mask from high likelihood pixels

var cloudmask = LC8_image.mask().and(cloud01.not());

Map.addLayer(cloudmask,{}, ‘Cloud Mask step 2’);

  1. Bây giờ bạn đã sẵn sàng sử dụng mặt nạ lọc mây/mask, cloudmask để tách mây khỏi ảnh Landsat. Copy dòng lệnh sau và paste xuống dưới cùng script của bạn. Click Run code và kiểm tra kết quả

//mask those pixels from the image

var LC8_imageNoClouds = LC8_image.mask(cloudmask);

//Review the result

Map.addLayer(LC8_imageNoClouds, {bands:[‘B6’,‘B5’,‘B4’], min:0.1, max:0.5},‘Landsat8scene_cloudmasked’);

Ghi chú- Masking pixel là loại bỏ những pixel đó trong ảnh bằng cách chuyển chúng thành giá trị 0. Xác định được pixel trong ảnh Landsat có khả năng là mây, bạn có thể tạo một mặt nạ lọc/mask để loại bỏ các pixel này trong ảnh gốc. Hàm đó có thể được dùng với cú pháp chung:

LandsatImage.mask(cloudMaskImage).

Ghi chú: Cũng có thể áp dụng một mặt nạ lọc/mask cho một ảnh đã được lọc, bạn có thể thấy khó hiểu- vì vậy hãy bảo đảm rằng bạn có một sơ đồ lý thuyết và các bước thực hiện rõ ràng

  1. Chỉnh sửa script để loại bỏ vùng hơi nước bao quanh mây
  1. Ảnh Landsat 8 nguyên gốc đang được tắt chế độ hiển thị, phóng to đến mép biên của mây trong ảnh. Bạn có nhìn thấy sương mù/hơi nước trong ảnh đã được lọc mây.
  2. Bạn có thể thử loại bỏ sương mù bằng cách giảm ngưỡng của khoảng mây/cloud likelihood threshold. Tìm lại biến cloud_thresh và đổi giá trị từ 40 xuống 20.  Click Run và xem kết quả
  1. Ngưỡng của khoảng giá trị mây/likelihood từ 40 xuống đến 20 có thể hạn chế đáng kể sự có mặt của các pixel mây và hơi nước trong ảnh- các pixel còn lại hiển thị rõ và sáng,
  2. Bạn có nghĩ đây là giá trị phù hợp cho ngưỡng của khoảng giá trị mây hay không? / cloud likelihood?
  3. Sử dụng công cụ viewer để tìm hiểu các ảnh kết quả và thử các ngưỡng giá trị khác mà bạn muốn

Ghi chú: Bóng mây không được loại bỏ trong ảnh trên

Phần 3: (Không bắt buộc) Truy Nhập Metadata / Siêu Dữ Liệu

Biết cách truy nhập vào metadata/siêu dữ liệu của ảnh là rất quan trọng khi bạn tạo các srcript của mình

Ghi chú: Những ví dụ này là từ Hướng Dẫn của Earth Engine, có thể đọc tại: https://developers.google.com/earth-engine/image_info

  1. Xóa các script trước trong code editor
  2. Đọc kỹ các dòng lệnh dưới đâySau đó copy  paste vào code editor. Chạy/Run script và kiểm tra kết quả sau mỗi lệnh print/in.

// Get the image.

var LC8_image = ee.Image(‘LANDSAT/LC8_L1T_TOA/LC81290502015036LGN00’);

//Add the image to the map as a false color composite.

Map.addLayer(LC8_image,{bands:‘B6,B5,B4’, min: 0.05, max: 0.8,gamma: 1.6}, ‘Landsat8scene’);

//center map on the tile

Map.centerObject(LC8_image, 9);

// Get information about the bands as a list.

var bandNames = LC8_image.bandNames();

print(‘Band names: ‘, bandNames); // ee.List of band names

// Get projection information from band 1.

var b1proj = LC8_image.select(‘B1’).projection();

print(‘Band 1 projection: ‘, b1proj); // ee.Projection object

// Get scale (in meters) information from band 1.

var b1scale = LC8_image.select(‘B1’).projection().nominalScale();

print(‘Band 1 scale: ‘, b1scale); // ee.Number

// Note that different bands can have different projections and scale.

var b8scale = LC8_image.select(‘B8’).projection().nominalScale();

print(‘Band 8 scale: ‘, b8scale); // ee.Number

// Get a list of all metadata properties.

var properties = LC8_image.propertyNames();

print(‘Metadata properties: ‘, properties); // ee.List of metadata properties

// Get a specific metadata property.

var cloudiness = LC8_image.get(‘CLOUD_COVER’);

print(‘CLOUD_COVER: ‘, cloudiness); // ee.Number

// Get the timestamp and convert it to a date.

var date = ee.Date(LC8_image.get(‘system:time_start’));

print(‘Timestamp: ‘, date); // ee.Date

Phần 4: (Đọc thêm) Một Số Khái Niệm Cơ Bản Về Đối Tượng

  1. Các Đối Tượng

Một đối tượng trong JavaScript là gì?

 “JavaScrip là ngôn ngữ lập trình được thiết kế dựa trên đối tượng. Một đối tượng là một tập hợp các thuộc tính, và một thuộc tính là sự liên kết giữa tên (chìa khóa) và giá trị. Giá trị của thuộc tính có thể là một hàm, trong trường hợp đó thuộc tính được biết đến như một hàm. Cùng với các đối tượng được định nghĩa trước trong trình duyệt, bạn có thể định nghĩa đối tượng cho riêng mình (Mozilla Developer Network website)

Đọc thêm về đối tượng trong JavaScript tại đây: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects hoặc đây: http://eloquentjavascript.net/06_object.html.

Earth Engine cũng có các đối tượng. Đó là các đối tượng tồn tại trong Earth Engine nhưng không nhất thiết là một ứng dụng của JavaScript. Ví dụ đối tượng trong Earth Engine bao gồm ảnh (ví dụ: các cảnh ảnh Landsat), và danh mục ảnh (tập hợp các cảnh ảnh Landsat). Trong khóa học  này, chúng ta sẽ tập trung chủ yếu vào các đối tượng của Earth Enghine và các phương pháp xử lý liên quan.

  1. Thuộc tính của đối tượng và các phương pháp liên quan

Thuộc tính: các đối tượng có chung các thuộc tính. Mỗi thuộc tính có tên (name) và giá trị (value). Cặp tên và giá trị cho bạn biết về đặc tính riêng của đối tượng. Ví dụ, một đối tượng ảnh có thuộc tính cụ thể cho đối tượng đó, ví dụ một cảnh Landsat là một ảnh có dạng dữ liệu, 12 band/kênh phổ và một lượng lớn metadata / siêu dữ liệu (về ngày bay, hệ tọa độ, etc …)

Phương pháp: các hàm được lập cho từng dạng đối tượng được gọi là phương pháp. Chúng có thể thu nhận dữ liệu, sắp xếp dữ liệu, cập nhật giá trị thuộc tính của một đối tượng. Chúng ta không nhất thiết lúc nào cũng cần biết máy tính làm thế nào để thực hiện các lệnh, tuy nhiên bạn cần biết cần cách hỏi và yêu cầu máy tính và kiểm tra những kết quả nhận được. Ví dụ, bạn đã sử dụng NormalizedDifference là một chức năng phân tích đối tượng ảnh.

  1. Các Đối Tượng Ảnh Earth Engine

Trong GEE Code Editor, dữ liệu raster có thể được thể hiện dưới hai dạng đối tượng: đối tượng ảnh, hoặc tập hợp ảnh.

Ảnh: dữ liệu raster được biểu diễn dưới dạng đối tượng  ảnh trong Earth Engine. Một đối tượng ảnh thể hiện một ảnh raster độc lập, ví dụ một cảnh ảnh Landsat được thu nhận trong một ngày nhất định, một ảnh Landsat tổ hợp bằng phép lọc trung bình (median), hoặc các tập dữ liệu địa hình (DEM). Các ảnh được tổ hợp từ một hay nhiều band/kệnh phổ, mỗi band có tên, dạng dữ liệu, độ phân giải pixel và lưới chiếu. Mỗi ảnh cũng có  metadata bao gồm thư mục các các thuộc tính. Xem thêm tại đây – https://developers.google.com/earth-engine/image_info 

Tập hợp ảnh : là một tập hợp hoặc nhóm các ảnh. Ví dụ tập hợp ảnh Landsat 8 TOA Reflectance (LANDSAT/LC8_L1T_TOA) gồm toàn bộ các ảnh Landsat 8 được thu nhận từ 11 Tháng 4, 2013, được nắn chỉnh và quy đổi theo Hệ số phản xạ từ bề mặt khí quyển (Top of Atmosphere reflectance). Những tập ảnh rất có ích cho phân tích theo thời gian hoặc tạo ra tổ hợp ảnh ít mây sử dụng các ảnh có được từ một vài phép thu nhận ảnh khác nhau

  1. Các đối tượng Vector trong Earth Engine

Earth Engine sử dụng các dữ liệu dạng hình học (như GeoJSON  hoặc GeoJSONGeometryCollection) để lưu trữ các dữ liệu vector; gồm có điểm (point), chuỗi đường thẳng (line string), đường vòng (linear rings), và dạng vùng (polygon). Bạn có thể tạo các đối tượng hình học sử dụng công cụ draw hoặc với dạnh sách của các hệ tọa độ. Một đối tượng có một dạng hình học, cũng như ảnh, kèm theo thư mục của các thuộc tính.

Bạn có thể tạo một đối tượng hình học trong Earth Engine,  GeoJSON Feature hoặc tập hợp các đối tượng, Shapefile có thể được chuyển đổi thành Fusion Table và được truy nhập qua  Earth Engine như một tập hợp đối tượng

Bài tập 2: Đối tượng ảnh trong Earth Engine và các hàm  

]]>
Categories
Tài liệu

[Note] Các thuật toán unsupervised classification cho người mới bắt đầu + chút ứng dụng thực tế

Các thuật toán unsupervised classification cho người mới bắt đầu + chút ứng dụng thực tế

Nguồn: https://forum.machinelearningcoban.com/t/cac-thuat-toan-unsupervised-classification-cho-nguoi-moi-bat-dau-chut-ung-dung-thuc-te/3036

Mình đang có một số bài toán của công ty cần giải quyết cần research về vụ này, sẵn tiện viết ra để vừa nhớ vừa chia sẻ với các bạn luôn.

:smiley:

Bài toán của mình cũng đơn giản và khá tiêu biểu: một số đối tượng có các features A, B, C, D, E, F, cần classify các đối tượng này thành một số group nào đó để các đội vận hành xử lý tiếp. Bài toán thì không nói ra cụ thể được, anh em thông cảm  Nhưng điểm chung là các đối tượng này chưa từng được phân nhóm (clustering), tức là không có nhãn sẵn (label). Bạn phải đi tìm nhãn cho chúng.

Tiếp, mình chỉ viết mấy cái mình đã đụng, đã làm thôi nhé, còn mấy cái chưa xài thì không dám chém. Reference của mình là từ bài viết này:https://towardsdatascience.com/the-5-clustering-algorithms-data-scientists-need-to-know-a36d136ef68 112. 5 cái lận, mà mình viết 2 thôi.

K Mean

K Mean kiểu như là thuật toán phân loại nổi tiếng nhất, ở đâu cũng thấy, mấy môn học ML, data cơ bản thấy người ta cũng dạy nhiều. Bản thân team mình cũng dùng vài lần cho một số bài toán và thấy nó khá đúng, outcome đưa ra khá hài lòng. Bạn có thể xem giải thích chi tiết về K Mean và các nền tảng toán của nó 93, mình thì không hiểu nên thôi bỏ qua hihihi.

Về ứng dụng thực tế thì mình từng dùng K Mean thành công để phân loại khách hàng và phân loại nhóm đối tượng để bắn coupon cho hiệu quả (ví dụ: team marketing có 3 loại coupon cần gửi cho khách, bạn có thể dùng K Mean để tìm ra 3 nhóm này trong tập khách hàng của bạn dựa theo số đơn hàng, loại món, giờ mua hàng, tần suất mua hàng).

K Mean hoạt động theo cách cơ bản như sau: giả sử bạn có 1 loạt các điểm X, Y trong không gian.

Bước 1: Thuật toán sẽ tạo ra một số điểm bất kì trong không gian, ví dụ bạn muốn chia thành 3 nhóm thì k = 3. 3 điểm này gọi là centroids. Bước 2: Với mỗi điểm dữ liệu, nó sẽ tạm thời được phân vào một nhóm (cluster) dựa theo khoảng cách của điểm dữ liệu tới điểm k gần nhất. Bước 3: Với mỗi cluster này, tính mean của các điểm rồi gán điểm mean này là centroids mới Bước 4: Người ta sẽ lặp đi lặp lại bước 2 và 3 cho tới khi kết quả không còn thay đổi nhiều.

Bạn có thể xem được các bước này trong hình dưới.

1_KrcZK0xYgTa4qFrVr0fO2w

Một cái hạn chế của K Mean là bạn buộc phải định nghĩa cho thuật toán biết bạn muốn tìm ra bao nhiêu nhóm. Bạn phải biết trước số này. Có một cách mình hay dùng để chọn số K, đó là thuật toán Elbow. Xem chi tiết ở đây, 61 còn bên dưới là một biểu đồ của mình để chọn K, thấy nó gấp khúc ngay K = 2 nên mình chọn phân làm 2 nhóm.

Unknown

Code để implement K Mean thì dễ lắm. Cứ lấy một dataframe X với một loạt các features cần phân loại bỏ vào là xong.

# Number of clusters

kmeans = KMeans(n_clusters=2)

# Fitting the input data

kmeans = kmeans.fit(X)

# Getting the cluster labels

labels = kmeans.predict(X)

# Centroid values

centroids = kmeans.cluster_centers_

Với K Mean, nhớ cẩn thận dữ liệu NULL, dữ liệu sai, hoặc các nhóm quá lệch nhau. Có thể nó sẽ cho ra kết quả rất khác nhau đấy.

Mean Shifting

Thuật toán này cũng có thể giải những bài toán tương tự như trên với phân bố dữ liệu không có gì quá đặc biệt. Mình sẽ dùng Mean Shifting (MS) khi K Mean cho ra kết quả không phù hợp hoặc có gì đó lạ lạ so với thực tế, hoặc giải pháp elbow không đưa ra được một con số K đủ tốt để chọn. Các bạn có kinh nghiệm nào khi dùng MS thì chia sẻ thêm nhé.

Trong Mean Shift, bạn cũng chọn 1 số điểm để bắt đầu. Các điểm này sẽ dần dần dịch chuyển về khu vực có mật độ data dày hơn, như hình bên dưới. Bạn thấy là mấy cái chấm màu đen không dịch ra xa về phía khu vực có nhiều khoảng trống mà toàn dịch vào tâm của các điểm dữ liệu.

meanshift

Điều này có được là do chúng dịch chuyển một khoảng = mean của các điểm nằm trong một khu vực mà bạn muốn xét (khu vực này gọi là window). Cũng vì phương thức dịch chuyển (shift) dựa vào mean nên thuật toán này mới có cái tên như trên. Sau khi lặp đi lặp lại nhiều lần, những điểm nằm trong cùng window sẽ được nhóm thành 1 nhóm.

MS có cái hay là bạn không cần chọn trước số nhóm cần phân loại. Thuật toán có thể tìm được số nhóm đó cho bạn luôn vì chúng sẽ dịch chuyển tự động.

Cái khó của MS là chọn window – bán kính vùng quét để tính mean – là bao nhiêu. Mình hiện đang dùng hàm estimate_bandwidth của SkLearn để chọn thông số này.

bandwidth = estimate_bandwidth(your_dataset, quantile=0.2, n_samples=500)

ms = MeanShift(bandwidth=bandwidth, bin_seeding=True)

ms.fit(X)

labels = ms.labels_

cluster_centers = ms.cluster_centers_

labels_unique = np.unique(labels)

n_clusters_ = len(labels_unique)

#add the label back to the dataframe

df_run[‘meanshift_grouping_label’] = labels

print(“number of estimated clusters : %d” % n_clusters_)

Đang thấy có cái Agglomerative Hierarchical Clustering khá thú vị, để mình thử rồi có gì sẽ chia sẻ với các bạn trong bài viết mới.

]]>
Categories
GIS

[Note] PostgreSQL – Snap points to nearest line

Hallo

If you have your data stored in PostGIS you can do it directly in the

database.

To get a new table with the snapped points and the line attribudes you

can run:

CREATE TABLE line_attribute_point AS

SELECT distinct on (linetable.id) linetable.*,

ST_ClosestPoint(linetable.geom, pointtable.geom) as snapped_point

FROM

linetable,pointtable

ORDER BY ST_Distance(linetable.geom, pointtable.geom);

Something like that.

But this will be slow if you have many points and polygons. Then you can

use ST_Dwithin to speed it up if you know how far away the line and

point can be that should be snapped. Say you don’t want to snap longer

than 100 meters then:

CREATE TABLE line_attribute_point AS

SELECT distinct on (linetable.id) linetable.*,

ST_ClosestPoint(linetable.geom, pointtable.geom) as snapped_point

FROM

linetable INNER JOIN pointtable on ST_Dwithin(linetable.geom,

pointtable.geom, 100)

ORDER BY ST_Distance(linetable.geom, pointtable.geom);

Something like that.

HTH

Nicklas

http://osgeo-org.1560.x6.nabble.com/Snap-points-to-nearest-line-td4126948.html

Hi Cameron

Two suggestions, but not an excact solution:

You can use the mmqgis plugin and select “Hub Distance”. With this you can transfer an attribute (or an ID and then use a join afterwards) to a pointlayer from the nearest line in a linelayer.

But be aware that “nearest” line will be based only on a “centre point” for the line and if your lines are very curved or of varying lengths you may not get the expected result.

You might use the “Vector-Geometry Tools-Extract Nodes” to convert your line layer to a point layer and use this point layer as the Hublayer instead of the line layer.

Anybody knows an excact method?

]]>