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