Files
opencv_contrib/modules/wechat_qrcode/src/zxing/common/unicomblock.cpp
2022-05-06 02:00:27 +08:00

128 lines
4.2 KiB
C++

// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
#include "../../precomp.hpp"
#include "unicomblock.hpp"
namespace zxing {
short UnicomBlock::SEARCH_POS[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
UnicomBlock::UnicomBlock(int iMaxHeight, int iMaxWidth)
: m_iHeight(iMaxHeight), m_iWidth(iMaxWidth), m_bInit(false) {}
UnicomBlock::~UnicomBlock() {}
void UnicomBlock::Init() {
if (m_bInit) return;
m_vcIndex = std::vector<unsigned short>(m_iHeight * m_iWidth, 0);
m_vcCount = std::vector<unsigned short>(m_iHeight * m_iWidth, 0);
m_vcMinPnt = std::vector<int>(m_iHeight * m_iWidth, 0);
m_vcMaxPnt = std::vector<int>(m_iHeight * m_iWidth, 0);
m_vcQueue = std::vector<int>(m_iHeight * m_iWidth, 0);
m_bInit = true;
}
void UnicomBlock::Reset(Ref<BitMatrix> poImage) {
m_poImage = poImage;
memset(&m_vcIndex[0], 0, m_vcIndex.size() * sizeof(short));
m_iNowIdx = 0;
}
unsigned short UnicomBlock::GetUnicomBlockIndex(int y, int x) {
if (y >= m_iHeight || x >= m_iWidth) return 0;
if (m_vcIndex[y * m_iWidth + x]) return m_vcIndex[y * m_iWidth + x];
Bfs(y, x);
return m_vcIndex[y * m_iWidth + x];
}
int UnicomBlock::GetUnicomBlockSize(int y, int x) {
if (y >= m_iHeight || x >= m_iWidth) return 0;
if (m_vcIndex[y * m_iWidth + x]) return m_vcCount[y * m_iWidth + x];
Bfs(y, x);
return m_vcCount[y * m_iWidth + x];
}
int UnicomBlock::GetMinPoint(int y, int x, int &iMinY, int &iMinX) {
if (y >= m_iHeight || x >= m_iWidth) return -1;
if (m_vcIndex[y * m_iWidth + x]) {
iMinY = m_vcMinPnt[y * m_iWidth + x] >> 16;
iMinX = m_vcMinPnt[y * m_iWidth + x] & (0xFFFF);
return 0;
}
Bfs(y, x);
iMinY = m_vcMinPnt[y * m_iWidth + x] >> 16;
iMinX = m_vcMinPnt[y * m_iWidth + x] & (0xFFFF);
return 0;
}
int UnicomBlock::GetMaxPoint(int y, int x, int &iMaxY, int &iMaxX) {
if (y >= m_iHeight || x >= m_iWidth) return -1;
if (m_vcIndex[y * m_iWidth + x]) {
iMaxY = m_vcMaxPnt[y * m_iWidth + x] >> 16;
iMaxX = m_vcMaxPnt[y * m_iWidth + x] & (0xFFFF);
return 0;
}
Bfs(y, x);
iMaxY = m_vcMaxPnt[y * m_iWidth + x] >> 16;
iMaxX = m_vcMaxPnt[y * m_iWidth + x] & (0xFFFF);
return 0;
}
void UnicomBlock::Bfs(int y, int x) {
m_iNowIdx++;
int iFront = 0;
int iTail = 0;
int iCount = 1;
int iMaxX = x, iMaxY = y;
int iMinX = x, iMinY = y;
const bool bValue = (m_poImage->get(x, y) != (unsigned char)0);
m_vcIndex[y * m_iWidth + x] = m_iNowIdx;
m_vcQueue[iTail++] = y << 16 | x;
while (iFront < iTail) {
int iNode = m_vcQueue[iFront++];
int iX = iNode & (0xFFFF);
int iY = iNode >> 16;
iMaxX = max(iX, iMaxX);
iMaxY = max(iY, iMaxY);
iMinX = min(iX, iMinX);
iMinY = min(iY, iMinY);
iCount++;
for (int i = 0; i < 4; ++i) {
const int iNextX = iX + SEARCH_POS[i][0], iNextY = iY + SEARCH_POS[i][1];
const int iPosition = iNextY * m_iWidth + iNextX;
if (iPosition >= 0 && iPosition < int(m_vcIndex.size()) && 0 == m_vcIndex[iPosition]) {
if (iNextX < 0 || iNextX >= m_poImage->getWidth() || iNextY < 0 ||
iNextY >= m_poImage->getHeight() ||
bValue != (m_poImage->get(iNextX, iNextY) != (unsigned char)0))
continue;
m_vcIndex[iPosition] = m_iNowIdx;
m_vcQueue[iTail++] = iNextY << 16 | iNextX;
}
}
}
if (iCount >= (1 << 16) - 1) iCount = 0xFFFF;
const int iMinCombine = iMinY << 16 | iMinX;
const int iMaxCombine = iMaxY << 16 | iMaxX;
for (int i = 0; i < iTail; ++i) {
const int iPosition = (m_vcQueue[i] >> 16) * m_iWidth + (m_vcQueue[i] & (0xFFFF));
m_vcCount[iPosition] = iCount;
m_vcMinPnt[iPosition] = iMinCombine;
m_vcMaxPnt[iPosition] = iMaxCombine;
}
}
} // namespace zxing