使用Java中的ZXing库解码彩色图像
我正在尝试使用 ZXing 库解码 Java 中的彩色 QR 码。通过一些研究,我知道ZXing已经有能力做到这一点。但我已经这样做了 2 天,我所做的是尝试从文件中读取 QR 图像并计算图像中最暗和最亮的颜色。然后将每个前景像素更改为黑色,将其他像素更改为白色。之后我会得到一个像标准二维码一样的二维码。然后用一个函数来读取二维码:
不过,这只适用于两种不同颜色的二维码,如果变成了三种颜色,那么大多数情况下就不起作用了。除非,从彩色图像转换为灰度图像的新图像不会超过纠错百分比。
我尝试过其他方法,但每种方法仅适用于特定类型的 QR 码(带有徽标、多色、形状的查找器图案等)。
而我正在寻找的是一种解码各种二维码的方法。至少对于多色和形状的查找器图案来说是这样。
有关更多详细信息:
1)这是我用来解码 此页面(第二个QR),也用于解码在同一网站上找到的第三个QR(在对齐图案上方有一种徽标),这绝对不起作用:
public class Decoder
{
public static void main(String[] args)
{
// input image file
File imageFile = new File("/Users/User/Desktop/QR/green.png");
BufferedImage image = null;
try
{
image = ImageIO.read(imageFile);
}
catch (IOException e)
{
System.out.println("io outch");
}
int imageWidth = image.getWidth();
int imageHeight = image.getHeight();
int total = 0;
int dark = image.getRGB(0, 0);
int light = image.getRGB(0, 0);
int backgroundColor = 0;
int foregroundColor = 0;
FinderPattern topLeftFinder;
for (int x = 0; x < imageWidth; x ++)
{
for (int y = 0; y <imageHeight; y ++)
{
total = total + image.getRGB(x, y);
}
}
//int average = total / (imageWidth * imageHeight);
//System.out.println("total" + total + " average " + average);
for (int x = 0; x < imageWidth; x ++)
{
for (int y = 0; y <imageHeight; y ++)
{
if (image.getRGB(x, y) < dark)
{
dark = image.getRGB(x, y);
}
if (image.getRGB(x, y) > light)
{
light = image.getRGB(x, y);
}
}
}
for (int x = 0; x < imageWidth; x ++)
{
for (int y = 0; y <imageHeight; y ++)
{
if (image.getRGB(x, y) >= (dark - light) / 4)
{
image.setRGB(x, y, -1);
}
else if (image.getRGB(x, y) <= (dark - light) * 3 / 4)
{
image.setRGB(x, y, -16777216);
}
else
{
image.setRGB(x, y, -1);
}
}
}
System.out.println("total" + dark + " average " + light);
File outputFile = new File("/Users/Desktop/QR/outputQR.png");
//ImageIO.write(image, "png", file);
try
{
ImageIO.write(image, "png", outputFile);
}
catch (IOException e)
{
System.out.println(e.getMessage());
}
// creating binary bitmap from source image
LuminanceSource lumSource = new BufferedImageLuminanceSource(image);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(lumSource));
Hashtable<DecodeHintType, Object> hint = new Hashtable<DecodeHintType, Object>();
hint.put(DecodeHintType.TRY_HARDER, BarcodeFormat.QR_CODE);
// decoding
QRCodeReader QRreader = new QRCodeReader();
Result result = null;
try
{
result = QRreader.decode(bitmap, hint);
}
catch (ReaderException e)
{
System.out.println("error during reading");
}
// getting output text
String decodedText = result.getText();
System.out.println(decodedText);
}
}
2)这个是用于解码 此 QR 的代码最初工作正常,但不知道为什么它现在不工作。并且此代码不会解码上述 QR。
public class Decoder
{
public static void main(String[] args)
{
// input image file
File imageFile = new File("/Users/User/Desktop/QR/bigfinderQR.png");
BufferedImage image = null;
try
{
image = ImageIO.read(imageFile);
}
catch (IOException e)
{
System.out.println("io outch");
}
// creating binary bitmap from source image
LuminanceSource lumSource = new BufferedImageLuminanceSource(image);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(lumSource));
Hashtable<DecodeHintType, Object> hint = new Hashtable<DecodeHintType, Object>();
hint.put(DecodeHintType.TRY_HARDER, BarcodeFormat.QR_CODE);
// decoding
QRCodeReader QRreader = new QRCodeReader();
Result result = null;
try
{
result = QRreader.decode(bitmap, hint);
}
catch (ReaderException e)
{
System.out.println("error during reading");
}
// getting output text
String decodedText = result.getText();
System.out.println(decodedText);
}
}
I am trying to decode a colored QR code in Java with ZXing library. From some research, I know that ZXing already has the ability to do this. But i have been doing this for 2 days and what i have done is trying to read a QR image from a file and calculating the darkest and brightest color in the image. Then change every foreground pixel to black and others to white. After this I will get a QR code just like the standard ones. Then use a function to read the QR code:
However, this only works for QR code with two different colors, if it gets to three colors, then it won't work in the most case. Unless, the new image, which converted from color to gray image, wouldn't exceed the error correction percentage.
And I had tried other methods but each method is working only for a specific kind of QR code (with logo, multi-colored, shaped Finder Patterns, etc.).
And what I am looking for is a way to decode all kinds of QR code. At least for multi-colored and shaped Finder Patterns.
For more detail:
1) This is the code I'm using to decode the Green QR on this page (second QR) and also used to decode the third QR (with a kind of logo thing above the alignment pattern) found on the same website which is definitely not working:
public class Decoder
{
public static void main(String[] args)
{
// input image file
File imageFile = new File("/Users/User/Desktop/QR/green.png");
BufferedImage image = null;
try
{
image = ImageIO.read(imageFile);
}
catch (IOException e)
{
System.out.println("io outch");
}
int imageWidth = image.getWidth();
int imageHeight = image.getHeight();
int total = 0;
int dark = image.getRGB(0, 0);
int light = image.getRGB(0, 0);
int backgroundColor = 0;
int foregroundColor = 0;
FinderPattern topLeftFinder;
for (int x = 0; x < imageWidth; x ++)
{
for (int y = 0; y <imageHeight; y ++)
{
total = total + image.getRGB(x, y);
}
}
//int average = total / (imageWidth * imageHeight);
//System.out.println("total" + total + " average " + average);
for (int x = 0; x < imageWidth; x ++)
{
for (int y = 0; y <imageHeight; y ++)
{
if (image.getRGB(x, y) < dark)
{
dark = image.getRGB(x, y);
}
if (image.getRGB(x, y) > light)
{
light = image.getRGB(x, y);
}
}
}
for (int x = 0; x < imageWidth; x ++)
{
for (int y = 0; y <imageHeight; y ++)
{
if (image.getRGB(x, y) >= (dark - light) / 4)
{
image.setRGB(x, y, -1);
}
else if (image.getRGB(x, y) <= (dark - light) * 3 / 4)
{
image.setRGB(x, y, -16777216);
}
else
{
image.setRGB(x, y, -1);
}
}
}
System.out.println("total" + dark + " average " + light);
File outputFile = new File("/Users/Desktop/QR/outputQR.png");
//ImageIO.write(image, "png", file);
try
{
ImageIO.write(image, "png", outputFile);
}
catch (IOException e)
{
System.out.println(e.getMessage());
}
// creating binary bitmap from source image
LuminanceSource lumSource = new BufferedImageLuminanceSource(image);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(lumSource));
Hashtable<DecodeHintType, Object> hint = new Hashtable<DecodeHintType, Object>();
hint.put(DecodeHintType.TRY_HARDER, BarcodeFormat.QR_CODE);
// decoding
QRCodeReader QRreader = new QRCodeReader();
Result result = null;
try
{
result = QRreader.decode(bitmap, hint);
}
catch (ReaderException e)
{
System.out.println("error during reading");
}
// getting output text
String decodedText = result.getText();
System.out.println(decodedText);
}
}
2) And this is the code used for decoding this QR which is working fine originally but don't know why it's not working right now. And this code won't decode the QRs mentioned above.
public class Decoder
{
public static void main(String[] args)
{
// input image file
File imageFile = new File("/Users/User/Desktop/QR/bigfinderQR.png");
BufferedImage image = null;
try
{
image = ImageIO.read(imageFile);
}
catch (IOException e)
{
System.out.println("io outch");
}
// creating binary bitmap from source image
LuminanceSource lumSource = new BufferedImageLuminanceSource(image);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(lumSource));
Hashtable<DecodeHintType, Object> hint = new Hashtable<DecodeHintType, Object>();
hint.put(DecodeHintType.TRY_HARDER, BarcodeFormat.QR_CODE);
// decoding
QRCodeReader QRreader = new QRCodeReader();
Result result = null;
try
{
result = QRreader.decode(bitmap, hint);
}
catch (ReaderException e)
{
System.out.println("error during reading");
}
// getting output text
String decodedText = result.getText();
System.out.println(decodedText);
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
它只是根据计算出的每个像素的亮度进行二值化。任何像深色加浅色这样的合理的东西都应该没问题。一千种颜色就够了。如果是亮暗(反转),那么您确实需要反转图像或修改代码以反转图像。这几乎肯定不是问题所在。
扭曲取景器模式是一件比较棘手的事情,因为这样更容易使其无效。您需要保持几乎 1:1:3:1:1 的暗-亮-暗-亮-暗比例水平和垂直扫描图案。把角弄圆一点就好了。例如,您不能在黑色模块之间放置空白。
您可以发布您尝试解码的原始图像吗?我可以很快告诉你什么是对的,什么是错的。
It just binarizes based on the computed luminance of each pixel. Anything reasonably like dark-on-light should be fine. A thousand colors are fine. If it's light-on-dark (inverted), then you do need to invert the image or modify the code to invert the image. This is almost surely not the issue.
Distorting finder patterns is a trickier business since it's easier to make it invalid this way. You will need to preserve pretty nearly the 1:1:3:1:1 dark-light-dark-light-dark ratios scanning across the pattern horizontally and vertically. Rounding the corners a bit is fine. You couldn't for example put white space between black modules.
Can you post the original image you're trying to decode? I could tell you very quickly what's right and wrong.
篡改二维码总是有风险的。 ZXing 被定义为符合 ISO 标准,而颜色代码(更不用说“形状查找器图案”)远未达到标准。如果您扭曲了 QR 码,您应该预料到一些(如果不是全部)解码器会失败。
ZXing 旨在最大限度地提高标准图像的成功率。它所做的一些事情实际上会使其在扭曲的图像上无法正常工作。例如,提高带有阴影的图像的解码率的算法可能不利于处理均匀照明但彩色的图像。
众所周知,ZXing 对取景器图案失真很敏感。由于这种扭曲是非标准的,因此没有兴趣改变它。
Mangling a QR code is always risky. ZXing is defined to work to the ISO standard and a colored code, let alone "shaped Finder Patterns", is nowhere near standard. If you distort a QR code, you should expect some, if not all, decoders to fail.
ZXing is designed to maximize success on standard images. Some of the things it does to do so will actually make it not work well on distorted images. For example, the algorithms that improve decode rates on images with shadows may work against handling uniformly lit but colored images.
And ZXing is known to be sensitive to finder pattern distortions. Since such distortions are non-standard, there's no interest changing that.