Đọc QR Code sử dụng Vision API
Bài đăng này đã không được cập nhật trong 8 năm
Có nhiều bạn muốn tạo một ứng dụng trong đó có chức năng đọc mã QR code. Hôm nay mình xin hướng dẫn các bạn viết 1 app như vậy.
Giới thiệu
- Với việc giới thiệu Google Play service 9.6 thì Google đã cho ra mắt Mobile Vision API cung cấp các API để đọc mã vạch(barcode) của nhiều loại khác nhau một cách dễ dàng và nhanh chóng.
Đọc barcode
-
Class để phát hiện và phân tích barcode có trong namspace com.google.android.gms.vision.barcode. Class BarcodeDetector xử lý và trả về loại SparseArray<Barcode>.
-
Loại Barcode thể hiện qua mã vạch và giá trị của nó .
-
Trong trường hợp barcode 1D như mã UPC, đơn giản nó chỉ là một số được mã hóa thành mã vạch .
-
Trường hợp barcode 2D mà bao gồm cả dữ liệu như mã QR thì biến valueFormat sẽ dùng để phát hiện loại giá trị và dữ liệu tương ứng . Ví dụ, nếu URL được phát hiện, thì nó sẽ được load giá trị vào trong biến valueFormat, và Barcode.UrlBookmark sẽ bao gồm giá trị URL.
-
Khi sử dụng Mobile Vision API, bạn có thể đọc barcode ở hướng bất kỳ . Một điều quan trọng là tất cả các mã vạch được xử lý hoàn toàn cục bộ, vì thế mà bạn không cần một server để đọc dữ liệu từ code.
Điều kiện
- Trước khi bắt đầu bạn nên kiểm tra xem đã đầy đủ các điều kiện bên dưới chưa nhé:
Android Studio Thiết bị android chạy Android 4.2.2 trở lên Phiên bản mới nhất Android SDK Google Play service SDK
- Trong app này mình sẽ sử dụng thư viện google play services. Để cài đặt thư viện này ta làm như sau. Trong file build.gradle của modul app của bạn cho vào như sau
compile 'com.google.android.gms:play-services:7.8.0'
- Tiếp theo ta sửa file Manifest. Trong file AndroidManifest bạn thêm dòng sau
<meta-data android:name="com.google.android.gms.vision.DEPENDENCIES" android:value="barcode"/>
- Ta cần xin quyền truy cập vào camera nữa.
<uses-permission android:name="android.permission.CAMERA" />
I. Đọc một Mã QR Từ một hình ảnh
-
Bây giờ hãy viết một số mã có thể đọc mã QR từ một bức ảnh được lưu trữ trong ứng dụng của bạn . Tôi sẽ đặt tên cho ảnh myqrcode.jpg nằm trong thư mục assets. Nếu bạn không có bất kỳ ảnh có chứa mã QR tiện dụng, bạn có thể nhận được một số từ Flickr .
Bước 1: Chuyển đổi các hình ảnh vào một Bitmap.
-
Bạn cần convert image của bạn nằm trong mục assets ra một đinh dạng của bitmap . Mục đích là API từ sdk có thể nhận diện Mã QR code thông qua bitmap của một image bất kì .
Bitmap myQRCode = BitmapFactory.decodeStream(
getAssets().open("myqrcode.jpg")
);
**Bước 2: Tạo một Detector mã vạch**
- Để phát hiện mã QR (và các loại mã vạch), bạn nên sử dụng lớp BarcodeDetector. Các mã sau đây cho bạn thấy làm thế nào để tạo ra một cách sử dụng .
BarcodeDetector barcodeDetector =
new BarcodeDetector.Builder(this)
.setBarcodeFormats(Barcode.QR_CODE)
.build();
-
Sét phướng thức setBarcodeFormats để phát hiện mã QR Code.
Bước 3: Đọc mã QR
-
Sử dụng Frame.Builder để tạo ra một Frame cách sử dụng Bitmap mà bạn đã tạo trước đó.
Frame myFrame = new Frame.Builder()
.setBitmap(myQRCode)
.build();
- Trong class BarcodeDetector gọi phương thức detect mục đích để tạo ra một mảng chứa tất cả các mã BarcodeDetector để nhận biết mã hình ảnh của bạn .
SparseArray<Barcode> barcodes = barcodeDetector.detect(myFrame);
- Trong class SparseArray chứa đối tượng Barcode để lấy các nội dung cơ bản nhất của mã QR . Trong đó rawValue chứa hầu hết các nội dung hay cách nhận dạng đối tượng bạn cần quan tâm . Nhưng để bạn dễ sử dụng hơn bạn có thể sử dụng dislayValue để kiểm tra và tim ra những thông báo của mã QR code .
// Check if at least one barcode was detected
if(barcodes.size() != 0) {
// Print the QR code's message
Log.d("My QR Code's Data",
barcodes.valueAt(0).displayValue
);
}
II. Đọc một Mã QR Từ một hình ảnh
Tạo một giao diện cho app
-
Bây giờ chúng ta sẽ xây dựng giao diện nhằm mục đích phát hiện hình ảnh barcode trong một bức ảnh và sau đó bao quanh nó một box.
-
Trong Android Studio, chọn thư mục “res”, mở “layout” bạn sẽ thấy file activity_main.xml.
-
Mở file này ra và chọn tab Text ở dưới cùng (gần tab Design). Android Studio sẽ trông như sau:
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView android:text=""
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/txtContent"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Process"
android:id="@+id/button"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/imgview"/>
</LinearLayout>
-
layout trên có một button để load và xử lý một hình ảnh xuất hiện trong ImageView. Sau khi xử lý xong, dữ liệu từ barcode sẽ xuất hiện trong TextView.
-
Thêm Barcode cho app
-
Thường thì bạn chụp hình mã vạch bằng camera trên máy hoặc xử lý một hình ảnh . Quá trình này sẽ thêm vài dòng code nữa, bước sau sẽ làm việc này . Còn hiện tại để đơn giản, bạn sẽ xử lý một hình ảnh mà đã có sẵn trong app.
-
Đây là hình ảnh:
Bắt đầu code
-
Khi bạn tạo một activity như vậy, android studio đã tạo một menu trên app. Bạn không cần sử dụng nó, cho nên xóa đi. Mở file MainActivity và tìm phương thức onCreateOptionMenu và onOptionsItemSelected và xóa .
-
Mục đích của ứng dụng là load một hình ảnh, phát hiện hình ảnh barcode và vẽ một hình chữ nhật màu đỏ bao quanh nó . Bây giờ viết code để làm việc này:
Include
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.util.SparseArray;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import com.google.android.gms.vision.Frame;
import com.google.android.gms.vision.barcode.Barcode;
import com.google.android.gms.vision.barcode.BarcodeDetector;
Gọi button và cài đặt sự kiện
- Trong phương thức onCreate() của file MainActivity.java, thêm đoạn code sau:
Button btn = (Button) findViewById(R.id.button);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
- Việc này sẽ tạo sự kiện onClick khi người dùng chạm vào button. Khi đó, chúng ta sẽ load mã vạch, xử lý nó và đẩy kết quả lên TextView.
Load hình ảnh
- Gọi Image từ layout và đặt tên cho nó là “myImageView”. Sau đó sử dụng BitMapFactory để xử lý file R.drawable.puppy vào trong một Bitmap. Sau đó gán Bitmap này cho ImageView:
ImageView myImageView = (ImageView) findViewById(R.id.imgview);
Bitmap myBitmap = BitmapFactory.decodeResource(
getApplicationContext().getResources(),
R.drawable.puppy);
myImageView.setImageBitmap(myBitmap);
Cài đặt Barcode Detector
-
Tiếp theo chúng ta sẽ tạo một detector để phát hiện barcode.
-
Tạo BarcodeDetector sử dụng mọt builder và yêu cầu nó tìm mã QR và ma trận dữ liệu (có nhiều loại barcode khác nhau nhé)
-
B ạn cần kiểm ta xem detector của chúng ta có hoạt động hay không trước khi sử dụng nó . Nếu không thì cần phải đợi để download hoàn thành hoặc để người dùng biết rằng cần phải kết nối internet hoặc bộ nhớ không còn trên thiết bị …
BarcodeDetector detector =
new BarcodeDetector.Builder(getApplicationContext())
.setBarcodeFormats(Barcode.DATA_MATRIX | Barcode.QR_CODE)
.build();
if(!detector.isOperational()){
txtView.setText("Could not set up the detector!");
return;
}
Phát hiện barcode
-
Code sau sẽ tạo một frame từ bitmap và truyền nó đến detector. Điều này sẽ trả về một SparseArray của barcode.
-
Nhớ là API có khả năng phát hiện nhiều barcode trong cùng một hình ảnh. Ví dụ của chúng ta chỉ có một
Frame frame = new Frame.Builder().setBitmap(myBitmap).build();
SparseArray<Barcode> barcodes = detector.detect(frame);
Xử lý Barcode
- Thường thì phải duyệt qua SparseArray để tìm kiếm nhiều barcode và xử lý từng cái một, hoặc có thể không có barcode nào . Trong ví dụ nay ta biết chắc chắc nó có một barcode nên viết code cứng nhắc dành cho nó thôi, các trường hợp các bạn tự viết nhé. Ở đây sẽ lấy phần tử đầu tiên của mảng:
Barcode thisCode = barcodes.valueAt(0);
TextView txtView = (TextView) findViewById(R.id.txtContent);
txtView.setText(thisCode.rawValue);
Kết quả
- Bây giờ chạy app. Kết quả như hình dưới:
- Mình xin hết.
All rights reserved