From 174de1034b3b66dcf37516f593726eae976eb4f4 Mon Sep 17 00:00:00 2001 From: Victor Phan Date: Sun, 14 Dec 2025 09:36:37 +0700 Subject: [PATCH] =?UTF-8?q?c=E1=BA=ADp=20nh=E1=BA=ADt=20=20ch=E1=BB=A9c=20?= =?UTF-8?q?n=C4=83ng=20predict=20c=C3=A1c=20lo=E1=BA=A1i=20=C4=91=E1=BA=A5?= =?UTF-8?q?t?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __pycache__/api_server.cpython-310.pyc | Bin 11817 -> 13759 bytes api_server.py | 189 +++++++++-- .../giai_thich_quy_trinh_phan_loai_dat.md | 164 ++++++++++ requirement.txt | 309 ++++++++++++++++++ 4 files changed, 626 insertions(+), 36 deletions(-) create mode 100644 document/giai_thich_quy_trinh_phan_loai_dat.md create mode 100644 requirement.txt diff --git a/__pycache__/api_server.cpython-310.pyc b/__pycache__/api_server.cpython-310.pyc index c6efe027e6c6f2d457565731b1489d1fd21759de..4463aa3ef2f36cfec00a12fc6194ecf1bfcb8c88 100644 GIT binary patch delta 3565 zcmaJ?S!^4}8Q$4lE)P-EVcn9g)h*g0by$)W#dhNRkR7MCYd4Do%!;!Tmm-()?2@*G z*|Lt%rk4r_G*FVj9=u2PuP=I~&OZyZQ=@ImwB_%5fP!T)x z&p-eFegAxO=)v1hmjbEUS|1008$Ad0&(A*!taP`|z>xWh@R_p`$6ZG^_||R5Zi+egbTcT3lTj0!T%ZEM8cZ<8juc7ylRg?Eqseo*^ zRZHDgV2vkp)Sa)xUhsJw%LkU%5UJbtVA1yCnhHKoJDzKk6&;V}3?eOckE#OXw@55c|F1r!$tj09rUF}@HA9usbchE*GZ;hJh4%*bl zv9^`NJ*^yQ+l+g&v@yexFCerRh+Ak2?pxxa?O);#bI=b|`$5**t+Y8mKwIlLfN#b_ zRnq48ARflSbrc_}^mZHGU7c%-592*}WF6&$1a$~C$!*c~8I zM^&Ou+Ia(!HQKpNn@&fYPDh)uZQ68xO`CD14Qyq7t_tLHm2S^l8Zdw$)Oq;AD z)lL{rZb`KZPgSeixxIR)@@~58TRs_2+dW1t-dD-OGcc0yD=$ZQwqnDkw#WCt-uF7z z2w2%Z#|(klPy1+p6K4-Ba`vDVroC(EDECf-Jp@Ukbcl%K{~R?Ga4ZMivzglYk=}M$_xP>EX={N%G#KB9+uAv}0|&SE*^{54K`0?iy;w}cD?$#hx~Vt+3Jo*wWzG;0 z$9`{dOw9$}9;M;@EFFc}G5lI}TT%Q~ItHqa(DrORgkQhS<3srHB9D*Yqi{>d;Q=}Z z8!|yB;`{M5KE4h@Qz3t#z~v9(69BcBPT-StFO+ubjsO>F5}&T_@N00B=GJ&9>?UoD zzaBqSE%PQFhtc7xZyKLj=MiUkXx4G#vq0mxoUkL-Q98MX@EiCX3j?u^(J`Q%qElcW zr&9$~$H8$u0cT+f&j9tC`#JobY6(s**yrITt=PNhC~U(Ndy+O)rMsZC@;sJfA+lK7{$V}Y?U`Ymd7T-%S6L^)QX%tdL*nbuNd<=U*8>f5D^0ZZ65!o zZw%%B+J7Xw2S(3ssE}?IKQUsml`0kt`HiEOPRW^KUcOe|_(V<=KbMomyDQ;vSP>47 z%_#1LL`t>xPO#DB;_T1I{`QNNV+R%C!jUsC1OR;DVT~6Wat4}o5Sj|fvk&z0#&ttp z)Qbh#BIS2BekRYCp^3({O%C!a2oIu?fc0ehTlJAN)H+{$2(>y@S}`ppTQR75(W!6z z>@ip*gGh&R|LE(_j?2U6RjiUAOs@t^&9HPsON7Ql#EJ$5@=J&$KVnTSG^@?B8PyEU zlrL-rvb;u9wPw|MGnGhNS|mm0bt~wqq}^t@cUUtDjUp!WC9T9~V(?|sBV2ZK=~aEV z)qm;a=%q_g`}PG~OwR(!T&(y9XGDkKRl2p@Lfr?yL zV;a#E*TRCHNGPs(r}MzpsLADoRuYq%YAEh#D!B~D)wvAh7NgXmDY*z-cTEv>Q%jVj zjG9PmCcDzAWoZU6Aw=;<;h-mt2%}#r2}wO`C=$Tys~W6Zh1I4aMmk9zuwZxfsZknq z1GF@?hy@JhLW(36HzY9)74K2iQV&(umt4X+A#bx zc&`#2ZW}XmJ;QC1OE-Z#H#6MZIYZ`H7=Mi@ys=#3u|*y-JRYmLE5m)$k6=K4&l>jJ zmE2KaPox$rH}-vSDPD6TVrnXh#uN{jK$J9dPlr3Qf*DOHzGxzq#*rlKic-TiHNqs; zu;Oan}MDADCZB( zq2J{$1P6DVMjXfgKomX5BY2P>!I%4KurupN63-(MNnbU&8evWpM8v}n{QvR0MTiUV zO^6qm&j%kw{@ddX2m#dOAjtw?2~C1WsAuD?eCfY_N#a@5_FNuG|7!9DP=MvYoRsA~ zyo5YF5D7lP2NWJ80%RkE_yo!EGzu`{neU|)5L#F~lodb{lm*%Fi7*xcOZ-X_f$B?7 zjUO_hFup@*LG^qS?*m#7&jgTwmj@q9hL5ex_s^D^$3we+&7)6qe;oNUx|zEfvOBn} OuLe~6#;=7JzxW^Uqz~o* delta 1666 zcmZ8gTW=Fb6rR~#uQ!fwNqmiy*iJ%7NN^kocQ>Ww(g#$j7o@6NP-J;F&Kh6R*$Fgg zwl1|=iqur0`&LNtRuwJk6XLC@)CYLv7x<~^ALvsb5D4{*9eAi$^PMy2@|`nh#(!RU za4Fab1bhg7_X`DcdFf$rBORZBt*||YWqlwcbOUeU>ow=c^ueae5RnRqd5E`#IjX2B zWP7-$?RAlrXByFj?GDYZ=aMkt_ z#nwoFkDtgysRr%7t_;~e-d71%28h4OeU(8H*p%#kC^Q5s0xJqDR#t33$oL&Zf*=#n zglq>$s7J{AD@hVAWA5hxGC&3)V%WqcCPSNw9b_pUY>&98h3yazSzBzBM8pAjh$s*_ z_LY=Gc8Ek-GtEOS3?*XQ^6O6H)lAK2hcV(|9^!tIAW8U!@5&?v$yqY8>9GgM=w2fO zWDLj#`2b0S9O8p~D1ijV5y`|6%rn9xm2r|K5L!tUb*W?HL!j7^6@B;!^tnkHMIe+}obzNzjHx28>o@%-JbE z+&;)tU?1VQlH()borjetlXoSuk4%*%vY$-DoJLvGLuOz|V|=W#Kn{@EO(?;Jf9K5V?(gnKW{n!eEHSfD2enZ$EX$dm+J5wODv!N0m{N#zUhF@E zC!N#N(etIpZYfh*-QBsBv37TE=W;n+emj3$z+(C2xB0)n+c>wROAGHp>JN~*9szi= zRjijYWOwIb=E?2GW4G?8vlsA1=l$7voOEu?CYOL`2J2q4zE&-k4Bhk2MRR2ZEGnVq zRfC?VDWIX>2p9pF@pMJUW33j~4Bh!>HW{Na;Y|pL3b-ZWPCM_-O*%K{R-I>aW>eQ1 zq?EH*u|(&=t83J-inX<>(NStfvEK1e=+o%-tt+NwR6FX`Vs+iHs3pR^E7c-nMqT%p z8rAh$eOWMF(Y<>Uq;59|IJ-^toh`EBTa*?z=pArS6CFUPlmKUhB{@fgoM3o3tato$E@STs3vSz~x$_&Q_}%dSJyUvUNDZ za@Dk02Qyvm`kAi1^3Z#N&$mXMNdByIIX~X~0}Rp^ilSjn*03Lgl!Bmzu}|{JKCmc~ z0yg1QB?&87eHrl#f<=)PEWzi;>I=UYVsKE3NPb0vC<*&uLF{u)(||jI!?MU2#6iI< z`{W>SE3!1-rB`06iiFi?TE8Di!ayF81&W45QGd6P?|IDoXlLP`gnxEES$vAWcczcn P311Xi{@)jqlz;yNaqp|S diff --git a/api_server.py b/api_server.py index e2f670d..9f1455e 100644 --- a/api_server.py +++ b/api_server.py @@ -330,7 +330,7 @@ def update_prediction_progress(message: str): async def run_prediction(config: PredictionConfig): - """Chạy prediction process""" + """Chạy prediction process - Áp dụng phương pháp từ 02.predict_ODC.ipynb""" global prediction_status try: @@ -341,6 +341,7 @@ async def run_prediction(config: PredictionConfig): import numpy as np from datetime import datetime as dt import rioxarray + import dask.array as da prediction_status["progress"] = "Đang load model..." @@ -364,6 +365,7 @@ async def run_prediction(config: PredictionConfig): # Import and use Microsoft Planetary Computer STAC API import pystac_client import planetary_computer + from odc.stac import load catalog = pystac_client.Client.open( "https://planetarycomputer.microsoft.com/api/stac/v1", @@ -373,65 +375,168 @@ async def run_prediction(config: PredictionConfig): bbox = [config.min_lon, config.min_lat, config.max_lon, config.max_lat] time_range = f"{config.start_date}/{config.end_date}" + # ============ BƯỚC 1: TẢI DỮ LIỆU SENTINEL-2 ============ prediction_status["progress"] = "Đang tải dữ liệu Sentinel-2..." # Search Sentinel-2 data - search = catalog.search( + s2_search = catalog.search( collections=["sentinel-2-l2a"], bbox=bbox, datetime=time_range, query={"eo:cloud_cover": {"lt": config.cloud_cover}} ) - items = list(search.items()) # Changed from items_as_dicts() to items() - if not items: + s2_items = list(s2_search.items()) + if not s2_items: raise ValueError("Không tìm thấy dữ liệu Sentinel-2 cho khu vực và thời gian này") - items = items[:config.max_scenes] - - prediction_status["progress"] = f"Đang xử lý {len(items)} scenes Sentinel-2..." - - # Load and process Sentinel-2 data (simplified) - # Note: This is a simplified version. Full implementation would need more processing - from odc.stac import load + s2_items = s2_items[:config.max_scenes] + prediction_status["progress"] = f"Đang xử lý {len(s2_items)} scenes Sentinel-2..." + # Load Sentinel-2 data s2_data = load( - items, + s2_items, bbox=bbox, chunks={"time": 1, "x": 2048, "y": 2048}, groupby="solar_day", resolution=config.resolution ) - prediction_status["progress"] = "Đang tính toán các chỉ số..." + # ============ BƯỚC 2: TÍNH NDVI VÀ XỬ LÝ MÂY ============ + prediction_status["progress"] = "Đang tính toán NDVI và xử lý mây..." - # Calculate NDVI using Sentinel-2 band names - # B08 = NIR, B04 = Red - nir = s2_data["B08"] # NIR band - red = s2_data["B04"] # Red band - ndvi = (nir - red) / (nir + red + 1e-8) # Add small value to avoid division by zero + # Calculate NDVI using Sentinel-2 band names (B08 = NIR, B04 = Red) + nir = s2_data["B08"].astype('float32') + red = s2_data["B04"].astype('float32') + ndvi = (nir - red) / (nir + red + 1e-8) - # Resample to monthly - ndvi_monthly = ndvi.resample(time="1M").mean() + # Mask clouds using SCL band if available + if "SCL" in s2_data: + scl = s2_data["SCL"] + # SCL values: 4=vegetation, 5=bare soil, 6=water - these are clear + # 3=cloud shadow, 8=cloud medium, 9=cloud high, 10=cirrus - mask these + cloud_mask = (scl == 3) | (scl == 8) | (scl == 9) | (scl == 10) + ndvi = ndvi.where(~cloud_mask) - prediction_status["progress"] = "Đang dự đoán..." + # ============ BƯỚC 3: ĐIỀN GIÁ TRỊ NAN (FILL NAN) ============ + prediction_status["progress"] = "Đang điền giá trị bị che mây..." - # Prepare features for prediction - features_list = [] - for t in range(len(ndvi_monthly.time)): - ndvi_t = ndvi_monthly.isel(time=t).values - features_list.append(ndvi_t.flatten()) + # Fill NaN using forward fill and backward fill + ndvi_filled = ndvi.ffill(dim='time').bfill(dim='time') - # Stack features - features = np.column_stack(features_list) + # Resample to monthly average + prediction_status["progress"] = "Đang tính trung bình NDVI theo tháng..." + ndvi_monthly = ndvi_filled.resample(time="1ME").mean() + + # Compute NDVI (convert from dask to numpy) + ndvi_monthly = ndvi_monthly.compute() + + # ============ BƯỚC 4: TẢI DỮ LIỆU SENTINEL-1 (VH, VV) ============ + prediction_status["progress"] = "Đang tải dữ liệu Sentinel-1 (Radar)..." + + # Search Sentinel-1 data + s1_search = catalog.search( + collections=["sentinel-1-rtc"], + bbox=bbox, + datetime=time_range, + ) + + s1_items = list(s1_search.items()) + + if s1_items: + s1_items = s1_items[:config.max_scenes] + prediction_status["progress"] = f"Đang xử lý {len(s1_items)} scenes Sentinel-1..." + + # Load Sentinel-1 data + s1_data = load( + s1_items, + bbox=bbox, + chunks={"time": 1, "x": 2048, "y": 2048}, + groupby="sat:absolute_orbit", + resolution=config.resolution, + like=ndvi_monthly # Align with NDVI grid + ) + + # Extract VH and VV bands + if "vh" in s1_data and "vv" in s1_data: + vh = s1_data["vh"].astype('float32') + vv = s1_data["vv"].astype('float32') + + # Resample to monthly average + prediction_status["progress"] = "Đang tính trung bình VH/VV theo tháng..." + vh_monthly = vh.resample(time="1ME").mean().compute() + vv_monthly = vv.resample(time="1ME").mean().compute() + + use_radar = True + else: + prediction_status["progress"] = "Không tìm thấy bands VH/VV, tiếp tục với NDVI..." + use_radar = False + else: + prediction_status["progress"] = "Không có dữ liệu Sentinel-1, tiếp tục với NDVI..." + use_radar = False + + # ============ BƯỚC 5: CHUẨN BỊ FEATURES CHO DỰ ĐOÁN ============ + prediction_status["progress"] = "Đang chuẩn bị features cho dự đoán..." + + # Get shape information + n_times_ndvi = len(ndvi_monthly.time) + y_size = len(ndvi_monthly.y) + x_size = len(ndvi_monthly.x) + n_pixels = y_size * x_size + + # Prepare NDVI features (flatten each time step) + ndvi_features = [] + for t in range(n_times_ndvi): + ndvi_t = ndvi_monthly.isel(time=t).values.flatten() + ndvi_features.append(ndvi_t) + + # Stack NDVI features + features = np.column_stack(ndvi_features) + + # Add radar features if available + if use_radar: + n_times_vh = len(vh_monthly.time) + n_times_vv = len(vv_monthly.time) + + # Add VH features + for t in range(min(n_times_vh, n_times_ndvi)): + vh_t = vh_monthly.isel(time=t).values.flatten() + # Resize if needed + if len(vh_t) != n_pixels: + vh_t = np.resize(vh_t, n_pixels) + features = np.column_stack([features, vh_t]) + + # Add VV features + for t in range(min(n_times_vv, n_times_ndvi)): + vv_t = vv_monthly.isel(time=t).values.flatten() + # Resize if needed + if len(vv_t) != n_pixels: + vv_t = np.resize(vv_t, n_pixels) + features = np.column_stack([features, vv_t]) + + # Handle NaN values in features + features = np.nan_to_num(features, nan=0.0) + + # ============ BƯỚC 6: DỰ ĐOÁN ============ + prediction_status["progress"] = f"Đang dự đoán với {features.shape[1]} features..." # Make prediction predictions = model.predict(features) + # Decode labels if label_encoder exists + if label_encoder is not None: + try: + predictions = label_encoder.inverse_transform(predictions) + except: + pass # Keep numeric predictions if inverse_transform fails + # Reshape to original shape - pred_shape = ndvi_monthly.isel(time=0).shape + pred_shape = (y_size, x_size) predictions_2d = predictions.reshape(pred_shape) + # ============ BƯỚC 7: TẠO OUTPUT VÀ LƯU KẾT QUẢ ============ + prediction_status["progress"] = "Đang tạo bản đồ phân loại..." + # Create output xarray prediction_da = xr.DataArray( predictions_2d, @@ -450,21 +555,33 @@ async def run_prediction(config: PredictionConfig): timestamp = dt.now().strftime("%Y%m%d_%H%M%S") output_file = output_dir / f"prediction_{timestamp}.tif" - prediction_status["progress"] = "Đang lưu kết quả..." + prediction_status["progress"] = "Đang lưu kết quả GeoTIFF..." - # Save as GeoTIFF - prediction_da.rio.write_crs(s2_data.rio.crs, inplace=True) - prediction_da.rio.to_raster(output_file, driver="GTiff") + # Set CRS and save as GeoTIFF + if hasattr(s2_data, 'rio') and s2_data.rio.crs is not None: + prediction_da.rio.write_crs(s2_data.rio.crs, inplace=True) + else: + prediction_da.rio.write_crs("EPSG:4326", inplace=True) + + prediction_da.rio.to_raster(str(output_file), driver="GTiff") + + # Get unique classes for result + unique_classes = np.unique(predictions_2d) + unique_classes = unique_classes[~np.isnan(unique_classes)].tolist() prediction_status["is_predicting"] = False prediction_status["progress"] = "Hoàn thành!" prediction_status["output_file"] = str(output_file) prediction_status["result"] = { "output_file": str(output_file), - "shape": pred_shape, - "unique_classes": np.unique(predictions).tolist(), + "shape": list(pred_shape), + "unique_classes": unique_classes, "bbox": bbox, - "time_range": time_range + "time_range": time_range, + "n_features": features.shape[1], + "n_times_ndvi": n_times_ndvi, + "used_radar": use_radar, + "model_used": config.model_filename } prediction_status["end_time"] = dt.now().isoformat() diff --git a/document/giai_thich_quy_trinh_phan_loai_dat.md b/document/giai_thich_quy_trinh_phan_loai_dat.md new file mode 100644 index 0000000..297ed3b --- /dev/null +++ b/document/giai_thich_quy_trinh_phan_loai_dat.md @@ -0,0 +1,164 @@ +# 🌾 Giải Thích Quy Trình Phân Loại Đất Trồng Cây + +File notebook `02.predict_ODC.ipynb` sử dụng **Machine Learning** kết hợp với **dữ liệu vệ tinh** để phân loại các loại đất/cây trồng. Dưới đây là quy trình chi tiết: + +--- + +## **Bước 1: Thu thập dữ liệu vệ tinh** (Cell 3-4) + +```python +date_range = ('2022-09-01', '2023-10-01') +longtitude_range = (105.86575, 105.94120) +latitude_range = (9.65070, 9.69850) +data = load_data(dc, date_range, longtitude_range, latitude_range) +``` + +- Lấy ảnh **Sentinel-2** (ảnh quang học) từ kho dữ liệu trong khoảng thời gian và vị trí cụ thể + +--- + +## **Bước 2: Xử lý mây** (Cell 5) + +```python +result = mask_clean(data) +``` + +- Loại bỏ các pixel bị mây che phủ để đảm bảo dữ liệu chính xác + +--- + +## **Bước 3: Tính chỉ số NDVI** (Cell 6-10) + +```python +ndvi = calculate_indices(result, index='NDVI', satellite_mission='s2') +fill_nan_ndvi = fill_nan(ndvi, time_split) +average_ndvi = fill_nan_ndvi.resample(time='1M').mean() +``` + +- **NDVI** (Normalized Difference Vegetation Index) = (NIR - Red) / (NIR + Red) +- Giá trị từ **-1 đến 1**: cao = thực vật xanh tốt, thấp = đất trống/nước +- Điền giá trị nan (mây) và tính trung bình theo tháng + +--- + +## **Bước 4: Lấy dữ liệu Radar Sentinel-1** (Cell 11) + +```python +dsvh, dsvv = load_data_sen1(dc, date_range, coordinates) +average_vv = calculate_average(dsvv, time_pattern='1M') +average_vh = calculate_average(dsvh, time_pattern='1M') +``` + +- **VH, VV**: Dữ liệu radar (xuyên mây), cho biết cấu trúc bề mặt +- Giúp phân biệt lúa ngập nước, cây trồng cạn, mặt nước... + +--- + +## **Bước 5: Dự đoán bằng Model ML** (Cell 12) ⭐ **QUAN TRỌNG NHẤT** + +```python +loaded_model = joblib.load("model_train/model_odc.joblib") +data_array = predict(loaded_model, data.rio.crs, average_ndvi, average_vh, average_vv) +``` + +**Model đã được train trước** với dữ liệu mẫu (training data) gồm: +- **Đầu vào (Features)**: NDVI theo tháng + VH + VV (chuỗi thời gian) +- **Đầu ra (Labels)**: Loại đất đã được gắn nhãn thủ công + +### Cách model phân loại: + +| Đặc điểm | Loại đất | +|----------|----------| +| NDVI cao đều, VV thấp | Rừng | +| NDVI biến đổi theo mùa vụ, VH cao (nước) | Lúa | +| NDVI thấp, VV rất thấp | Sông/nước | +| NDVI trung bình ổn định | Cây lâu năm (CLN) | + +--- + +## **Bước 6: Hiển thị kết quả** (Cell 13-15) + +```python +colors = ["#abcee9", "#ffef44", "#c4ff9e", "#ffd6a8", "#93ddda", "#1aeef7", "#ffa7f2", "#33ee33"] +labels = ["Lúa tôm", "Lúa", "CHN", "CLN", "TS", "Sông", "Đất xây dựng", "Rừng"] +``` + +### 8 lớp phân loại: + +| Mã | Tên | Màu | Ý nghĩa | +|----|-----|-----|---------| +| 0 | Lúa tôm | 🔵 Xanh nhạt | Luân canh lúa-tôm | +| 1 | Lúa | 🟡 Vàng | Đất trồng lúa | +| 2 | CHN | 🟢 Xanh lá nhạt | Cây hàng năm | +| 3 | CLN | 🟠 Cam nhạt | Cây lâu năm (cây ăn trái) | +| 4 | TS | 🩵 Xanh ngọc | Thủy sản | +| 5 | Sông | 🔷 Cyan | Mặt nước sông | +| 6 | Đất XD | 💗 Hồng | Đất xây dựng | +| 7 | Rừng | 💚 Xanh đậm | Rừng | + +--- + +## **Bước 7: Lưu kết quả** (Cell 16) + +```python +region_result.rio.to_raster("KetQuaPhanLoaiDatODC.tif") +``` + +- Xuất file GeoTIFF chứa mã phân loại (0-7) cho từng pixel + +--- + +## 📊 **Tóm tắt quy trình:** + +``` +Ảnh vệ tinh (Sentinel-1 + Sentinel-2) + ↓ +Xử lý (loại mây, tính NDVI, VH, VV) + ↓ +Kết hợp features theo thời gian (13 tháng) + ↓ +Model ML (Random Forest/XGBoost) dự đoán + ↓ +Bản đồ phân loại 8 lớp đất + ↓ +File .tif (mỗi pixel = 1 mã loại đất) +``` + +--- + +## 📁 Cấu trúc dữ liệu đầu vào cho Model + +### Features (Đặc trưng): +- **NDVI theo 13 tháng**: 13 bands +- **VH (radar) theo 13 tháng**: 13 bands +- **VV (radar) theo 13 tháng**: 13 bands +- **Tổng cộng**: ~39 features cho mỗi pixel + +### Labels (Nhãn): +- Được lấy từ shapefile training: `train/ST_training data_updated_1130points_new.shp` +- 1130 điểm mẫu đã được gắn nhãn thủ công bởi chuyên gia + +--- + +## 🔧 Các thư viện sử dụng + +| Thư viện | Mục đích | +|----------|----------| +| `datacube` | Truy vấn dữ liệu vệ tinh | +| `xarray` | Xử lý dữ liệu đa chiều | +| `rioxarray` | Đọc/ghi GeoTIFF | +| `joblib` | Load/save model ML | +| `sklearn` / `xgboost` | Training model | +| `matplotlib` / `hvplot` | Trực quan hóa | + +--- + +## 📝 Ghi chú + +- **Độ phân giải**: 10-20m (tùy cấu hình) +- **Thời gian xử lý**: Phụ thuộc vào kích thước vùng và số scenes +- **Yêu cầu**: Cần kết nối internet để tải dữ liệu vệ tinh từ Planetary Computer hoặc ODC + +--- + +*Tài liệu được tạo ngày 14/12/2025* diff --git a/requirement.txt b/requirement.txt new file mode 100644 index 0000000..4732269 --- /dev/null +++ b/requirement.txt @@ -0,0 +1,309 @@ +affine @ file:///home/conda/feedstock_root/build_artifacts/affine_1733762038348/work +aiobotocore==2.25.0 +aiohappyeyeballs==2.6.1 +aiohttp==3.12.15 +aioitertools==0.12.0 +aiosignal==1.4.0 +alembic==1.16.5 +annotated-doc==0.0.4 +annotated-types==0.7.0 +antimeridian @ file:///home/conda/feedstock_root/build_artifacts/antimeridian_1753706324394/work +anyio @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_anyio_1758634638/work +argon2-cffi @ file:///home/conda/feedstock_root/build_artifacts/argon2-cffi_1749017159514/work +argon2-cffi-bindings @ file:///home/conda/feedstock_root/build_artifacts/argon2-cffi-bindings_1649500328244/work +arrow @ file:///home/conda/feedstock_root/build_artifacts/arrow_1733584251875/work +asciitree==0.3.3 +asttokens @ file:///home/conda/feedstock_root/build_artifacts/asttokens_1733250440834/work +async-lru @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_async-lru_1742153708/work +async-timeout==3.0.1 +attrs @ file:///home/conda/feedstock_root/build_artifacts/attrs_1741918516150/work +babel @ file:///home/conda/feedstock_root/build_artifacts/babel_1738490167835/work +beautifulsoup4 @ file:///home/conda/feedstock_root/build_artifacts/beautifulsoup4_1759146011391/work +bleach @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_bleach_1737382993/work +blinker==1.9.0 +bokeh==3.7.3 +boto3==1.40.18 +botocore==1.40.49 +Bottleneck @ file:///croot/bottleneck_1731058641041/work +branca @ file:///croot/branca_1675157607453/work +Brotli @ file:///croot/brotli-split_1736182456865/work +brotlicffi @ file:///croot/brotlicffi_1736182461069/work +cached-property @ file:///home/conda/feedstock_root/build_artifacts/cached_property_1615209429212/work +cachetools==6.2.0 +Cartopy==0.25.0 +certifi @ file:///home/conda/feedstock_root/build_artifacts/certifi_1759648874697/work/certifi +cffi @ file:///croot/cffi_1736182485317/work +cftime @ file:///home/conda/feedstock_root/build_artifacts/cftime_1649636873066/work +chardet @ file:///home/conda/feedstock_root/build_artifacts/chardet_1649184137891/work +charset-normalizer @ file:///croot/charset-normalizer_1721748349566/work +ciso8601==2.3.3 +click @ file:///home/conda/feedstock_root/build_artifacts/click_1747811314515/work +click-plugins @ file:///home/conda/feedstock_root/build_artifacts/click-plugins_1750848229740/work +cligj @ file:///home/conda/feedstock_root/build_artifacts/cligj_1733749956636/work +cloudpickle @ file:///home/conda/feedstock_root/build_artifacts/cloudpickle_1736947526808/work +colorama==0.4.6 +colorcet==3.1.0 +comm @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_comm_1753453984/work +contourpy @ file:///croot/contourpy_1732540045555/work +cycler @ file:///tmp/build/80754af9/cycler_1637851556182/work +cytoolz==0.11.2 +dask @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_dask-core_1760473436/work +dask-gateway @ file:///Users/runner/miniforge3/conda-bld/bld/rattler-build_dask-gateway_1744370153/work/dask-gateway +dask-glm @ file:///home/conda/feedstock_root/build_artifacts/dask-glm_1701346265909/work +dask-image==2024.5.3 +dask-ml @ file:///home/conda/feedstock_root/build_artifacts/dask-ml_1679705292494/work +datacube==1.8.15 +datacube_ows==1.9.4 +datashader==0.18.2 +dea-tools==0.3.0 +debugpy @ file:///home/task_175706711740264/conda-bld/debugpy_1757067131873/work +decorator @ file:///home/conda/feedstock_root/build_artifacts/decorator_1740384970518/work +deepdiff==8.6.1 +defusedxml @ file:///home/conda/feedstock_root/build_artifacts/defusedxml_1615232257335/work +deprecat @ file:///home/conda/feedstock_root/build_artifacts/deprecat_1734684036993/work +distributed @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_distributed_1760476147/work +eo-tides==0.8.2 +exceptiongroup @ file:///home/conda/feedstock_root/build_artifacts/exceptiongroup_1746947292760/work +executing @ file:///home/conda/feedstock_root/build_artifacts/executing_1756729339227/work +fastapi==0.124.3 +fasteners @ file:///home/conda/feedstock_root/build_artifacts/fasteners_1734943108928/work +fastjsonschema @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_python-fastjsonschema_1755304154/work/dist +filelock==3.19.1 +fiona==1.10.1 +Flask==3.1.2 +flask-babel==4.0.0 +flatbuffers==25.2.10 +folium==0.20.0 +fonttools @ file:///croot/fonttools_1737039080035/work +fqdn @ file:///home/conda/feedstock_root/build_artifacts/fqdn_1733327382592/work/dist +frozenlist==1.7.0 +fsspec @ file:///home/conda/feedstock_root/build_artifacts/fsspec_1756908513222/work +GDAL @ file:///croot/gdal-split_1734448174900/work/build/swig/python +GeoAlchemy2 @ file:///home/conda/feedstock_root/build_artifacts/geoalchemy2_1753372953474/work +geographiclib==2.1 +geojson==3.2.0 +geomad==1.0.0 +geopandas @ file:///croot/geopandas-split_1755761494241/work +geopy==2.4.1 +greenlet @ file:///home/conda/feedstock_root/build_artifacts/greenlet_1648882383677/work +h11 @ file:///home/conda/feedstock_root/build_artifacts/h11_1745526374115/work +h2 @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_h2_1756364871/work +h3==4.3.1 +hdstats==0.2.1 +holoviews==1.21.0 +hpack @ file:///home/conda/feedstock_root/build_artifacts/hpack_1737618293087/work +httpcore @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_httpcore_1745602916/work +httpx @ file:///home/conda/feedstock_root/build_artifacts/httpx_1733663348460/work +hvplot==0.12.1 +hyperframe @ file:///home/conda/feedstock_root/build_artifacts/hyperframe_1737618333194/work +idna==3.10 +imagecodecs==2025.3.30 +imageio==2.37.0 +importlib_metadata @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_importlib-metadata_1747934053/work +ipykernel @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_ipykernel_1760459840/work +ipyleaflet==0.20.0 +ipython @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_ipython_1748711175/work +ipywidgets==8.1.7 +iso8601==2.1.0 +isoduration @ file:///home/conda/feedstock_root/build_artifacts/isoduration_1733493628631/work/dist +itsdangerous==2.2.0 +jedi @ file:///home/conda/feedstock_root/build_artifacts/jedi_1733300866624/work +Jinja2 @ file:///croot/jinja2_1741710844255/work +jmespath @ file:///home/conda/feedstock_root/build_artifacts/jmespath_1733229141657/work +joblib @ file:///home/conda/feedstock_root/build_artifacts/joblib_1756321760188/work +json5 @ file:///home/conda/feedstock_root/build_artifacts/json5_1755034879854/work +jsonpointer @ file:///home/conda/feedstock_root/build_artifacts/jsonpointer_1756754132747/work +jsonschema @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_jsonschema_1755595646/work +jsonschema-specifications==2025.4.1 +jupyter-events @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_jupyter_events_1738765986/work +jupyter-leaflet==0.20.0 +jupyter-lsp @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_jupyter-lsp_1756388269/work/jupyter-lsp +jupyter-ui-poll==1.0.0 +jupyter_client @ file:///home/conda/feedstock_root/build_artifacts/jupyter_client_1733440914442/work +jupyter_core @ file:///home/conda/feedstock_root/build_artifacts/jupyter_core_1748333051527/work +jupyter_server @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_jupyter_server_1755870522/work +jupyter_server_terminals @ file:///home/conda/feedstock_root/build_artifacts/jupyter_server_terminals_1733427956852/work +jupyterlab @ file:///home/conda/feedstock_root/build_artifacts/jupyterlab_1758913905644/work +jupyterlab_pygments @ file:///home/conda/feedstock_root/build_artifacts/jupyterlab_pygments_1733328101776/work +jupyterlab_server @ file:///home/conda/feedstock_root/build_artifacts/jupyterlab_server_1733599573484/work +jupyterlab_widgets==3.0.15 +kiwisolver @ file:///croot/kiwisolver_1737039087198/work +lark==1.2.2 +lark-parser==0.12.0 +lazy_loader==0.4 +linkify-it-py==2.0.3 +llvmlite @ file:///croot/llvmlite_1741209858218/work +locket @ file:///home/conda/feedstock_root/build_artifacts/locket_1650660393415/work +lxml==5.4.0 +lz4 @ file:///croot/lz4_1736366683208/work +Mako @ file:///home/conda/feedstock_root/build_artifacts/mako_1744317760971/work +mapclassify @ file:///croot/mapclassify_1675157730177/work +Markdown==3.9 +markdown-it-py==4.0.0 +MarkupSafe @ file:///croot/markupsafe_1738584038848/work +matplotlib==3.10.5 +matplotlib-inline @ file:///home/conda/feedstock_root/build_artifacts/matplotlib-inline_1733416936468/work +mdit-py-plugins==0.5.0 +mdurl==0.1.2 +mistune @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_mistune_1756495311/work +mpmath==1.3.0 +msgpack @ file:///home/conda/feedstock_root/build_artifacts/msgpack-python_1648745999384/work +multidict @ file:///home/conda/feedstock_root/build_artifacts/multidict_1648882415384/work +multipledispatch @ file:///home/conda/feedstock_root/build_artifacts/multipledispatch_1721907546485/work +narwhals==2.3.0 +nbclient @ file:///home/conda/feedstock_root/build_artifacts/nbclient_1734628800805/work +nbconvert @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_nbconvert-core_1738067871/work +nbformat @ file:///home/conda/feedstock_root/build_artifacts/nbformat_1733402752141/work +nest_asyncio @ file:///home/conda/feedstock_root/build_artifacts/nest-asyncio_1733325553580/work +netCDF4 @ file:///croot/netcdf4_1743512888672/work +networkx @ file:///croot/networkx_1737039604450/work +notebook @ file:///home/conda/feedstock_root/build_artifacts/notebook_1759152069573/work +notebook_shim @ file:///home/conda/feedstock_root/build_artifacts/notebook-shim_1733408315203/work +numba @ file:///croot/numba_1750798165355/work +numcodecs @ file:///croot/numcodecs_1707513121886/work +numexpr @ file:///croot/numexpr_1755766469354/work +numpy @ file:///croot/numpy_and_numpy_base_1755590845055/work/dist/numpy-1.26.4-cp310-cp310-linux_x86_64.whl#sha256=1096d33ad9a9757a1b4b46634d809e894263fc8b78780bff36801684b6e8cc88 +nvidia-cublas-cu12==12.8.4.1 +nvidia-cuda-cupti-cu12==12.8.90 +nvidia-cuda-nvrtc-cu12==12.8.93 +nvidia-cuda-runtime-cu12==12.8.90 +nvidia-cudnn-cu12==9.10.2.21 +nvidia-cufft-cu12==11.3.3.83 +nvidia-cufile-cu12==1.13.1.3 +nvidia-curand-cu12==10.3.9.90 +nvidia-cusolver-cu12==11.7.3.90 +nvidia-cusparse-cu12==12.5.8.93 +nvidia-cusparselt-cu12==0.7.1 +nvidia-nccl-cu12==2.27.3 +nvidia-nvjitlink-cu12==12.8.93 +nvidia-nvtx-cu12==12.8.90 +odc-algo==0.2.3 +odc-geo==0.4.10 +odc-io==0.2.2 +odc-loader @ file:///home/conda/feedstock_root/build_artifacts/odc-loader_1743656085024/work +odc-stac @ file:///home/conda/feedstock_root/build_artifacts/odc-stac_1746136311934/work +odc-ui==0.2.1 +orderly-set==5.5.0 +overrides @ file:///home/conda/feedstock_root/build_artifacts/overrides_1734587627321/work +OWSLib==0.34.1 +packaging @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_packaging_1745345660/work +pandas @ file:///home/task_175982153789305/conda-bld/pandas_1759822248912/work/dist/pandas-2.3.3-cp310-cp310-linux_x86_64.whl#sha256=0de7c83109c411cc2a74419a396c92f65e3d1e457fb4d835e5f100cfb04393a7 +pandocfilters @ file:///home/conda/feedstock_root/build_artifacts/pandocfilters_1631603243851/work +panel==1.7.5 +param==2.2.1 +parso @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_parso_1755974222/work +partd @ file:///home/conda/feedstock_root/build_artifacts/partd_1715026491486/work +pexpect @ file:///home/conda/feedstock_root/build_artifacts/pexpect_1733301927746/work +pickleshare @ file:///home/conda/feedstock_root/build_artifacts/pickleshare_1733327343728/work +pillow @ file:///croot/pillow_1738010226202/work +PIMS==0.7 +planetary-computer==1.0.0 +platformdirs @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_platformdirs_1756227402/work +prometheus_client==0.22.1 +prometheus_flask_exporter==0.23.2 +prompt_toolkit @ file:///home/conda/feedstock_root/build_artifacts/prompt-toolkit_1756321756983/work +propcache==0.3.2 +psutil @ file:///home/conda/feedstock_root/build_artifacts/psutil_1653089181607/work +psycopg2 @ file:///croot/psycopg2_1744919787325/work +ptyprocess @ file:///home/conda/feedstock_root/build_artifacts/ptyprocess_1733302279685/work/dist/ptyprocess-0.7.0-py2.py3-none-any.whl#sha256=92c32ff62b5fd8cf325bec5ab90d7be3d2a8ca8c8a3813ff487a8d2002630d1f +pure_eval @ file:///home/conda/feedstock_root/build_artifacts/pure_eval_1733569405015/work +pyarrow @ file:///home/task_175983338836370/conda-bld/pyarrow_1759833584228/work/python +pycparser @ file:///tmp/build/80754af9/pycparser_1636541352034/work +pyct==0.5.0 +pydantic==2.11.7 +pydantic_core==2.33.2 +Pygments @ file:///home/conda/feedstock_root/build_artifacts/pygments_1750615794071/work +pyogrio @ file:///croot/pyogrio_1741107161422/work +pyows==0.3.1 +pyparsing @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_pyparsing_1753873557/work +pyproj @ file:///croot/pyproj_1739284761968/work +PyQt6==6.7.1 +PyQt6_sip @ file:///croot/pyqt-split_1753427276959/work/pyqt_sip +pyshp==2.3.1 +PySocks @ file:///home/builder/ci_310/pysocks_1640793678128/work +pystac @ file:///home/conda/feedstock_root/build_artifacts/pystac_1758218055393/work +pystac-client==0.9.0 +python-dateutil==2.9.0.post0 +python-dotenv==1.1.1 +python-json-logger @ file:///home/conda/feedstock_root/build_artifacts/python-json-logger_1677079630776/work +python-slugify==8.0.4 +pyTMD==2.2.8 +pytz @ file:///home/conda/feedstock_root/build_artifacts/pytz_1742920838005/work +pyviz_comms==3.0.6 +PyYAML==6.0.2 +pyzmq @ file:///croot/pyzmq_1734687138743/work +rasterio @ file:///croot/rasterio_1740069178893/work +rasterstats==0.20.0 +referencing==0.36.2 +regex==2025.9.1 +requests @ file:///croot/requests_1756709366904/work +rfc3339_validator @ file:///home/conda/feedstock_root/build_artifacts/rfc3339-validator_1733599910982/work +rfc3986-validator @ file:///home/conda/feedstock_root/build_artifacts/rfc3986-validator_1598024191506/work +rfc3987==1.3.8 +rfc3987-syntax @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_rfc3987-syntax_1752876729/work +rioxarray @ file:///home/conda/feedstock_root/build_artifacts/rioxarray_1737140588464/work +rpds-py @ file:///croot/rpds-py_1736541261634/work +ruamel.yaml @ file:///home/conda/feedstock_root/build_artifacts/ruamel.yaml_1649033201098/work +ruamel.yaml.clib==0.2.12 +s3fs==2025.9.0 +s3transfer==0.13.1 +scikit-image==0.25.2 +scikit-learn==1.7.1 +scipy @ file:///croot/scipy_1747238027288/work/dist/scipy-1.15.3-cp310-cp310-linux_x86_64.whl#sha256=2a791554880ad4f358fcc4cd2a982ffe1e9d472e9241011216b2be797457f1f9 +seaborn==0.13.2 +Send2Trash @ file:///home/conda/feedstock_root/build_artifacts/send2trash_1733322040660/work +setuptools-scm==9.2.0 +shapely @ file:///croot/shapely_1754380812723/work +simplejson==3.20.1 +sip @ file:///croot/sip_1738856193618/work +six==1.17.0 +slicerator==1.1.0 +sniffio @ file:///home/conda/feedstock_root/build_artifacts/sniffio_1733244044561/work +snuggs @ file:///home/conda/feedstock_root/build_artifacts/snuggs_1733818638588/work +sortedcontainers @ file:///home/conda/feedstock_root/build_artifacts/sortedcontainers_1738440353519/work +soupsieve @ file:///home/conda/feedstock_root/build_artifacts/soupsieve_1756330469801/work +sparse @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_sparse_1747799051/work +SQLAlchemy==1.4.54 +stack_data @ file:///home/conda/feedstock_root/build_artifacts/stack_data_1733569443808/work +starlette==0.50.0 +sympy==1.14.0 +tblib @ file:///home/conda/feedstock_root/build_artifacts/tblib_1743515515538/work +terminado @ file:///home/conda/feedstock_root/build_artifacts/terminado_1710262609923/work +text-unidecode==1.3 +threadpoolctl @ file:///home/conda/feedstock_root/build_artifacts/threadpoolctl_1741878222898/work +tifffile==2025.5.10 +timescale==0.0.9 +timezonefinder==8.0.0 +tinycss2 @ file:///home/conda/feedstock_root/build_artifacts/tinycss2_1729802851396/work +tomli @ file:///croot/tomli_1753774587605/work +toolz @ file:///home/conda/feedstock_root/build_artifacts/toolz_1733736030883/work +torch==2.8.0 +tornado @ file:///croot/tornado_1748956929273/work +tqdm==4.67.1 +traitlets @ file:///home/conda/feedstock_root/build_artifacts/traitlets_1733367359838/work +traittypes==0.2.1 +triton==3.4.0 +types-python-dateutil @ file:///home/conda/feedstock_root/build_artifacts/types-python-dateutil_1759899809376/work +typing-inspection==0.4.1 +typing_extensions @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_typing_extensions_1756220668/work +typing_utils @ file:///home/conda/feedstock_root/build_artifacts/typing_utils_1733331286120/work +tzdata @ file:///croot/python-tzdata_1746123641790/work +uc-micro-py==1.0.3 +unicodedata2 @ file:///croot/unicodedata2_1736541023050/work +uri-template @ file:///home/conda/feedstock_root/build_artifacts/uri-template_1733323593477/work/dist +urllib3 @ file:///croot/urllib3_1750775463400/work +uvicorn==0.38.0 +wcwidth @ file:///home/conda/feedstock_root/build_artifacts/wcwidth_1733231326287/work +webcolors @ file:///home/conda/feedstock_root/build_artifacts/webcolors_1733359735138/work +webencodings @ file:///home/conda/feedstock_root/build_artifacts/webencodings_1733236011802/work +websocket-client @ file:///home/conda/feedstock_root/build_artifacts/websocket-client_1759928050786/work +Werkzeug==3.1.3 +widgetsnbextension==4.0.14 +wrapt @ file:///home/conda/feedstock_root/build_artifacts/wrapt_1651495243689/work +xarray @ file:///home/conda/feedstock_root/build_artifacts/xarray_1749743207754/work +xgboost==3.1.2 +xyzservices @ file:///croot/xyzservices_1675159059961/work +yarl==1.20.1 +zarr @ file:///home/conda/feedstock_root/build_artifacts/zarr_1733237197728/work +zict @ file:///home/conda/feedstock_root/build_artifacts/zict_1733261551178/work +zipp @ file:///home/conda/feedstock_root/build_artifacts/zipp_1749421620841/work