OLD | NEW |
| (Empty) |
1 // Copyright 2014 PDFium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | |
6 // Original code is licensed as follows: | |
7 /* | |
8 * Copyright 2009 ZXing authors | |
9 * | |
10 * Licensed under the Apache License, Version 2.0 (the "License"); | |
11 * you may not use this file except in compliance with the License. | |
12 * You may obtain a copy of the License at | |
13 * | |
14 * http://www.apache.org/licenses/LICENSE-2.0 | |
15 * | |
16 * Unless required by applicable law or agreed to in writing, software | |
17 * distributed under the License is distributed on an "AS IS" BASIS, | |
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
19 * See the License for the specific language governing permissions and | |
20 * limitations under the License. | |
21 */ | |
22 | |
23 #include "barcode.h" | |
24 #include "include/BC_Binarizer.h" | |
25 #include "include/BC_LuminanceSource.h" | |
26 #include "include/BC_CommonBitMatrix.h" | |
27 #include "include/BC_CommonBitArray.h" | |
28 #include "include/BC_GlobalHistogramBinarizer.h" | |
29 const FX_INT32 LUMINANCE_BITS = 5; | |
30 const FX_INT32 LUMINANCE_SHIFT = 8 - LUMINANCE_BITS; | |
31 const FX_INT32 LUMINANCE_BUCKETS = 1 << LUMINANCE_BITS; | |
32 CBC_GlobalHistogramBinarizer::CBC_GlobalHistogramBinarizer(CBC_LuminanceSource *
source): CBC_Binarizer(source) | |
33 { | |
34 } | |
35 CBC_GlobalHistogramBinarizer::~CBC_GlobalHistogramBinarizer() | |
36 { | |
37 } | |
38 CBC_CommonBitArray *CBC_GlobalHistogramBinarizer::GetBlackRow(FX_INT32 y, CBC_Co
mmonBitArray *row, FX_INT32 &e) | |
39 { | |
40 CBC_LuminanceSource *source = GetLuminanceSource(); | |
41 FX_INT32 width = source->GetWidth(); | |
42 CBC_AutoPtr<CBC_CommonBitArray> result(FX_NEW CBC_CommonBitArray(width)); | |
43 InitArrays(width); | |
44 CFX_ByteArray *localLuminances = source->GetRow(y, m_luminance, e); | |
45 if (e != BCExceptionNO) { | |
46 return result.release(); | |
47 } | |
48 CFX_Int32Array localBuckets; | |
49 localBuckets.Copy(m_buckets); | |
50 FX_INT32 x; | |
51 for (x = 0; x < width; x++) { | |
52 FX_INT32 pixel = (*localLuminances)[x] & 0xff; | |
53 localBuckets[pixel >> LUMINANCE_SHIFT]++; | |
54 } | |
55 FX_INT32 blackPoint = EstimateBlackPoint(localBuckets, e); | |
56 if (e != BCExceptionNO) { | |
57 return result.release(); | |
58 } | |
59 FX_INT32 left = (*localLuminances)[0] & 0xff; | |
60 FX_INT32 center = (*localLuminances)[1] & 0xff; | |
61 for (x = 1; x < width - 1; x++) { | |
62 FX_INT32 right = (*localLuminances)[x + 1] & 0xff; | |
63 FX_INT32 luminance = ((center << 2) - left - right) >> 1; | |
64 if (luminance < blackPoint) { | |
65 result->Set(x); | |
66 } | |
67 left = center; | |
68 center = right; | |
69 } | |
70 return result.release(); | |
71 } | |
72 CBC_CommonBitMatrix *CBC_GlobalHistogramBinarizer::GetBlackMatrix(FX_INT32 &e) | |
73 { | |
74 CBC_LuminanceSource *source = GetLuminanceSource(); | |
75 FX_INT32 width = source->GetWidth(); | |
76 FX_INT32 height = source->GetHeight(); | |
77 CBC_CommonBitMatrix *BitMatrixTemp = FX_NEW CBC_CommonBitMatrix(); | |
78 BitMatrixTemp->Init(width, height); | |
79 CBC_AutoPtr<CBC_CommonBitMatrix> matrix(BitMatrixTemp); | |
80 InitArrays(width); | |
81 CFX_Int32Array localBuckets; | |
82 localBuckets.Copy(m_buckets); | |
83 FX_INT32 y; | |
84 for (y = 1; y < 5; y++) { | |
85 FX_INT32 row = height * y / 5; | |
86 CFX_ByteArray *localLuminances = source->GetRow(row, m_luminance, e); | |
87 BC_EXCEPTION_CHECK_ReturnValue(e, NULL); | |
88 FX_INT32 right = (width << 2) / 5; | |
89 FX_INT32 x; | |
90 for (x = width / 5; x < right; x++) { | |
91 FX_INT32 pixel = (*localLuminances)[x] & 0xff; | |
92 localBuckets[pixel >> LUMINANCE_SHIFT]++; | |
93 } | |
94 } | |
95 FX_INT32 blackPoint = EstimateBlackPoint(localBuckets, e); | |
96 BC_EXCEPTION_CHECK_ReturnValue(e, NULL); | |
97 CBC_AutoPtr<CFX_ByteArray> localLuminances(source->GetMatrix()); | |
98 for (y = 0; y < height; y++) { | |
99 FX_INT32 offset = y * width; | |
100 for (FX_INT32 x = 0; x < width; x++) { | |
101 FX_INT32 pixel = (*localLuminances)[offset + x] & 0xff; | |
102 if (pixel < blackPoint) { | |
103 matrix->Set(x, y); | |
104 } | |
105 } | |
106 } | |
107 return matrix.release(); | |
108 } | |
109 void CBC_GlobalHistogramBinarizer::InitArrays(FX_INT32 luminanceSize) | |
110 { | |
111 if(m_luminance.GetSize() < luminanceSize) { | |
112 m_luminance.SetSize(luminanceSize); | |
113 } | |
114 if(m_buckets.GetSize() <= 0) { | |
115 m_buckets.SetSize(LUMINANCE_BUCKETS); | |
116 } else { | |
117 FX_INT32 x; | |
118 for(x = 0; x < LUMINANCE_BUCKETS; x++) { | |
119 m_buckets[x] = 0; | |
120 } | |
121 } | |
122 } | |
123 FX_INT32 CBC_GlobalHistogramBinarizer::EstimateBlackPoint(CFX_Int32Array &bucket
s, FX_INT32 &e) | |
124 { | |
125 FX_INT32 numBuckets = buckets.GetSize(); | |
126 FX_INT32 maxBucketCount = 0; | |
127 FX_INT32 firstPeak = 0; | |
128 FX_INT32 firstPeakSize = 0; | |
129 FX_INT32 x; | |
130 for (x = 0; x < numBuckets; x++) { | |
131 if (buckets[x] > firstPeakSize) { | |
132 firstPeak = x; | |
133 firstPeakSize = buckets[x]; | |
134 } | |
135 if (buckets[x] > maxBucketCount) { | |
136 maxBucketCount = buckets[x]; | |
137 } | |
138 } | |
139 FX_INT32 secondPeak = 0; | |
140 FX_INT32 secondPeakScore = 0; | |
141 for (x = 0; x < numBuckets; x++) { | |
142 FX_INT32 distanceToBiggest = x - firstPeak; | |
143 FX_INT32 score = buckets[x] * distanceToBiggest * distanceToBiggest; | |
144 if (score > secondPeakScore) { | |
145 secondPeak = x; | |
146 secondPeakScore = score; | |
147 } | |
148 } | |
149 if (firstPeak > secondPeak) { | |
150 FX_INT32 temp = firstPeak; | |
151 firstPeak = secondPeak; | |
152 secondPeak = temp; | |
153 } | |
154 if (secondPeak - firstPeak <= numBuckets >> 4) { | |
155 e = BCExceptionRead; | |
156 return 0; | |
157 } | |
158 FX_INT32 bestValley = secondPeak - 1; | |
159 FX_INT32 bestValleyScore = -1; | |
160 for (x = secondPeak - 1; x > firstPeak; x--) { | |
161 FX_INT32 fromFirst = x - firstPeak; | |
162 FX_INT32 score = fromFirst * fromFirst * (secondPeak - x) * (maxBucketCo
unt - buckets[x]); | |
163 if (score > bestValleyScore) { | |
164 bestValley = x; | |
165 bestValleyScore = score; | |
166 } | |
167 } | |
168 return bestValley << LUMINANCE_SHIFT; | |
169 } | |
OLD | NEW |