Get the coordinate of alignment pattern with ZXing - java

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!

Related

Reading DataMatrix/QR code zxing java

The below data matrix is being read well using Barcode Scanner, zxing mobile app. However, the same is not being read by zxing java library.
I have some image transformation code commented. Even transforming the image, rotation or scaling doesn't help.
Ideally, I would like to perform all possible image pre-processing programatically until decoded.
What is the logic the mobile app using, since am scanning the same image from the computer screen and it is working.
Please find below, the code am using for decoding.
public class BarcodeReader {
private static Map<DecodeHintType,Object> hintsMap;
public static void main(String...args){
BufferedImage before = null;
hintsMap = new EnumMap<DecodeHintType, Object>(DecodeHintType.class);
hintsMap.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
hintsMap.put(DecodeHintType.POSSIBLE_FORMATS, EnumSet.allOf(BarcodeFormat.class));
//hintsMap.put(DecodeHintType.PURE_BARCODE, Boolean.FALSE);
try
{
before = ImageIO.read(new File("C:/ocr.jpg"));
decode(before);
/* for(int i=1; i < 1000;i++){
AffineTransform transform = new AffineTransform();
double rad = (double)i/100;
double scale = (double)i/100;
System.out.println("rad "+scale);
//transform.rotate(rad, before.getWidth()/2, before.getHeight()/2);
transform.scale(scale, scale);
BufferedImage after = new BufferedImage(before.getWidth(), before.getHeight(), BufferedImage.TYPE_INT_ARGB);
AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
after = op.filter(before, after);
decode(after);
}*/
//tmpBfrImage = tmpBfrImage.getSubimage(200, 100, 800, 800);
}
catch (IOException tmpIoe)
{
tmpIoe.printStackTrace();
}
}
public static void decode(BufferedImage tmpBfrImage){
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);
System.exit(0);;
}
catch (Exception tmpExcpt)
{
tmpExcpt.printStackTrace();
}
}
}
I had problems at multiple levels. I downloaded zxing source from github and debugged it.
The first problem was adding the below line as hints screws up the recognition hintsMap.put(DecodeHintType.PURE_BARCODE, Boolean.FALSE);
Looking at their source code for DataMatrixReader, there was a line doing this
if (hints != null && hints.containsKey(DecodeHintType.PURE_BARCODE))
So, irrespective of setting PURE_BARCODE true or false, it considers it as true. Ideally hints should not contain the key.
The second problem was with the way the detector for DataMatrix works.
The detector was identifying the 'L' by looking at the number of black and white transitions from each vertices. Ideally, the transitions from Top-Left to Bottom-Left and Bottom-Left to Bottom-Right should have 0 transitions.
However, since the line was drawn closer towards the outer edge of the box, the transitions were not becoming 0. I made changes to move it closer to the center of the Left and Bottom Black Lines. This means moving the vertical red line to the right and the bottom red line a bit upwards. I added a new method Correct Points, that makes the necessary correction. This correction works for me, ideally one should be making the correction a bit more smarter.
ResultPoint pointA = correctPoints(cornerPoints[0], Vertices.TOPLEFT);
ResultPoint pointB = correctPoints(cornerPoints[1], Vertices.BOTTOMLEFT);
ResultPoint pointC = correctPoints(cornerPoints[2], Vertices.TOPRIGHT);
ResultPoint pointD = correctPoints(cornerPoints[3], Vertices.BOTTOMRIGHT);
---
---
private ResultPoint correctPoints(ResultPoint point, Vertices vertice){
if(vertice.equals(Vertices.TOPLEFT))
return new ResultPoint(point.getX()+10, point.getY()+5);
else if(vertice.equals(Vertices.BOTTOMLEFT)){
return new ResultPoint(point.getX()+10, point.getY()-5);
}else if(vertice.equals(Vertices.TOPRIGHT)){
return new ResultPoint(point.getX(), point.getY()+10);
}else{
return new ResultPoint(point.getX()-10, point.getY()-5);
}
}
After making these changes, data matrix detection was working for images that were as bad as or even poorer than these.
I was having similar problems using ZXing to decode DataMatrix barcodes. From what I can see, ZXing doesn't traverse the entire image you send it, but rather starts from the middle and expands out until it has found a barcode. So, if the DataMatrix barcode isn't centered in the image, ZXing will not be able to reliably find it. I implemented (a rather slow) workaround that fixes this problem, by creating different cropped versions of the image:
My core decode method is similar to that of the original post. My image traversal logic is as follows:
// Read the original image
final BufferedImage image = ImageIO.read(...);
final int width = image.getWidth();
final int height = image.getHeight();
// Try detect codes using different sections of the image.
//
// +------+------+
// | ##|## |
// | ##|## |
// | ##|## |
// +------+------+
// | | |
// | | |
// | | |
// +------+------+
//
// We create 9 cropped versions of the image, with each cropped
// version being 1/4 of the original image. We traverse the
// original image from left-to-right, top-to-bottom, and create
// 9 sub-images that we try to decode in turn.
for (int i=0; i<3; i++) {
for (int j=0; j<3; j++) {
final int x = i * width / 4;
final int y = j * height / 4;
final BufferedImage crop = image.getSubimage(x, y, width / 2, height / 2);
decoded(crop);
}
}

Java3D - Mapping animated gif to sphere

I have a simple solar system consisting of two planets and a sun.
I can now map images to spheres, but I want to map an animated gif to a sphere.
I assumed this would be the same code, but when I load the animated gif, it simply plays the first frame and doesn't animated through the other frames.
The code that loads the image
Texture tex = null;
File img = new File("src/images/earth.jpg");
try {
tex = new TextureLoader(ImageIO.read(img)).getTexture();
} catch (IOException e) {
e.printStackTrace();
}
tex.setBoundaryModeS(Texture.WRAP);
tex.setBoundaryModeT(Texture.WRAP);
TextureAttributes texAttr = new TextureAttributes();
texAttr.setTextureMode(TextureAttributes.MODULATE);
Appearance ap = new Appearance();
ap.setTexture(tex);
ap.setTextureAttributes(texAttr);
------
Node earth = new Sphere(earthRadius, primflags, 100, ap);
Am I missing something obvious?
Any help or pointers would be fanatics. If I have failed to give enough detail, please ask and I will be more than happy to supply more code.

Decode specific areas of image in Bitmapfactory?

I'm working with GeoTiff/PNG files too large for handling as a whole in my code.
Is there any possibility to decode specific areas (e.g. given by two x,y coordinates) of a file in bitmapfactory? Haven't found anything looking similar at http://developer.android.com/reference/android/graphics/BitmapFactory.html(Android's developer reference).
Thanks!
With kcoppock's hint I've set up the following solution.
Though I'm wondering why rect needs to be initialized by Rect(left, bottom, right, top) instead of Rect(left, top, right, bottom)...
Example call:
Bitmap myBitmap = loadBitmapRegion(context, R.drawable.heightmap,
0.08f, 0.32f, 0.13f, 0.27f);
Function:
public static Bitmap loadBitmapRegion(
Context context, int resourceID,
float regionLeft, float regionTop,
float regionRight, float regionBottom) {
// Get input stream for resource
InputStream is = context.getResources().openRawResource(resourceID);
// Set options
BitmapFactory.Options opt = new BitmapFactory.Options();
//opt.inPreferredConfig = Bitmap.Config.ARGB_8888; //standard
// Create decoder
BitmapRegionDecoder decoder = null;
try {
decoder = BitmapRegionDecoder.newInstance(is, false);
} catch (IOException e) {
e.printStackTrace();
}
// Get resource dimensions
int h = decoder.getHeight();
int w = decoder.getWidth();
// Set region to decode
Rect region = new Rect(
Math.round(regionLeft*w), Math.round(regionBottom*h),
Math.round(regionRight*w), Math.round(regionTop*h));
// Return bitmap
return decoder.decodeRegion(region, opt);
}
You should look into BitmapRegionDecoder. It seems to describe exactly the use case that you are looking for.
I don't know exactly what you mean by "Decode specific areas" but if by decoding you mean, to actually "copy" certain areas of a bitmap, what you can do is make use of canvas in order to get it as shown below:
Bitmap bmpWithArea = Bitmap.createBitmap(widthDesired, heightDesired, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmpWithArea);
Rect area = new Rect(arealeft, areatop, arearight, areabottom);
Rect actualSize = new Rect(0, 0, widthDesired, heightDesired);
canvas.drawBitmap(bitmapWithAreaYouWantToGet, area, actual, paintIfAny);
//And done, starting from this line "bmpWithArea" has the bmp that you wanted, you can assign it to ImageView and use it as regular bmp...
Hope this helps...
Regards!

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

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.

Lossless JPEG Rotate (90/180/270 degrees) in Java?

Is there a Java library for rotating JPEG files in increments of 90 degrees, without incurring image degradation?
I found this: http://mediachest.sourceforge.net/mediautil/
API: http://mediachest.sourceforge.net/mediautil/javadocs/mediautil/image/jpeg/LLJTran.html
Building on Henry's answer, here's an example of how to use MediaUtil to perform lossless JPEG rotation based on the EXIF data:
try {
// Read image EXIF data
LLJTran llj = new LLJTran(imageFile);
llj.read(LLJTran.READ_INFO, true);
AbstractImageInfo<?> imageInfo = llj.getImageInfo();
if (!(imageInfo instanceof Exif))
throw new Exception("Image has no EXIF data");
// Determine the orientation
Exif exif = (Exif) imageInfo;
int orientation = 1;
Entry orientationTag = exif.getTagValue(Exif.ORIENTATION, true);
if (orientationTag != null)
orientation = (Integer) orientationTag.getValue(0);
// Determine required transform operation
int operation = 0;
if (orientation > 0
&& orientation < Exif.opToCorrectOrientation.length)
operation = Exif.opToCorrectOrientation[orientation];
if (operation == 0)
throw new Exception("Image orientation is already correct");
OutputStream output = null;
try {
// Transform image
llj.read(LLJTran.READ_ALL, true);
llj.transform(operation, LLJTran.OPT_DEFAULTS
| LLJTran.OPT_XFORM_ORIENTATION);
// Overwrite original file
output = new BufferedOutputStream(new FileOutputStream(imageFile));
llj.save(output, LLJTran.OPT_WRITE_ALL);
} finally {
IOUtils.closeQuietly(output);
llj.freeMemory();
}
} catch (Exception e) {
// Unable to rotate image based on EXIF data
...
}
Regarding the issue of EXIF data not necessarily being handled correctly, since EXIF data is irrelevant in many situations, here's example code demonstrating only the LLJTran lossless JPEG rotation feature (with thanks to user113215):
final File SrcJPEG = new File("my-input.jpg");
final File DestJPEG = new File("my-output.jpg");
final FileInputStream In = new FileInputStream(SrcJPEG);
try {
final LLJTran LLJT = new LLJTran(In);
LLJT.read(LLJTran.READ_ALL, true);
LLJT.transform(LLJTran.ROT_90);
final FileOutputStream Out = new FileOutputStream(DestJPEG);
try {
LLJT.save(Out, LLJTran.OPT_WRITE_ALL);
} finally {
Out.close();
}
} finally {
In.close();
}
If you make the input and output File objects refer to the same file, you can run this over and over again, and observe that the image does not degrade, no matter how many iterations it is put through.
For Android specifically, I found this fork:
https://github.com/juanitobananas/AndroidMediaUtil
Benefits over upstream:
Gradle/Android Studio project
Compatible with jitpack.io
It might even be usable on normal Java, as the code does not import any Android-specific package (I haven't tried though).
You don't need an external library for this kind of thing, it's all built into SE. The easiest being the rotate() function of the Graphics2D object.
For example:
Image rotatedImage = new BufferedImage(imageToRotate.getHeight(null), imageToRotate.getWidth(null), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = (Graphics2D) rotatedImage.getGraphics();
g2d.rotate(Math.toRadians(90.0));
g2d.drawImage(imageToRotate, 0, -rotatedImage.getWidth(null), null);
g2d.dispose();
no loss!
Or, if you want to be extra careful, just use BufferedImage.getRGB(x,y), and translate it pixel by pixel on to the new image.

Categories

Resources