1 // This file is part of OpenCV project.
2 // It is subject to the license terms in the LICENSE file found in the top-level directory
3 // of this distribution and at http://opencv.org/license.html.
4 //
5 // Tencent is pleased to support the open source community by making WeChat QRCode available.
6 // Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
7 #include "../../precomp.hpp"
8 #include "unicomblock.hpp"
9
10 namespace zxing {
11 short UnicomBlock::SEARCH_POS[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
UnicomBlock(int iMaxHeight,int iMaxWidth)12 UnicomBlock::UnicomBlock(int iMaxHeight, int iMaxWidth)
13 : m_iHeight(iMaxHeight), m_iWidth(iMaxWidth), m_bInit(false) {}
14
~UnicomBlock()15 UnicomBlock::~UnicomBlock() {}
16
Init()17 void UnicomBlock::Init() {
18 if (m_bInit) return;
19 m_vcIndex = std::vector<unsigned int>(m_iHeight * m_iWidth, 0);
20 m_vcCount = std::vector<unsigned int>(m_iHeight * m_iWidth, 0);
21 m_vcMinPnt = std::vector<int>(m_iHeight * m_iWidth, 0);
22 m_vcMaxPnt = std::vector<int>(m_iHeight * m_iWidth, 0);
23 m_vcQueue = std::vector<int>(m_iHeight * m_iWidth, 0);
24 m_bInit = true;
25 }
26
Reset(Ref<BitMatrix> poImage)27 void UnicomBlock::Reset(Ref<BitMatrix> poImage) {
28 m_poImage = poImage;
29 memset(&m_vcIndex[0], 0, m_vcIndex.size() * sizeof(short));
30 m_iNowIdx = 0;
31 }
32
GetUnicomBlockIndex(int y,int x)33 unsigned short UnicomBlock::GetUnicomBlockIndex(int y, int x) {
34 if (y >= m_iHeight || x >= m_iWidth) return 0;
35 if (m_vcIndex[y * m_iWidth + x]) return m_vcIndex[y * m_iWidth + x];
36 Bfs(y, x);
37 return m_vcIndex[y * m_iWidth + x];
38 }
39
GetUnicomBlockSize(int y,int x)40 int UnicomBlock::GetUnicomBlockSize(int y, int x) {
41 if (y >= m_iHeight || x >= m_iWidth) return 0;
42 if (m_vcIndex[y * m_iWidth + x]) return m_vcCount[y * m_iWidth + x];
43 Bfs(y, x);
44 return m_vcCount[y * m_iWidth + x];
45 }
46
GetMinPoint(int y,int x,int & iMinY,int & iMinX)47 int UnicomBlock::GetMinPoint(int y, int x, int &iMinY, int &iMinX) {
48 if (y >= m_iHeight || x >= m_iWidth) return -1;
49 if (m_vcIndex[y * m_iWidth + x]) {
50 iMinY = m_vcMinPnt[y * m_iWidth + x] >> 16;
51 iMinX = m_vcMinPnt[y * m_iWidth + x] & (0xFFFF);
52 return 0;
53 }
54 Bfs(y, x);
55 iMinY = m_vcMinPnt[y * m_iWidth + x] >> 16;
56 iMinX = m_vcMinPnt[y * m_iWidth + x] & (0xFFFF);
57 return 0;
58 }
59
GetMaxPoint(int y,int x,int & iMaxY,int & iMaxX)60 int UnicomBlock::GetMaxPoint(int y, int x, int &iMaxY, int &iMaxX) {
61 if (y >= m_iHeight || x >= m_iWidth) return -1;
62 if (m_vcIndex[y * m_iWidth + x]) {
63 iMaxY = m_vcMaxPnt[y * m_iWidth + x] >> 16;
64 iMaxX = m_vcMaxPnt[y * m_iWidth + x] & (0xFFFF);
65 return 0;
66 }
67 Bfs(y, x);
68 iMaxY = m_vcMaxPnt[y * m_iWidth + x] >> 16;
69 iMaxX = m_vcMaxPnt[y * m_iWidth + x] & (0xFFFF);
70 return 0;
71 }
72
Bfs(int y,int x)73 void UnicomBlock::Bfs(int y, int x) {
74 m_iNowIdx++;
75
76 int iFront = 0;
77 int iTail = 0;
78 int iCount = 1;
79
80 int iMaxX = x, iMaxY = y;
81 int iMinX = x, iMinY = y;
82
83 const bool bValue = (m_poImage->get(x, y) != (unsigned char)0);
84
85 m_vcIndex[y * m_iWidth + x] = m_iNowIdx;
86 m_vcQueue[iTail++] = y << 16 | x;
87
88 while (iFront < iTail) {
89 int iNode = m_vcQueue[iFront++];
90 int iX = iNode & (0xFFFF);
91 int iY = iNode >> 16;
92 iMaxX = max(iX, iMaxX);
93 iMaxY = max(iY, iMaxY);
94 iMinX = min(iX, iMinX);
95 iMinY = min(iY, iMinY);
96
97 iCount++;
98
99 for (int i = 0; i < 4; ++i) {
100 const int iNextX = iX + SEARCH_POS[i][0], iNextY = iY + SEARCH_POS[i][1];
101 const int iPosition = iNextY * m_iWidth + iNextX;
102
103 if (iPosition >= 0 && iPosition < int(m_vcIndex.size()) && 0 == m_vcIndex[iPosition]) {
104 if (iNextX < 0 || iNextX >= m_poImage->getWidth() || iNextY < 0 ||
105 iNextY >= m_poImage->getHeight() ||
106 bValue != (m_poImage->get(iNextX, iNextY) != (unsigned char)0))
107 continue;
108
109 m_vcIndex[iPosition] = m_iNowIdx;
110 m_vcQueue[iTail++] = iNextY << 16 | iNextX;
111 }
112 }
113 }
114
115 if (iCount >= (1 << 16) - 1) iCount = 0xFFFF;
116
117 const int iMinCombine = iMinY << 16 | iMinX;
118 const int iMaxCombine = iMaxY << 16 | iMaxX;
119 for (int i = 0; i < iTail; ++i) {
120 const int iPosition = (m_vcQueue[i] >> 16) * m_iWidth + (m_vcQueue[i] & (0xFFFF));
121
122 m_vcCount[iPosition] = iCount;
123 m_vcMinPnt[iPosition] = iMinCombine;
124 m_vcMaxPnt[iPosition] = iMaxCombine;
125 }
126 }
127 } // namespace zxing
128