Detect and decode multiple 2d (Datamatrix, QRcode) from an image - java

I'm working on a project which involves taking an image file as input on my desktop and then detecting and decoding all the barcodes present, both 1D and 2D.
I've been working with zxing and with the help of GenericMultipleBarcodeReader I was able to read multiple 1D barcodes from the image. However, it fails to detect 2D barcodes.
But if I crop the 2D barcode and input this cropped part separately it detects and decodes it without any problem.
So, if my image has 2 1D barcode and a 2D barcode my output consists of just the 2 1D barcodes decoded.
I also tried using ByQuadrantReader but that doesn't work either.
My code:
LuminanceSource source = new BufferedImageLuminanceSource(image);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
Result[] result;
HashMap<DecodeHintType,Object> hints = new HashMap<>();
hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
try
{
result = new GenericMultipleBarcodeReader(new MultiFormatReader()).decodeMultiple(bitmap, hints);
}
catch (ReaderException re)
{
return re.toString();
}
List<String> strings = new ArrayList<String>();
for (Result r: result)
{
strings.add(r.getText());
}
return String.valueOf(Arrays.toString(strings.toArray()));
Could anyone tell me a way to do this?

QR codes can be found anywhere in the image, but Data Matrix must be in the center of the image to be found. This is why it's working when you crop the image.

Related

Android: image saved using copyPixelsFromBuffer is distorted

I am trying to make an image processing program in Android Studio and I have a problem concerning how to save a Bitmap.
My problem is about saving an image which comes from a ByteBuffer.
To show it here, I have done this: I load an image in a ByteBuffer and I try to save it, rescaled to 1014x1163 pixels. And the image I get is distorted, messy.
For example, here is an image I load:
And here is what I get in the image I save:
Here is my code:
imageSize = (int) (bmWidth*bmHeight*4);
ByteBuffer pixelsArray = ByteBuffer.allocateDirect(imageSize);
ByteBuffer outputArray = ByteBuffer.allocateDirect(imageSize);
workingBitmap.copyPixelsToBuffer(pixelsArray);
workingBitmap.copyPixelsToBuffer(outputArray);
int thiswidth = workingBitmap.getWidth();
int thisheight = workingBitmap.getHeight();
Bitmap copiedBitmap = Bitmap.createScaledBitmap(workingBitmap, Width, Height, false);
int thiswidth2 = copiedBitmap.getWidth();
int thisheight2 = copiedBitmap.getHeight();
outputArray.rewind();
copiedBitmap.copyPixelsFromBuffer(outputArray);
SaveJPG(copiedBitmap);
The function SaveJPG works fine because if I call SaveJPG(workingBitmap) it saves a normal image.
Here is the code with variables values during debugging:
I am wondering if the problem comes from the fact that the output resolution is not a multiple of 4. That's mandatory in my program: the output image resolution can be of any value (odd or even).
I have tried many different things (copying workingBitmap and resizing the copy for example).
No success. I don't know what the cause of the problem is.
Does anyone have some source code which can save an image of any resolution, stored in a ByteBuffer ?
Thanks in advance.
Try this
try (FileOutputStream out = new FileOutputStream(yourFileName)) {
yourBitmap.compress(Bitmap.CompressFormat.PNG, 100, out); // bmp is your Bitmap instance
// PNG is a lossless format, the compression factor (100) is ignored
} catch (IOException e) {
e.printStackTrace();
}
Or use this
MediaStore.Images.Media.insertImage(getContentResolver(), yourbitmap,
"File name", "description of the image");
I have found the cause of the problem. It was simply due to a problem in the width and height of the input image: I was using the width and height of the View which displays the input bitmap, instead of using the bitmap's width and height.

Trouble generating Barcode using ZXing library with large data

I need to generate barcode in 128A format with data: 900000588548001100001305000000000207201512345.6|12345.7
I'm using ZXing library and Here is my method:
private void barcodeGenerator(String data)
{
try
{
com.google.zxing.MultiFormatWriter writer = new MultiFormatWriter();
BitMatrix bm = writer.encode(data, BarcodeFormat.CODE_128, 700, 200);
Bitmap ImageBitmap = Bitmap.createBitmap(700, 200, Config.ARGB_8888);
for (int i = 0; i < 700; i++)
{//width
for (int j = 0; j < 200; j++)
{//height
ImageBitmap.setPixel(i, j, bm.get(i, j) ? Color.BLACK : Color.WHITE);
}
}
File f = new File(Environment.getExternalStorageDirectory() + "/barcode1.png");
FileOutputStream fos = new FileOutputStream(f);
ImageBitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
}
catch(Exception e)
{
e.printStackTrace();
}
}
This method generates and stores the barcode image in SDCard which m scanning using ZXing Barcode Scanner.
Barcode is successfully scanned when data is small. eg: 123.4|456.7
But if data is large, eg: 900000588548001100001305000000000207201512345.6|12345.7
It looks like some wrong barcode is generated and Scanner is not able to scan the generated barcode.
Thanks in advance for help.
Edit: Have added generated barcode images
You can upload the barcode image you produced to the ZXing Decoder Online to confirm if it is valid:
http://zxing.org/w/decode.jspx
There is no intrinsic limit to the length of a Code 128 barcode, and all the characters you have are valid.
Having said that, with Code 128A barcodes, having more than 20 characters encoded makes the resultant barcode very wide and hard to scan.
It is likely that the barcode is valid but the scanners camera is not able to get a clear enough picture of such a large barcode.
Take a look at this question for more information: Unable to scan Code 128
If possible, it would be recommended to use an alternative barcode format, such as QR code, which can store more data without increasing the barcode size.
https://play.google.com/store/apps/details?id=com.srowen.bs.android
android app scans perfectly. But while generating barcode make sure it's less width and height as possible, to easily fit to mobile camera to scan.
I regenerated barcode of CODE-128 for 900000588548001100001305000000000207201512345.6|12345.7 with just 300 and 150 it's able to scan, if it's not working for you then can scale up width and height.
Barcode generated: https://i.stack.imgur.com/UF0qJ.png
Screenshot after scanning

Get the coordinate of alignment pattern with ZXing

I am using Zxing library for my android project.I am scaning qr code via Intent.I can get QR code contents. But I don't know how to get its alignment pattern positions which are the smaller square patterns found in all but the simplest QR Codes. How can i access it? Any help would be appreciated. Thank you!
This is a very simple way to get the e corners coordinates:
private Result readQRCode(BufferedImage bi){
BinaryBitmap binaryBitmap;
Result result;
try{
binaryBitmap = new BinaryBitmap( new HybridBinarizer(new BufferedImageLuminanceSource( bi )));
result = new QRCodeReader().decode(binaryBitmap);
return result;
}catch(Exception ex){
ex.printStackTrace();
return null;
}
}
The result.getResultPoints() contains 3 points, that are the tree main corners. So, you can do:
//position of reference
posX = result.getResultPoints()[1].getX();
posY = result.getResultPoints()[1].getY();
That's it!

PDFBox draw black image from BufferedImage

I try to draw an image from a bufferedImage into a PDF using PDFBox but fails, and I get black images and Acrobat Reader warns whith errors like "Out of memory" (but PDF is display).
I use a bufferedImage because I need to draw a JavaFX Image object (with came from call to Funciones.crearImagenDesdeTexto(), is a function which converts a text into an Image) into PDF. Rest of images works well without using bufferedimage.
PDPixelMap img = null;
BufferedImage bi;
try {
//If item has id, I try to get image with that id (image it's shows OK on PDF)
img = new PDPixelMap(documento, read(getClass().getResourceAsStream("/com/img/" + item.getId() + ".png")));
}
catch (Exception e) {
//If item has not id or fails load image, I create image on the fly (which contains item name. This not work on PDF, shows black images)
bi = new BufferedImage(alto, ancho, BufferedImage.TYPE_INT_ARGB);
bi.createGraphics().drawImage(SwingFXUtils.fromFXImage(Funciones.crearImagenDesdeTexto(item.getNombre()), null), ancho, alto, null);
img = new PDPixelMap(documento, bi);
}
finally {
contenedor.drawXObject(img, x, y, alto, ancho);
}
NOTE: crearImagenDesdeTexto() returns a JavaFX Image Object that is create on the fly (I try this function in other parts of the program and works well, function is take from other stackOverflow response).
Your code is confusing, you have three "new PDJpeg" and one of them is in a catch (which should just handle the error). And what does "read()" do? Does it pass a stream or a BufferedImage? If it is a stream, then it is wrong, because PDJpeg is for JPEGs, not for PNG.
The second one
img = new PDJpeg(documento, (getClass().getResourceAsStream("/com/img/" + Byte.toString(item.getId()) + ".png")));
is definitively wrong for the same reason: PDJPeg is not for PNG files / streams.
If you want to create an image from a PNG file / stream, use PDPixelMap.
It is possible to create a PDJpeg object from a BufferedImage, but this is recommended only if the image wasn't encoded before. Because if you would read a BufferedImage from a JPEG, and then use PDJPeg for this, you'll have a slight loss of quality as the image is decoded and encoded again (JPEG is a "lossy" compression format).
If my advice doesn't help, please upload the JPEG file and the PDF somewhere.
Also make sure that you're using the latest version, which is 1.8.7.
Update after comments:
the parameters to createGraphics.drawImage() should be 0, 0 and not width, height. The two parameters are a location, not a size.
Finally, I find a solution (thanks also to Tilman Hausherr):
private void dibujarImagen(Item i, int x, int y, int alto, int ancho) throws IOException {
PDPixelMap img = null;
try {
img = new PDPixelMap(documento, read(getClass().getResourceAsStream("/com/img/" + i.getId() + ".png")));
}
catch (IllegalArgumentException e) {
img = new PDPixelMap(documento, SwingFXUtils.fromFXImage(Funciones.crearImagenDesdeTexto(i.getNombre()),null));
}
finally {
contenedor.drawXObject(img, x, y, alto, ancho);
}
}

Converting BufferedImage to Mat (OpenCV) in Java [duplicate]

This question already has answers here:
Converting `BufferedImage` to `Mat` in OpenCV
(9 answers)
Closed 6 years ago.
I've tried this link and have the code below. My program imports images in a BufferedImage format and then displays it to the users. I'm using the matchingTemplate function in OpenCV which requires me to convert it to a Mat format.
The code works if I import the image -> convert it to Mat then save the image using imwrite. The program also allows the user to crop an image and then use the Template matching to compare it to another image. The issue come when I tried to convert the cropped image to Mat I need to convert it from Int to Byte using this code:
im = new BufferedImage(im.getWidth(), im.getHeight(),BufferedImage.TYPE_3BYTE_BGR);
This however results in a black image. But if I get rid of it it only works with imported images and not cropped. What is going on here? I'm certain it is something to do with the coversion process as I have tested the template matching function using read in images.
// Convert image to Mat
public Mat matify(BufferedImage im) {
// Convert INT to BYTE
//im = new BufferedImage(im.getWidth(), im.getHeight(),BufferedImage.TYPE_3BYTE_BGR);
// Convert bufferedimage to byte array
byte[] pixels = ((DataBufferByte) im.getRaster().getDataBuffer())
.getData();
// Create a Matrix the same size of image
Mat image = new Mat(im.getHeight(), im.getWidth(), CvType.CV_8UC3);
// Fill Matrix with image values
image.put(0, 0, pixels);
return image;
}
You can try this method, to actually convert the image to TYPE_3BYTE_BGR (your code simply created a blank image of the same size, that is why it was all black).
Usage:
// Convert any type of image to 3BYTE_BGR
im = toBufferedImageOfType(im, BufferedImage.TYPE_3BYTE_BGR);
// Access pixels as in original code
And the conversion method:
public static BufferedImage toBufferedImageOfType(BufferedImage original, int type) {
if (original == null) {
throw new IllegalArgumentException("original == null");
}
// Don't convert if it already has correct type
if (original.getType() == type) {
return original;
}
// Create a buffered image
BufferedImage image = new BufferedImage(original.getWidth(), original.getHeight(), type);
// Draw the image onto the new buffer
Graphics2D g = image.createGraphics();
try {
g.setComposite(AlphaComposite.Src);
g.drawImage(original, 0, 0, null);
}
finally {
g.dispose();
}
return image;
}

Categories

Resources