Bộ lọc chuyển động cho Vertex AI Vision

1. Mục tiêu

Tổng quan

Lớp học lập trình này tập trung vào việc tạo một ứng dụng Vertex AI Vision toàn diện để minh hoạ gửi video có tính năng lọc chuyển động. Trong hướng dẫn này, chúng ta sẽ tìm hiểu các thông số trong cấu hình bộ lọc chuyển động:

  • Độ nhạy phát hiện chuyển động
  • Thời lượng tối thiểu của sự kiện
  • Giai đoạn xem lại
  • Thời gian hạ nhiệt
  • Vùng phát hiện chuyển động

Kiến thức bạn sẽ học được

  • Cách nhập video để phát trực tuyến
  • Các tính năng có trong Bộ lọc chuyển động và cách sử dụng các tính năng đó
  • Nơi kiểm tra số liệu thống kê của Bộ lọc chuyển động
  • Cách điều chỉnh chế độ cài đặt dựa trên video của bạn

2. Trước khi bắt đầu

  1. Trong Google Cloud Console, trên trang chọn dự án, hãy chọn hoặc tạo một dự án trên Google Cloud. Lưu ý: Nếu bạn không có ý định giữ lại các tài nguyên mà bạn tạo trong quy trình này, hãy tạo một dự án thay vì chọn một dự án hiện có. Sau khi hoàn tất các bước này, bạn có thể xoá dự án và loại bỏ mọi tài nguyên liên quan đến dự án đó. Chuyển đến bộ chọn dự án
  2. Đảm bảo rằng bạn đã bật tính năng thanh toán cho dự án trên đám mây. Tìm hiểu cách kiểm tra xem tính năng thanh toán có được bật trên một dự án hay không.
  3. Bật Compute Engine và Vision AI API. Bật các API

Tạo một tài khoản dịch vụ:

  1. Trong bảng điều khiển Cloud, hãy chuyển đến trang Tạo tài khoản dịch vụ. Chuyển đến phần Tạo tài khoản dịch vụ
  2. Chọn dự án của bạn.
  3. Trong trường Tên tài khoản dịch vụ, hãy nhập một tên. Bảng điều khiển Cloud sẽ điền trường Mã tài khoản dịch vụ dựa trên tên này. Trong trường Nội dung mô tả tài khoản dịch vụ, hãy nhập nội dung mô tả. Ví dụ: Tài khoản dịch vụ cho hướng dẫn bắt đầu nhanh.
  4. Nhấp vào Tạo và tiếp tục.
  5. Để cấp quyền truy cập vào dự án, hãy cấp(các) vai trò sau cho tài khoản dịch vụ của bạn: Vision AI > Vision AI Editor, Compute Engine > Compute Instance Admin (beta), Storage > Storage Object Viewer † . Trong danh sách Chọn vai trò, hãy chọn một vai trò. Đối với các vai trò khác, hãy nhấp vào Thêm vai trò khác rồi thêm từng vai trò khác. Lưu ý: Trường Vai trò ảnh hưởng đến những tài nguyên mà tài khoản dịch vụ của bạn có thể truy cập trong dự án. Bạn có thể thu hồi các vai trò này hoặc cấp thêm vai trò sau. Trong môi trường sản xuất, đừng cấp vai trò Chủ sở hữu, Người chỉnh sửa hoặc Người xem. Thay vào đó, hãy cấp một vai trò được xác định trước hoặc vai trò tuỳ chỉnh đáp ứng nhu cầu của bạn.
  6. Nhấp vào Tiếp tục.
  7. Nhấp vào Xong để hoàn tất quá trình tạo tài khoản dịch vụ. Đừng đóng cửa sổ trình duyệt. Bạn sẽ sử dụng chỉ mục này trong bước tiếp theo.

Tạo khoá tài khoản dịch vụ:

  1. Trong bảng điều khiển Cloud, hãy nhấp vào địa chỉ email của tài khoản dịch vụ mà bạn đã tạo.
  2. Nhấp vào Khoá.
  3. Nhấp vào Thêm khoá, rồi nhấp vào Tạo khoá mới.
  4. Nhấp vào Tạo. Một tệp khoá JSON sẽ được tải xuống máy tính của bạn.
  5. Nhấp vào Close (Đóng).
  6. Cài đặtkhởi động Google Cloud CLI.

† Bạn chỉ cần có vai trò này nếu sao chép một tệp video mẫu từ một nhóm Cloud Storage.

3. Bộ lọc chuyển động

Bộ lọc chuyển động ghi lại các đoạn video chuyển động và video sản phẩm có chứa các sự kiện chuyển động. Bằng cách điều chỉnh độ nhạy chuyển động, độ dài tối thiểu của sự kiện, khoảng thời gian xem lại, khoảng thời gian chờ và vùng phát hiện chuyển động, người dùng có thể định cấu hình bộ lọc theo nhu cầu của riêng mình.

Cấu hình bộ lọc chuyển động

Bộ lọc chuyển động có 5 cấu hình để bạn tuỳ chỉnh.

  1. Độ nhạy chuyển động: độ nhạy cần thiết để kích hoạt chuyển động.
  2. Thời lượng tối thiểu của sự kiện: thời lượng tối thiểu mà một sự kiện chuyển động sẽ được ghi lại.
  3. Giai đoạn xem lại: khoảng thời gian mà video sẽ bắt đầu quay trước khi phát hiện thấy một sự kiện chuyển động.
  4. Thời gian chờ: sau khi một sự kiện chuyển động kết thúc, thời gian chờ có thời lượng được chỉ định sẽ diễn ra. Trong thời gian chờ, các sự kiện chuyển động sẽ không được kích hoạt.
  5. Vùng phát hiện chuyển động: vùng do người dùng định cấu hình để chỉ định vị trí cần chạy tính năng phát hiện chuyển động. (Sẽ được trình bày chi tiết trong phần sau)

Độ nhạy chuyển động

Sử dụng cờ motion_detection_sensitivity trong lệnh vaictl.
Chuỗi. Phương tiện mặc định. Có thể chọn mức thấp, trung bình hoặc cao.

Độ nhạy phát hiện chuyển động càng cao thì camera càng nhạy cảm với tiếng ồn và những chuyển động nhỏ. Bạn nên dùng chế độ cài đặt này ở những nơi có các vật thể chuyển động nhỏ (chẳng hạn như người ở khoảng cách xa) và ánh sáng ổn định.

Mặt khác, độ nhạy thấp ít nhạy cảm hơn với sự can thiệp của ánh sáng. Chế độ cài đặt này phù hợp khi có nhiều nhiễu ánh sáng, chẳng hạn như trong môi trường ngoài trời và khi chất lượng video thấp hơn, có thể có nhiều tạp âm hơn. Vì chế độ cài đặt này lọc mạnh nhất trong tất cả các chế độ, nên chế độ này có thể bỏ qua chuyển động của các vật thể nhỏ.

Thời lượng tối thiểu của sự kiện

Sử dụng cờ min_event_length_in_seconds trong lệnh vaictl.
Số nguyên. Mặc định là 10 giây. Phạm vi từ 0 giây đến 3.600 giây.

Thời lượng tối thiểu của video sự kiện chuyển động sẽ được phân tích cú pháp sau khi một phân khúc sự kiện chuyển động được phát hiện trong khung hình.

Giai đoạn xem lại

Sử dụng cờ look_back_window_in_seconds trong lệnh vaictl.
Số nguyên. Mặc định là 3 giây. Phạm vi từ 0 giây đến 3.600 giây.

Giai đoạn xem lại là khoảng thời gian được lưu vào bộ nhớ đệm trước khi phát hiện thấy một sự kiện chuyển động. Điều này hữu ích khi chúng ta muốn xem điều gì xảy ra trong khung hình vài giây trước khi phát hiện thấy sự kiện chuyển động.

Thời gian chờ

Sử dụng cờ cool_down_period_in_seconds trong lệnh vaictl.
Số nguyên. Mặc định là 300 giây. Phạm vi từ 0 giây đến 3.600 giây.

Khoảng thời gian tạm dừng là khoảng thời gian mà tính năng phát hiện chuyển động sẽ tạm dừng sau khi một sự kiện chuyển động được ghi lại. Trong thời gian chờ, hệ thống sẽ không chạy quy trình tính toán để phát hiện chuyển động.

4. Ví dụ về bộ lọc chuyển động cơ bản

Hướng dẫn về Vaictl SDK

Để kiểm tra hướng dẫn sử dụng vaictl cho luồng đầu vào có bộ lọc chuyển động, hãy dùng lệnh bên dưới.

vaictl send video-file applying motion-filter -h

Chuẩn bị video mẫu

  1. Bạn có thể sao chép một video mẫu bằng lệnh gsutil cp sau đây. Thay thế biến sau:
  • NGUỒN: Vị trí của tệp video cần dùng. Bạn có thể sử dụng tệp video nguồn của riêng mình (ví dụ: gs://BUCKET_NAME/FILENAME.mp4) hoặc sử dụng video mẫu (gs://cloud-samples-data/vertex-ai-vision/street_vehicles_people.mp4)(video có người và xe, nguồn)
export SOURCE=gs://cloud-samples-data/vertex-ai-vision/street_vehicles_people.mp4
gsutil cp $SOURCE .

Chuẩn bị các biến môi trường

Đặt các biến môi trường bên dưới để sử dụng mẫu lệnh được cung cấp.

Biến vaictl

  • PROJECT_ID: Mã dự án trên Google Cloud.
  • LOCATION_ID: Mã vị trí của bạn. Ví dụ: us-central1. Để biết thêm thông tin, hãy xem bài viết Vị trí trên đám mây.
  • LOCAL_FILE: Tên tệp của một tệp video cục bộ. Ví dụ: street_vehicles_people.mp4.
  • –loop flag: Không bắt buộc. Lặp lại dữ liệu tệp để mô phỏng hoạt động truyền trực tuyến.
export PROJECT_ID=<Your Google Cloud project ID>
export LOCATION_ID=us-central1

Các biến bộ lọc chuyển động

  • MOTION_SENSITIVITY: Độ nhạy của tính năng phát hiện chuyển động.
  • MIN_EVENT_LENGTH: Thời lượng tối thiểu của các sự kiện chuyển động.
  • LOOK_BACK_WINDOW: Khoảng thời gian cần ghi lại trước chuyển động đầu tiên trong một sự kiện chuyển động.
  • COOL_DOWN_PERIOD: Khoảng thời gian mà tính năng phát hiện chuyển động sẽ tạm dừng sau khi một sự kiện chuyển động được ghi lại.
export MOTION_SENSITIVITY=<low or medium or high>
export MIN_EVENT_LENGTH=<0-3600>
export LOOK_BACK_WINDOW=<0-3600>
export COOL_DOWN_PERIOD=<0-3600>

Chuẩn bị lệnh bộ lọc chuyển động

Có hai lựa chọn để sử dụng bộ lọc chuyển động với luồng đầu vào. Lựa chọn đầu tiên là gửi các sự kiện chuyển động đến một luồng trong bảng điều khiển trên đám mây. Lựa chọn thứ hai là gửi các sự kiện chuyển động đến bộ nhớ cục bộ.

Gửi kết quả đến bảng điều khiển trên đám mây

Bạn có thể dùng vaictl để truyền trực tuyến dữ liệu video đầu ra đến bảng điều khiển đám mây. Bắt đầu bằng cách kích hoạt Vision AI API trong Cloud Console.

Đăng ký một luồng mới

  1. Nhấp vào thẻ luồng nhấp trên bảng điều khiển bên trái của Vertex AI Vision.
  2. Nhấp vào Đăng ký
  3. Trong phần Tên luồng, hãy nhập motion-detection-stream
  4. Nhập us-central1 vào khu vực
  5. Nhấp vào đăng ký

Gửi kết quả đến luồng

Lệnh này truyền trực tuyến một tệp video đến một luồng. Nếu bạn dùng cờ –loop, video sẽ được lặp lại trong luồng cho đến khi bạn dừng lệnh. Chúng ta sẽ chạy lệnh này dưới dạng một công việc ở chế độ nền để lệnh này tiếp tục truyền phát.

Thêm nohup ở đầu và & ở cuối để biến thành một tác vụ nền.

INPUT_VIDEO=street_vehicles_people.mp4

vaictl -p $PROJECT \
       -l $LOCATION_ID \
       -c application-cluster-0 \
       --service-endpoint visionai.googleapis.com \
  send video-file  --file-path $INPUT_VIDEO \
  applying motion-filter
         --motion-sensitivity=$MOTION_SENSITIVITY \
         --min-event-length=$MIN_EVENT_LENGTH \
         --lookback-length=$LOOK_BACK_WINDOW \
         --cooldown-length=$COOL_DOWN_PERIOD \
  to streams motion-detection-stream --loop

Có thể mất khoảng 100 giây từ khi bạn bắt đầu thao tác truyền vaictl cho đến khi video xuất hiện trong trang tổng quan.

Sau khi có thể truyền trực tiếp, bạn có thể xem nguồn cấp dữ liệu video trong thẻ Luồng của trang tổng quan Vertex AI Vision bằng cách chọn luồng dữ liệu giao thông.

Chuyển đến thẻ Sự kiện phát trực tiếp

Gửi kết quả đến bộ nhớ cục bộ

Lệnh này truyền trực tuyến một tệp video đến một luồng.

Thêm nohup ở đầu và & ở cuối để biến thành một tác vụ nền.

INPUT_VIDEO=street_vehicles_people.mp4
OUTPUT_PATH=<path_to_store_motion_events_on_local_disk>

nohup vaictl -p $PROJECT \
             -l $LOCATION_ID \
             -c application-cluster-0 \
             --service-endpoint visionai.googleapis.com \
  send video-file  --file-path $INPUT_VIDEO \
  applying motion-filter
         --motion-sensitivity=$MOTION_SENSITIVITY \
         --min-event-length=$MIN_EVENT_LENGTH \
         --lookback-length=$LOOK_BACK_WINDOW \
         --cooldown-length=$COOL_DOWN_PERIOD \
  to mp4file --mp4-file-path=$OUTPUT_PATH --loop

5. Vùng phát hiện chuyển động

Trong phần này, chúng ta sẽ tìm hiểu kỹ về cách sử dụng vùng phát hiện chuyển động và cách định cấu hình vùng này. Vùng này nhằm mục đích cải thiện tính năng phát hiện chuyển động bằng cách che đi chuyển động đến từ những khu vực mà bạn không quan tâm.

Vùng phát hiện chuyển động có 2 loại: (1) vùng dương tính, nơi tính năng phát hiện chuyển động chỉ chạy trong khu vực được chú thích; (2) vùng âm tính, nơi tính năng phát hiện chuyển động bỏ qua mọi chuyển động trong khu vực được chú thích.

Chú thích vùng

Sử dụng cờ zone_annotation trong lệnh vaictl để nhập toạ độ cho đa giác vùng.
Chuỗi. Giá trị mặc định là trống đối với chú thích vùng.

Chú thích theo vùng sẽ là một chuỗi do người dùng nhập, biểu thị các vùng trong khung hình mà người dùng muốn ẩn hoặc tập trung vào. Để chú thích vùng, người dùng cần chỉ định toạ độ hình ảnh của trục x và trục y cho từng nút trong vùng. Một khu vực cần có từ 3 nút trở lên để tạo thành một đa giác. Một khung hình có thể có nhiều vùng. Nếu các vùng chồng lên nhau, thì khu vực do cả hai vùng bao phủ vẫn sẽ được bao phủ.

Chú giải vùng có một cú pháp đầu vào cụ thể cần tuân theo.

  • Để biểu thị một nút duy nhất, hãy dùng : để kết nối trục x và trục y của một toạ độ hình ảnh. Ví dụ: một nút (0,0) ở góc trên bên trái sẽ được biểu thị là 0:0.
  • Để biểu thị tất cả các nút trong một vùng duy nhất, hãy dùng ; để kết nối các nút. Ví dụ: đối với một vùng có các nút (0,0), (100,0), (100,100)(0, 100), vùng đó sẽ được biểu thị là 0:0;100:0;100:100;0:100. Luôn nhập các nút dưới dạng các nút kết nối bên cạnh nhau, thứ tự có thể là theo chiều kim đồng hồ hoặc ngược chiều kim đồng hồ.

Vùng phát hiện chuyển động – hình vuông*Một vùng hình vuông có 4 nút.

Vùng phát hiện chuyển động – hình tam giác*Một vùng tam giác có 3 nút.

  • Để biểu thị nhiều vùng trong một khung hình, hãy dùng - để kết nối các vùng riêng biệt. Ví dụ: nếu chúng ta muốn nhập cả (0,0), (100,0), (100,100), (0,100)(120,120), (110,150), (200,160), thì chú thích vùng nhập sẽ là 0:0;100:0;100:100;0:100-120:120;110:150;200:160.

Vùng phát hiện chuyển động – khung hình có 2 vùng*Hai vùng trong một khung hình.

Để lấy toạ độ từ hình ảnh, bạn có thể dùng một số công cụ trực tuyến để lấy toạ độ. Ví dụ: xem Wolfram – Lấy toạ độ từ hình ảnh

Loại trừ vùng được chú thích

Sử dụng cờ exclude_annotated_zone trong lệnh vaictl để định cấu hình tính năng phát hiện chuyển động trong vùng hoặc bên ngoài vùng.
Boolean. Mặc định là false.

Vùng loại trừ được chú thích là một đầu vào boolean của người dùng, cho biết liệu người dùng có muốn loại trừ vùng được chú thích trong tính năng phát hiện chuyển động hay không.

  • Nếu bạn đặt thành true, vùng được chú thích sẽ hoạt động như một vùng âm. Hệ thống sẽ không phát hiện chuyển động trong các vùng được chú thích.

Vùng phát hiện chuyển động – lựa chọn loại trừ *Chỉ chạy tính năng phát hiện chuyển động bên ngoài các vùng đầu vào.

  • Nếu bạn đặt thành false, vùng này sẽ hoạt động như một vùng dương, nơi tính năng phát hiện chuyển động sẽ tập trung vào.

Vùng phát hiện chuyển động – lựa chọn bao gồm *Chỉ chạy tính năng phát hiện chuyển động trong các vùng đầu vào.

6. Ví dụ về bộ lọc chuyển động có vùng phát hiện chuyển động

Trong ví dụ này, chúng ta sẽ sử dụng một video có hình ảnh một cái cây liên tục di chuyển ở tiền cảnh. Trong chế độ cài đặt bộ lọc chuyển động thông thường, video sẽ chỉ tạo ra một sự kiện chuyển động có thời lượng bằng thời lượng của video gốc vì bộ lọc chuyển động đăng ký cây chuyển động là "liên tục chuyển động trong toàn bộ video". Tuy nhiên, với sự trợ giúp của vùng phát hiện chuyển động, chúng ta có thể che đi chuyển động của cây một cách thích hợp và tập trung vào chuyển động của ô tô và người đi bộ.

Chuẩn bị video

Video mẫu (gs://cloud-samples-data/vertex-ai-vision/dynamic-background-fall.mp4) có cây, ô tô và người đi bộ lấy từ www.changedetection.net.

Nguồn video: N. Goyette, P.-M. Jodoin, F. Porikli, J. Konrad và P. Ishwar, changedetection.net: A new change detection benchmark dataset, in Proc. IEEE Workshop on Change Detection (CDW-2012) at CVPR-2012, Providence, RI, 16-21 Jun., 2012

Chuẩn bị biến môi trường

Các biến dự án trên Google Cloud.

export PROJECT_ID=<Your Google Cloud project ID>
export LOCATION_ID=us-central1
export LOCAL_FILE=street_vehicles_people.mp4

Cấu hình bộ lọc chuyển động cơ bản.

export MOTION_SENSITIVITY=<low or medium or high>
export MIN_EVENT_LENGTH=<0-3600>
export LOOK_BACK_WINDOW=<0-3600>
export COOL_DOWN_PERIOD=<0-3600>

Cấu hình vùng phát hiện chuyển động.

Chọn một trong các lựa chọn bên dưới để xem các loại cách sử dụng khác nhau cho vùng phát hiện chuyển động.

Loại trừ cây khỏi tính năng phát hiện chuyển động.

export ZONE_ANNOTATION="0:0;680:0;660:70;380:320;100:150"
export EXCLUDE_ANNOTATED_ZONE=true

Vùng phát hiện chuyển động – loại trừ hoạt động phát hiện chuyển động khỏi vùng được chú thích trong video ví dụ *Chỉ chạy tính năng phát hiện chuyển động bên ngoài các vùng đầu vào.

Tập trung phát hiện chuyển động trên đường.

export ZONE_ANNOTATION="0:300;780:300;780:480;0:480"
export EXCLUDE_ANNOTATED_ZONE=false

Vùng phát hiện chuyển động – chạy tính năng phát hiện chuyển động từ vùng được chú thích trong video mẫu *Chỉ chạy tính năng phát hiện chuyển động bên ngoài các vùng đầu vào.

Gửi luồng video có bộ lọc chuyển động

Gửi các sự kiện chuyển động đến bảng điều khiển trên đám mây

Bạn có thể dùng vaictl để truyền trực tuyến dữ liệu video đầu ra đến bảng điều khiển đám mây. Bắt đầu bằng cách kích hoạt Vision AI API trong Cloud Console.

Đăng ký một luồng mới

  1. Nhấp vào thẻ luồng nhấp trên bảng điều khiển bên trái của Vertex AI Vision.
  2. Nhấp vào Đăng ký
  3. Trong phần Tên luồng, hãy nhập motion-detection-stream
  4. Nhập us-central1 vào khu vực
  5. Nhấp vào đăng ký

Gửi kết quả đến luồng

Lệnh này truyền trực tuyến một tệp video đến một luồng. Nếu bạn dùng cờ –loop, video sẽ được lặp lại trong luồng cho đến khi bạn dừng lệnh. Chúng ta sẽ chạy lệnh này dưới dạng một công việc ở chế độ nền để lệnh này tiếp tục truyền phát.

Thêm nohup ở đầu và & ở cuối để biến thành một tác vụ nền.

vaictl -p $PROJECT \
       -l $LOCATION_ID \
       -c application-cluster-0 \
       --service-endpoint visionai.googleapis.com \
  send video-file  --file-path $INPUT_VIDEO \
  applying motion-filter
         --motion-sensitivity=$MOTION_SENSITIVITY \
         --min-event-length=$MIN_EVENT_LENGTH \
         --lookback-length=$LOOK_BACK_WINDOW \
         --cooldown-length=$COOL_DOWN_PERIOD \
         --zone_annotation=ZONE_ANNOTATION \
         --exclude_annotated_zone=$EXCLUDE_ANNOTATED_ZONE \
  to streams motion-detection-stream --loop

Có thể mất khoảng 100 giây từ khi bạn bắt đầu thao tác truyền vaictl cho đến khi video xuất hiện trong trang tổng quan.

Sau khi có thể truyền trực tiếp, bạn có thể xem nguồn cấp dữ liệu video trong thẻ Luồng của trang tổng quan Vertex AI Vision bằng cách chọn luồng dữ liệu giao thông.

Chuyển đến thẻ Sự kiện phát trực tiếp

Gửi kết quả đến bộ nhớ cục bộ

Lệnh này truyền trực tuyến một tệp video đến một luồng. Nếu bạn dùng cờ –loop, video sẽ được lặp lại trong luồng cho đến khi bạn dừng lệnh. Chúng ta sẽ chạy lệnh này dưới dạng một công việc ở chế độ nền để lệnh này tiếp tục truyền phát.

Thêm nohup ở đầu và & ở cuối để biến thành một tác vụ nền.

OUTPUT_PATH=<path_to_store_motion_events>

vaictl -p $PROJECT \
       -l $LOCATION_ID \
       -c application-cluster-0 \
       --service-endpoint visionai.googleapis.com \
  send video-file  --file-path $INPUT_VIDEO \
  applying motion-filter
         --motion-sensitivity=$MOTION_SENSITIVITY \
         --min-event-length=$MIN_EVENT_LENGTH \
         --lookback-length=$LOOK_BACK_WINDOW \
         --cooldown-length=$COOL_DOWN_PERIOD \
         --zone_annotation=$ZONE_ANNOTATION \
         --exclude_annotated_zone=$EXCLUDE_ANNOTATED_ZONE \
  to mp4file --mp4-file-path=$OUTPUT_PATH --loop

7. Xin chúc mừng

Xin chúc mừng, bạn đã hoàn thành bài thực hành!

Dọn dẹp

Để tránh phát sinh phí cho tài khoản Google Cloud của bạn đối với các tài nguyên được dùng trong hướng dẫn này, hãy kết thúc thao tác SDK vaictl thông qua dòng lệnh bằng ctrl + z.

Tài nguyên

https://cloud.google.com/vision-ai/docs/overview

https://cloud.google.com/vision-ai/docs/motion-filtering-model

https://cloud.google.com/vision-ai/docs/create-manage-streams

Phản hồi

Nhấp vào đây để gửi ý kiến phản hồi

Bản khảo sát

Bạn sẽ sử dụng hướng dẫn này như thế nào?

Chỉ đọc Đọc và hoàn thành bài tập

Lớp học lập trình này có hữu ích không?

Rất hữu ích Khá hữu ích