Triển khai nhận diện đối tượng trên thiết bị Android với YOLO.pdf
aicandy
19 views
16 slides
Nov 29, 2024
Slide 1 of 16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
About This Presentation
Triển khai nhận diện đối tượng trên thiết bị Android với YOLO
Nội dung
1. Giới thiệu
2. Cấu trúc dự án
3. Cấu hình AndroidManifest
4. Giao diện hiển thị
5. Model và xử lý ảnh
5.1. Model
5.2. Tính toán NMS, IOU
5.3. Xử lý kích thước hộp bao the...
Triển khai nhận diện đối tượng trên thiết bị Android với YOLO
Nội dung
1. Giới thiệu
2. Cấu trúc dự án
3. Cấu hình AndroidManifest
4. Giao diện hiển thị
5. Model và xử lý ảnh
5.1. Model
5.2. Tính toán NMS, IOU
5.3. Xử lý kích thước hộp bao theo kích thước ảnh
5.4. Hiển thị ảnh và thông tin lên màn hình
6. Chương trình chính
7. Demo và source code
Size: 1.25 MB
Language: none
Added: Nov 29, 2024
Slides: 16 pages
Slide Content
https://aicandy.vn/cach-du-doan-gia-co-phieu-hieu-qua-bang-mo-hinh-lstm/
Bản quyền thuộc về: https://aicandy.vn
Học tập toàn diện: Kết nối lý thuyết, thực hành và dữ liệu thực tế
https://aicandy.vn
1
Triển khai nhận diện đối tượng trên thiết
bị Android với YOLO
Nội dung
1. Giới thiệu
2. Cấu trúc dự án
3. Cấu hình AndroidManifest
4. Giao diện hiển thị
5. Model và xử lý ảnh
o 5.1. Model
o 5.2. Tính toán NMS, IOU
o 5.3. Xử lý kích thước hộp bao theo kích thước ảnh
o 5.4. Hiển thị ảnh và thông tin lên màn hình
6. Chương trình chính
7. Demo và source code
1. Giới thiệu
YOLO là một thuật toán deep learning nổi tiếng, giúp phát hiện và phân loại
đối tượng nhanh chóng chỉ qua một lần quét hình ảnh. Khi tích hợp YOLO
vào ứng dụng Android, người dùng có thể nhận diện các đối tượng từ
camera hoặc ảnh tĩnh với độ chính xác cao, mở ra nhiều cơ hội phát triển cho
các ứng dụng liên quan đến an ninh, tự động hóa và nhận diện thông minh.
Bài viết này sẽ hướng dẫn bạn cách triển khai một ứng dụng Android có khả
năng nhận diện đối tượng, xác định tên đối tượng, vị trí của đối tượng trong
ảnh. Chúng ta sẽ tìm hiểu cách tích hợp mô hình đã huấn luyện YOLOv5
vào ứng dụng, đồng thời tối ưu hiệu suất cho thiết bị di động.
Ứng dụng sẽ tải model đã được huấn luyện, hiển thị ảnh đã có trong ứng
dụng, nhấn nút trên màn hình để bắt đầu nhận diện, sau khi nhận diện xong
thì hiển thị tên đối tượng, vẽ khung bao đối tượng và hiển thị ảnh lên màn
hình. Mỗi lần nhấn nút tiếp theo sẽ thay ảnh trên màn hình và lặp lại quá
trình nhận diện và hiển thị kết quả.
https://aicandy.vn/cach-du-doan-gia-co-phieu-hieu-qua-bang-mo-hinh-lstm/
Bản quyền thuộc về: https://aicandy.vn
Học tập toàn diện: Kết nối lý thuyết, thực hành và dữ liệu thực tế
https://aicandy.vn
2
2. Cấu trúc dự án
Sử dụng phần mềm lập trình Android studio, dùng ngôn ngữ Java, các tệp
và thư mục chính được tổ chức như sau:
root@aicandy:/aicandy/projects/app/src# tree
.
└── main
├── AndroidManifest.xml
├── assets
│ ├── image_test
│ │ ├── ...
│ │ └── ...
│ ├── model_classes.txt
│ └── yolov5s.ptl
├── java
│ └── com
https://aicandy.vn/cach-du-doan-gia-co-phieu-hieu-qua-bang-mo-hinh-lstm/
Bản quyền thuộc về: https://aicandy.vn
Học tập toàn diện: Kết nối lý thuyết, thực hành và dữ liệu thực tế
https://aicandy.vn
3
│ └── aicandy
│ └── objectdetection
│ └── yolo
│ ├── DetectionOverla y.java
│ ├── ImageProcesso r.java
│ └── MainActivity.java
└── res
├── values
| ├── colors.xml
│ ├── strings.xml
│ └── styles.xml
├── layout
│ └── activity_main.xml
└── ....
├── ...
└── ...
Trong đó:
Thư mục image_test chứa các cảnh cần kiểm tra.
Tệp yolov5s.ptl là model đã được huấn luyện
Tệp DetectionOverlay.java chứa mã nguồn để xử lý phần hiển thị ảnh
lên màn hình.
Tệp ImageProcessor.java chứa mã nguồn để xử lý ảnh đầu vào, phân
tích và tính toán IOU.
Tệp MainActivity.java chứa chương trình chính của ứng dụng.
Thư mục layout chứa các tệp cấu hình giao diện hiển thị.
3. Cấu hình AndroidManifest
Tệp AndroidManifest là nơi cấu hình thông tin quan trọng về ứng dụng, bao
gồm các activity (màn hình), biểu tượng, tên ứng dụng, và các tính năng hỗ
trợ khác.
https://aicandy.vn/cach-du-doan-gia-co-phieu-hieu-qua-bang-mo-hinh-lstm/
Bản quyền thuộc về: https://aicandy.vn
Học tập toàn diện: Kết nối lý thuyết, thực hành và dữ liệu thực tế
https://aicandy.vn
4
Một số cấu hình chính trong tệp:
<uses-permission
android:name=”android.permission.READ_EXTERNAL_ STORAGE” />:
Khai báo quyền truy cập. Ở đây, ứng dụng yêu cầu quyền đọc dữ liệu từ bộ
nhớ ngoài (READ_EXTERNAL_STORAGE). Điều này cần thiết nếu ứng
dụng muốn truy cập hình ảnh, video hoặc các tệp khác từ bộ nhớ ngoài của
thiết bị.
android:allowBackup=”true”
Cho phép hệ thống sao lưu và phục hồi dữ liệu ứng dụng khi cần (như khi
cài lại app).
android:icon=”@mipmap/ic_launcher”
Chỉ định biểu tượng chính của ứng dụng, thường được hiển thị trên màn
hình chính.
android:label=”@string/app_name”
Đặt tên của ứng dụng, được định nghĩa trong tệp string resources
(res/values/strings.xml).
android:theme=”@style/AppTheme”
Chỉ định theme (giao diện) chung cho ứng dụng, được định nghĩa trong tệp
styles (res/values/styles.xml).
android:name=”.Result”
Đây là tên class của activity, là màn hình được điều hướng đến khi cần hiển
thị kết quả (nằm trong gói chính của ứng dụng).
android:name=”.MainActivity”
Đây là tên class của MainActivity, là màn hình khởi động chính của ứng
dụng.
https://aicandy.vn/cach-du-doan-gia-co-phieu-hieu-qua-bang-mo-hinh-lstm/
Bản quyền thuộc về: https://aicandy.vn
Học tập toàn diện: Kết nối lý thuyết, thực hành và dữ liệu thực tế
https://aicandy.vn
5
<action android:name=”android.intent.action.MAIN” />
Định nghĩa đây là “main entry point”, tức là điểm vào chính của ứng dụng.
<category android:name=”android.intent.category.LAUNCHER” />
Chỉ định activity này xuất hiện trong danh sách ứng dụng (launcher) của
thiết bị, là nơi người dùng có thể khởi động ứng dụng từ màn hình chính.
<activity
android:name=".MainActivity"
android:configChanges="orientation"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
4. Giao diện hiển thị
Ứng dụng có giao diện với các thành phần chính để hiển thị thông tin trạng
thái chương trình, hiển thị hình ảnh và hiển thị kết quả.
https://aicandy.vn/cach-du-doan-gia-co-phieu-hieu-qua-bang-mo-hinh-lstm/
Bản quyền thuộc về: https://aicandy.vn
Học tập toàn diện: Kết nối lý thuyết, thực hành và dữ liệu thực tế
https://aicandy.vn
6
Khai báo app_name trong AndroidManifest.xml
android:label="@string/app_name"
Tạo ImageView để hiển thị hình ảnh trên màn hình.
<ImageView
android:id="@+id/imageView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="60dp"
android:background="#FFFFFF"
android:contentDescription="@string/image_view"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
https://aicandy.vn/cach-du-doan-gia-co-phieu-hieu-qua-bang-mo-hinh-lstm/
Bản quyền thuộc về: https://aicandy.vn
Học tập toàn diện: Kết nối lý thuyết, thực hành và dữ liệu thực tế
https://aicandy.vn
7
Tiếp theo tạo Button để mỗi khi “click” vào đây thì chươn trình sẽ tải ảnh
tiếp theo và nhận diện ảnh này.
<Button
android:id="@+id/detectButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="@string/run"
android:textAllCaps="false"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView"/>
5. Model và xử lý ảnh
Chú ý rằng các đoạn code trong bài là các key chính, code đầy đủ cần xem
phần source code ở mục 7.
5.1. Model
Để tải model đã huấn luyện, sử dụng phương thức LiteModuleLoader trong
pytorch và load model với tham số đầu vào là đường dẫn của model. Đồng
thời tải tên các đối tượng tương ứng trong model từ file model_classes.txt
vào list.
modelModule =
LiteModuleLoader.load(MainActivity.getAssetPath(getApplicationContex
t(), "yolov5s.ptl"));
BufferedReader br = new BufferedReader(new
InputStreamReader(getAssets().open("model_classes.txt")));
String line;
List classes = new ArrayList<>();
while ((line = br.readLine()) != null) {
classes.add(line);
https://aicandy.vn/cach-du-doan-gia-co-phieu-hieu-qua-bang-mo-hinh-lstm/
Bản quyền thuộc về: https://aicandy.vn
Học tập toàn diện: Kết nối lý thuyết, thực hành và dữ liệu thực tế
https://aicandy.vn
8
}
ImageProcessor.CLASSES = new String[classes.size()];
classes.toArray(ImageProcessor.CLASSES);
5.2. Tính toán NMS, IOU
Tính toán NMS
Thuật toán Non-Maximum Suppression (NMS), một kỹ thuật thường được
sử dụng trong các bài toán phát hiện đối tượng (object detection) để loại bỏ
các hộp bao (bounding boxes) trùng lặp hoặc không cần thiết.
Để thực hiện NMS, cần thực hiện các công việc sau:
Sắp xếp các phát hiện theo độ tự tin: Các kết quả phát hiện (detections)
được sắp xếp theo độ tự tin (confidence). Điều này giúp xử lý từ hộp có
độ tự tin thấp nhất đến cao nhất.
Collections.sort(detections, new Comparator() {
@Override
public int compare(DetectionResult o1, DetectionResult o2) {
return o1.confidence.compareTo(o2.confidence);
}
});
Tiếp theo, duyệt qua từng hộp phát hiện (detections). Nếu hộp đó còn hoạt
động (active[i] == true), nó được chọn và thêm vào danh sách selected. Nếu
danh sách selected đã đạt đến giới hạn limit, vòng lặp dừng lại. Sau khi chọn
một hộp (boxA), thuật toán so sánh nó với các hộp tiếp theo (boxB). Nếu chỉ
số IoU (Intersection over Union) giữa boxA và boxB lớn hơn threshold, hộp
boxB được đánh dấu là không còn hợp lệ (active[j] = false), vì nó trùng lặp
quá nhiều với boxA. Nếu số lượng hộp còn hoạt động (numActive) giảm về
0, vòng lặp kết thúc.
for (int i=0; i<detections.size() && !done; i++) {
if (active[i]) { DetectionResult boxA = detections.get(i);
selected.add(boxA); if (selected.size() >= limit) break;
https://aicandy.vn/cach-du-doan-gia-co-phieu-hieu-qua-bang-mo-hinh-lstm/
Bản quyền thuộc về: https://aicandy.vn
Học tập toàn diện: Kết nối lý thuyết, thực hành và dữ liệu thực tế
https://aicandy.vn
9
for (int j=i+1; j<detections.size(); j++) { if (active[j]) {
DetectionResult boxB = detections.get(j); if
(calculateIOU(boxA.boundingBox, boxB.boundingBox) > threshold) {
active[j] = false;
numActive -= 1;
if (numActive <= 0) {
done = true;
break;
}
}
}
}
}
}
Tính toán IOU
IoU (Intersection over Union) là một chỉ số dùng để đo lường mức độ chồng
chéo giữa hai hình chữ nhật, thường được sử dụng trong các bài toán phát
hiện đối tượng (object detection). Cụ thể, IoU so sánh giữa hộp bao dự đoán
(predicted bounding box) và hộp bao thực tế (ground truth bounding box).
Công thức tính IoU như sau:
ệíầệíầợIoU=Diện tích phần giaoDiện tích phần hợp
Trong đó, phần giao là diện tích vùng mà hai hộp bao chồng lấp lên nhau,
và phần hợp là tổng diện tích của hai hộp bao trừ đi phần giao.
IoU có giá trị từ 0 đến 1:
IoU = 1: Hai hộp bao trùng khớp hoàn toàn.
IoU = 0: Hai hộp bao không chồng lên nhau.
https://aicandy.vn/cach-du-doan-gia-co-phieu-hieu-qua-bang-mo-hinh-lstm/
Bản quyền thuộc về: https://aicandy.vn
Học tập toàn diện: Kết nối lý thuyết, thực hành và dữ liệu thực tế
https://aicandy.vn
10
IoU thường được dùng làm tiêu chí đánh giá mức độ chính xác của việc dự
đoán đối tượng, và là cơ sở để áp dụng thuật toán Non-Maximum
Suppression (NMS) để loại bỏ các hộp bao trùng lặp.
Áp dụng thực hiện, tính toán diện tích của hai hình chữ nhật
float areaA = (a.right - a.left) * (a.bottom - a.top);
if (areaA <= 0.0) return 0.0f;
float areaB = (b.right - b.left) * (b.bottom - b.top);
if (areaB <= 0.0) return 0.0f;
Tiếp theo là xác định phần giao của 2 hình chữ nhật
float intersectionMinX = Math.max(a.left, b.left);
float intersectionMinY = Math.max(a.top, b.top);
float intersectionMaxX = Math.min(a.right, b.right);
float intersectionMaxY = Math.min(a.bottom, b.bottom);
Và cuối cùng là tính IOU:
return intersectionArea / (areaA + areaB - intersectionArea);
5.3. Xử lý kích thước hộp bao theo kích thước ảnh
Do ảnh đầu vào có kích thước thường khác với kích thước ảnh mà model
yêu cầu, nên cần phải resize lại ảnh. Tương tự, kích thước ảnh đầu vào cũng
khác với kích thước ảnh hiển thị trên màn hình, nên cũng cần resize lại ảnh.
Sau khi resize ảnh, cần tính toán lại kích thước của các hộp bounding box
cho phù hợp với ảnh.
imgScaleX, imgScaleY: Tỷ lệ co dãn của ảnh gốc theo trục X và Y (do ảnh có
thể được thu phóng hoặc cắt cúp).
ivScaleX, ivScaleY: Tỷ lệ co dãn của ImageView (hoặc vùng hiển thị ảnh)
theo trục X và Y.
https://aicandy.vn/cach-du-doan-gia-co-phieu-hieu-qua-bang-mo-hinh-lstm/
Bản quyền thuộc về: https://aicandy.vn
Học tập toàn diện: Kết nối lý thuyết, thực hành và dữ liệu thực tế
https://aicandy.vn
11
Tính toán vị trí hộp bao (bounding box):
float x = outputs[i * OUTPUT_COL];
float y = outputs[i * OUTPUT_COL + 1];
float w = outputs[i * OUTPUT_COL + 2];
float h = outputs[i * OUTPUT_COL + 3];
float left = imgScaleX * (x - w / 2);
float top = imgScaleY * (y - h / 2);
float right = imgScaleX * (x + w / 2);
float bottom = imgScaleY * (y + h / 2);
Tiếp theo là chuyển đổi vị trí hộp bao sang tọa độ hiển thị.
Rect rect = new Rect((int)(startX + ivScaleX * left),
(int)(startY + top * ivScaleY),
(int)(startX + ivScaleX * right),
(int)(startY + ivScaleY * bottom));
5.4. Hiển thị ảnh và thông tin lên màn hình
Sau khi nhận diện được đối tượng xong, chúng ta sử dụng canvas để hiển
thị và vẽ bounding box lên hình ảnh sau đó là hiển thị chúng lên màn hình
thiết bị.
for (DetectionResult detection : detectionResults)
Vòng lặp này duyệt qua tất cả các kết quả nhận diện (mỗi kết quả là một đối
tượng DetectionResult).
canvas.drawRect(detection.boundingBox, boxPaint)
Lệnh này vẽ một khung chữ nhật (bounding box) quanh đối tượng được
phát hiện, dựa trên tọa độ trong detection.boundingBox và sử dụng boxPaint
để định dạng (màu sắc, độ dày…).
String labelText = ImageProcessor.CLASSES[detection.classId]
https://aicandy.vn/cach-du-doan-gia-co-phieu-hieu-qua-bang-mo-hinh-lstm/
Bản quyền thuộc về: https://aicandy.vn
Học tập toàn diện: Kết nối lý thuyết, thực hành và dữ liệu thực tế
https://aicandy.vn
12
Lấy nhãn của đối tượng được phát hiện từ một mảng CLASSES (lưu trữ tên
của các lớp đối tượng), dựa trên classId của đối tượng được phát hiện.
float textWidth = textBounds.width( ); float textHeight
= textBounds.height()
Lưu lại chiều rộng và chiều cao của nhãn để sử dụng khi vẽ khung chứa
nhãn.
RectF labelRect = new RectF(…)
Tạo một đối tượng RectF (tọa độ khung hình chữ nhật) để đại diện cho vị trí
và kích thước của khung chứa nhãn, ngay trên góc của bounding box.
canvas.drawRect(labelRect, labelPaint)
Vẽ khung chữ nhật chứa nhãn lên Canvas với màu và kiểu từ labelPaint.
Những cấu hình trên sẽ giúp cho khung bao tên của đối tượng có kích thước
linh hoạt tùy thuộc vào độ dài tên của đối tượng, điều này giúp cho dễ quan
sát đối tượng và nhìn đẹp hơn.
6. Chương trình chính
https://aicandy.vn/cach-du-doan-gia-co-phieu-hieu-qua-bang-mo-hinh-lstm/
Bản quyền thuộc về: https://aicandy.vn
Học tập toàn diện: Kết nối lý thuyết, thực hành và dữ liệu thực tế
https://aicandy.vn
13
Trong chương trình này sẽ thực hiện các công việc như duyệt và lấy tên các
file ảnh trong thư mục, chuyển đổi sang bitmap (là cấu trúc dữ liệu được sử
dụng phổ biến để lưu trữ và quản lý các hình ảnh. Nó đại diện cho một ma
trận các pixel với mỗi pixel chứa thông tin về màu sắc. Bitmap cho phép bạn
dễ dàng truy xuất giá trị pixel để thực hiện chuyển ảnh sang dạng tensor),
dự đoán đối tượng từ ảnh, hiển thị ảnh và hiển thị tên đối tượng lên màn
hình.
Bước 1: Duyệt ảnh
Để duyệt ảnh được lưu trong thư mục “asset” cần sử dụng AssetManager
List imageFiles = new ArrayList<>();
AssetManager assetManager = this.getAssets();
String[] files = assetManager.list(folderPath);
Bước 2: Tạo ảnh đầu vào cho mô hình
Sử dụng Bitmap.createScaledBitmap để resize ảnh cho phù hợp với kích
thước yêu cầu của mô hình (INPUT_WIDTH và INPUT_HEIGHT). Tiếp
theo, ảnh sau khi được thay đổi kích thước được chuyển đổi thành một
tensor (định dạng ma tr ận số học) bằng cách sử
dụng TensorImageUtils.bitmapToFloat32Tensor. Quá trình này cũng
chuẩn hóa giá trị RGB của ảnh bằng các giá
trị NO_MEAN_RGB và NO_STD_RGB. (Đối với model yolo5s thì không
yêu cầu chuẩn hóa, một số mô hình khác thì yêu cầu chuẩn hóa).
Bitmap resizedImage = Bitmap.createScaledBitmap(inputImage,
ImageProcessor.INPUT_WIDTH, ImageProcessor.INPUT_HEIGHT, true);
final Tensor inputTensor =
TensorImageUtils.bitmapToFloat32Tensor(resizedImage,
ImageProcessor.NO_MEAN_RGB, ImageProcessor.NO_STD_RGB);
Bước 3: Chạy mô hình và lấy đầu ra
Sử dụng phương thức forward để truyền tensor đầu vào và lấy ra mảng giá
trị kiểu IValue ở đầu ra. Sau đó, lấy đầu ra chính (có kiểu là tensor) được lấy
từ phần tử đầu tiên của mảng outputTuple.
https://aicandy.vn/cach-du-doan-gia-co-phieu-hieu-qua-bang-mo-hinh-lstm/
Bản quyền thuộc về: https://aicandy.vn
Học tập toàn diện: Kết nối lý thuyết, thực hành và dữ liệu thực tế
https://aicandy.vn
14
Cuối cùng, để dễ dàng thao tác và xử lý, chúng ta chuyển tensor đầu ra thành
mảng float.
IValue[] outputTuple =
modelModule.forward(IValue.from(inputTensor)).toTuple();
final Tensor outputTensor = outputTuple[0].toTensor();
final float[] outputs = outputTensor.getDataAsFloatArray();
Bước 4: Tính toán tỷ lệ co giãn của ảnh
imageScaleX và imageScaleY: Tính toán tỷ lệ co dãn của ảnh đầu vào ban
đầu so với kích thước ảnh được đưa vào mô hình. Điều này giúp đảm bảo
rằng tọa độ các hộp bao phát hiện được sẽ được chuyển đổi trở lại đúng kích
thước ban đầu của ảnh.
imageScaleX = (float)inputImage.getWidth() /
ImageProcessor.INPUT_WIDTH;
imageScaleY = (float)inputImage.getHeight() /
ImageProcessor.INPUT_HEIGHT;
viewScaleX và viewScaleY: Tính toán tỷ lệ co dãn giữa kích thước của ảnh
đầu vào và vùng hiển thị (ImageView). Điều này cần thiết để chuyển đổi tọa
độ các hộp bao từ kích thước của ảnh đầu vào sang kích thước thực tế của
vùng hiển thị.
viewScaleX = (inputImage.getWidth() > inputImage.getHeight() ?
(float)imageDisplay.getWidth() / inputImage.getWidth() :
(float)imageDisplay.getHeight() / inputImage.getHeight());
viewScaleY = (inputImage.getHeight() > inputImage.getWidth() ?
(float)imageDisplay.getHeight() / inputImage.getHeight() :
(float)imageDisplay.getWidth() / inputImage.getWidth());
Bước 5: Cập nhật giao diện người dùng
Chúng ta xử lý phân tích hình ảnh chạy dự đoán trên luồng phụ sau khi có
kết quả mới chuyển sang luồng chính để hiển thị bởi vì:
Luồng chính phải xử lý UI liên tục: Nếu các tác vụ dài như xử lý hình ảnh
hoặc tính toán phức tạp được thực hiện trên luồng chính, nó sẽ gây treo giao
https://aicandy.vn/cach-du-doan-gia-co-phieu-hieu-qua-bang-mo-hinh-lstm/
Bản quyền thuộc về: https://aicandy.vn
Học tập toàn diện: Kết nối lý thuyết, thực hành và dữ liệu thực tế
https://aicandy.vn
15
diện (UI freeze) vì giao diện sẽ không được cập nhật thường xuyên. Người
dùng sẽ cảm thấy ứng dụng bị đơ, phản hồi chậm.
Tách biệt xử lý nặng khỏi luồng chính: Các tác vụ nặng (ví dụ: xử lý ảnh, tính
toán mô hình AI) nên được thực hiện trên các luồng khác để giữ cho luồng
chính luôn “nhẹ nhàng”, đảm bảo trải nghiệm người dùng mượt mà và ứng
dụng có thể phản hồi nhanh chóng.
Sử dụng runOnUiThread để cập nhật UI: Sau khi hoàn thành xử lý trên luồng
phụ, chúng ta cần quay lại luồng chính để cập nhật UI (hiển thị kết quả phát
hiện đối tượng, v.v.). Do đó, phương pháp runOnUiThread được sử dụng
để đảm bảo rằng các thay đổi UI sẽ chạy an toàn trên luồng chính mà không
gây ra lỗi hoặc xung đột luồng.
runOnUiThread(() -> {
imageDisplay.setImageBitmap(inputImage);
detectButton.setEnabled(true);
detectButton.setText(getString(R.string.run));
loadingBar.setVisibility(ProgressBar.INVISIBLE);
detectionOverlay.setDetections(results);
detectionOverlay.invalidate();
detectionOverlay.setVisibility(View.VISIBLE);
// Load the next image for the next detection
loadNextImage();
});
7. Demo và source code
Video demo có tại đây
Source code miễn phí có tại đây
Bài trước
Danh mục
Bài sau
https://aicandy.vn/cach-du-doan-gia-co-phieu-hieu-qua-bang-mo-hinh-lstm/
Bản quyền thuộc về: https://aicandy.vn
Học tập toàn diện: Kết nối lý thuyết, thực hành và dữ liệu thực tế
https://aicandy.vn
16
Chúc bạn thành công trong hành trình khám phá và ứng dụng trí tuệ nhân tạo
vào học tập và công việc. Đừng quên truy cập thường xuyên để cập nhật thêm
kiến thức mới tại AIcandy