Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Data Matrix Scan takes too long #932

Open
smi42 opened this issue Jun 27, 2024 · 0 comments
Open

Data Matrix Scan takes too long #932

smi42 opened this issue Jun 27, 2024 · 0 comments

Comments

@smi42
Copy link

smi42 commented Jun 27, 2024

I'm currently working on a Java application that needs to scan Data Matrix QR-Codes, specifically to extract and display XML data in a text box. The QR-Codes I'm dealing with contain BMP (German medication plans). For testing purposes, I'm using examples from this document: https://download.hl7.de/ukf/Testfaelle_ukf201.pdf im running this on a microsoft surface go 4 business webcam specs are : Rear Camera:

Resolution: 8.0 megapixels Video Resolution: 1080p HD video

Logging in german btw

Here's the code I have so far:

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import com.github.sarxos.webcam.Webcam;
import com.github.sarxos.webcam.WebcamPanel;
import com.github.sarxos.webcam.WebcamResolution;
import com.google.zxing.*;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;

import javax.swing.*;
import java.awt.*;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.logging.Logger;

public class QRCodeScanner extends JFrame implements Runnable, ThreadFactory {

    private static final Logger LOGGER = Logger.getLogger(QRCodeScanner.class.getName());
    
    private static final long serialVersionUID = 1L;

    private BlockingQueue<String> decodedResultsQueue = new LinkedBlockingQueue<>();

    
    private Executor executor = Executors.newSingleThreadExecutor(this);
    private Webcam webcam = null;
    private WebcamPanel panel = null;
    private JTextArea textarea = null;
    private JScrollPane scrollPane = null;

    public QRCodeScanner() {
        super();

        setLayout(new BorderLayout());
        setTitle("QR Code Scanner");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        Dimension size = WebcamResolution.VGA.getSize();

        webcam = Webcam.getWebcams().get(1);
        webcam.setViewSize(size);

        panel = new WebcamPanel(webcam);
        panel.setPreferredSize(size);

        textarea = new JTextArea();
        textarea.setEditable(false);
        scrollPane = new JScrollPane(textarea);
        scrollPane.setPreferredSize(size);

        add(panel, BorderLayout.WEST);
        add(scrollPane, BorderLayout.CENTER);

        pack();
        setVisible(true);

        executor.execute(this);
    }

    @Override
    public void run() {
        do {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                LOGGER.severe("Thread interrupted: " + e.getMessage());
            }

            BufferedImage image = null;

            if (webcam.isOpen()) {
                LOGGER.info("Webcam is open.");
                if ((image = webcam.getImage()) == null) {
                    LOGGER.warning("Webcam image is null.");
                    continue;
                }
            } else {
                LOGGER.warning("Webcam is not open.");
            }

            Result result = processImageAndDecodeQRCode(image);

            if (result != null) {
                if (result.getBarcodeFormat() == BarcodeFormat.UPC_E) {
                    LOGGER.info("Detected UPC_E format, rescanning...");
                    continue;
                }
                result.getBarcodeFormat();
                LOGGER.info("QR code format: " + result.getBarcodeFormat());
                result.getNumBits();
                LOGGER.info("QR code num bits: " + result.getNumBits());
                result.getResultMetadata();
                LOGGER.info("QR code result metadata: " + result.getResultMetadata());
                result.getRawBytes();
                LOGGER.info("QR code raw bytes: " + result.getRawBytes());
                String text = result.getText();
                LOGGER.info("QR code text: " + text);
                decodedResultsQueue.add(text);
            }
        } while (true);
    }

    private Result processImageAndDecodeQRCode(BufferedImage image) {
        // Preprocess image: convert to grayscale and apply thresholding
        BufferedImage grayscaleImage = new BufferedImage(
            image.getWidth(), image.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
        Graphics g = grayscaleImage.getGraphics();
        g.drawImage(image, 0, 0, null);
        g.dispose();

        LuminanceSource source = new BufferedImageLuminanceSource(grayscaleImage);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));

        Result result = null;
        try {
            result = new MultiFormatReader().decode(bitmap);
        } catch (NotFoundException e) {
            LOGGER.warning("No QR code found.");
            e.getCause();
        }

        return result;
    }

    public void startUIUpdateThread() {
        new Thread(() -> {
            while (true) {
                try {
                    // Take the next decoded result from the queue and update the UI
                    String text = decodedResultsQueue.take();
                    textarea.append(text + "\n");
                } catch (InterruptedException e) {
                    LOGGER.severe("UI update thread interrupted: " + e.getMessage());
                }
            }
        }).start();
    }
    
    
    
    
    @Override
    public Thread newThread(Runnable r) {
        Thread t = new Thread(r, "example-runner");
        t.setDaemon(true);
        return t;
    }

    public static void main(String[] args) {
        QRCodeScanner scanner = new QRCodeScanner();
        scanner.startUIUpdateThread();  // Start the UI update thread
    }
}

Tried it on online generated Data Matrix QR Codes and it works really well https://barcode.tec-it.com/en/DataMatrix?data=This%20is%20a%20Data%20Matrix%20by%20TEC-IT99999 Sometimes I'm able to scan those example codes from the PDF, but it takes too long, if it even works. I want this app to perform as well as those QR code scanners from the Play Store.

Maybe someone with more knowledge in computer vision can help me optimize the scanning process or suggest a more efficient approach?

Any assistance or pointers would be greatly appreciated. Thanks in advance!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant