forked from makiuchi-d/gozxing
-
Notifications
You must be signed in to change notification settings - Fork 0
/
mask_util.go
206 lines (196 loc) · 5.23 KB
/
mask_util.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
package encoder
import (
errors "golang.org/x/xerrors"
)
const (
// Penalty weights from section 6.8.2.1
maskUtilN1 = 3
maskUtilN2 = 3
maskUtilN3 = 40
maskUtilN4 = 10
)
// MaskUtil_applyMaskPenaltyRule1 Apply mask penalty rule 1 and return the penalty.
// Find repetitive cells with the same color and give penalty to them. Example: 00000 or 11111.
func MaskUtil_applyMaskPenaltyRule1(matrix *ByteMatrix) int {
return applyMaskPenaltyRule1Internal(matrix, true) + applyMaskPenaltyRule1Internal(matrix, false)
}
// MaskUtil_applyMaskPenaltyRule2 Apply mask penalty rule 2 and return the penalty.
// Find 2x2 blocks with the same color and give penalty to them.
// This is actually equivalent to the spec's rule, which is to find MxN blocks and give a penalty
// proportional to (M-1)x(N-1), because this is the number of 2x2 blocks inside such a block.
func MaskUtil_applyMaskPenaltyRule2(matrix *ByteMatrix) int {
penalty := 0
array := matrix.GetArray()
width := matrix.GetWidth()
height := matrix.GetHeight()
for y := 0; y < height-1; y++ {
arrayY := array[y]
for x := 0; x < width-1; x++ {
value := arrayY[x]
if value == arrayY[x+1] && value == array[y+1][x] && value == array[y+1][x+1] {
penalty++
}
}
}
return maskUtilN2 * penalty
}
// MaskUtil_applyMaskPenaltyRule3 Apply mask penalty rule 3 and return the penalty.
// Find consecutive runs of 1:1:3:1:1:4 starting with black, or 4:1:1:3:1:1 starting with white,
// and give penalty to them. If we find patterns like 000010111010000, we give penalty once.
func MaskUtil_applyMaskPenaltyRule3(matrix *ByteMatrix) int {
numPenalties := 0
array := matrix.GetArray()
width := matrix.GetWidth()
height := matrix.GetHeight()
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
arrayY := array[y] // We can at least optimize this access
if x+6 < width &&
arrayY[x] == 1 &&
arrayY[x+1] == 0 &&
arrayY[x+2] == 1 &&
arrayY[x+3] == 1 &&
arrayY[x+4] == 1 &&
arrayY[x+5] == 0 &&
arrayY[x+6] == 1 &&
(isWhiteHorizontal(arrayY, x-4, x) || isWhiteHorizontal(arrayY, x+7, x+11)) {
numPenalties++
}
if y+6 < height &&
array[y][x] == 1 &&
array[y+1][x] == 0 &&
array[y+2][x] == 1 &&
array[y+3][x] == 1 &&
array[y+4][x] == 1 &&
array[y+5][x] == 0 &&
array[y+6][x] == 1 &&
(isWhiteVertical(array, x, y-4, y) || isWhiteVertical(array, x, y+7, y+11)) {
numPenalties++
}
}
}
return numPenalties * maskUtilN3
}
func isWhiteHorizontal(rowArray []int8, from, to int) bool {
if from < 0 {
from = 0
}
if to > len(rowArray) {
to = len(rowArray)
}
for i := from; i < to; i++ {
if rowArray[i] == 1 {
return false
}
}
return true
}
func isWhiteVertical(array [][]int8, col, from, to int) bool {
if from < 0 {
from = 0
}
if to > len(array) {
to = len(array)
}
for i := from; i < to; i++ {
if array[i][col] == 1 {
return false
}
}
return true
}
// MaskUtil_applyMaskPenaltyRule4 Apply mask penalty rule 4 and return the penalty.
// Calculate the ratio of dark cells and give penalty if the ratio is far from 50%.
// It gives 10 penalty for 5% distance.
func MaskUtil_applyMaskPenaltyRule4(matrix *ByteMatrix) int {
numDarkCells := 0
array := matrix.GetArray()
width := matrix.GetWidth()
height := matrix.GetHeight()
for y := 0; y < height; y++ {
arrayY := array[y]
for x := 0; x < width; x++ {
if arrayY[x] == 1 {
numDarkCells++
}
}
}
numTotalCells := matrix.GetHeight() * matrix.GetWidth()
distance := numDarkCells*2 - numTotalCells
if distance < 0 {
distance = -distance
}
fivePercentVariances := distance * 10 / numTotalCells
return fivePercentVariances * maskUtilN4
}
// MaskUtil_getDataMaskBit Return the mask bit for "getMaskPattern" at "x" and "y".
// See 8.8 of JISX0510:2004 for mask pattern conditions.
func MaskUtil_getDataMaskBit(maskPattern, x, y int) (bool, error) {
var intermediate int
switch maskPattern {
case 0:
intermediate = (y + x) & 0x1
break
case 1:
intermediate = y & 0x1
break
case 2:
intermediate = x % 3
break
case 3:
intermediate = (y + x) % 3
break
case 4:
intermediate = ((y / 2) + (x / 3)) & 0x1
break
case 5:
temp := y * x
intermediate = (temp & 0x1) + (temp % 3)
break
case 6:
temp := y * x
intermediate = ((temp & 0x1) + (temp % 3)) & 0x1
break
case 7:
temp := y * x
intermediate = ((temp % 3) + ((y + x) & 0x1)) & 0x1
break
default:
return false, errors.Errorf("IllegalArgumentException: Invalid mask pattern: %d", maskPattern)
}
return (intermediate == 0), nil
}
func applyMaskPenaltyRule1Internal(matrix *ByteMatrix, isHorizontal bool) int {
penalty := 0
iLimit := matrix.GetWidth()
jLimit := matrix.GetHeight()
if isHorizontal {
iLimit, jLimit = jLimit, iLimit
}
array := matrix.GetArray()
for i := 0; i < iLimit; i++ {
numSameBitCells := 0
prevBit := -1
for j := 0; j < jLimit; j++ {
var bit int
if isHorizontal {
bit = int(array[i][j])
} else {
bit = int(array[j][i])
}
if bit == prevBit {
numSameBitCells++
} else {
if numSameBitCells >= 5 {
penalty += maskUtilN1 + (numSameBitCells - 5)
}
numSameBitCells = 1 // Include the cell itself.
prevBit = bit
}
}
if numSameBitCells >= 5 {
penalty += maskUtilN1 + (numSameBitCells - 5)
}
}
return penalty
}