sharpen camera image preprocessing, check original and preprocessed camera images
This commit is contained in:
parent
5f417a2592
commit
862030b296
|
@ -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
|
||||
},
|
||||
|
||||
|
|
10
index.html
10
index.html
|
@ -1,6 +1,11 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<!-- DTD taken from https://www.w3.org/wiki/Choosing_the_right_doctype_for_your_HTML_documents -->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
||||
|
||||
<!-- Language and charset taken from https://www.w3.org/International/questions/qa-html-encoding-declarations -->
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style>
|
||||
body
|
||||
{
|
||||
|
@ -8,6 +13,7 @@
|
|||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- WebGL output will be drawn here through Emscripten. The dimensions will be set by Emscripten. -->
|
||||
<canvas id="canvas"></canvas>
|
||||
|
|
2
lib/sb
2
lib/sb
|
@ -1 +1 @@
|
|||
Subproject commit 24f6d3ed3d4962a88078c5024473834812968d1a
|
||||
Subproject commit 346a059ee2c98fee814df51b560bbde7e6b733db
|
|
@ -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<void*>(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<cv::Mat&>(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<void*>(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 */
|
||||
|
|
|
@ -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<std::string, std::map<std::string, GLuint>> uniform;
|
||||
GLuint flat_program, mvp_program;
|
||||
|
|
Loading…
Reference in New Issue