From 954aabf92059bde43253a47937e2d876a5e6b426 Mon Sep 17 00:00:00 2001 From: Tae-Young Chung Date: Mon, 19 Apr 2021 17:21:56 +0900 Subject: Add rotation functionality and CLAHE preprocessing in Barcode module Change-Id: I806ad1e20a2b3a436b14b26d41218dbfa3c7fe32 Signed-off-by: Tae-Young Chung (cherry picked from commit a9bcad59c6c72b617a836e0e4687f0a9ef52a7e6) --- mv_barcode/barcode_detector/CMakeLists.txt | 10 +- mv_barcode/barcode_detector/include/BarcodeUtils.h | 13 ++ mv_barcode/barcode_detector/src/BarcodeUtils.cpp | 100 ++++++++++ .../src/mv_barcode_detect_open.cpp | 218 +++++++++++++++------ 4 files changed, 275 insertions(+), 66 deletions(-) (limited to 'mv_barcode') diff --git a/mv_barcode/barcode_detector/CMakeLists.txt b/mv_barcode/barcode_detector/CMakeLists.txt index 8ff46123..123d3fbe 100644 --- a/mv_barcode/barcode_detector/CMakeLists.txt +++ b/mv_barcode/barcode_detector/CMakeLists.txt @@ -15,12 +15,20 @@ file(GLOB MV_BARCODE_DET_INC_LIST "${PROJECT_SOURCE_DIR}/include/*.h") file(GLOB MV_BARCODE_DET_SRC_LIST "${PROJECT_SOURCE_DIR}/src/*.cpp" "${PROJECT_SOURCE_DIR}/src/*.c") +find_package(OpenCV REQUIRED core imgproc) +if(NOT OpenCV_FOUND) + message(SEND_ERROR "Failed to find OpenCV") + return() +else() + include_directories(${OpenCV_INCLUDE_DIRS}) +endif() + if(FORCED_STATIC_BUILD) add_library(${PROJECT_NAME} STATIC ${MV_BARCODE_DET_INC_LIST} ${MV_BARCODE_DET_SRC_LIST}) else() add_library(${PROJECT_NAME} SHARED ${MV_BARCODE_DET_INC_LIST} ${MV_BARCODE_DET_SRC_LIST}) endif() -target_link_libraries(${PROJECT_NAME} ${MV_COMMON_LIB_NAME} zbar dlog) +target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBS} ${MV_COMMON_LIB_NAME} zbar dlog) INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR}) diff --git a/mv_barcode/barcode_detector/include/BarcodeUtils.h b/mv_barcode/barcode_detector/include/BarcodeUtils.h index 58f30c61..4b06ae53 100644 --- a/mv_barcode/barcode_detector/include/BarcodeUtils.h +++ b/mv_barcode/barcode_detector/include/BarcodeUtils.h @@ -18,6 +18,8 @@ #define __MEDIA_VISION_BARCODE_UTILS_H__ #include "mv_common.h" +#include +#include namespace zbar { class Image; @@ -37,6 +39,17 @@ namespace Barcode { */ int convertSourceMV2Zbar(mv_source_h mvSource, zbar::Image& zbarSource); +/** + * @brief This function converts media vision image handle to cv::Mat with gray color. + * + * @since_tizen 6.5 + * @param [in] mvSource Media vision image handle + * @param [out] cv::Mat + * @return @c MEDIA_VISION_ERROR_NONE on success, + otherwise a negative error value + */ +int convertSourceMV2GrayCV(mv_source_h mvSource, cv::Mat& cvSource); + } /* Barcode */ } /* MediaVision */ diff --git a/mv_barcode/barcode_detector/src/BarcodeUtils.cpp b/mv_barcode/barcode_detector/src/BarcodeUtils.cpp index b8c70d97..6f4c7d21 100644 --- a/mv_barcode/barcode_detector/src/BarcodeUtils.cpp +++ b/mv_barcode/barcode_detector/src/BarcodeUtils.cpp @@ -103,5 +103,105 @@ int convertSourceMV2Zbar(mv_source_h mvSource, zbar::Image& zbarSource) return err; } +int convertSourceMV2GrayCV(mv_source_h mvSource, cv::Mat& cvSource) +{ + MEDIA_VISION_INSTANCE_CHECK(mvSource); + + int depth = CV_8U; // Default depth. 1 byte for channel. + unsigned int channelsNumber = 0u; + unsigned int width = 0u, height = 0u; + unsigned int bufferSize = 0u; + unsigned char *buffer = NULL; + + mv_colorspace_e colorspace = MEDIA_VISION_COLORSPACE_INVALID; + + MEDIA_VISION_ASSERT(mv_source_get_width(mvSource, &width), + "Failed to get the width."); + MEDIA_VISION_ASSERT(mv_source_get_height(mvSource, &height), + "Failed to get the height."); + MEDIA_VISION_ASSERT(mv_source_get_colorspace(mvSource, &colorspace), + "Failed to get the colorspace."); + MEDIA_VISION_ASSERT(mv_source_get_buffer(mvSource, &buffer, &bufferSize), + "Failed to get the buffer size."); + + int conversionType = -1; /* Type of conversion from given colorspace to gray */ + switch(colorspace) { + case MEDIA_VISION_COLORSPACE_INVALID: + LOGE("Error: mv_source has invalid colorspace."); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + case MEDIA_VISION_COLORSPACE_Y800: + channelsNumber = 1; + /* Without convertion */ + break; + case MEDIA_VISION_COLORSPACE_I420: + channelsNumber = 1; + height *= 1.5; + conversionType = cv::COLOR_YUV2GRAY_I420; + break; + case MEDIA_VISION_COLORSPACE_NV12: + channelsNumber = 1; + height *= 1.5; + conversionType = cv::COLOR_YUV2GRAY_NV12; + break; + case MEDIA_VISION_COLORSPACE_YV12: + channelsNumber = 1; + height *= 1.5; + conversionType = cv::COLOR_YUV2GRAY_YV12; + break; + case MEDIA_VISION_COLORSPACE_NV21: + channelsNumber = 1; + height *= 1.5; + conversionType = cv::COLOR_YUV2GRAY_NV21; + break; + case MEDIA_VISION_COLORSPACE_YUYV: + channelsNumber = 2; + conversionType = cv::COLOR_YUV2GRAY_YUYV; + break; + case MEDIA_VISION_COLORSPACE_UYVY: + channelsNumber = 2; + conversionType = cv::COLOR_YUV2GRAY_UYVY; + break; + case MEDIA_VISION_COLORSPACE_422P: + channelsNumber = 2; + conversionType = cv::COLOR_YUV2GRAY_Y422; + break; + case MEDIA_VISION_COLORSPACE_RGB565: + channelsNumber = 2; + conversionType = cv::COLOR_BGR5652GRAY; + break; + case MEDIA_VISION_COLORSPACE_RGB888: + channelsNumber = 3; + conversionType = cv::COLOR_RGB2GRAY; + break; + case MEDIA_VISION_COLORSPACE_RGBA: + channelsNumber = 4; + conversionType = cv::COLOR_RGBA2GRAY; + break; + default: + LOGE("Error: mv_source has unsupported colorspace."); + return MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT; + } + + if (conversionType == -1) {/* Without conversion */ + cvSource = cv::Mat(cv::Size(width, height), + CV_MAKETYPE(depth, channelsNumber), buffer).clone(); + } else {/* With conversion */ + /* Class for representation the given image as cv::Mat before conversion */ + cv::Mat origin; + + try { + origin = cv::Mat(cv::Size(width, height), + CV_MAKETYPE(depth, channelsNumber), buffer); + + cv::cvtColor(origin, cvSource, conversionType); + } catch (const cv::Exception &e) { + LOGE("Failed to cvtColor with %s", e.what()); + return MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT; + } + } + + return MEDIA_VISION_ERROR_NONE; +} + } /* Barcode */ } /* MediaVision */ diff --git a/mv_barcode/barcode_detector/src/mv_barcode_detect_open.cpp b/mv_barcode/barcode_detector/src/mv_barcode_detect_open.cpp index 0d4be8e8..54dee63a 100644 --- a/mv_barcode/barcode_detector/src/mv_barcode_detect_open.cpp +++ b/mv_barcode/barcode_detector/src/mv_barcode_detect_open.cpp @@ -20,7 +20,9 @@ #include "BarcodeUtils.h" #include - +#include +#include +#include #include using namespace MediaVision::Barcode; @@ -35,29 +37,16 @@ int mv_barcode_detect_open( if (!source || !detect_cb) return MEDIA_VISION_ERROR_INVALID_PARAMETER; - zbar::Image image; - int err = convertSourceMV2Zbar(source, image); - if (err != MEDIA_VISION_ERROR_NONE) { - LOGW("convertSourceMV2Zbar failed"); - return err; - } - - zbar::Image greyImage = image.convert("Y800"); - if (!greyImage.get_data()) { - LOGE("fail to image convert by zbar"); - return MEDIA_VISION_ERROR_INVALID_OPERATION; - } - - greyImage.set_crop(roi.point.x, roi.point.y, roi.width, roi.height); zbar::ImageScanner scanner; int target_val; - err = mv_engine_config_get_int_attribute( + int err = mv_engine_config_get_int_attribute( engine_cfg, "MV_BARCODE_DETECT_ATTR_TARGET", &target_val); if (err != MEDIA_VISION_ERROR_NONE || engine_cfg == NULL) { - LOGW("mv_engine_config_get_int_attribute failed"); + LOGW("mv_engine_config_get_int_attribute failed." + "MV_BARCODE_DETECT_ATTR_TARGET_ALL is used as default"); /* Default value */ target_val = 0; } @@ -110,65 +99,164 @@ int mv_barcode_detect_open( LOGW("Unavailable target value %d", target_val); } - int numberOfBarcodes = scanner.scan(greyImage); - LOGI("ZBar scanner has found %i barcodes on the mv_source_h", - numberOfBarcodes); - mv_quadrangle_s *barcodeLocations = NULL; - mv_barcode_type_e *types = NULL; - - if (numberOfBarcodes == 0) { - LOGI("Call the detect callback for 0 detected barcodes"); - detect_cb(source, engine_cfg, barcodeLocations, NULL, - types, numberOfBarcodes, user_data); - return MEDIA_VISION_ERROR_NONE; - } else if (numberOfBarcodes < 0) { - LOGW("Incorrect number of barcodes (%i), detection is terminated", - numberOfBarcodes); - return MEDIA_VISION_ERROR_INTERNAL; + int rotateDegree = 0; + int rotateNumber = 0; + int rotateDirection = 0; + bool isEnhancementMode = false; + if (engine_cfg != NULL) { + err = mv_engine_config_get_int_attribute( + engine_cfg, + MV_BARCODE_DETECT_ATTR_ROTATION_DEGREES, + &rotateDegree); + if (err != MEDIA_VISION_ERROR_NONE) { + LOGE("mv_engine_config_get_int_attribute failed to get MV_BARCODE_DETECT_ATTR_ROTATE_DEGREES"); + return err; + } + + err = mv_engine_config_get_int_attribute( + engine_cfg, + MV_BARCODE_DETECT_ATTR_ROTATION_COUNT, + &rotateNumber); + if (err != MEDIA_VISION_ERROR_NONE) { + LOGE("mv_engine_config_get_int_attribute failed to get MV_BARCODE_DETECT_ATTR_ROTATE_COUNT"); + return err; + } + + err = mv_engine_config_get_int_attribute( + engine_cfg, + MV_BARCODE_DETECT_ATTR_ROTATION_DIRECTION, + &rotateDirection); + if (err != MEDIA_VISION_ERROR_NONE) { + LOGE("mv_engine_config_get_int_attribute failed to get MV_BARCODE_DETECT_ATTR_ROTATE_DIRECTION"); + return err; + } + + err = mv_engine_config_get_bool_attribute( + engine_cfg, + MV_BARCODE_DETECT_ATTR_USE_ENHANCEMENT, + &isEnhancementMode); + if (err != MEDIA_VISION_ERROR_NONE) { + LOGE("mv_engine_config_get_bool_attribute failed to get MV_BARCODE_DETECT_ATTR_USE_ENHANCEMENT"); + return err; + } } - const char **messagesArray = new const char*[numberOfBarcodes]; - barcodeLocations = new mv_quadrangle_s[numberOfBarcodes]; - types = new mv_barcode_type_e[numberOfBarcodes]; + cv::Mat graySource; + cv::Mat rotMat, rotBuffer; + err = convertSourceMV2GrayCV(source, graySource); + if (err != MEDIA_VISION_ERROR_NONE) { + LOGE("Failed to convertSourceMV2GrayCV[%d]", err); + return err; + } - int i = 0; - /* extract results and prepare them for callback passing */ - for (zbar::SymbolIterator symbol = greyImage.symbol_begin(); - symbol != greyImage.symbol_end(); - ++symbol, ++i) { - Barcode curBarcode(*symbol); + cv::Mat rawBuffer = graySource(cv::Rect(roi.point.x, roi.point.y, roi.width, roi.height)); - size_t messageLength = curBarcode.getMessage().size(); - char *curMessage = new char[messageLength + 1]; - curBarcode.getMessage().copy(curMessage, messageLength); - curMessage[messageLength] = '\0'; - messagesArray[i] = curMessage; + if (isEnhancementMode) { + cv::Mat clacheBuffer; + cv::Ptr clache = cv::createCLAHE(); + clache->setClipLimit(2.0); + clache->apply(rawBuffer, clacheBuffer); - types[i] = curBarcode.getType(); + cv::threshold(clacheBuffer, rawBuffer, 240, 255, cv::THRESH_TRUNC | cv::THRESH_OTSU); + } - LOGI("barcode type: %d with message %s", types[i], curMessage); - int err = curBarcode.calculateLocation(barcodeLocations[i]); - if (err != MEDIA_VISION_ERROR_NONE) { - LOGW("Can't determine location for barcode, detection is terminated"); - for (int j = 0; j <= i; ++j) + std::vector barcodeMessages; + std::vector barcodeLocations; + std::vector barcodeTypes; + zbar::Image _image; + + LOGI("%d numbers with %d degree to %d direction", rotateNumber, rotateDegree, rotateDirection); + + if (rotateDirection == MV_BARCODE_DETECT_ATTR_ROTATION_ALL) + rotateNumber *= 2; + + rotateNumber++; + + int degree = 0; + for (int i = 0; i < rotateNumber; ++i) { + if (rotateDirection == MV_BARCODE_DETECT_ATTR_ROTATION_CLOCKWISE) { + degree = -1 * rotateDegree * i; + } else if (rotateDirection == MV_BARCODE_DETECT_ATTR_ROTATION_COUNTER_CLOCKWISE) { + degree = rotateDegree * i; + } else { // MV_BARCODE_DETECT_ATTR_ROTATE_ALL + if (i%2) { + degree = -1 * rotateDegree * ((i+1)/2); + } else { + degree = rotateDegree * (i/2); + } + } + + rotMat = cv::getRotationMatrix2D(cv::Point((roi.width/2), (roi.height/2)), degree, 1.0); + warpAffine(rawBuffer, rotBuffer, rotMat, rawBuffer.size()); + + _image.set_format("Y800"); + _image.set_size(rotBuffer.cols, rotBuffer.rows); + _image.set_data(rotBuffer.data, rotBuffer.total() * rotBuffer.elemSize()); + + LOGW("%p", _image.get_data()); + if (!_image.get_data()) { + LOGE("fail to get image data"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + int numberOfBarcodes = scanner.scan(_image); + if (numberOfBarcodes <= 0) + continue; + + LOGI("[rot:%d]: %d barcodes detected", i, numberOfBarcodes); + barcodeMessages.clear(); + barcodeTypes.clear(); + barcodeLocations.clear(); + bool isDetected = true; + for (zbar::SymbolIterator symbol = _image.symbol_begin(); + symbol != _image.symbol_end(); ++symbol) { + + Barcode curBarcode(*symbol); + mv_quadrangle_s location; + int err = curBarcode.calculateLocation(location); + if (err != MEDIA_VISION_ERROR_NONE) { + isDetected = false; + break; + } + + barcodeMessages.push_back(curBarcode.getMessage()); + barcodeTypes.push_back(curBarcode.getType()); + barcodeLocations.push_back(location); + } + + if (isDetected) { + LOGI("Call the detect callback for %d detected barcodes", numberOfBarcodes); + const char **messagesArray = new const char*[numberOfBarcodes]; + mv_barcode_type_e *types = new mv_barcode_type_e[numberOfBarcodes]; + mv_quadrangle_s *locations = new mv_quadrangle_s[numberOfBarcodes]; + + for (int i = 0; i < numberOfBarcodes; ++i) { + + size_t messageLength = barcodeMessages[i].size(); + char *curMessage = new char[messageLength + 1]; + barcodeMessages[i].copy(curMessage, messageLength); + curMessage[messageLength] = '\0'; + messagesArray[i] = curMessage; + + types[i] = barcodeTypes[i]; + locations[i] = barcodeLocations[i]; + LOGI("%d: barcode with %s with type %d", i, messagesArray[i], types[i]); + } + detect_cb(source, engine_cfg, locations, messagesArray, types, + numberOfBarcodes, user_data); + LOGI("Clean the memory from barcodes messages and types"); + for (int j = 0; j < numberOfBarcodes; ++j) delete[] messagesArray[j]; delete[] messagesArray; - delete[] barcodeLocations; + delete[] locations; delete[] types; - return err; + + return MEDIA_VISION_ERROR_NONE; } } - - LOGI("Call the detect callback for %i detected barcodes", numberOfBarcodes); - detect_cb(source, engine_cfg, barcodeLocations, messagesArray, types, - numberOfBarcodes, user_data); - - LOGI("Clean the memory from barcodes messages, locations and types"); - for (int j = 0; j < numberOfBarcodes; ++j) - delete[] messagesArray[j]; - delete[] messagesArray; - delete[] barcodeLocations; - delete[] types; + LOGI("Call the detect callback for 0 detected barcodes"); + detect_cb(source, engine_cfg, NULL, NULL, + NULL, 0, user_data); return MEDIA_VISION_ERROR_NONE; } -- cgit v1.2.3