How to read datamatrix embedded in document?

759 Views Asked by At

I try to read a datamatrix which is embedded into a document. This is for an opensource project which helps to create and read 2DCODE standard.

I try with this code :

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Hashtable;

import javax.imageio.ImageIO;

import org.junit.Test;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.LuminanceSource;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.Result;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.HybridBinarizer;

public class ZxingTest {

    @Test
    public void test() {

        readQRCode("sfr-facture-1048469311-1.jpg");
        readQRCode("sfr-facture-1048469311-1.png");

    }

    public static void readQRCode(String fileName) {

        System.out.println("Try reading " + fileName);

        File file = new File(fileName);
        BufferedImage image = null;

        try {
            image = ImageIO.read(file);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        if (image == null)
            return;

        Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>();
        // hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
        hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
        hints.put(DecodeHintType.POSSIBLE_FORMATS, Arrays.asList(BarcodeFormat.DATA_MATRIX));

        decode(image, hints);

    }

    public static void decode(BufferedImage tmpBfrImage, Hashtable<DecodeHintType, Object> hintsMap) {
        if (tmpBfrImage == null)
            throw new IllegalArgumentException("Could not decode image.");
        LuminanceSource tmpSource = new BufferedImageLuminanceSource(tmpBfrImage);
        BinaryBitmap tmpBitmap = new BinaryBitmap(new HybridBinarizer(tmpSource));
        MultiFormatReader tmpBarcodeReader = new MultiFormatReader();

        Result tmpResult;
        String tmpFinalResult;
        try {
            
            if (hintsMap != null && !hintsMap.isEmpty())
                tmpResult = tmpBarcodeReader.decode(tmpBitmap, hintsMap);
            else
                tmpResult = tmpBarcodeReader.decode(tmpBitmap);
            
            // setting results.
            tmpFinalResult = String.valueOf(tmpResult.getText());
            System.out.println("tmpFinalResult=" + tmpFinalResult);
        } catch (Exception tmpExcpt) {
            tmpExcpt.printStackTrace();
        }
    }

}

and those images found on the net :

sfr-facture-1048469311-1.jpg
sfr-facture-1048469311-1.png

But I get this exception regardless of the image format: com.google.zxing.NotFoundException

May you advise me an lib which parses the page and detect the datamatrix coordinates for a pre-processing cropping?

Or a better a example of code which read the datamatrix?

1

There are 1 best solutions below

0
On

I have a solution to my problem. I use opencv to locate any barcode then, after extraction according to the returned coordinates, I read them with zxing.

I based my solution the work of http://karthikj1.github.io/BarcodeLocalizer/

this the code i use :

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;

import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.LuminanceSource;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.Reader;
import com.google.zxing.ReaderException;
import com.google.zxing.Result;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.HybridBinarizer;

import barcodelocalizer.Barcode;
import barcodelocalizer.CandidateResult;
import barcodelocalizer.ImageDisplay;
import barcodelocalizer.MatrixBarcode;
import barcodelocalizer.TryHarderFlags;

public class OpencvUtils {

    private static boolean SHOW_INTERMEDIATE_STEPS = false;
    private static boolean showImages = false;

    public static String process_bufferedImage(BufferedImage bufferedImage) {
        Barcode barcode;

        String barcodeText = null;

        // instantiate a class of type MatrixBarcode with the image filename
        try {
            barcode = new MatrixBarcode(bufferedImage, SHOW_INTERMEDIATE_STEPS, TryHarderFlags.VERY_SMALL_MATRIX);

            // locateBarcode() returns a List<CandidateResult> with all possible candidate
            // barcode regions from
            // within the image. These images then get passed to a decoder(we use ZXing here
            // but could be any decoder)
            List<CandidateResult> results = barcode.locateBarcode();
            System.out.println("Decoding buffered image " + results.size() + " candidate codes found");

            String barcodeName = barcode.getName();

            barcodeText = decodeBarcode(results, barcodeName, "Localizer");

        } catch (IOException ioe) {
            System.out.println("IO Exception when finding barcode " + ioe.getMessage());
        }

        return barcodeText;
    }

    public static String process_image(String imgFile) {
        Barcode barcode;

        String barcodeText = null;

        // instantiate a class of type MatrixBarcode with the image filename
        try {
            barcode = new MatrixBarcode(imgFile, SHOW_INTERMEDIATE_STEPS, TryHarderFlags.VERY_SMALL_MATRIX);

            // locateBarcode() returns a List<CandidateResult> with all possible candidate
            // barcode regions from
            // within the image. These images then get passed to a decoder(we use ZXing here
            // but could be any decoder)
            List<CandidateResult> results = barcode.locateBarcode();
            System.out.println("Decoding " + imgFile + " " + results.size() + " candidate codes found");

            String barcodeName = barcode.getName();

            barcodeText = decodeBarcode(results, barcodeName, "Localizer");

        } catch (IOException ioe) {
            System.out.println("IO Exception when finding barcode " + ioe.getMessage());
        }

        return barcodeText;
    }

    private static String decodeBarcode(List<CandidateResult> candidateCodes, String filename, String caption) {
        // decodes barcode using ZXing and either print the barcode text or says no
        // barcode found
        BufferedImage decodedBarcode = null;
        String title = null;
        Result result = null;

        String barcodeText = null;

        for (CandidateResult cr : candidateCodes) {
            BufferedImage candidate = cr.candidate;
            decodedBarcode = null;
            LuminanceSource source = new BufferedImageLuminanceSource(candidate);
            BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
            Reader reader = new MultiFormatReader();

            Map<DecodeHintType, Object> hints = new EnumMap<>(DecodeHintType.class);
            hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);

            try {
                result = reader.decode(bitmap, hints);
                decodedBarcode = candidate;
                title = filename + " " + caption + " - barcode text " + result.getText() + " " + cr.getROI_coords();
            } catch (ReaderException re) {
            }
            if (decodedBarcode == null) {
                title = filename + " - no barcode found - " + cr.getROI_coords();
                if (showImages)
                    ImageDisplay.showImageFrame(candidate, title);
            } else {
                if (showImages)
                    ImageDisplay.showImageFrame(decodedBarcode, title);

                System.out.println("Barcode text for " + filename + " is " + result.getText());
                barcodeText = result.getText();
            }
        }

        return barcodeText;

    }

}

i added the method process_bufferedImage which process a java.awt.image.BufferedImage of a String filename.

And this sub-method to get the matrix of the BufferedImage bi.

protected Mat loadBufferedImage(BufferedImage bi) throws IOException {
        // reads the BufferedImage passed in parameter
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ImageIO.write(bi, "png", byteArrayOutputStream);
        byteArrayOutputStream.flush();

        Mat mat = Imgcodecs.imdecode(new MatOfByte(byteArrayOutputStream.toByteArray()), Imgcodecs.IMREAD_UNCHANGED);

        return mat;
    }