提问人:Anatoliy Voronin 提问时间:8/24/2023 更新时间:10/2/2023 访问量:80
MLKit Android 倒置数据矩阵扫描时间过长
MLKit Android inverted datamatrix scan takes too long time
问:
首先 - 对不起我的英语:)
我在项目中使用 MLKit 扫描条形码(数据矩阵)。但是我在黑色背景上有白色数据矩阵,就像这张 Datamatrix 图像一样
在我的代码中,我在扫描之前裁剪图像。在此之后,我反转了这张裁剪图像的颜色,并将这张图片放入扫描仪。
我遇到的问题是扫描仪无法定义具有良好图像的代码。它正在经历一些分析,并从第 6-10 次分析中阅读它。
例如。这是数据矩阵扫描的屏幕截图。中间有方形图像。imageView被裁剪和反转的图像进入扫描仪。但它并没有给出快速的结果。我需要等待 3-5 秒才能从那里获取代码。而它的扫描扫描仪可在 3 秒内进行 4-1-1 次分析。
我有这个 MLKit 扫描的 iOS 应用程序替代品。它执行相同的步骤(裁剪和反转),但 iOS 应用程序正在扫描此步骤 1 秒,可能更快。
我尝试了一切方法来加快扫描速度,但没有任何帮助。请帮忙
我把我的类放在 git 中。所以我在这里放了短代码。
这是我的带有初始化的 ScanFragment.java
private CamcorderProfile camProfile;
private ListenableFuture cameraProviderFuture;
private ExecutorService cameraExecutor;
private PreviewView previewView;
private ImageAnalyser analyser;
private androidx.camera.core.Camera camera;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_scan_ui, container, false);
previewView = view.findViewById(R.id.previewview);
requireActivity().getWindow().setFlags(1024, 1024);
cameraExecutor = Executors.newSingleThreadExecutor();
cameraProviderFuture = ProcessCameraProvider.getInstance(requireActivity());
try {
processCameraProvider = (ProcessCameraProvider) cameraProviderFuture.get();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
cameraProviderFuture.addListener(() -> {
if (ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA) != (PackageManager.PERMISSION_GRANTED)) {
requestPermissionLauncher.launch(Manifest.permission.CAMERA);
} else {
bindpreview();
}
}, ContextCompat.getMainExecutor(requireContext()));
return view;
}
private void setTabDatamatrix() {
camProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_1080P);
BarcodeScannerOptions barcodeScanOptions = new BarcodeScannerOptions.Builder()
.setBarcodeFormats(
Barcode.FORMAT_DATA_MATRIX
).build();
if (analyser == null)
analyser = new ImageAnalyser(getParentFragmentManager(), barcodeScanOptions, this, this);
else
analyser.setScanOptions(barcodeScanOptions, ScanType.DATAMATRIX);
scanType = ScanType.DATAMATRIX;
hideProgressBar();
bottomBar.performShow();
showCursor();
setTabBackground(ivScanTabDatamatrix);
tvScanHintMoveCamera.setVisibility(View.VISIBLE);
tvScanHintMoveCamera.setText(Utils.getString(R.string.scanner_tab_mark_hint, requireContext()));
tooltip.show(ivScanTabDatamatrix, Utils.getString(R.string.scanner_tab_mark, requireContext()));
showHint(coordinatorLayout, ScanHintView.ScanHintType.MARK);
bindpreview();
}
private void bindpreview() {
Preview preview = new Preview.Builder().build();
CameraSelector cameraSelector = new CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build();
preview.setSurfaceProvider(previewView.getSurfaceProvider());
ImageCapture imageCapture = new ImageCapture.Builder().build();
ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
.setTargetResolution(new Size(camProfile.videoFrameHeight, camProfile.videoFrameWidth)) //480 320
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build();
imageAnalysis.setAnalyzer(cameraExecutor, analyser);
processCameraProvider.unbindAll();
camera = processCameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture, imageAnalysis);
}
这是 ImageAnalyser .java类。我在这里分析扫描的图像。
@Override
public void analyze(@NonNull ImageProxy image) {
scanbarcode(image);
}
private void scanbarcode(ImageProxy image) {
@SuppressLint("UnsafeOptInUsageError") Bitmap bitmap = BitmapUtils.getBitmap(image);
assert bitmap != null;
Bitmap cropped = Bitmap.createBitmap(bitmap, bitmap.getWidth() / 4, (bitmap.getHeight() / 2) - bitmap.getWidth() / 4, bitmap.getWidth() / 2, bitmap.getWidth() / 2);
Bitmap inverted = inverseBitmapColors(cropped);
InputImage invertedImage = InputImage.fromBitmap(inverted, image.getImageInfo().getRotationDegrees());
BarcodeScanner scanner = BarcodeScanning.getClient(barcodeScannerOptions);
scanner.process(invertedImage)
.addOnSuccessListener(barcodes -> {
if (active) {
readerBarcodeData(barcodes);
}
})
.addOnFailureListener(e -> {
})
.addOnCompleteListener(task -> image.close());
}
private Bitmap inverseBitmapColors(Bitmap bitmap) {
Bitmap invBitmap = bitmap.copy(bitmap.getConfig(), true);
for (int i = 0; i < invBitmap.getWidth(); i++) {
for (int j = 0; j < invBitmap.getHeight(); j++) {
invBitmap.setPixel(i, j, invBitmap.getPixel(i, j) ^ 0x00ffffff);
}
}
return invBitmap;
}
我尝试了许多裁剪、吟唱质量的操作,尝试了许多反转颜色的方法。 我希望它会在 1 秒或更快的时间内像 iOS 应用程序一样扫描。不是 3-5 秒。
答:
1赞
Anatoliy Voronin
10/2/2023
#1
我是这样做的。InputImage
@SuppressLint("UnsafeOptInUsageError") Image image = imageProxy.getImage();
assert image != null;
byte[] imageByteArray = YUV_420_888toNV21(image);
int size = min(image.getWidth(), image.getHeight()) / 2;
byte[] cropped = cropNV21(imageByteArray, image.getWidth(), image.getHeight(), (image.getWidth() - size) / 2, (image.getHeight() - size) / 2, size, size);
assert cropped != null;
InputImage inputImage = InputImage.fromByteArray(cropped, size, size, imageProxy.getImageInfo().getRotationDegrees(), InputImage.IMAGE_FORMAT_NV21);
InputImage invertedImage = InputImage.fromByteArray(inverse(cropped), size, size, imageProxy.getImageInfo().getRotationDegrees(), InputImage.IMAGE_FORMAT_NV21);
private byte[] YUV_420_888toNV21(Image image) {
byte[] nv21;
ByteBuffer yBuffer = image.getPlanes()[0].getBuffer();
ByteBuffer uBuffer = image.getPlanes()[1].getBuffer();
ByteBuffer vBuffer = image.getPlanes()[2].getBuffer();
int ySize = yBuffer.remaining();
int uSize = uBuffer.remaining();
int vSize = vBuffer.remaining();
nv21 = new byte[ySize + uSize + vSize];
//U and V are swapped
yBuffer.get(nv21, 0, ySize);
vBuffer.get(nv21, ySize, vSize);
uBuffer.get(nv21, ySize + vSize, uSize);
return nv21;
}
private byte[] inverse(byte[] bytes) {
byte[] inverted = new byte[bytes.length];
for (int i = 0; i < bytes.length; i++) {
inverted[i] = (byte) (bytes[i] ^ 0xff);
}
return inverted;
}
private byte[] cropNV21(byte[] src, int width, int height, int left, int top, int clip_w, int clip_h) {
if (left > width || top > height) {
return null;
}
// Take the couple
int x = left * 2 / 2, y = top * 2 / 2;
int w = clip_w * 2 / 2, h = clip_h * 2 / 2;
int y_unit = w * h;
int src_unit = width * height;
int uv = y_unit >> 1;
byte[] nData = new byte[y_unit + uv];
for (int i = y, len_i = y + h; i < len_i; i++) {
for (int j = x, len_j = x + w; j < len_j; j++) {
nData[(i - y) * w + j - x] = src[i * width + j];
nData[y_unit + ((i - y) / 2) * w + j - x] = src[src_unit + i / 2 * width + j];
}
}
return nData;
}
评论