diff --git a/config.json b/config.json index accda9d..6205f5e 100644 --- a/config.json +++ b/config.json @@ -59,8 +59,8 @@ "json-save-directory": "local/scans", "barcode": "", "capture-device": "/dev/video0", - "brightness-addition": 10, - "contrast-multiplication": 1.3, + "brightness-addition": 20, + "contrast-multiplication": 1.4, "camera-device-id": 0 }, diff --git a/index.html b/index.html index a1333ed..7f91ecb 100644 --- a/index.html +++ b/index.html @@ -1,6 +1,11 @@ - - + + + + + + + + diff --git a/lib/sb b/lib/sb index 24f6d3e..346a059 160000 --- a/lib/sb +++ b/lib/sb @@ -1 +1 @@ -Subproject commit 24f6d3ed3d4962a88078c5024473834812968d1a +Subproject commit 346a059ee2c98fee814df51b560bbde7e6b733db diff --git a/src/Pudding.cpp b/src/Pudding.cpp index c5e67f7..99cb073 100644 --- a/src/Pudding.cpp +++ b/src/Pudding.cpp @@ -780,11 +780,11 @@ void Pudding::web_get_bytes(std::string url, const web_callback& callback, const Request* request = new Request(callback, url); requests.push_back(request); - /* Use the CORS anywhere proxy */ - url = "https://mario.shampoo.ooo:8088/" + url; - #if defined(__EMSCRIPTEN__) + /* Use the CORS anywhere proxy */ + url = CORS_ANYWHERE_PROXY_URL + url; + /* Create a fetch attributes object. Set the callback that will be called when response data is received. Attach the user * submitted callback to the userData attribute. Set the headers. */ emscripten_fetch_attr_t attr; @@ -1006,9 +1006,7 @@ void Pudding::capture_frame() new_frame_available = false; /* Load camera frame data into `cv::Mat` */ - time_it("read frame")([&]{ capture >> camera_frame; - }); #else @@ -1021,12 +1019,19 @@ void Pudding::capture_frame() if (!camera_frame.empty()) { + /* Sharpen image for barcode detection */ + float sigma = 1.0f, threshold = 5.0f, amount = 1.0f; + cv::GaussianBlur(camera_frame, blurred, cv::Size(), sigma, sigma); + low_contrast_mask = cv::abs(camera_frame - blurred) < threshold; + sharpened_frame = camera_frame * (1.0f + amount) + blurred * (-amount); + camera_frame.copyTo(sharpened_frame, low_contrast_mask); + /* Brightness and contrast adjustment, see https://docs.opencv.org/2.4.13.7/doc/tutorials/core/basic_linear_transform/basic_linear_transform.html */ int brightness = configuration()["scan"]["brightness-addition"]; float contrast = configuration()["scan"]["contrast-multiplication"]; if (brightness != 0 || contrast != 1.0) { - camera_frame.convertTo(camera_frame, -1, contrast, brightness); + camera_frame.convertTo(contrasted_frame, -1, contrast, brightness); } /* Finished loading into `cv::Mat`, so it is new data that is safe to read. */ @@ -1082,32 +1087,40 @@ void Pudding::update() #endif camera_view.texture().bind(); - /* Fill camera view texture memory with last frame's pixels */ - camera_view.texture().load(camera_frame.ptr(), {camera_frame_width, camera_frame_height}, pixel_format, GL_UNSIGNED_BYTE); - /* Frame data has been loaded, so there is not a new frame available anymore. */ - new_frame_available = false; - /* Convert to grayscale, for ZBar */ - cv::cvtColor(camera_frame, camera_frame, cv::COLOR_BGR2GRAY); - if (configuration()["scan"]["enabled"]) + + /* Check the original camera frame and the pre-processed ones for barcodes */ + for (const cv::Mat& frame : {camera_frame, contrasted_frame, sharpened_frame}) { - zbar::Image query_image(camera_frame.cols, camera_frame.rows, "Y800", static_cast(camera_frame.data), - camera_frame.cols * camera_frame.rows); - int result = image_scanner.scan(query_image); - if (result > 0) + /* Fill camera view texture memory with last frame's pixels */ + camera_view.texture().load(const_cast(frame).ptr(), {camera_frame_width, camera_frame_height}, pixel_format, GL_UNSIGNED_BYTE); + /* Convert to grayscale, for ZBar */ + cv::cvtColor(frame, zbar_frame, cv::COLOR_BGR2GRAY); + if (configuration()["scan"]["enabled"]) { - time_it("barcode lookup")([&] { - for (zbar::Image::SymbolIterator symbol = query_image.symbol_begin(); symbol != query_image.symbol_end(); ++symbol) - { - std::ostringstream message; - message << "camera scanned " << symbol->get_type_name() << " symbol " << symbol->get_data(); - sb::Log::log(message); - current_camera_barcode = symbol->get_data(); - current_barcode = current_camera_barcode; - } - }); + zbar::Image query_image( + camera_frame_width, camera_frame_height, "Y800", static_cast(zbar_frame.data), camera_frame_width * camera_frame_height); + int result = image_scanner.scan(query_image); + if (result > 0) + { + time_it("barcode lookup")([&] { + for (zbar::Image::SymbolIterator symbol = query_image.symbol_begin(); symbol != query_image.symbol_end(); ++symbol) + { + std::ostringstream message; + message << "camera scanned " << symbol->get_type_name() << " symbol " << symbol->get_data(); + sb::Log::log(message); + current_camera_barcode = symbol->get_data(); + current_barcode = current_camera_barcode; + } + }); + /* No need to check the other pre-processed frames */ + break; + } + query_image.set_data(nullptr, 0); } - query_image.set_data(nullptr, 0); } + + /* Frame data has been processed, so there is not a new frame available anymore. */ + new_frame_available = false; } /* viewport box will be used to tell GL where to draw */ diff --git a/src/Pudding.hpp b/src/Pudding.hpp index 64ae2a7..8ca88e6 100644 --- a/src/Pudding.hpp +++ b/src/Pudding.hpp @@ -412,6 +412,7 @@ private: inline static const std::string NUTRITIONIX_NOT_FOUND = "resource not found"; inline static const std::string GOOGLE_BOOKS_API_URL = "https://www.googleapis.com/books/v1/volumes?q=isbn:"; inline static const std::string GIANTBOMB_API_URL = "https://www.giantbomb.com/api/release/?api_key="; + inline static const std::string CORS_ANYWHERE_PROXY_URL = "https://mario.shampoo.ooo:8088/"; inline static const glm::vec3 ZERO_VECTOR_3D {0, 0, 0}; inline static const glm::vec3 Y_UNIT_NORMAL_3D {0, 1, 0}; inline static const glm::mat4 VIEW_MATRIX = glm::lookAt({4.0f, 2.0f, 1.0f}, {0.0f, -0.325f, 0.0f}, Y_UNIT_NORMAL_3D); @@ -428,7 +429,7 @@ private: #ifndef __EMSCRIPTEN__ cv::VideoCapture capture; #endif - cv::Mat camera_frame; + cv::Mat camera_frame, contrasted_frame, sharpened_frame, zbar_frame, blurred, low_contrast_mask; zbar::ImageScanner image_scanner; std::map> uniform; GLuint flat_program, mvp_program;