FinderPatternFinder.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  1. // -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
  2. /*
  3. * FinderPatternFinder.cpp
  4. * zxing
  5. *
  6. * Created by Christian Brunschen on 13/05/2008.
  7. * Copyright 2008 ZXing authors All rights reserved.
  8. *
  9. * Licensed under the Apache License, Version 2.0 (the "License");
  10. * you may not use this file except in compliance with the License.
  11. * You may obtain a copy of the License at
  12. *
  13. * http://www.apache.org/licenses/LICENSE-2.0
  14. *
  15. * Unless required by applicable law or agreed to in writing, software
  16. * distributed under the License is distributed on an "AS IS" BASIS,
  17. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18. * See the License for the specific language governing permissions and
  19. * limitations under the License.
  20. */
  21. #include <algorithm>
  22. #include <zxing/qrcode/detector/FinderPatternFinder.h>
  23. #include <zxing/ReaderException.h>
  24. #include <zxing/DecodeHints.h>
  25. using std::sort;
  26. using std::max;
  27. using std::abs;
  28. using std::vector;
  29. using zxing::Ref;
  30. using zxing::qrcode::FinderPatternFinder;
  31. using zxing::qrcode::FinderPattern;
  32. using zxing::qrcode::FinderPatternInfo;
  33. // VC++
  34. using zxing::BitMatrix;
  35. using zxing::ResultPointCallback;
  36. using zxing::ResultPoint;
  37. using zxing::DecodeHints;
  38. namespace {
  39. class FurthestFromAverageComparator {
  40. private:
  41. const float averageModuleSize_;
  42. public:
  43. FurthestFromAverageComparator(float averageModuleSize) :
  44. averageModuleSize_(averageModuleSize) {
  45. }
  46. bool operator()(Ref<FinderPattern> a, Ref<FinderPattern> b) {
  47. float dA = abs(a->getEstimatedModuleSize() - averageModuleSize_);
  48. float dB = abs(b->getEstimatedModuleSize() - averageModuleSize_);
  49. return dA > dB;
  50. }
  51. };
  52. class CenterComparator {
  53. const float averageModuleSize_;
  54. public:
  55. CenterComparator(float averageModuleSize) :
  56. averageModuleSize_(averageModuleSize) {
  57. }
  58. bool operator()(Ref<FinderPattern> a, Ref<FinderPattern> b) {
  59. // N.B.: we want the result in descending order ...
  60. if (a->getCount() != b->getCount()) {
  61. return a->getCount() > b->getCount();
  62. } else {
  63. float dA = abs(a->getEstimatedModuleSize() - averageModuleSize_);
  64. float dB = abs(b->getEstimatedModuleSize() - averageModuleSize_);
  65. return dA < dB;
  66. }
  67. }
  68. };
  69. }
  70. int FinderPatternFinder::CENTER_QUORUM = 2;
  71. int FinderPatternFinder::MIN_SKIP = 3;
  72. int FinderPatternFinder::MAX_MODULES = 57;
  73. float FinderPatternFinder::centerFromEnd(int* stateCount, int end) {
  74. return (float)(end - stateCount[4] - stateCount[3]) - stateCount[2] / 2.0f;
  75. }
  76. bool FinderPatternFinder::foundPatternCross(int* stateCount) {
  77. int totalModuleSize = 0;
  78. for (int i = 0; i < 5; i++) {
  79. if (stateCount[i] == 0) {
  80. return false;
  81. }
  82. totalModuleSize += stateCount[i];
  83. }
  84. if (totalModuleSize < 7) {
  85. return false;
  86. }
  87. float moduleSize = (float)totalModuleSize / 7.0f;
  88. float maxVariance = moduleSize / 2.0f;
  89. // Allow less than 50% variance from 1-1-3-1-1 proportions
  90. return abs(moduleSize - stateCount[0]) < maxVariance && abs(moduleSize - stateCount[1]) < maxVariance && abs(3.0f
  91. * moduleSize - stateCount[2]) < 3.0f * maxVariance && abs(moduleSize - stateCount[3]) < maxVariance && abs(
  92. moduleSize - stateCount[4]) < maxVariance;
  93. }
  94. float FinderPatternFinder::crossCheckVertical(size_t startI, size_t centerJ, int maxCount, int originalStateCountTotal) {
  95. int maxI = image_->getHeight();
  96. int stateCount[5];
  97. for (int i = 0; i < 5; i++)
  98. stateCount[i] = 0;
  99. // Start counting up from center
  100. int i = startI;
  101. while (i >= 0 && image_->get(centerJ, i)) {
  102. stateCount[2]++;
  103. i--;
  104. }
  105. if (i < 0) {
  106. return nan();
  107. }
  108. while (i >= 0 && !image_->get(centerJ, i) && stateCount[1] <= maxCount) {
  109. stateCount[1]++;
  110. i--;
  111. }
  112. // If already too many modules in this state or ran off the edge:
  113. if (i < 0 || stateCount[1] > maxCount) {
  114. return nan();
  115. }
  116. while (i >= 0 && image_->get(centerJ, i) && stateCount[0] <= maxCount) {
  117. stateCount[0]++;
  118. i--;
  119. }
  120. if (stateCount[0] > maxCount) {
  121. return nan();
  122. }
  123. // Now also count down from center
  124. i = startI + 1;
  125. while (i < maxI && image_->get(centerJ, i)) {
  126. stateCount[2]++;
  127. i++;
  128. }
  129. if (i == maxI) {
  130. return nan();
  131. }
  132. while (i < maxI && !image_->get(centerJ, i) && stateCount[3] < maxCount) {
  133. stateCount[3]++;
  134. i++;
  135. }
  136. if (i == maxI || stateCount[3] >= maxCount) {
  137. return nan();
  138. }
  139. while (i < maxI && image_->get(centerJ, i) && stateCount[4] < maxCount) {
  140. stateCount[4]++;
  141. i++;
  142. }
  143. if (stateCount[4] >= maxCount) {
  144. return nan();
  145. }
  146. // If we found a finder-pattern-like section, but its size is more than 40% different than
  147. // the original, assume it's a false positive
  148. int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4];
  149. if (5 * abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) {
  150. return nan();
  151. }
  152. return foundPatternCross(stateCount) ? centerFromEnd(stateCount, i) : nan();
  153. }
  154. float FinderPatternFinder::crossCheckHorizontal(size_t startJ, size_t centerI, int maxCount,
  155. int originalStateCountTotal) {
  156. int maxJ = image_->getWidth();
  157. int stateCount[5];
  158. for (int i = 0; i < 5; i++)
  159. stateCount[i] = 0;
  160. int j = startJ;
  161. while (j >= 0 && image_->get(j, centerI)) {
  162. stateCount[2]++;
  163. j--;
  164. }
  165. if (j < 0) {
  166. return nan();
  167. }
  168. while (j >= 0 && !image_->get(j, centerI) && stateCount[1] <= maxCount) {
  169. stateCount[1]++;
  170. j--;
  171. }
  172. if (j < 0 || stateCount[1] > maxCount) {
  173. return nan();
  174. }
  175. while (j >= 0 && image_->get(j, centerI) && stateCount[0] <= maxCount) {
  176. stateCount[0]++;
  177. j--;
  178. }
  179. if (stateCount[0] > maxCount) {
  180. return nan();
  181. }
  182. j = startJ + 1;
  183. while (j < maxJ && image_->get(j, centerI)) {
  184. stateCount[2]++;
  185. j++;
  186. }
  187. if (j == maxJ) {
  188. return nan();
  189. }
  190. while (j < maxJ && !image_->get(j, centerI) && stateCount[3] < maxCount) {
  191. stateCount[3]++;
  192. j++;
  193. }
  194. if (j == maxJ || stateCount[3] >= maxCount) {
  195. return nan();
  196. }
  197. while (j < maxJ && image_->get(j, centerI) && stateCount[4] < maxCount) {
  198. stateCount[4]++;
  199. j++;
  200. }
  201. if (stateCount[4] >= maxCount) {
  202. return nan();
  203. }
  204. // If we found a finder-pattern-like section, but its size is significantly different than
  205. // the original, assume it's a false positive
  206. int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4];
  207. if (5 * abs(stateCountTotal - originalStateCountTotal) >= originalStateCountTotal) {
  208. return nan();
  209. }
  210. return foundPatternCross(stateCount) ? centerFromEnd(stateCount, j) : nan();
  211. }
  212. bool FinderPatternFinder::confirmCenter135(float estimatedModuleSize,float centerI,float centerJ) {
  213. int stateCount[5];
  214. memset(stateCount,0,sizeof(stateCount));
  215. int maxx =image_->getWidth();
  216. int maxy =image_->getHeight();
  217. int x,y;
  218. x = centerJ,y=centerI;
  219. while (x<maxx&&y<maxy&&image_->get(x, y))
  220. {
  221. stateCount[2]++;
  222. x++;y++;
  223. }
  224. if(x==maxx||y==maxy) return false;
  225. while (x<maxx&&y<maxy&&!image_->get(x, y))
  226. {
  227. stateCount[3]++;
  228. x++;y++;
  229. }
  230. if(x==maxx||y==maxy) return false;
  231. while (x<maxx&&y<maxy&&image_->get(x, y))
  232. {
  233. stateCount[4]++;
  234. x++;y++;
  235. }
  236. x = centerJ,y=centerI;
  237. stateCount[2]--;
  238. while (x>=0&&y>=0&&image_->get(x, y))
  239. {
  240. stateCount[2]++;
  241. x--;y--;
  242. }
  243. if(x==maxx||y==maxy) return false;
  244. while (x>=0&&y>=0&&!image_->get(x, y))
  245. {
  246. stateCount[1]++;
  247. x--;y--;
  248. }
  249. if(x==maxx||y==maxy) return false;
  250. while (x>=0&&y>=0&&image_->get(x, y))
  251. {
  252. stateCount[0]++;
  253. x--;y--;
  254. }
  255. return foundPatternCross(stateCount);
  256. }
  257. bool FinderPatternFinder::confirmCenter45(float estimatedModuleSize,float centerI,float centerJ) {
  258. int stateCount[5];
  259. memset(stateCount,0,sizeof(stateCount));
  260. int maxx =image_->getWidth();
  261. int maxy =image_->getHeight();
  262. int x,y;
  263. x = centerJ,y=centerI;
  264. while (x>=0&&y<maxy&&image_->get(x, y))
  265. {
  266. stateCount[2]++;
  267. x--;y++;
  268. }
  269. if(x==maxx||y==maxy) return false;
  270. while (x>=0&&y<maxy&&!image_->get(x, y))
  271. {
  272. stateCount[3]++;
  273. x--;y++;
  274. }
  275. if(x==maxx||y==maxy) return false;
  276. while (x>=0&&y<maxy&&image_->get(x, y))
  277. {
  278. stateCount[4]++;
  279. x--;y++;
  280. }
  281. x = centerJ,y=centerI;
  282. stateCount[2]--;
  283. while (x<maxx&&y>=0&&image_->get(x, y))
  284. {
  285. stateCount[2]++;
  286. x++;y--;
  287. }
  288. if(x==maxx||y==maxy) return false;
  289. while (x<maxx&&y>=0&&!image_->get(x, y))
  290. {
  291. stateCount[1]++;
  292. x++;y--;
  293. }
  294. if(x==maxx||y==maxy) return false;
  295. while (x<maxx&&y>=0&&image_->get(x, y))
  296. {
  297. stateCount[0]++;
  298. x++;y--;
  299. }
  300. return foundPatternCross(stateCount);
  301. }
  302. bool FinderPatternFinder::handlePossibleCenter(int* stateCount, size_t i, size_t j) {
  303. int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4];
  304. float centerJ = centerFromEnd(stateCount, j);
  305. float centerI = crossCheckVertical(i, (size_t)centerJ, stateCount[2], stateCountTotal);
  306. if (!isnan(centerI)) {
  307. // Re-cross check
  308. centerJ = crossCheckHorizontal((size_t)centerJ, (size_t)centerI, stateCount[2], stateCountTotal);
  309. if (!isnan(centerJ)) {
  310. float estimatedModuleSize = (float)stateCountTotal / 7.0f;
  311. if(!confirmCenter45(estimatedModuleSize,centerI,centerJ)&&!confirmCenter135(estimatedModuleSize,centerI,centerJ))return false;
  312. bool found = false;
  313. size_t max = possibleCenters_.size();
  314. for (size_t index = 0; index < max; index++) {
  315. Ref<FinderPattern> center = possibleCenters_[index];
  316. // Look for about the same center and module size:
  317. if (center->aboutEquals(estimatedModuleSize, centerI, centerJ)) {
  318. possibleCenters_[index] = center->combineEstimate(centerI, centerJ, estimatedModuleSize);
  319. found = true;
  320. break;
  321. }
  322. }
  323. if (!found) {
  324. Ref<FinderPattern> newPattern(new FinderPattern(centerJ, centerI, estimatedModuleSize));
  325. possibleCenters_.push_back(newPattern);
  326. if (callback_ != 0) {
  327. callback_->foundPossibleResultPoint(*newPattern);
  328. }
  329. }
  330. return true;
  331. }
  332. }
  333. return false;
  334. }
  335. int FinderPatternFinder::findRowSkip() {
  336. size_t max = possibleCenters_.size();
  337. if (max <= 1) {
  338. return 0;
  339. }
  340. Ref<FinderPattern> firstConfirmedCenter;
  341. for (size_t i = 0; i < max; i++) {
  342. Ref<FinderPattern> center = possibleCenters_[i];
  343. if (center->getCount() >= CENTER_QUORUM) {
  344. if (firstConfirmedCenter == 0) {
  345. firstConfirmedCenter = center;
  346. } else {
  347. // We have two confirmed centers
  348. // How far down can we skip before resuming looking for the next
  349. // pattern? In the worst case, only the difference between the
  350. // difference in the x / y coordinates of the two centers.
  351. // This is the case where you find top left first. Draw it out.
  352. hasSkipped_ = true;
  353. return (int)(abs(firstConfirmedCenter->getX() - center->getX()) - abs(firstConfirmedCenter->getY()
  354. - center->getY()))/2;
  355. }
  356. }
  357. }
  358. return 0;
  359. }
  360. bool FinderPatternFinder::haveMultiplyConfirmedCenters() {
  361. int confirmedCount = 0;
  362. float totalModuleSize = 0.0f;
  363. size_t max = possibleCenters_.size();
  364. for (size_t i = 0; i < max; i++) {
  365. Ref<FinderPattern> pattern = possibleCenters_[i];
  366. if (pattern->getCount() >= CENTER_QUORUM) {
  367. confirmedCount++;
  368. totalModuleSize += pattern->getEstimatedModuleSize();
  369. }
  370. }
  371. if (confirmedCount < 3) {
  372. return false;
  373. }
  374. // OK, we have at least 3 confirmed centers, but, it's possible that one is a "false positive"
  375. // and that we need to keep looking. We detect this by asking if the estimated module sizes
  376. // vary too much. We arbitrarily say that when the total deviation from average exceeds
  377. // 5% of the total module size estimates, it's too much.
  378. float average = totalModuleSize / max;
  379. float totalDeviation = 0.0f;
  380. for (size_t i = 0; i < max; i++) {
  381. Ref<FinderPattern> pattern = possibleCenters_[i];
  382. totalDeviation += abs(pattern->getEstimatedModuleSize() - average);
  383. }
  384. return totalDeviation <= 0.05f * totalModuleSize;
  385. }
  386. vector< Ref<FinderPattern> > FinderPatternFinder::selectBestPatterns() {
  387. size_t startSize = possibleCenters_.size();
  388. if (startSize < 3) {
  389. // Couldn't find enough finder patterns
  390. throw zxing::ReaderException("Could not find three finder patterns");
  391. }
  392. // Filter outlier possibilities whose module size is too different
  393. if (startSize > 3) {
  394. // But we can only afford to do so if we have at least 4 possibilities to choose from
  395. float totalModuleSize = 0.0f;
  396. float square = 0.0f;
  397. for (size_t i = 0; i < startSize; i++) {
  398. float size = possibleCenters_[i]->getEstimatedModuleSize();
  399. totalModuleSize += size;
  400. square += size * size;
  401. }
  402. float average = totalModuleSize / (float) startSize;
  403. float stdDev = (float)sqrt(square / startSize - average * average);
  404. sort(possibleCenters_.begin(), possibleCenters_.end(), FurthestFromAverageComparator(average));
  405. float limit = max(0.2f * average, stdDev);
  406. for (size_t i = 0; i < possibleCenters_.size() && possibleCenters_.size() > 3; i++) {
  407. if (abs(possibleCenters_[i]->getEstimatedModuleSize() - average) > limit) {
  408. possibleCenters_.erase(possibleCenters_.begin()+i);
  409. i--;
  410. }
  411. }
  412. }
  413. if (possibleCenters_.size() > 3) {
  414. // Throw away all but those first size candidate points we found.
  415. float totalModuleSize = 0.0f;
  416. for (size_t i = 0; i < possibleCenters_.size(); i++) {
  417. float size = possibleCenters_[i]->getEstimatedModuleSize();
  418. totalModuleSize += size;
  419. }
  420. float average = totalModuleSize / (float) possibleCenters_.size();
  421. sort(possibleCenters_.begin(), possibleCenters_.end(), CenterComparator(average));
  422. }
  423. if (possibleCenters_.size() > 3) {
  424. possibleCenters_.erase(possibleCenters_.begin()+3,possibleCenters_.end());
  425. }
  426. vector<Ref<FinderPattern> > result(3);
  427. result[0] = possibleCenters_[0];
  428. result[1] = possibleCenters_[1];
  429. result[2] = possibleCenters_[2];
  430. return result;
  431. }
  432. vector<Ref<FinderPattern> > FinderPatternFinder::orderBestPatterns(vector<Ref<FinderPattern> > patterns) {
  433. // Find distances between pattern centers
  434. float abDistance = distance(patterns[0], patterns[1]);
  435. float bcDistance = distance(patterns[1], patterns[2]);
  436. float acDistance = distance(patterns[0], patterns[2]);
  437. Ref<FinderPattern> topLeft;
  438. Ref<FinderPattern> topRight;
  439. Ref<FinderPattern> bottomLeft;
  440. // Assume one closest to other two is top left;
  441. // topRight and bottomLeft will just be guesses below at first
  442. if (bcDistance >= abDistance && bcDistance >= acDistance) {
  443. topLeft = patterns[0];
  444. topRight = patterns[1];
  445. bottomLeft = patterns[2];
  446. } else if (acDistance >= bcDistance && acDistance >= abDistance) {
  447. topLeft = patterns[1];
  448. topRight = patterns[0];
  449. bottomLeft = patterns[2];
  450. } else {
  451. topLeft = patterns[2];
  452. topRight = patterns[0];
  453. bottomLeft = patterns[1];
  454. }
  455. // Use cross product to figure out which of other1/2 is the bottom left
  456. // pattern. The vector "top-left -> bottom-left" x "top-left -> top-right"
  457. // should yield a vector with positive z component
  458. if ((bottomLeft->getY() - topLeft->getY()) * (topRight->getX() - topLeft->getX()) < (bottomLeft->getX()
  459. - topLeft->getX()) * (topRight->getY() - topLeft->getY())) {
  460. Ref<FinderPattern> temp = topRight;
  461. topRight = bottomLeft;
  462. bottomLeft = temp;
  463. }
  464. vector<Ref<FinderPattern> > results(3);
  465. results[0] = bottomLeft;
  466. results[1] = topLeft;
  467. results[2] = topRight;
  468. return results;
  469. }
  470. float FinderPatternFinder::distance(Ref<ResultPoint> p1, Ref<ResultPoint> p2) {
  471. float dx = p1->getX() - p2->getX();
  472. float dy = p1->getY() - p2->getY();
  473. return (float)sqrt(dx * dx + dy * dy);
  474. }
  475. FinderPatternFinder::FinderPatternFinder(Ref<BitMatrix> image,
  476. Ref<ResultPointCallback>const& callback) :
  477. image_(image), possibleCenters_(), hasSkipped_(false), callback_(callback) {
  478. }
  479. Ref<FinderPatternInfo> FinderPatternFinder::find(DecodeHints const& hints) {
  480. bool tryHarder = hints.getTryHarder();
  481. size_t maxI = image_->getHeight();
  482. size_t maxJ = image_->getWidth();
  483. // We are looking for black/white/black/white/black modules in
  484. // 1:1:3:1:1 ratio; this tracks the number of such modules seen so far
  485. // As this is used often, we use an integer array instead of vector
  486. int stateCount[5];
  487. bool done = false;
  488. // Let's assume that the maximum version QR Code we support takes up 1/4
  489. // the height of the image, and then account for the center being 3
  490. // modules in size. This gives the smallest number of pixels the center
  491. // could be, so skip this often. When trying harder, look for all
  492. // QR versions regardless of how dense they are.
  493. int iSkip = (3 * maxI) / (4 * MAX_MODULES);
  494. if (iSkip < MIN_SKIP || tryHarder) {
  495. iSkip = MIN_SKIP;
  496. }
  497. // This is slightly faster than using the Ref. Efficiency is important here
  498. BitMatrix& matrix = *image_;
  499. for (size_t i = iSkip - 1; i < maxI && !done; i += iSkip) {
  500. // Get a row of black/white values
  501. stateCount[0] = 0;
  502. stateCount[1] = 0;
  503. stateCount[2] = 0;
  504. stateCount[3] = 0;
  505. stateCount[4] = 0;
  506. int currentState = 0;
  507. for (size_t j = 0; j < maxJ; j++) {
  508. if (matrix.get(j, i)) {
  509. // Black pixel
  510. if ((currentState & 1) == 1) { // Counting white pixels
  511. currentState++;
  512. }
  513. stateCount[currentState]++;
  514. } else { // White pixel
  515. if ((currentState & 1) == 0) { // Counting black pixels
  516. if (currentState == 4) { // A winner?
  517. if (foundPatternCross(stateCount)) { // Yes
  518. bool confirmed = handlePossibleCenter(stateCount, i, j);
  519. if (confirmed) {
  520. // Start examining every other line. Checking each line turned out to be too
  521. // expensive and didn't improve performance.
  522. iSkip = 2;
  523. if (hasSkipped_) {
  524. done = haveMultiplyConfirmedCenters();
  525. } else {
  526. int rowSkip = findRowSkip();
  527. if (rowSkip > stateCount[2]) {
  528. // Skip rows between row of lower confirmed center
  529. // and top of presumed third confirmed center
  530. // but back up a bit to get a full chance of detecting
  531. // it, entire width of center of finder pattern
  532. // Skip by rowSkip, but back off by stateCount[2] (size
  533. // of last center of pattern we saw) to be conservative,
  534. // and also back off by iSkip which is about to be
  535. // re-added
  536. i += rowSkip - stateCount[2] - iSkip;
  537. j = maxJ - 1;
  538. }
  539. }
  540. } else {
  541. stateCount[0] = stateCount[2];
  542. stateCount[1] = stateCount[3];
  543. stateCount[2] = stateCount[4];
  544. stateCount[3] = 1;
  545. stateCount[4] = 0;
  546. currentState = 3;
  547. continue;
  548. }
  549. // Clear state to start looking again
  550. currentState = 0;
  551. stateCount[0] = 0;
  552. stateCount[1] = 0;
  553. stateCount[2] = 0;
  554. stateCount[3] = 0;
  555. stateCount[4] = 0;
  556. } else { // No, shift counts back by two
  557. stateCount[0] = stateCount[2];
  558. stateCount[1] = stateCount[3];
  559. stateCount[2] = stateCount[4];
  560. stateCount[3] = 1;
  561. stateCount[4] = 0;
  562. currentState = 3;
  563. }
  564. } else {
  565. stateCount[++currentState]++;
  566. }
  567. } else { // Counting white pixels
  568. stateCount[currentState]++;
  569. }
  570. }
  571. }
  572. if (foundPatternCross(stateCount)) {
  573. bool confirmed = handlePossibleCenter(stateCount, i, maxJ);
  574. if (confirmed) {
  575. iSkip = stateCount[0];
  576. if (hasSkipped_) {
  577. // Found a third one
  578. done = haveMultiplyConfirmedCenters();
  579. }
  580. }
  581. }
  582. }
  583. vector<Ref<FinderPattern> > patternInfo = selectBestPatterns();
  584. patternInfo = orderBestPatterns(patternInfo);
  585. Ref<FinderPatternInfo> result(new FinderPatternInfo(patternInfo));
  586. return result;
  587. }
  588. Ref<BitMatrix> FinderPatternFinder::getImage() {
  589. return image_;
  590. }
  591. vector<Ref<FinderPattern> >& FinderPatternFinder::getPossibleCenters() {
  592. return possibleCenters_;
  593. }