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",
|
"json-save-directory": "local/scans",
|
||||||
"barcode": "",
|
"barcode": "",
|
||||||
"capture-device": "/dev/video0",
|
"capture-device": "/dev/video0",
|
||||||
"brightness-addition": 10,
|
"brightness-addition": 20,
|
||||||
"contrast-multiplication": 1.3,
|
"contrast-multiplication": 1.4,
|
||||||
"camera-device-id": 0
|
"camera-device-id": 0
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
10
index.html
10
index.html
|
@ -1,6 +1,11 @@
|
||||||
<!doctype html>
|
<!-- DTD taken from https://www.w3.org/wiki/Choosing_the_right_doctype_for_your_HTML_documents -->
|
||||||
<html>
|
<!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>
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
<style>
|
<style>
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
|
@ -8,6 +13,7 @@
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<!-- WebGL output will be drawn here through Emscripten. The dimensions will be set by Emscripten. -->
|
<!-- WebGL output will be drawn here through Emscripten. The dimensions will be set by Emscripten. -->
|
||||||
<canvas id="canvas"></canvas>
|
<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);
|
Request* request = new Request(callback, url);
|
||||||
requests.push_back(request);
|
requests.push_back(request);
|
||||||
|
|
||||||
/* Use the CORS anywhere proxy */
|
|
||||||
url = "https://mario.shampoo.ooo:8088/" + url;
|
|
||||||
|
|
||||||
#if defined(__EMSCRIPTEN__)
|
#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
|
/* 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. */
|
* submitted callback to the userData attribute. Set the headers. */
|
||||||
emscripten_fetch_attr_t attr;
|
emscripten_fetch_attr_t attr;
|
||||||
|
@ -1006,9 +1006,7 @@ void Pudding::capture_frame()
|
||||||
new_frame_available = false;
|
new_frame_available = false;
|
||||||
|
|
||||||
/* Load camera frame data into `cv::Mat` */
|
/* Load camera frame data into `cv::Mat` */
|
||||||
time_it("read frame")([&]{
|
|
||||||
capture >> camera_frame;
|
capture >> camera_frame;
|
||||||
});
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
@ -1021,12 +1019,19 @@ void Pudding::capture_frame()
|
||||||
|
|
||||||
if (!camera_frame.empty())
|
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 */
|
/* 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"];
|
int brightness = configuration()["scan"]["brightness-addition"];
|
||||||
float contrast = configuration()["scan"]["contrast-multiplication"];
|
float contrast = configuration()["scan"]["contrast-multiplication"];
|
||||||
if (brightness != 0 || contrast != 1.0)
|
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. */
|
/* Finished loading into `cv::Mat`, so it is new data that is safe to read. */
|
||||||
|
@ -1082,32 +1087,40 @@ void Pudding::update()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
camera_view.texture().bind();
|
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);
|
/* Check the original camera frame and the pre-processed ones for barcodes */
|
||||||
/* Frame data has been loaded, so there is not a new frame available anymore. */
|
for (const cv::Mat& frame : {camera_frame, contrasted_frame, sharpened_frame})
|
||||||
new_frame_available = false;
|
|
||||||
/* Convert to grayscale, for ZBar */
|
|
||||||
cv::cvtColor(camera_frame, camera_frame, cv::COLOR_BGR2GRAY);
|
|
||||||
if (configuration()["scan"]["enabled"])
|
|
||||||
{
|
{
|
||||||
zbar::Image query_image(camera_frame.cols, camera_frame.rows, "Y800", static_cast<void*>(camera_frame.data),
|
/* Fill camera view texture memory with last frame's pixels */
|
||||||
camera_frame.cols * camera_frame.rows);
|
camera_view.texture().load(const_cast<cv::Mat&>(frame).ptr(), {camera_frame_width, camera_frame_height}, pixel_format, GL_UNSIGNED_BYTE);
|
||||||
int result = image_scanner.scan(query_image);
|
/* Convert to grayscale, for ZBar */
|
||||||
if (result > 0)
|
cv::cvtColor(frame, zbar_frame, cv::COLOR_BGR2GRAY);
|
||||||
|
if (configuration()["scan"]["enabled"])
|
||||||
{
|
{
|
||||||
time_it("barcode lookup")([&] {
|
zbar::Image query_image(
|
||||||
for (zbar::Image::SymbolIterator symbol = query_image.symbol_begin(); symbol != query_image.symbol_end(); ++symbol)
|
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);
|
||||||
std::ostringstream message;
|
if (result > 0)
|
||||||
message << "camera scanned " << symbol->get_type_name() << " symbol " << symbol->get_data();
|
{
|
||||||
sb::Log::log(message);
|
time_it("barcode lookup")([&] {
|
||||||
current_camera_barcode = symbol->get_data();
|
for (zbar::Image::SymbolIterator symbol = query_image.symbol_begin(); symbol != query_image.symbol_end(); ++symbol)
|
||||||
current_barcode = current_camera_barcode;
|
{
|
||||||
}
|
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 */
|
/* 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 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 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 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 ZERO_VECTOR_3D {0, 0, 0};
|
||||||
inline static const glm::vec3 Y_UNIT_NORMAL_3D {0, 1, 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);
|
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__
|
#ifndef __EMSCRIPTEN__
|
||||||
cv::VideoCapture capture;
|
cv::VideoCapture capture;
|
||||||
#endif
|
#endif
|
||||||
cv::Mat camera_frame;
|
cv::Mat camera_frame, contrasted_frame, sharpened_frame, zbar_frame, blurred, low_contrast_mask;
|
||||||
zbar::ImageScanner image_scanner;
|
zbar::ImageScanner image_scanner;
|
||||||
std::map<std::string, std::map<std::string, GLuint>> uniform;
|
std::map<std::string, std::map<std::string, GLuint>> uniform;
|
||||||
GLuint flat_program, mvp_program;
|
GLuint flat_program, mvp_program;
|
||||||
|
|
Loading…
Reference in New Issue