C++ port: fixed warnings for Symbian build
[zxing.git] / cpp / core / src / zxing / qrcode / detector / QREdgeDetector.cpp
1 /*\r
2  *  QREdgeDetector.cpp\r
3  *  zxing\r
4  *\r
5  *  Created by Ralf Kistner on 7/12/2009.\r
6  *  Copyright 2008 ZXing authors All rights reserved.\r
7  *\r
8  * Licensed under the Apache License, Version 2.0 (the "License");\r
9  * you may not use this file except in compliance with the License.\r
10  * You may obtain a copy of the License at\r
11  *\r
12  *      http://www.apache.org/licenses/LICENSE-2.0\r
13  *\r
14  * Unless required by applicable law or agreed to in writing, software\r
15  * distributed under the License is distributed on an "AS IS" BASIS,\r
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
17  * See the License for the specific language governing permissions and\r
18  * limitations under the License.\r
19  */\r
20 \r
21 #include <zxing/qrcode/detector/QREdgeDetector.h>\r
22 #include <zxing/common/EdgeDetector.h>\r
23 \r
24 using namespace std;\r
25 \r
26 namespace zxing {\r
27 namespace qrcode {\r
28 \r
29 static const float patternEdgeThreshold = 2;\r
30 static const int patternEdgeWidth = 3;\r
31 static const float patternEdgeSearchRatio = 1.1;\r
32 static const int patternEdgeSkip = 2;\r
33 \r
34 static const float accurateEdgeThreshold = 3.3;\r
35 static const int accurateEdgeWidth = 7;\r
36 static const int accurateEdgeSkip = 2;\r
37 \r
38 static Point guessLastPattern(Point topLeft, Point topRight, Point bottomLeft) {\r
39   return Point(topRight.x - topLeft.x + bottomLeft.x, topRight.y - topLeft.y + bottomLeft.y);\r
40 }\r
41 \r
42 static Point rp(Ref<ResultPoint> rp) {\r
43   return Point(rp->getX(), rp->getY());\r
44 }\r
45 \r
46 QREdgeDetector::QREdgeDetector(Ref<BitMatrix> image) : Detector(image) { }\r
47 \r
48 Ref<PerspectiveTransform> QREdgeDetector::createTransform(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref <\r
49       ResultPoint > bottomLeft, Ref<ResultPoint> alignmentPattern, int dimension) {\r
50 \r
51   if(alignmentPattern == NULL) {\r
52     Point corner = findCorner(*Detector::getImage(), rp(topLeft), rp(topRight), rp(bottomLeft), dimension);\r
53     return get1CornerTransform(rp(topLeft), rp(topRight), rp(bottomLeft), corner, dimension);\r
54   } else {\r
55     return Detector::createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension);\r
56   }\r
57 }\r
58 \r
59 \r
60 \r
61 \r
62 Point QREdgeDetector::findCorner(const BitMatrix& image, Point topLeft, Point topRight, Point bottomLeft, int dimension) {\r
63   Point bottomRight = guessLastPattern(topLeft, topRight, bottomLeft);\r
64 \r
65   Line bottomEst = findPatternEdge(image, bottomLeft, topLeft, bottomRight, false);\r
66   Line rightEst = findPatternEdge(image, topRight, topLeft, bottomRight, true);\r
67 \r
68   //return EdgeDetector::intersection(bottomEst, rightEst);\r
69 \r
70   Line bottom = EdgeDetector::findLine(image, bottomEst, false, accurateEdgeWidth, accurateEdgeThreshold, accurateEdgeSkip);\r
71   Line right = EdgeDetector::findLine(image, rightEst, true, accurateEdgeWidth, accurateEdgeThreshold, accurateEdgeSkip);\r
72 \r
73 \r
74   return EdgeDetector::intersection(bottom, right);\r
75 }\r
76 \r
77 Line QREdgeDetector::findPatternEdge(const BitMatrix& image, Point pattern, Point opposite, Point direction, bool invert) {\r
78   Point start = endOfReverseBlackWhiteBlackRun(image, pattern, opposite);\r
79 \r
80   float dx = pattern.x - start.x;\r
81   float dy = pattern.y - start.y;\r
82   float dist = sqrt(dx*dx + dy*dy);\r
83 \r
84   float dirX = direction.x - pattern.x;\r
85   float dirY = direction.y - pattern.y;\r
86   float dirSize = sqrt(dirX*dirX + dirY*dirY);\r
87 \r
88   float nx = dirX/dirSize;\r
89   float ny = dirY/dirSize;\r
90 \r
91   float search = dist * patternEdgeSearchRatio;\r
92   Point a(start.x + nx*search, start.y + ny*search);\r
93   Point b(start.x - nx*search, start.y - ny*search);\r
94 \r
95   return EdgeDetector::findLine(image, Line(a, b), invert, patternEdgeWidth, patternEdgeThreshold, patternEdgeSkip);\r
96 }\r
97 \r
98 \r
99 Ref<PerspectiveTransform> QREdgeDetector::get1CornerTransform(Point topLeft, Point topRight, Point bottomLeft, Point corner, int dimension) {\r
100   float dimMinusThree = (float) dimension - 3.5f;\r
101 \r
102   Ref<PerspectiveTransform> transform(PerspectiveTransform::quadrilateralToQuadrilateral(3.5f, 3.5f, dimMinusThree, 3.5f, dimension,\r
103                                       dimension, 3.5f, dimMinusThree, topLeft.x, topLeft.y, topRight.x,\r
104                                       topRight.y, corner.x, corner.y, bottomLeft.x, bottomLeft.y));\r
105 \r
106   return transform;\r
107 }\r
108 \r
109 // Adapted from "sizeOfBlackWhiteBlackRun" in zxing::qrcode::Detector\r
110 Point QREdgeDetector::endOfReverseBlackWhiteBlackRun(const BitMatrix& image, Point from, Point to) {\r
111   int fromX = (int)from.x;\r
112   int fromY = (int)from.y;\r
113   int toX = (int)to.x;\r
114   int toY = (int)to.y;\r
115 \r
116   bool steep = abs(toY - fromY) > abs(toX - fromX);\r
117   if (steep) {\r
118     int temp = fromX;\r
119     fromX = fromY;\r
120     fromY = temp;\r
121     temp = toX;\r
122     toX = toY;\r
123     toY = temp;\r
124   }\r
125 \r
126   int dx = abs(toX - fromX);\r
127   int dy = abs(toY - fromY);\r
128   int error = -dx >> 1;\r
129   int ystep = fromY < toY ? -1 : 1;\r
130   int xstep = fromX < toX ? -1 : 1;\r
131   int state = 0; // In black pixels, looking for white, first or second time\r
132 \r
133   // In case there are no points, prepopulate to from\r
134   int realX = fromX;\r
135   int realY = fromY;\r
136   for (int x = fromX, y = fromY; x != toX; x += xstep) {\r
137     realX = steep ? y : x;\r
138     realY = steep ? x : y;\r
139 \r
140     if(realX < 0 || realY < 0 || realX >= (int)image.getWidth() || realY >= (int)image.getHeight())\r
141       break;\r
142 \r
143     if (state == 1) { // In white pixels, looking for black\r
144       if (image.get(realX, realY)) {\r
145         state++;\r
146       }\r
147     } else {\r
148       if (!image.get(realX, realY)) {\r
149         state++;\r
150       }\r
151     }\r
152 \r
153     if (state == 3) { // Found black, white, black, and stumbled back onto white; done\r
154       return Point(realX, realY);\r
155     }\r
156     error += dy;\r
157     if (error > 0) {\r
158       y += ystep;\r
159       error -= dx;\r
160     }\r
161   }\r
162 \r
163   // B-W-B run not found, return the last point visited.\r
164   return Point(realX, realY);\r
165 }\r
166 \r
167 } // namespace qrcode\r
168 } // namespace zxing\r