報表中含有單號二維碼,紙質單據經掃描儀掃描為圖片后,使用com.google.zxing
解析二維碼生成單號供程序使用。在實際使用過程中發現二維碼解析時而有失敗的情況,對掃描的單據圖片進行分析后發現,解析失敗得到都是掃描質量稍差者。
為了提高解析的成功率,首先想到的是報表單據打印的質量以及掃描為圖片的質量都要好才能保證圖片的質量,但實操的過程中受限於使用者的打印機和掃描儀,以及操作人員的水平,只好建議他們盡量使用較好的設備。其次,就是優化代碼,看看是否能在代碼的層面提高二維碼識別率。
從代碼的層面提高識別率,想到2個方案,其一對圖片進行去除噪點的操作,生成高質量的圖片;另外就是考慮到把整個圖給Zxing
進行識別,此時圖片質量稍差就無法識,那么只是截取圖片的中的二維碼部分給ZXing
識別是不是能提高識別率呢?
經實戰發現對圖片進行降噪,代價太大,在筆者的計算機上一張圖降噪處理需要5秒鍾左右,對於批量識別的情況不大適合。
所以,只要采取截取圖片的中的二維碼部分給ZXing識別這個方案試下了。
代碼如下,其中 image = image.getSubimage(x,y,width,height);
為核心代碼。
public static String decode(BufferedImage image,int x,int y,double width,double height) {
try {
image = image.getSubimage(x,y,width,height);
LuminanceSource luminanceSource = new BufferedImageLuminanceSource(image);
Binarizer binarizer = new HybridBinarizer(luminanceSource);
BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer);
Map<DecodeHintType, Object> hints = new HashMap<>();
// 解碼設置編碼方式為:utf-8,
hints.put(DecodeHintType.CHARACTER_SET, "utf-8");
//優化精度
hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
Result result = new QRCodeReader().decode(binaryBitmap, hints);
return result.getText();
} catch (NotFoundException | ChecksumException | FormatException e) {
log.error("圖片中不存在二維碼或者解析而二維碼失敗", e);
throw new ServiceException("圖片中不存在二維碼或者解析而二維碼失敗", e);
}
}
經過測試,上面的代碼大大提高了二維碼的解析成功率。
備注,另外根據測試發現識別的精度還和二維碼的大小有關系,如果二維碼過大可以通過等比率縮放的方式將二維碼縮小,代碼如下:
public static BufferedImage getScale(BufferedImage image,double scale) {
AffineTransformOp transformOp = new AffineTransformOp(AffineTransform.getScaleInstance(scale, scale), null);
image = transformOp.filter(image, null);
return image;
}