📄 qrcodeimagereader.java
字号:
package jp.sourceforge.qrcode.codec.reader;
import java.util.Vector;
import jp.sourceforge.qrcode.codec.QRCodeDecoder;
import jp.sourceforge.qrcode.codec.data.*;
import jp.sourceforge.qrcode.codec.exception.AlignmentPatternNotFoundException;
import jp.sourceforge.qrcode.codec.exception.FinderPatternNotFoundException;
import jp.sourceforge.qrcode.codec.exception.SymbolNotFoundException;
import jp.sourceforge.qrcode.codec.exception.InvalidVersionException;
import jp.sourceforge.qrcode.codec.exception.VersionInformationException;
import jp.sourceforge.qrcode.codec.geom.*;
import jp.sourceforge.qrcode.codec.reader.pattern.*;
import jp.sourceforge.qrcode.codec.util.*;
public class QRCodeImageReader {
DebugCanvas canvas;
//boolean[][] image;
//DP =
//23 ...side pixels of image will be limited maximum 255 (8 bits)
//22 .. side pixels of image will be limited maximum 511 (9 bits)
//21 .. side pixels of image will be limited maximum 1023 (10 bits)
//I think it's good idea to use DECIMAL_POINT with type "long" too.
public static int DECIMAL_POINT = 21;
public static final boolean POINT_DARK = true;
public static final boolean POINT_LIGHT = false;
SamplingGrid samplingGrid;
boolean[][] bitmap;
//int numModuleAtSide; //デコード対象のシンボルにおける一辺のモジュールの数
public QRCodeImageReader() {
this.canvas = QRCodeDecoder.getCanvas();
}
// local class for module pitch
private class ModulePitch
{
public int top;
public int left;
public int bottom;
public int right;
};
boolean[][] applyMedianFilter(boolean[][] image, int threshold) {
boolean[][] filteredMatrix = new boolean[image.length][image[0].length];
//filtering noise in image with median filter
int numPointDark;
for (int y = 1; y < image[0].length - 1; y++) {
for (int x = 1; x < image.length - 1; x++) {
//if (image[x][y] == true) {
numPointDark = 0;
for (int fy = -1; fy < 2; fy++) {
for (int fx = -1; fx < 2; fx++) {
if (image[x + fx][y + fy] == true) {
numPointDark++;
}
}
}
if (numPointDark > threshold)
filteredMatrix[x][y] = POINT_DARK;
}
}
return filteredMatrix;
}
boolean[][] applyCrossMaskingMedianFilter(boolean[][] image, int threshold) {
boolean[][] filteredMatrix = new boolean[image.length][image[0].length];
//filtering noise in image with median filter
int numPointDark;
for (int y = 2; y < image[0].length - 2; y++) {
for (int x = 2; x < image.length - 2; x++) {
//if (image[x][y] == true) {
numPointDark = 0;
for (int f = -2; f < 3; f++) {
if (image[x+f][y] == true)
numPointDark++;
if (image[x][y+f] == true)
numPointDark++;
}
if (numPointDark > threshold)
filteredMatrix[x][y] = POINT_DARK;
}
}
return filteredMatrix;
}
boolean[][] filterImage(int[][] image) {
imageToGrayScale(image);
boolean[][] bitmap = grayScaleToBitmap(image);
return bitmap;
}
void imageToGrayScale(int[][] image) {
for (int y = 0; y < image[0].length; y++) {
for (int x = 0; x < image.length; x++) {
int r = image[x][y] >> 16 & 0xFF;
int g = image[x][y] >> 8 & 0xFF;
int b = image[x][y] & 0xFF;
int m = (r * 30 + g * 59 + b * 11) / 100;
image[x][y] = m;
}
}
}
boolean[][] grayScaleToBitmap(int[][] grayScale) {
int[][] middle = getMiddleBrightnessPerArea(grayScale);
int sqrtNumArea = middle.length;
int areaWidth = grayScale.length / sqrtNumArea;
int areaHeight = grayScale[0].length / sqrtNumArea;
boolean[][] bitmap = new boolean[grayScale.length][grayScale[0].length];
for (int ay = 0; ay < sqrtNumArea; ay++) {
for (int ax = 0; ax < sqrtNumArea; ax++) {
for (int dy = 0; dy < areaHeight; dy++) {
for (int dx = 0; dx < areaWidth; dx++) {
bitmap[areaWidth * ax + dx][areaHeight * ay + dy] = (grayScale[areaWidth * ax + dx][areaHeight * ay + dy] < middle[ax][ay]) ? true : false;
}
}
}
}
return bitmap;
}
int[][] getMiddleBrightnessPerArea(int[][] image) {
final int numSqrtArea = 4;
//obtain middle brightness((min + max) / 2) per area
int areaWidth = image.length / numSqrtArea;
int areaHeight = image[0].length / numSqrtArea;
int[][][] minmax = new int[numSqrtArea][numSqrtArea][2];
for (int ay = 0; ay < numSqrtArea; ay++) {
for (int ax = 0; ax < numSqrtArea; ax++) {
minmax[ax][ay][0] = 0xFF;
for (int dy = 0; dy < areaHeight; dy++) {
for (int dx = 0; dx < areaWidth; dx++) {
int target = image[areaWidth * ax + dx][areaHeight * ay + dy];
if (target < minmax[ax][ay][0]) minmax[ax][ay][0] = target;
if (target > minmax[ax][ay][1]) minmax[ax][ay][1] = target;
}
}
//minmax[ax][ay][0] = (minmax[ax][ay][0] + minmax[ax][ay][1]) / 2;
}
}
int[][] middle = new int[numSqrtArea][numSqrtArea];
for (int ay = 0; ay < numSqrtArea; ay++) {
for (int ax = 0; ax < numSqrtArea; ax++) {
middle[ax][ay] = (minmax[ax][ay][0] + minmax[ax][ay][1]) / 2;
//System.out.print(middle[ax][ay] + ",");
}
//System.out.println("");
}
//System.out.println("");
return middle;
}
public QRCodeSymbol getQRCodeSymbol(int[][] image)
throws SymbolNotFoundException {
int longSide = (image.length < image[0].length) ? image[0].length : image.length;
QRCodeImageReader.DECIMAL_POINT = 23 - QRCodeUtility.sqrt(longSide / 256);
bitmap = filterImage(image);
canvas.println("Drawing matrix.");
canvas.drawMatrix(bitmap);
canvas.println("Scanning Finder Pattern.");
FinderPattern finderPattern = null;
try {
finderPattern = FinderPattern.findFinderPattern(bitmap);
} catch (FinderPatternNotFoundException e) {
canvas.println("Not found, now retrying...");
bitmap = applyCrossMaskingMedianFilter(bitmap, 5);
canvas.drawMatrix(bitmap);
for (int i=0; i< 1000000000;i++);
try {
finderPattern = FinderPattern.findFinderPattern(bitmap);
} catch (FinderPatternNotFoundException e2) {
throw new SymbolNotFoundException(e2.getMessage());
} catch (VersionInformationException e2) {
throw new SymbolNotFoundException(e2.getMessage());
}
} catch (VersionInformationException e) {
throw new SymbolNotFoundException(e.getMessage());
}
canvas.println("FinderPattern at");
String finderPatternCoordinates =
finderPattern.getCenter(FinderPattern.UL).toString() +
finderPattern.getCenter(FinderPattern.UR).toString() +
finderPattern.getCenter(FinderPattern.DL).toString();
canvas.println(finderPatternCoordinates);
int[] sincos = finderPattern.getAngle();
canvas.println("Angle*4098: Sin " + Integer.toString(sincos[0]) + " " + "Cos " + Integer.toString(sincos[1]));
int version = finderPattern.getVersion();
canvas.println("Version: " + Integer.toString(version));
if (version < 1 || version > 40)
throw new InvalidVersionException("Invalid version: " + version);
AlignmentPattern alignmentPattern = null;
try {
alignmentPattern = AlignmentPattern.findAlignmentPattern(bitmap, finderPattern);
} catch (AlignmentPatternNotFoundException e) {
throw new SymbolNotFoundException(e.getMessage());
}
int matrixLength = alignmentPattern.getCenter().length;
canvas.println("AlignmentPatterns at");
for (int y = 0; y < matrixLength; y++) {
String alignmentPatternCoordinates = "";
for (int x = 0; x < matrixLength; x++) {
alignmentPatternCoordinates += alignmentPattern.getCenter()[x][y].toString();
}
canvas.println(alignmentPatternCoordinates);
}
//for(int i = 0; i < 500000; i++) System.out.println("");
canvas.println("Creating sampling grid.");
//[TODO] need all-purpose method
//samplingGrid = getSamplingGrid2_6(finderPattern, alignmentPattern);
samplingGrid = getSamplingGrid(finderPattern, alignmentPattern);
canvas.println("Reading grid.");
boolean[][] qRCodeMatrix = null;
try {
qRCodeMatrix = getQRCodeMatrix(bitmap, samplingGrid);
} catch (ArrayIndexOutOfBoundsException e) {
throw new SymbolNotFoundException("Sampling grid exceeded image boundary");
}
//canvas.drawMatrix(qRCodeMatrix);
return new QRCodeSymbol(qRCodeMatrix);
}
public QRCodeSymbol getQRCodeSymbolWithAdjustedGrid(Point adjust)
throws IllegalStateException, SymbolNotFoundException {
if (bitmap == null || samplingGrid == null) {
throw new IllegalStateException("This method must be called after QRCodeImageReader.getQRCodeSymbol() called");
}
samplingGrid.adjust(adjust);
canvas.println("Sampling grid adjusted d("+adjust.getX()+","+adjust.getY()+")");
boolean[][] qRCodeMatrix = null;
try {
qRCodeMatrix = getQRCodeMatrix(bitmap, samplingGrid);
} catch (ArrayIndexOutOfBoundsException e) {
throw new SymbolNotFoundException("Sampling grid exceeded image boundary");
}
return new QRCodeSymbol(qRCodeMatrix);
}
// For only version 1 which has no Alignement Patterns
/* SamplingGrid getSamplingGrid1(FinderPattern finderPattern) {
int sqrtNumArea = 1;
int sqrtNumModules = finderPattern.getSqrtNumModules(); //get nummber of modules at side
int sqrtNumAreaModules = sqrtNumModules / sqrtNumArea;
Point[] centers = finderPattern.getCenter();
int logicalDistance = 14;
SamplingGrid samplingGrid = new SamplingGrid(sqrtNumArea);
Line baseLineX, baseLineY, gridLineX, gridLineY;
ModulePitch modulePitch = new ModulePitch(); //store (up,left) order
modulePitch.top = getAreaModulePitch(centers[0], centers[1], logicalDistance);
modulePitch.left = getAreaModulePitch(centers[0], centers[2], logicalDistance);
//X軸に垂直の基線(一般に縦)
baseLineX = new Line(
finderPattern.getCenter(FinderPattern.UL),
finderPattern.getCenter(FinderPattern.DL));
Axis axis = new Axis(finderPattern.getAngle(), modulePitch.top);
axis.setOrigin(baseLineX.getP1());
baseLineX.setP1(axis.translate(-3, -3));
axis.setModulePitch(modulePitch.left);
axis.setOrigin(baseLineX.getP2());
baseLineX.setP2(axis.translate(-3, 3));
//Y軸に垂直の基線(一般に横)
baseLineY =
new Line(finderPattern.getCenter(FinderPattern.UL),
finderPattern.getCenter(FinderPattern.UR));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -