add zbar to scan barcodes in video capture feed

This commit is contained in:
frank 2021-06-28 16:30:12 -04:00
parent 7b9549d413
commit cc9aa231ff
4 changed files with 50 additions and 13 deletions

View File

@ -63,7 +63,8 @@ linux : CFLAGS = -g3 -Wall -Wextra -Og -c -I$(SFW_LIB_DIR) -I$(SFW_SRC_DIR) $(SD
linux : CPP_FLAGS = $(CFLAGS) --std=c++17 linux : CPP_FLAGS = $(CFLAGS) --std=c++17
linux : LFLAGS = $(shell $(SDLCONFIG) --libs) -lpthread -lGL -lGLESv2 -lSDL2_image -lSDL2_ttf -lSDL2_mixer -lcurl -lstdc++fs \ linux : LFLAGS = $(shell $(SDLCONFIG) --libs) -lpthread -lGL -lGLESv2 -lSDL2_image -lSDL2_ttf -lSDL2_mixer -lcurl -lstdc++fs \
-L/home/frank/local/opencv/lib -Wl,-rpath,/home/frank/local/opencv/lib -Wl,--enable-new-dtags -lopencv_videoio -lopencv_core \ -L/home/frank/local/opencv/lib -Wl,-rpath,/home/frank/local/opencv/lib -Wl,--enable-new-dtags -lopencv_videoio -lopencv_core \
-lopencv_highgui -lopencv_highgui -lopencv_imgproc \
-L/home/frank/local/zbar/lib -Wl,-rpath,/home/frank/local/zbar/lib -Wl,--enable-new-dtags -lzbar
linux : $(GLEW_DIR)glew.o $(addprefix $(SDLGFX2_DIR),SDL2_rotozoom.o SDL2_gfxPrimitives.o) \ linux : $(GLEW_DIR)glew.o $(addprefix $(SDLGFX2_DIR),SDL2_rotozoom.o SDL2_gfxPrimitives.o) \
$(SFW_O_FILES) $(GAME_O_FILES) $(SFW_O_FILES) $(GAME_O_FILES)
$(CREATE_FONT_SYMLINK) $(CREATE_FONT_SYMLINK)

View File

@ -37,7 +37,7 @@
{ {
"json-save": true, "json-save": true,
"json-save-directory": "local/scans", "json-save-directory": "local/scans",
"barcode": "400063314395", "barcode": "",
"capture-device": "/dev/video0" "capture-device": "/dev/video0"
}, },
"api": "api":
@ -50,8 +50,8 @@
"best-buy-api-key": "vAC23XA5YWBzaYiGtOkoNlXZ", "best-buy-api-key": "vAC23XA5YWBzaYiGtOkoNlXZ",
"giantbomb-api-key": "91a395231f4e1fd9f9ba8840c52a61cda343cd70", "giantbomb-api-key": "91a395231f4e1fd9f9ba8840c52a61cda343cd70",
"nutronix-enabled": false, "nutronix-enabled": false,
"edamam-enabled": false, "edamam-enabled": true,
"open-food-enabled": false, "open-food-enabled": true,
"best-buy-enabled": true "best-buy-enabled": true
} }
} }

View File

@ -16,6 +16,7 @@
#include "Pudding.hpp" #include "Pudding.hpp"
/* Launch the Pudding instance's mainloop */
int main() int main()
{ {
Pudding pudding = Pudding(); Pudding pudding = Pudding();
@ -24,9 +25,12 @@ int main()
return 0; return 0;
} }
/* Initialize a Pudding instance */
Pudding::Pudding() Pudding::Pudding()
{ {
/* subscribe to command events */
get_delegate().subscribe(&Pudding::respond, this); get_delegate().subscribe(&Pudding::respond, this);
/* initialize an opencv capture device for getting images from an attached camera */
int device_id = 0; int device_id = 0;
capture.open(device_id); capture.open(device_id);
std::stringstream message; std::stringstream message;
@ -41,10 +45,14 @@ Pudding::Pudding()
message << "failed to open video capture device ID #" << device_id; message << "failed to open video capture device ID #" << device_id;
} }
log(message.str()); log(message.str());
/* initialize a zbar image scanner for reading barcodes of any format */
image_scanner.set_config(zbar::ZBAR_NONE, zbar::ZBAR_CFG_ENABLE, 1);
/* use sdl context for now */
load_sdl_context(); load_sdl_context();
items.reserve(10);
} }
// Respond to key press events /* Respond to command events */
void Pudding::respond(SDL_Event& event) void Pudding::respond(SDL_Event& event)
{ {
if (get_delegate().compare(event, "up")) if (get_delegate().compare(event, "up"))
@ -90,6 +98,7 @@ void Pudding::add_item(const std::string& upc)
incorporate_best_buy_api(item); incorporate_best_buy_api(item);
} }
items.push_back(item); items.push_back(item);
increment_item_index();
} }
/* Look for item upc in the Open Food API, and use the result to fill out item properties if found /* Look for item upc in the Open Food API, and use the result to fill out item properties if found
@ -199,7 +208,7 @@ void Pudding::incorporate_best_buy_api(Item& item)
{ {
nlohmann::json product = json["products"][0]; nlohmann::json product = json["products"][0];
// look up image (for games this is box art) and "alternate views image" (for games this is a screen shot) // look up image (for games this is box art) and "alternate views image" (for games this is a screen shot)
for (std::string key : {"image", "alternateViewsImage"}) for (std::string key : {"alternateViewsImage", "image"})
{ {
if (product.value(key, "") != "") if (product.value(key, "") != "")
{ {
@ -366,10 +375,13 @@ void Pudding::update()
/* reload the config file every frame to check for changes */ /* reload the config file every frame to check for changes */
get_root()->configuration.load("config.json"); get_root()->configuration.load("config.json");
get_root()->configuration.merge(); get_root()->configuration.merge();
if (current_barcode != get_configuration()["scan"]["barcode"]) if (current_config_barcode != get_configuration()["scan"]["barcode"])
{ {
current_barcode = get_configuration()["scan"]["barcode"]; current_config_barcode = get_configuration()["scan"]["barcode"];
add_item(current_barcode); current_barcode = current_config_barcode;
std::stringstream message;
message << "read new barcode from config " << current_barcode;
log(message.str());
} }
/* draw the current item image to the left half of the screen if items are available */ /* draw the current item image to the left half of the screen if items are available */
Box video_box = get_window_box(); Box video_box = get_window_box();
@ -391,11 +403,33 @@ void Pudding::update()
SDL_UpdateTexture(texture, nullptr, static_cast<void*>(capture_frame.data), capture_frame.step1()); SDL_UpdateTexture(texture, nullptr, static_cast<void*>(capture_frame.data), capture_frame.step1());
SDL_RenderCopyF(get_renderer(), texture, nullptr, &video_box); SDL_RenderCopyF(get_renderer(), texture, nullptr, &video_box);
SDL_DestroyTexture(texture); SDL_DestroyTexture(texture);
previously_captured_frame_index = capture.get(cv::CAP_PROP_POS_FRAMES); /* scan with zbar */
cv::Mat gray;
cv::cvtColor(capture_frame, gray, cv::COLOR_BGR2GRAY);
zbar::Image query_image(gray.cols, gray.rows, "Y800", static_cast<void*>(gray.data), gray.cols * gray.rows);
int result = image_scanner.scan(query_image);
if (result > 0)
{
for (zbar::Image::SymbolIterator symbol = query_image.symbol_begin(); symbol != query_image.symbol_end(); ++symbol)
{
std::stringstream message;
message << "camera scanned " << symbol->get_type_name() << " symbol " << symbol->get_data();
log(message.str());
current_camera_barcode = symbol->get_data();
current_barcode = current_camera_barcode;
}
}
query_image.set_data(nullptr, 0);
} }
else else
{ {
log("video capture device frame empty"); debug("video capture device frame empty");
} }
} }
/* add a new item if a new barcode was scanned or entered */
if (current_barcode != previous_barcode)
{
add_item(current_barcode);
previous_barcode = current_barcode;
}
} }

View File

@ -14,6 +14,7 @@
#include "opencv2/core.hpp" #include "opencv2/core.hpp"
#include "opencv2/videoio.hpp" #include "opencv2/videoio.hpp"
#include "opencv2/highgui.hpp" #include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include "zbar.h" #include "zbar.h"
#include "Game.hpp" #include "Game.hpp"
#include "Sprite.hpp" #include "Sprite.hpp"
@ -34,11 +35,12 @@ private:
const std::string BEST_BUY_API_URL_2 = ")?format=json&apiKey="; const std::string BEST_BUY_API_URL_2 = ")?format=json&apiKey=";
const std::string NUTRONIX_NOT_FOUND = "resource not found"; const std::string NUTRONIX_NOT_FOUND = "resource not found";
const std::string GIANTBOMB_API_URL = "https://www.giantbomb.com/api/release/?api_key="; const std::string GIANTBOMB_API_URL = "https://www.giantbomb.com/api/release/?api_key=";
std::string current_barcode; std::string current_barcode, previous_barcode, current_config_barcode, current_camera_barcode;
std::vector<Item> items; std::vector<Item> items;
int previously_captured_frame_index = -1, current_item_index = 0; int current_item_index = 0;
cv::VideoCapture capture; cv::VideoCapture capture;
cv::Mat capture_frame; cv::Mat capture_frame;
zbar::ImageScanner image_scanner;
void incorporate_open_food_api(Item&); void incorporate_open_food_api(Item&);
void incorporate_nutronix_api(Item&); void incorporate_nutronix_api(Item&);