#include "ImageApplyBarCodeRecognition.h" #ifndef _NOT_USE #include #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 getRow(int y, zxing::ArrayRef row) const { int width = getWidth(); if (row->size() != width) row.reset(zxing::ArrayRef(width)); for (int x = 0; x < width; ++x) row[x] = m_image.at(y, x); return row; } zxing::ArrayRef 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 tmpRow; tmpRow = getRow(y, zxing::ArrayRef(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 arr = zxing::ArrayRef(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(-1) != len) { std::unique_ptr buff(new char[len + 1]); len = std::wcsrtombs(buff.get(), &data, len, &state); if (static_cast(-1) != len) str.assign(buff.get(), len); } return str; } int CImageApplyBarCodeRecognition::recognize_ZXing(const cv::Mat& image, BarCodeInfo& result) { zxing::Ref res; auto ciw = new ImageWrapper(image); zxing::Ref 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(static_cast( 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(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>& contours, std::vector& 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 all_contours(cvTreeToNodeSeq(_ccontours, sizeof(CvSeq), storage)); size_t total = all_contours.size(); contours.resize(total); cv::SeqIterator it = all_contours.begin(); for (size_t i = 0; i < total; i++, ++it) { CvSeq* c = *it; reinterpret_cast(c)->color = static_cast(i); int count = c->total; int* data = new int[static_cast(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(c->h_next)->color : -1; int h_prev = c->h_prev ? reinterpret_cast(c->h_prev)->color : -1; int v_next = c->v_next ? reinterpret_cast(c->v_next)->color : -1; int v_prev = c->v_prev ? reinterpret_cast(c->v_prev)->color : -1; hierarchy[i] = cv::Vec4i(h_next, h_prev, v_next, v_prev); } storage.release(); } #endif //_NOT_USE