mirror of http://192.168.1.51:8099/lmh188/twain3
355 lines
12 KiB
C++
355 lines
12 KiB
C++
|
#include "ImageApplyBarCodeRecognition.h"
|
||
|
#ifndef _NOT_USE
|
||
|
#include <memory.h>
|
||
|
#include "zxing/BinaryBitmap.h"
|
||
|
#include "zxing/DecodeHints.h"
|
||
|
#include "zxing/common/GlobalHistogramBinarizer.h"
|
||
|
#include "zxing/LuminanceSource.h"
|
||
|
#include "zxing/MultiFormatReader.h"
|
||
|
#include "zxing/Result.h"
|
||
|
#include "zxing/multi/GenericMultipleBarcodeReader.h"
|
||
|
#include "zbar.h"
|
||
|
|
||
|
class ImageWrapper : public zxing::LuminanceSource
|
||
|
{
|
||
|
public:
|
||
|
ImageWrapper(const cv::Mat& sourceImage)
|
||
|
: LuminanceSource(sourceImage.cols, sourceImage.rows)
|
||
|
, m_image(sourceImage) {}
|
||
|
|
||
|
virtual ~ImageWrapper() = default;
|
||
|
|
||
|
// Callers take ownership of the returned memory and must call delete [] on it themselves.
|
||
|
zxing::ArrayRef<char> getRow(int y, zxing::ArrayRef<char> row) const
|
||
|
{
|
||
|
int width = getWidth();
|
||
|
|
||
|
if (row->size() != width)
|
||
|
row.reset(zxing::ArrayRef<char>(width));
|
||
|
|
||
|
for (int x = 0; x < width; ++x)
|
||
|
row[x] = m_image.at<char>(y, x);
|
||
|
|
||
|
return row;
|
||
|
}
|
||
|
|
||
|
zxing::ArrayRef<char> getMatrix() const
|
||
|
{
|
||
|
int width = m_image.cols;
|
||
|
int height = m_image.rows;
|
||
|
char* matrix = new char[width * height];
|
||
|
char* m = matrix;
|
||
|
|
||
|
for (int y = 0; y < height; ++y)
|
||
|
{
|
||
|
zxing::ArrayRef<char> tmpRow;
|
||
|
tmpRow = getRow(y, zxing::ArrayRef<char>(width));
|
||
|
#if __cplusplus > 199711L
|
||
|
memcpy(m, tmpRow->values().data(), width);
|
||
|
#else
|
||
|
memcpy(m, &tmpRow->values()[0], width);
|
||
|
#endif
|
||
|
m += width * sizeof(unsigned char);
|
||
|
|
||
|
//delete tmpRow;
|
||
|
}
|
||
|
|
||
|
zxing::ArrayRef<char> arr = zxing::ArrayRef<char>(matrix, width * height);
|
||
|
|
||
|
if (matrix) delete[] matrix;
|
||
|
|
||
|
return arr;
|
||
|
}
|
||
|
private:
|
||
|
cv::Mat m_image;
|
||
|
};
|
||
|
|
||
|
static std::string WstringToString(const std::wstring& wstr)
|
||
|
{
|
||
|
std::string str;
|
||
|
std::mbstate_t state = {};
|
||
|
const wchar_t* data = wstr.data();
|
||
|
size_t len = std::wcsrtombs(nullptr, &data, 0, &state);
|
||
|
if (static_cast<size_t>(-1) != len)
|
||
|
{
|
||
|
std::unique_ptr<char[]> buff(new char[len + 1]);
|
||
|
len = std::wcsrtombs(buff.get(), &data, len, &state);
|
||
|
|
||
|
if (static_cast<size_t>(-1) != len)
|
||
|
str.assign(buff.get(), len);
|
||
|
}
|
||
|
return str;
|
||
|
}
|
||
|
|
||
|
int CImageApplyBarCodeRecognition::recognize_ZXing(const cv::Mat& image, BarCodeInfo& result)
|
||
|
{
|
||
|
zxing::Ref<zxing::Result> res;
|
||
|
auto ciw = new ImageWrapper(image);
|
||
|
zxing::Ref<zxing::LuminanceSource> imageRef(ciw);
|
||
|
zxing::GlobalHistogramBinarizer* binz = new zxing::GlobalHistogramBinarizer(imageRef);
|
||
|
|
||
|
zxing::Ref< zxing::Binarizer > bz(binz);
|
||
|
zxing::BinaryBitmap* bb = new zxing::BinaryBitmap(bz);
|
||
|
|
||
|
zxing::Ref< zxing::BinaryBitmap > ref(bb);
|
||
|
zxing::MultiFormatReader decoder_;
|
||
|
try
|
||
|
{
|
||
|
res = decoder_.decode(ref, static_cast<zxing::DecodeHints>(static_cast<unsigned int>(
|
||
|
zxing::DecodeHints::QR_CODE_HINT |
|
||
|
zxing::DecodeHints::AZTEC_HINT |
|
||
|
zxing::DecodeHints::CODABAR_HINT |
|
||
|
zxing::DecodeHints::CODE_39_HINT |
|
||
|
zxing::DecodeHints::CODE_93_HINT |
|
||
|
zxing::DecodeHints::CODE_128_HINT |
|
||
|
zxing::DecodeHints::DATA_MATRIX_HINT |
|
||
|
zxing::DecodeHints::EAN_8_HINT |
|
||
|
zxing::DecodeHints::EAN_13_HINT |
|
||
|
zxing::DecodeHints::ITF_HINT |
|
||
|
zxing::DecodeHints::MAXICODE_HINT |
|
||
|
zxing::DecodeHints::PDF_417_HINT |
|
||
|
zxing::DecodeHints::QR_CODE_HINT |
|
||
|
zxing::DecodeHints::RSS_14_HINT |
|
||
|
zxing::DecodeHints::RSS_EXPANDED_HINT |
|
||
|
zxing::DecodeHints::UPC_A_HINT |
|
||
|
zxing::DecodeHints::UPC_E_HINT |
|
||
|
zxing::DecodeHints::UPC_EAN_EXTENSION_HINT)));
|
||
|
result.barCodeText = res->getText()->getText();
|
||
|
result.barCodeLength = result.barCodeText.length();
|
||
|
if (!result.barCodeText.empty())
|
||
|
{
|
||
|
result.barCodeType = -1;
|
||
|
switch (res->getBarcodeFormat())
|
||
|
{
|
||
|
case zxing::BarcodeFormat::NONE:
|
||
|
result.barCodeType = -1;
|
||
|
break;
|
||
|
case zxing::BarcodeFormat::AZTEC:
|
||
|
break;
|
||
|
case zxing::BarcodeFormat::CODABAR:
|
||
|
result.barCodeType = BarCodeType::CodaBar;
|
||
|
break;
|
||
|
case zxing::BarcodeFormat::CODE_39:
|
||
|
break;
|
||
|
case zxing::BarcodeFormat::CODE_93:
|
||
|
result.barCodeType = BarCodeType::Code93;
|
||
|
break;
|
||
|
case zxing::BarcodeFormat::CODE_128:
|
||
|
result.barCodeType = BarCodeType::Code128;
|
||
|
break;
|
||
|
case zxing::BarcodeFormat::DATA_MATRIX:
|
||
|
break;
|
||
|
case zxing::BarcodeFormat::EAN_8:
|
||
|
result.barCodeType = BarCodeType::Ean8;
|
||
|
break;
|
||
|
case zxing::BarcodeFormat::EAN_13:
|
||
|
result.barCodeType = BarCodeType::Ean13;
|
||
|
break;
|
||
|
case zxing::BarcodeFormat::ITF:
|
||
|
break;
|
||
|
case zxing::BarcodeFormat::MAXICODE:
|
||
|
result.barCodeType = BarCodeType::MaxiCode;
|
||
|
break;
|
||
|
case zxing::BarcodeFormat::PDF_417:
|
||
|
result.barCodeType = BarCodeType::Pdf417;
|
||
|
break;
|
||
|
case zxing::BarcodeFormat::QR_CODE:
|
||
|
result.barCodeType = BarCodeType::QrCode;
|
||
|
break;
|
||
|
case zxing::BarcodeFormat::RSS_14:
|
||
|
break;
|
||
|
case zxing::BarcodeFormat::RSS_EXPANDED:
|
||
|
break;
|
||
|
case zxing::BarcodeFormat::UPC_A:
|
||
|
break;
|
||
|
case zxing::BarcodeFormat::UPC_EAN_EXTENSION:
|
||
|
break;
|
||
|
default:
|
||
|
result.barCodeType = -1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
catch (zxing::Exception& e)
|
||
|
{
|
||
|
std::cout << e.what() << std::endl;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int CImageApplyBarCodeRecognition::recognize_Zbar(const cv::Mat& image, BarCodeInfo& result)
|
||
|
{
|
||
|
zbar::ImageScanner scanner;
|
||
|
zbar::Image img(image.cols, image.rows, "Y800", reinterpret_cast<void*>(image.data), image.total());
|
||
|
|
||
|
scanner.scan(img);
|
||
|
for (zbar::Image::SymbolIterator symbol = img.symbol_begin(); symbol != img.symbol_end(); ++symbol)
|
||
|
{
|
||
|
result.barCodeText = symbol->get_data();
|
||
|
result.barCodeLength = result.barCodeText.length();
|
||
|
if (!result.barCodeText.empty())
|
||
|
{
|
||
|
result.barCodeType = -1;
|
||
|
switch (symbol->get_type())
|
||
|
{
|
||
|
case zbar::zbar_symbol_type_t::ZBAR_NONE:
|
||
|
result.barCodeType = -1;
|
||
|
break;
|
||
|
case zbar::zbar_symbol_type_t::ZBAR_PARTIAL:
|
||
|
break;
|
||
|
case zbar::zbar_symbol_type_t::ZBAR_EAN8:
|
||
|
result.barCodeType = BarCodeType::Ean8;
|
||
|
break;
|
||
|
case zbar::zbar_symbol_type_t::ZBAR_UPCE:
|
||
|
break;
|
||
|
case zbar::zbar_symbol_type_t::ZBAR_ISBN10:
|
||
|
break;
|
||
|
case zbar::zbar_symbol_type_t::ZBAR_UPCA:
|
||
|
break;
|
||
|
case zbar::zbar_symbol_type_t::ZBAR_EAN13:
|
||
|
result.barCodeType = BarCodeType::Ean13;
|
||
|
break;
|
||
|
case zbar::zbar_symbol_type_t::ZBAR_ISBN13:
|
||
|
break;
|
||
|
case zbar::zbar_symbol_type_t::ZBAR_I25:
|
||
|
break;
|
||
|
case zbar::zbar_symbol_type_t::ZBAR_CODE39:
|
||
|
break;
|
||
|
case zbar::zbar_symbol_type_t::ZBAR_PDF417:
|
||
|
result.barCodeType = BarCodeType::Pdf417;
|
||
|
break;
|
||
|
case zbar::zbar_symbol_type_t::ZBAR_QRCODE:
|
||
|
result.barCodeType = BarCodeType::QrCode;
|
||
|
break;
|
||
|
case zbar::zbar_symbol_type_t::ZBAR_CODE128:
|
||
|
result.barCodeType = BarCodeType::Code128;
|
||
|
break;
|
||
|
case zbar::zbar_symbol_type_t::ZBAR_SYMBOL:
|
||
|
break;
|
||
|
case zbar::zbar_symbol_type_t::ZBAR_ADDON2:
|
||
|
break;
|
||
|
case zbar::zbar_symbol_type_t::ZBAR_ADDON5:
|
||
|
break;
|
||
|
case zbar::zbar_symbol_type_t::ZBAR_ADDON:
|
||
|
break;
|
||
|
default:
|
||
|
result.barCodeType = -1;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void CImageApplyBarCodeRecognition::decode(cv::Mat& image, CImageApplyBarCodeRecognition::BarCodeInfo& result)
|
||
|
{
|
||
|
if (image.empty()) return;
|
||
|
|
||
|
cv::Mat temp;
|
||
|
if (image.channels() == 3)
|
||
|
{
|
||
|
cv::cvtColor(image, temp, cv::COLOR_BGR2GRAY);
|
||
|
cv::threshold(temp, temp, 127, 255, cv::THRESH_OTSU);
|
||
|
}
|
||
|
else
|
||
|
cv::threshold(image, temp, 127, 255, cv::THRESH_OTSU);
|
||
|
|
||
|
//cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(m_direction == Direction::Horizontal ? 1 : 5, m_direction == Direction::Horizontal ? 5 : 1));
|
||
|
//cv::morphologyEx(temp, temp, cv::MORPH_ERODE, element);
|
||
|
|
||
|
recognize_Zbar(temp, result);
|
||
|
if (result.barCodeText.empty())
|
||
|
recognize_ZXing(temp, result);
|
||
|
}
|
||
|
|
||
|
CImageApplyBarCodeRecognition::CImageApplyBarCodeRecognition()
|
||
|
: m_mode(RecognizeMode::Single)
|
||
|
, m_direction(Direction::Horizontal)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
CImageApplyBarCodeRecognition::CImageApplyBarCodeRecognition(RecognizeMode mode, Direction dir)
|
||
|
: m_mode(mode)
|
||
|
, m_direction(dir)
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
CImageApplyBarCodeRecognition::~CImageApplyBarCodeRecognition()
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
void CImageApplyBarCodeRecognition::apply(cv::Mat& pDib, int side)
|
||
|
{
|
||
|
(void)side;
|
||
|
m_result = BarCodeInfo();
|
||
|
|
||
|
cv::Mat temp = pDib.clone();
|
||
|
decode(temp, m_result);
|
||
|
if (!m_result.barCodeText.empty()) return;
|
||
|
|
||
|
cv::transpose(pDib, temp);
|
||
|
cv::flip(temp, temp, 0);
|
||
|
decode(temp, m_result);
|
||
|
if (!m_result.barCodeText.empty()) return;
|
||
|
|
||
|
cv::flip(pDib, temp, 0);
|
||
|
cv::flip(temp, temp, 1);
|
||
|
decode(temp, m_result);
|
||
|
if (!m_result.barCodeText.empty()) return;
|
||
|
|
||
|
cv::transpose(pDib, temp);
|
||
|
cv::flip(temp, temp, 1);
|
||
|
decode(temp, m_result);
|
||
|
}
|
||
|
|
||
|
void findContours1(const cv::Mat& src, std::vector<std::vector<cv::Point>>& contours, std::vector<cv::Vec4i>& hierarchy, int retr, int method, cv::Point offset)
|
||
|
{
|
||
|
CvMat c_image = cvMat(src);
|
||
|
cv::MemStorage storage(cvCreateMemStorage());
|
||
|
CvSeq* _ccontours = nullptr;
|
||
|
cvFindContours(&c_image, storage, &_ccontours, sizeof(CvContour), retr, method, cvPoint(offset));
|
||
|
|
||
|
if (!_ccontours)
|
||
|
{
|
||
|
contours.clear();
|
||
|
return;
|
||
|
}
|
||
|
cv::Seq<CvSeq*> all_contours(cvTreeToNodeSeq(_ccontours, sizeof(CvSeq), storage));
|
||
|
size_t total = all_contours.size();
|
||
|
contours.resize(total);
|
||
|
|
||
|
cv::SeqIterator<CvSeq*> it = all_contours.begin();
|
||
|
for (size_t i = 0; i < total; i++, ++it)
|
||
|
{
|
||
|
CvSeq* c = *it;
|
||
|
reinterpret_cast<CvContour*>(c)->color = static_cast<int>(i);
|
||
|
int count = c->total;
|
||
|
int* data = new int[static_cast<size_t>(count * 2)];
|
||
|
cvCvtSeqToArray(c, data);
|
||
|
for (int j = 0; j < count; j++)
|
||
|
{
|
||
|
contours[i].push_back(cv::Point(data[j * 2], data[j * 2 + 1]));
|
||
|
}
|
||
|
delete[] data;
|
||
|
}
|
||
|
|
||
|
hierarchy.resize(total);
|
||
|
it = all_contours.begin();
|
||
|
for (size_t i = 0; i < total; i++, ++it)
|
||
|
{
|
||
|
CvSeq* c = *it;
|
||
|
int h_next = c->h_next ? reinterpret_cast<CvContour*>(c->h_next)->color : -1;
|
||
|
int h_prev = c->h_prev ? reinterpret_cast<CvContour*>(c->h_prev)->color : -1;
|
||
|
int v_next = c->v_next ? reinterpret_cast<CvContour*>(c->v_next)->color : -1;
|
||
|
int v_prev = c->v_prev ? reinterpret_cast<CvContour*>(c->v_prev)->color : -1;
|
||
|
hierarchy[i] = cv::Vec4i(h_next, h_prev, v_next, v_prev);
|
||
|
}
|
||
|
|
||
|
storage.release();
|
||
|
}
|
||
|
|
||
|
#endif //_NOT_USE
|