how to decode a qrcode using zxing through webcam - java

i have a code to decode a qrcode that take a image file and decode it. am using zxing library. but how can i make this capture qrcode from webcam and decode it. what are the changes i need to do?? can any one plz explain this step by step.
here is the code:
public class QrCodeDecoder
{
public String decode(File imageFile)
{
BufferedImage image;
try
{
image = ImageIO.read(imageFile);
}
catch (IOException e1)
{
return "io outch";
}
// creating luminance source
LuminanceSource lumSource = new BufferedImageLuminanceSource(image);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(lumSource));
// barcode decoding
QRCodeReader reader = new QRCodeReader();
Result result = null;
try {
result = reader.decode(bitmap);
}
catch (ReaderException e)
{
return "reader error";
}
return result.getText();
}
}

You are pretty far away from a solution, I don't think anyone can explain it "step by step". You will first need to find a library that is capable of grabbing an image from a webcam. You might start with this library, though I'm sure there are others.
Once you can capture an image, start to figure out if it is in a format that the above code expects. If you are lucky, it will be, if not you will have to convert between the two formats.

Related

ML Kit Barcode scanning: Invalid image data size

I would like to detect a barcode within a captured image. I capture an image using android's camera2. Following this, the image's metadata is retrieved and the image is saved to the device. The metadata is all passed along to the next activity, which is where the application attempts to detect a barcode.
This next activity creates a byte[] from the File saved previously. Next, the relevant FirebaseVision objects are created using the data passed with the intent. Finally, the application attempts to call the detectInImage() method, where an error is thrown:
"java.lang.IllegalArgumentException: Invalid image data size."
I suspect this is from the captured image being too large, however I cannot seem to figure out how to capture a smaller image, and I also cannot find anything in the reference documentation regarding the maximum size allowed. Information regarding this error and how to solve it would be very much appreciated. Below is what I believe to be the relevant code.
private final ImageReader.OnImageAvailableListener onImageAvailableListener
= new ImageReader.OnImageAvailableListener() {
#Override
public void onImageAvailable(ImageReader imageReader) {
try{
// Semaphore ensures date is recorded before starting next activity
storeData.acquire();
Image resultImg = imageReader.acquireNextImage(); // Image from camera
imgWidth = resultImg.getWidth();
imgHeight = resultImg.getHeight();
ByteBuffer buffer = resultImg.getPlanes()[0].getBuffer();
data = new byte[buffer.remaining()]; // Byte array with the images data
buffer.get(data);
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
// Note: mediaFile directs to Pictures/"ThisProject" folder
File media = new File(mediaFile.getPath() +
File.separator + "IMG_" + timeStamp + ".jpg");
// Saving the image
FileOutputStream fos = null;
try {
fos = new FileOutputStream(media);
fos.write(data);
uri = Uri.fromFile(media);
} catch (IOException e) {
Log.e(TAG, e.getMessage());
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
}
}
resultImg.close();
} catch (InterruptedException e) {
Log.e(TAG, e.getMessage());
}
storeData.release();
}
};
This essentially retrieves the image height & width, then writes it to a file.
The data sent to the next activity consists of the: Image width, Image height, Image rotation, and the Uri directing to the file.
Using this, I try to detect a barcode using Firebase ML Kit:
// uri is the uri referencing the saved image
File f = new File(uri.getPath());
data = new byte[(int) f.length()];
try{
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(f));
DataInputStream dis = new DataInputStream(bis);
dis.readFully(data);
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
FirebaseVisionBarcodeDetectorOptions options = new FirebaseVisionBarcodeDetectorOptions.Builder().setBarcodeFormats(
FirebaseVisionBarcode.FORMAT_QR_CODE,
FirebaseVisionBarcode.FORMAT_DATA_MATRIX
).build();
FirebaseVisionBarcodeDetector detector = FirebaseVision.getInstance().getVisionBarcodeDetector(options);
FirebaseVisionImage image;
int rotationResult;
switch (imgRotation) {
case 0: {
rotationResult = FirebaseVisionImageMetadata.ROTATION_0;
break;
}
case 90: {
rotationResult = FirebaseVisionImageMetadata.ROTATION_90;
break;
}
case 180: {
rotationResult = FirebaseVisionImageMetadata.ROTATION_180;
break;
}
case 270: {
rotationResult = FirebaseVisionImageMetadata.ROTATION_270;
break;
}
default: {
rotationResult = FirebaseVisionImageMetadata.ROTATION_0;
break;
}
}
FirebaseVisionImageMetadata metadata = new FirebaseVisionImageMetadata.Builder()
.setWidth(imgWidth)
.setHeight(imgHeight)
.setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21)
.setRotation(rotationResult)
.build();
image = FirebaseVisionImage.fromByteArray(data, metadata);
Task<List<FirebaseVisionBarcode>> result = detector.detectInImage(image)
A few things.
Your image format should not be NV21 if you use camera2. See here for all camera2 supported image formats:
https://developer.android.com/reference/android/media/Image#getFormat()
Your byte[] is not NV21 and you specified IMAGE_FORMAT_NV21 and led to the error
Most intuitive integration with camera2 is like below:
Specify JPEG format when you instantiate the ImageReader.
onImageAvailable will give you back an android.media.Image and you can directly use FirebaseVisionImage.fromMediaImage(...) to create a FirebaseVisionImage. (You can find how to compute the rotation info from official doc here)
If you must do two Activities, then you need to work around the fact that android.media.Image is not Parcelable. I'd suggest you convert it to Bitmap first which is Parcelable and you can directly set it as an Intent extra (Up to you. Just thinking from end user's perspective, it's non-common to see the barcode being saved to my image gallery.
So you might want to consider skipping the step of saving it to file). Later, in your 2nd Activity, you can use FirebaseVisionImage.fromBitmap(...).

Zxing Format Exception in Scanning PDF and converting to Buffered Image to Decode QR

I'm having problem with getting continuous successful QR decoding after PDF conversion. I keep getting,
"Exception in thread "main" com.google.zxing.FormatException."
My conversion attempts were done in:
PDFBox
public static BufferedImage convertPDFtoBufferedImageType2(String PDFPath) throws IOException{
PDDocument document = null;
try {
document = PDDocument.load(PDFPath);
PDPage firstPage = (PDPage) document.getDocumentCatalog().getAllPages().get(0);
return firstPage.convertToImage();
} catch (IOException ex) {
Logger.getLogger(PDF_Utility.class.getName()).log(Level.SEVERE, null, ex);
return null;
} finally {
if(document != null)
document.close();
}
}
Second Attempt with ghost4j
public static BufferedImage convertPDFtoBufferedImage(String PDFPath) throws IOException, RendererException, DocumentException{
System.setProperty("jna.library.path", "C:\\Program Files\\gs\\gs9.16\\bin\\");
PDFDocument document = new PDFDocument();
document.load(new File(PDFPath));
SimpleRenderer renderer = new SimpleRenderer();
renderer.setResolution(300);
List<Image> imgs = renderer.render(document);
Image im = imgs.get(0);
BufferedImage bi = new BufferedImage
(im.getWidth(null),im.getHeight(null),BufferedImage.TYPE_INT_RGB);
Graphics bg = bi.getGraphics();
bg.drawImage(im, 0, 0, null);
bg.dispose();
return bi;
}
My QR Decoder is:
public static String readQRCode(BufferedImage image, String charset, Map hintMap)
throws FileNotFoundException, IOException, NotFoundException, ChecksumException, FormatException {
Result qrCodeResult = null;
BinaryBitmap binaryBitmap = new BinaryBitmap(
new HybridBinarizer(new BufferedImageLuminanceSource(image)));
try{
qrCodeResult = new com.google.zxing.qrcode.QRCodeReader().decode(binaryBitmap,hintMap);
}catch(NotFoundException | FormatException e){ //attempt without hints
qrCodeResult = new com.google.zxing.qrcode.QRCodeReader().decode(binaryBitmap);
}
return qrCodeResult.getText();
}
And the reason why I called decode twice was because sometimes the "try harder"
hintMap.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
actually didn't catch the QR code, but the default did.
Anyways, these code snippets do catch most of my QR scans from a pile of documents, but there are times where it does not catch it at all. I even attempted to write it out as an image and then re-read it in:
ImageIO.write((RenderedImage) im, "png", new File("/path/to/my/img.png"));
Interestingly, http://zxing.org/w/decode.jspx does decode that output image, but my code couldn't.
I also tried different charset:
CHAR_SET = "UTF-8"; and CHAR_SET = "ISO-8859-1";
By getting Format Exceptions, the code was found, but "did not conform to the barcode's format rules. This could have been due to a mis-detection."
Apology for the messy code, but those attempts have gained majority of successful scans. 9/10 rate? Interestingly, sometimes another scanned copy of the same doc worked. Any help/advice/crazy voodoo combination is appreciated! Thanks!
EDIT: I got a sample (after whiting out the contents around. The real image has contents! Zxing website was able to catch this QR code too (with and without contents! (My program already ignored the other 1Ds at this same format and those with contents).
#Tilman Hausherr pointed out for the PDFBox default rendering size as low so I changed the default to 300dpi as he suggested. Overall, it worked for my case but definitely slowed down the speed. Will need to tweak my algorithm to run both a fast and this slower one as a backup.
return firstPage.convertToImage(BufferedImage.TYPE_4BYTE_ABGR, 300);
EDIT: Increased the success rate of catching barcodes, but did not successfully catch all. Increasing the dpi does not help.

Display dicom in JavaFX button

I have many dicom (dcm) images that I want to display as thumbnails in my program. I can load it and draw in a separate window with ImageJ plugin:
try {
FileInputStream fis = new FileInputStream(dcms);
DICOM d = new DICOM(fis);
d.run(dcms);
d.setTitle(title);
d.show();
d.draw();
} catch (Exception e) {e.printStackTrace();}
}
But I want to be able to load it as a Image in a JavaFX button (as thumbnails) as I can do with pngs:
try{
Image picture = new Image(getClass().getResourceAsStream(dcms));
bt.setGraphic(new ImageView(picture));
}
I couldn't find any similar example on Google (most of the results lead to programs to convert the dicom to another thing through a program). But I don't want to convert and then display, I just want to display it.
Do you know if it's possible? Or will I have to convert it before loading the thumbnails?
EDIT : I know that I can save each picture somewhere e.g temp folder and then load it as a Image, but I still think that it's a unnecessary workaround. And I would like to avoid it if possible.
I found a way to use it:
FileInputStream fis;
try {
fis = new FileInputStream(path);
DICOM d = new DICOM(fis);
d.run(path);
Image picture = SwingFXUtils.toFXImage(d.getBufferedImage(), null);
Button bt = new Button();
bt.setGraphic(new ImageView(picture));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Posted because it might be useful for someone else.

java ImageIO resolution

I've been searching for some solutions from the internet yet I still haven't found an answer to my problem.
I've been working or doing a program that would get an image file from my PC then will be edited using Java Graphics to add some text/object/etc. After that, Java ImageIO will save the newly modified image.
So far, I was able to do it nicely but I got a problem about the size of the image. The original image and the modified image didn't have the same size.
The original is a 2x3inches-image while the modified one which supposedly have 2x3inches too sadly got 8x14inches. So, it has gone BIGGER than the original one.
What is the solution/code that would give me an output of 2x3inches-image which will still have a 'nice quality'?
UPDATE:
So, here's the code I used.
public Picture(String filename) {
try {
File file = new File("originalpic.jpg");
image = ImageIO.read(file);
width = image.getWidth();
}
catch (IOException e) {
throw new RuntimeException("Could not open file: " + filename);
}
}
private void write(int id) {
try {
ImageIO.write(image, "jpg", new File("newpic.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
}
2nd UPDATE:
I now know what's the problem of the new image. As I check it from Photoshop, It has a different image resolution compared to the original one. The original has a 300 pixels/inch while the new image has a 72 pixels/inch resolution.
How will I be able to change the resolution using Java?

BufferedImage get resized with different colors

I am resizing many jpeg images using Apache Sanselan which also deals with CMYK colors.
I have a problem when trying to convert jpeg images that has an alpha channel... when doing it the result is an image with different colors, and i guess that java somehow handles these type of images as a different color format.
As i said, the RGB resizing works fine as well as CMYK. ARGB images turn out with different colors.
An example:
Any suggestions? Can i force somehow ignore the alpha channel and handle the image as an RGB image? or convert it to be an RGB image without losing the real colors?
The code that handles this image is:
ImageInputStream stream = ImageIO.createImageInputStream(file);
Iterator<ImageReader> iter = ImageIO.getImageReaders(stream);
while (iter.hasNext()) {
ImageReader reader = iter.next();
reader.setInput(stream);
BufferedImage image = null;
ICC_Profile profile = null;
try {
image = reader.read(0);
} catch (IIOException e) {
... (CMYK conversion if needed)
}
return image;
}
return null;
Thanks in advance
I found a good solution here (first solution worked great):
problem using ImageIO.write jpg file
Edit:
There is a new open source library which supports CMYK processing.
All you need to do is to add the dependency to your project and a new reader will be added to the list of readers (while the known JPEGImageReader can't deal with CMYK).
You will probably want to iterate over these readers and read the image using the first reader which doesn't throw exception.
This package is a release candidate, but i am using it and it solved a huge problem that we had hard time dealing with.
http://mvnrepository.com/artifact/com.twelvemonkeys.imageio/imageio-jpeg/3.0-rc5
You can do the iteration this way to get the BufferedImage, and after you got that, the rest is easy (you can use any existing image converting package to save it as another format):
try (ImageInputStream input = ImageIO.createImageInputStream(source)) {
// Find potential readers
Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
// For each reader: try to read
while (readers != null && readers.hasNext()) {
ImageReader reader = readers.next();
try {
reader.setInput(input);
BufferedImage image = reader.read(0);
return image;
} catch (IIOException e) {
// Try next reader, ignore.
} catch (Exception e) {
// Unexpected exception. do not continue
throw e;
} finally {
// Close reader resources
reader.dispose();
}
}
// Couldn't resize with any of the readers
throw new IIOException("Unable to resize image");
}

Categories