I am trying to read 2D Data matrix barcode using zxing library(GenericMultipleBarcodeReader). I have multiple barcodes on a single image.
The problem is that the efficiency of the zing reader is very low, it
recognizes 1 barcode from image 1.png and no barcode from image 2.png which has 48 barcodes. Is there
any way to get 100% efficiency or any other library which results 100%
My code to read barcode is:
public static void main(String[] args) throws Exception {
BufferedImage image = ImageIO.read(new File("1.png"));
if (image != null) {
LuminanceSource source = new BufferedImageLuminanceSource(image);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
DataMatrixReader dataMatrixReader = new DataMatrixReader();
Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>();
hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
GenericMultipleBarcodeReader reader = new GenericMultipleBarcodeReader(
dataMatrixReader);
Result[] results = reader.decodeMultiple(bitmap, hints);
for (Result result : results) {
System.out.println(result.toString());
}
}
}
And images I used are:
Please help to resolve this issue.
Thanks
It doesn't quite work this way. It will not read barcodes in a grid, as it makes an assumption that it can cut up the image in a certain way that won't be compatible with grids. You will have to write your own method to cut up the image into scannable regions.
It is also the case that the Data Matrix decoder assumes the center of the image is inside the barcode. This is another reason you need to pre-chop the image into squares around the cylinders and then scan. It ought to work fairly well then.
An alternative solution is to consider a barcode engine that can detect multiple barcodes in various orientations on one document. If you're running on Windows, the ClearImage Barcode SDK has a Java API and should be able to handle your needs without pre-processing. You can test if their engine can read your image using their Online Barcode Reader.
Some sample code:
public static void testDataMatrix () {
try {
String filename = "1.png ";
CiServer objCi = new CiServer();
Ci = objCi.getICiServer();
ICiDataMatrix reader = Ci.CreateDataMatrix(); // read DataMatrix Barcode
reader.getImage().Open(filename, 1);
int n = reader.Find(0); // find all the barcodes in the doc
for (i = 1; i <= n; i++) {
ICiBarcode Bc = reader.getBarcodes().getItem(i); // getItem is 1-based
System.out.println("Barcode " + i + " has Text: " + Bc.getText());
}
} catch (Exception ex) {System.out.println(ex.getMessage());}
}
Disclaimer: I've done some work for Inlite in the past.
Related
I am doing a project where I need to identify certain areas of the image. After processing the image and removing all the unnecessary things I finally get the area which I need as shown in the image (area inside the green circle).
I am unable to draw a circle around that area using OpenCV. I am currently using the Java version of OpenCV. If someone can point me to the right direction on how to implement that green circle over the image, it will be very helpful.
Things I have tried to detect that area.
blob detector - Did not achieve much.
Cluster - Same as blob detector.
HoughCircles - Draws unnecessary circles in the image.
FindContour - Did not draw anything since it is not a perfect circle, ellipse or any other well known polygon.
I appreciate your help.
Here is a solution:
Opening in order to clean the image from all the thin/elongate patterns.
Connected component labeling in order to count the remaining patterns
Size counting of each remaining pattern
The biggest pattern is the one you want to circle.
Note: is you want to perfectly preserve the pattern, you can replace the opening by an opening by reconstruction (erosion + geodesic reconstruction).
I finally found a solution for my problem. I used the feature detector from the OpenCV library and gave the right threshold to the detector. This did the trick for me. The code in Java looks like below.
public static void main(String[] args){
try{
//Validation whether a file name is passed to the function
if(args.length == 0){
System.out.println("here...");
log.error("No file was passed to the function");
throw new IOException();
}
//Read the image from the input
Mat inputMat = Highgui.imread(args[0],Highgui.CV_LOAD_IMAGE_GRAYSCALE);
//Create a feature detector. In this case we are using SURF (Speeded-Up Robust Features) detector.
MatOfKeyPoint objectKeyPoints = new MatOfKeyPoint();
FeatureDetector featureDetector = FeatureDetector.create(FeatureDetector.SURF);
//A temporary file is created to input Hessian Threshold to the SURF detector
File tempFile = File.createTempFile("config", ".yml");
String settings = "%YAML:1.0\nhessianThreshold: 7000.\noctaves: 3\noctaveLayers: 4\nupright: 0\n";
FileWriter writer = new FileWriter(tempFile, false);
writer.write(settings);
writer.close();
//Read the configuration from the temporary file to assign the threshold for the detector
featureDetector.read(tempFile.getPath());
//Detect the features in the image provided
featureDetector.detect(inputMat, objectKeyPoints);
//Iterate through the list of key points detected in the previous step and find the Key Point with the largest size
List<KeyPoint> objectKeyPointList = objectKeyPoints.toList();
KeyPoint impKeyPoint = new KeyPoint();
for(int i=0; i<objectKeyPointList.size(); i++){
if(impKeyPoint == null){
impKeyPoint = objectKeyPointList.get(i);
}
else if(impKeyPoint.size < objectKeyPointList.get(i).size){
impKeyPoint = objectKeyPointList.get(i);
}
}
//If the size of the Key Point is greater than 120 then reduce the size to 120 and if the size is less than 120 then increase to 120
if(impKeyPoint.size > 120){
KeyPoint tempKeyPoint = new KeyPoint();
tempKeyPoint = impKeyPoint;
tempKeyPoint.size = 120;
impKeyPoint = tempKeyPoint;
}
else if(impKeyPoint.size < 120){
KeyPoint tempKeyPoint = new KeyPoint();
tempKeyPoint = impKeyPoint;
tempKeyPoint.size = 120;
impKeyPoint = tempKeyPoint;
}
//Convert the Key Point to MatOfKeyPoint since drawKeyPoints accepts only MatOfKeyPoint
MatOfKeyPoint impMatOfKeyPoint = new MatOfKeyPoint(impKeyPoint);
//Mat for drawing the circle in the image
Mat outputImage = new Mat(inputMat.rows(), inputMat.cols(), Highgui.CV_LOAD_IMAGE_COLOR);
//Green color for the circle
Scalar greenCircle = new Scalar(0, 255, 0);
//Draw the circle around the optic nerve when detected
Features2d.drawKeypoints(inputMat, impMatOfKeyPoint, outputImage, greenCircle, Features2d.DRAW_RICH_KEYPOINTS);
//Write the image to a file
Highgui.imwrite("surf_keypoints.png", outputImage);
}catch(Exception e){
log.fatal(e.getMessage());
}
}
Hope this is helpful for others.
I have been trying to use Barcode4J on Android but I can not seem to get BufferedImage class and I am not sure how I am suppose to replace this class with anything from Android.graphic.* which does not seem to have something similar. Also the Barcode4J will not accept anything other then BufferedImage object for obvious reasons.
What could I use instead or is there a Barcode generator Lib better suited for Android?
I have tried Barcode4Android which really made no sense since the Example they gave on GIT used BufferedImage from the java.awt.image.BufferedReader package also >.< . So I was back at step 1.
I actually just need the QR generating function.
My Questions.
1. Is there an Alternative to Barcode4J for Android.
2. OR is there a work around for my problem ?
Here is one of the Java tutorials I tried to use
public class HelloExample1 {
public static void main(String[] args) throws Exception{
//Create the barcode bean
Code39Bean bean = new Code39Bean();
final int dpi = 150;
//Configure the barcode generator
bean.setModuleWidth(UnitConv.in2mm(1.0f / dpi)); //makes the narrow bar, width exactly one pixel
bean.setWideFactor(3);
bean.doQuietZone(false);
//Open output file
File outputFile = new File("resources"+"/"+"images"+"/"+"out.png");
OutputStream out = new FileOutputStream(outputFile);
try {
//Set up the canvas provider for monochrome PNG output
BitmapCanvasProvider canvas = new BitmapCanvasProvider(
out, "image/x-png", dpi, BufferedImage.TYPE_BYTE_BINARY, false, 0);
//Generate the barcode
bean.generateBarcode(canvas, "Hello World");
//Signal end of generation
canvas.finish();
} finally {
out.close();
}
}
}
Try Zxing, its a code generator and reader, easy to use in Android. Hope it helps.
I am working on Android development where once I get byte array from Google Glass frame, I am trying to scan array using Zxing library and trying to detect 1d barcode(UPC code).
I have tried this code snippet.
BufferedImage image = ImageIO.read(game);
BufferedImageLuminanceSource bils = new BufferedImageLuminanceSource(image);
HybridBinarizer hb = new HybridBinarizer(bils);
BitMatrix bm = **hb.getBlackMatrix();**
MultiDetector detector = new MultiDetector(bm);
DetectorResult dResult = detector.detect();
if(dResult == null)
{
System.out.println("Image does not contain any barcode");
}
else
{
BitMatrix QRImageData = dResult.getBits();
Decoder decoder = new Decoder();
DecoderResult decoderResult = decoder.decode(QRImageData);
String QRString = decoderResult.getText();
System.out.println(QRString);
}
It works fine for QRcode, detects and decodes QR code well. But does not detect UPC code.
I also tried this code snippet,
InputStream barCodeInputStream = new FileInputStream(game);
BufferedImage barCodeBufferedImage = ImageIO.read(barCodeInputStream);
BufferedImage image = ImageIO.read(game);
LuminanceSource source = new BufferedImageLuminanceSource(image);
BinaryBitmap bitmap = new BinaryBitmap(new GlobalHistogramBinarizer(source));
RSSExpandedReader rssExpandedReader = new RSSExpandedReader();
int rowNumber = bitmap.getHeight()/2;
BitArray row = **bitmap.getBlackRow(0, null);**
Result theResult = rssExpandedReader.decodeRow(rowNumber, row, new Hashtable());
and in both I am getting "Exception in thread "main" com.google.zxing.NotFoundException".
Does anyone know how to fix this issue?
getBlackMatrix() -
Converts a 2D array of luminance data to 1 bit. As above, assume this method is expensive and do not call it repeatedly. This method is intended for decoding 2D barcodes and may or may not apply sharpening. Therefore, a row from this matrix may not be identical to one fetched using getBlackRow(), so don't mix and match between them.
getBlackRow()-
Converts one row of luminance data to 1 bit data. May actually do the conversion, or return cached data. Callers should assume this method is expensive and call it as seldom as possible. This method is intended for decoding 1D barcodes and may choose to apply sharpening.
I have 5 single page tiff images.
I want to combine all these 5 tiff images in to one multipage tiff image.
I am using Java Advanced Imaging API.
I have read the JAI API documentation and tutorials given by SUN.
I am new to JAI. I know the basic core java.
I dont understand those documentation and turorial by SUN.
So friends Please tell me how to combine 5 tiff image file in to one multipage tiff image.
Please give me some guidence on above topic.
I have been searching internet for above topic but not getting any single clue.
I hope you have the computer memory to do this. TIFF image files are large.
You're correct in that you need to use the Java Advanced Imaging (JAI) API to do this.
First, you have to convert the TIFF images to a java.awt.image.BufferedImage. Here's some code that will probably work. I haven't tested this code.
BufferedImage image[] = new BufferedImage[numImages];
for (int i = 0; i < numImages; i++) {
SeekableStream ss = new FileSeekableStream(input_dir + file[i]);
ImageDecoder decoder = ImageCodec.createImageDecoder("tiff", ss, null);
PlanarImage op = new NullOpImage(decoder.decodeAsRenderedImage(0), null, null, OpImage.OP_IO_BOUND);
image[i] = op.getAsBufferedImage();
}
Then, you convert the BufferedImage array back into a multiple TIFF image. I haven't tested this code either.
TIFFEncodeParam params = new TIFFEncodeParam();
OutputStream out = new FileOutputStream(output_dir + image_name + ".tif");
ImageEncoder encoder = ImageCodec.createImageEncoder("tiff", out, params);
Vector vector = new Vector();
for (int i = 0; i < numImages; i++) {
vector.add(image[i]);
}
params.setExtraImages(vector.listIterator(1)); // this may need a check to avoid IndexOutOfBoundsException when vector is empty
encoder.encode(image[0]);
out.close();
-Edit-
FYI.. I am converting b&w documents scanned in as greyscale or color.
1)The first solution worked, it just reversed black & white (black background, white text). It also took nearly 10 minutes.
2)The JAI solution in the 2nd answer didn't work for me. I tried it before posting here.
Has anyone worked with other libraries free or pay that handle image manipulation well?
-Original-
I am trying to convert an PNG to a bitonal TIFF using Java ImageIO. Has anyone had any luck doing this? I have got it to convert from PNG to TIFF. I am not sure if I need to convert the BufferedImage (PNG) that I read in or convert on the TIFF as I write it. I have searched and searched but nothing seems to work? Does anyone have an suggestions where to look?
Here is the code that converts...
public static void test() throws IOException {
String fileName = "4848970_1";
// String fileName = "color";
String inFileType = ".PNG";
String outFileType = ".TIFF";
File fInputFile = new File("I:/HPF/UU/" + fileName + inFileType);
InputStream fis = new BufferedInputStream(new FileInputStream(fInputFile));
ImageReaderSpi spi = new PNGImageReaderSpi();
ImageReader reader = spi.createReaderInstance();
ImageInputStream iis = ImageIO.createImageInputStream(fis);
reader.setInput(iis, true);
BufferedImage bi = reader.read(0);
int[] xi = bi.getSampleModel().getSampleSize();
for (int i : xi) {
System.out.println("bitsize " + i);
}
ImageWriterSpi tiffspi = new TIFFImageWriterSpi();
TIFFImageWriter writer = (TIFFImageWriter) tiffspi.createWriterInstance();
// TIFFImageWriteParam param = (TIFFImageWriteParam) writer.getDefaultWriteParam();
TIFFImageWriteParam param = new TIFFImageWriteParam(Locale.US);
String[] strings = param.getCompressionTypes();
for (String string : strings) {
System.out.println(string);
}
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionType("LZW");
File fOutputFile = new File("I:\\HPF\\UU\\" + fileName + outFileType);
OutputStream fos = new BufferedOutputStream(new FileOutputStream(fOutputFile));
ImageOutputStream ios = ImageIO.createImageOutputStream(fos);
writer.setOutput(ios);
writer.write(null, new IIOImage(bi, null, null), param);
ios.flush();
writer.dispose();
ios.close();
}
I have tried changing the compression to type "CCITT T.6" as that appears to be what I want, but I get an error " Bits per sample must be 1 for T6 compression! " Any suggestion would be appreciated.
Most likely, you want something like this to convert to 1 bit before you save to TIFF with CCITT compression.
To expound a little bit - be aware that converting from other bit depths to 1 bit is non-trivial. You are doing a data reduction operation and there are dozens of domain specific solutions which vary greatly in output quality (blind threshold, adaptive threshold, dithering, local threshold, global threshold and so on). None of them are particularly good at all image types (adaptive threshold is pretty good for documents, but lousy for photographs, for example).
As plinth said, you have to do the conversion, Java won't do it magically for you...
If the PNG image is already black & white (as it seems, looking at your comment), using a threshold is probably the best solution.
Somebody seems to have the same problem: HELP: how to compress the tiff. A solution is given on the thread (untested!).