MLKit Android 倒置数据矩阵扫描需要很长时间

问题描述 投票:0回答:1

首先 - 对不起我的英语:)

我在项目中使用MLKit来扫描条形码(datamatrix)。但我在黑色背景上有白色数据矩阵,就像这样Datamatrix image

在我的代码中,我在扫描之前裁剪图像。之后,我反转该裁剪图像的颜色并将该图像放入扫描仪中。

我遇到的问题是扫描仪无法定义具有良好图像的代码。它会进行一些分析并从第 6-10 次分析中读取它。

例如。这是数据矩阵扫描的screenshot。中心有一个正方形图像。 imageView 被裁剪并反转图像发送到扫描仪。但它不会给出快速结果。我需要等待 3-5 秒才能从那里获取代码。而其扫描仪可在 1 秒内进行 3-4 次分析。

我有这个 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;
    }

我尝试了很多裁剪、改变质量的操作,尝试了很多反转颜色的方法。 我预计它会像 iOS 应用程序一样在 1 秒或更快的时间内进行扫描。不是3-5秒。

java android barcode google-mlkit datamatrix
1个回答
0
投票

我像这样制作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;
    }
© www.soinside.com 2019 - 2024. All rights reserved.