-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Save camera picture with points and show saved img
- Loading branch information
rozsatib
committed
Mar 13, 2020
1 parent
eaf5c56
commit 622eaf4
Showing
3 changed files
with
189 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
#ifndef _MACARON_BASE64_H_ | ||
#define _MACARON_BASE64_H_ | ||
|
||
/** | ||
* The MIT License (MIT) | ||
* Copyright (c) 2016 tomykaira | ||
* | ||
* Permission is hereby granted, free of charge, to any person obtaining | ||
* a copy of this software and associated documentation files (the | ||
* "Software"), to deal in the Software without restriction, including | ||
* without limitation the rights to use, copy, modify, merge, publish, | ||
* distribute, sublicense, and/or sell copies of the Software, and to | ||
* permit persons to whom the Software is furnished to do so, subject to | ||
* the following conditions: | ||
* | ||
* The above copyright notice and this permission notice shall be | ||
* included in all copies or substantial portions of the Software. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
*/ | ||
|
||
#include <string> | ||
|
||
namespace macaron { | ||
|
||
class Base64 { | ||
public: | ||
|
||
static std::string Encode(const std::string data) { | ||
static constexpr char sEncodingTable[] = { | ||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', | ||
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', | ||
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', | ||
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', | ||
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', | ||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', | ||
'w', 'x', 'y', 'z', '0', '1', '2', '3', | ||
'4', '5', '6', '7', '8', '9', '+', '/' | ||
}; | ||
|
||
size_t in_len = data.size(); | ||
size_t out_len = 4 * ((in_len + 2) / 3); | ||
std::string ret(out_len, '\0'); | ||
size_t i; | ||
char *p = const_cast<char*>(ret.c_str()); | ||
|
||
for (i = 0; i < in_len - 2; i += 3) { | ||
*p++ = sEncodingTable[(data[i] >> 2) & 0x3F]; | ||
*p++ = sEncodingTable[((data[i] & 0x3) << 4) | ((int) (data[i + 1] & 0xF0) >> 4)]; | ||
*p++ = sEncodingTable[((data[i + 1] & 0xF) << 2) | ((int) (data[i + 2] & 0xC0) >> 6)]; | ||
*p++ = sEncodingTable[data[i + 2] & 0x3F]; | ||
} | ||
if (i < in_len) { | ||
*p++ = sEncodingTable[(data[i] >> 2) & 0x3F]; | ||
if (i == (in_len - 1)) { | ||
*p++ = sEncodingTable[((data[i] & 0x3) << 4)]; | ||
*p++ = '='; | ||
} | ||
else { | ||
*p++ = sEncodingTable[((data[i] & 0x3) << 4) | ((int) (data[i + 1] & 0xF0) >> 4)]; | ||
*p++ = sEncodingTable[((data[i + 1] & 0xF) << 2)]; | ||
} | ||
*p++ = '='; | ||
} | ||
|
||
return ret; | ||
} | ||
|
||
static std::string Decode(const std::string& input, std::string& out) { | ||
static constexpr unsigned char kDecodingTable[] = { | ||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, | ||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, | ||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, | ||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, | ||
64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, | ||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, | ||
64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, | ||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, | ||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, | ||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, | ||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, | ||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, | ||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, | ||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, | ||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, | ||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 | ||
}; | ||
|
||
size_t in_len = input.size(); | ||
if (in_len % 4 != 0) return "Input data size is not a multiple of 4"; | ||
|
||
size_t out_len = in_len / 4 * 3; | ||
if (input[in_len - 1] == '=') out_len--; | ||
if (input[in_len - 2] == '=') out_len--; | ||
|
||
out.resize(out_len); | ||
|
||
for (size_t i = 0, j = 0; i < in_len;) { | ||
uint32_t a = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])]; | ||
uint32_t b = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])]; | ||
uint32_t c = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])]; | ||
uint32_t d = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])]; | ||
|
||
uint32_t triple = (a << 3 * 6) + (b << 2 * 6) + (c << 1 * 6) + (d << 0 * 6); | ||
|
||
if (j < out_len) out[j++] = (triple >> 2 * 8) & 0xFF; | ||
if (j < out_len) out[j++] = (triple >> 1 * 8) & 0xFF; | ||
if (j < out_len) out[j++] = (triple >> 0 * 8) & 0xFF; | ||
} | ||
|
||
return ""; | ||
} | ||
|
||
}; | ||
|
||
} | ||
|
||
#endif /* _MACARON_BASE64_H_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
#include <err.h> | ||
#include <boost/property_tree/ptree.hpp> | ||
#include <boost/property_tree/json_parser.hpp> | ||
#include "Base64.h" | ||
|
||
#include "CameraCenter.h" | ||
|
||
|
@@ -23,6 +24,7 @@ namespace pt = boost::property_tree; | |
bool enter_POI = false; | ||
string POI_export_path; | ||
string POI_import_path; | ||
string show_POI_path; | ||
string license_dir; | ||
string vid_in_path; | ||
string vid_out_path; | ||
|
@@ -263,10 +265,9 @@ void calcCurrStatus(im_status *curr, im_status *ref, Camera *camera, VideoCaptur | |
*/ | ||
} | ||
|
||
void writePOI(vector<poi> POI, string path) | ||
void writePOI(vector<poi> POI, Mat last_img, string path) | ||
{ | ||
pt::ptree root; | ||
pt::ptree POI_pt; | ||
pt::ptree root, POI_pt, POI_img; | ||
for (unsigned i = 0; i < POI.size(); i++) { | ||
pt::ptree elem; | ||
elem.put("name", POI[i].name); | ||
|
@@ -275,6 +276,13 @@ void writePOI(vector<poi> POI, string path) | |
POI_pt.push_back(std::make_pair("", elem)); | ||
} | ||
root.add_child("POI", POI_pt); | ||
|
||
vector<uchar> img_v; | ||
imencode(".jpg",last_img,img_v); | ||
string img_s(img_v.begin(),img_v.end()); | ||
POI_img.put("", macaron::Base64::Encode(img_s)); | ||
root.add_child("POI img", POI_img); | ||
|
||
pt::write_json(path, root); | ||
} | ||
|
||
|
@@ -288,6 +296,19 @@ vector<poi> readPOI(string path) | |
return POI; | ||
} | ||
|
||
Mat readJsonImg(string path) | ||
{ | ||
pt::ptree root; | ||
pt::read_json(path, root); | ||
pt::ptree img_ptree = root.get_child("POI img"); | ||
string img_encoded = img_ptree.get_value<string>(); | ||
string decoded; | ||
if(macaron::Base64::Decode(img_encoded,decoded) != "") | ||
err(1,"Base64 decoding: input data size is not a multiple of 4."); | ||
vector<uchar> decoded_v(decoded.begin(), decoded.end()); | ||
return imdecode(decoded_v,0); | ||
} | ||
|
||
void onMouse(int event, int x, int y, int flags, void *param) | ||
{ | ||
if (event == CV_EVENT_LBUTTONDOWN) { | ||
|
@@ -299,7 +320,7 @@ void onMouse(int event, int x, int y, int flags, void *param) | |
} | ||
} | ||
|
||
void inputPOI(Camera* camera, vector<poi>* POI, VideoCapture* video){ | ||
void inputPOI(Camera* camera, vector<poi>* POI, VideoCapture* video, Mat& last_img){ | ||
|
||
cout << "\nClick on the image to enter points.\nPress Esc to delete the last entered point.\nPress Enter to finish selection and store points.\nPress Tab to change between different views." << endl; | ||
|
||
|
@@ -316,10 +337,12 @@ void inputPOI(Camera* camera, vector<poi>* POI, VideoCapture* video){ | |
if (key == 9) // Tab | ||
curr_draw_mode = next(curr_draw_mode); | ||
initStatus(&s,camera,{},video); | ||
cvtColor(s.gray,s.gray,COLOR_GRAY2RGB); | ||
drawPOI(s.gray, *POI, s.rawtemp, camera, curr_draw_mode); | ||
imshow( "Selecting points of interest", s.gray); | ||
Mat img; | ||
cvtColor(s.gray,img,COLOR_GRAY2RGB); | ||
drawPOI(img, *POI, s.rawtemp, camera, curr_draw_mode); | ||
imshow( "Selecting points of interest", img); | ||
} | ||
last_img = s.gray.clone(); | ||
clearStatusImgs(&s); | ||
destroyWindow("Selecting points of interest"); | ||
} | ||
|
@@ -371,6 +394,24 @@ void recordVideo(Camera *camera, string vid_out_path) | |
clearStatusImgs(&curr); | ||
} | ||
|
||
void showPOIImg(string path){ | ||
vector<poi> POI = readPOI(path); | ||
Mat img = readJsonImg(path); | ||
This comment has been minimized.
Sorry, something went wrong. |
||
while(1) { | ||
Mat imdraw; | ||
cvtColor(img, imdraw, COLOR_GRAY2RGB); | ||
drawPOI(imdraw, POI, NULL, NULL, curr_draw_mode); | ||
string title = "Showing POI from " + path + " - Press Esc to exit"; | ||
imshow(title,imdraw); | ||
char key = waitKey(0) & 0xEFFFFF; | ||
if(key == 27) // Esc | ||
break; | ||
if(key == 9) // Tab | ||
This comment has been minimized.
Sorry, something went wrong.
wentasah
Member
|
||
curr_draw_mode = next(curr_draw_mode); | ||
} | ||
destroyAllWindows(); | ||
} | ||
|
||
static error_t parse_opt(int key, char *arg, struct argp_state *argp_state) | ||
{ | ||
switch (key) { | ||
|
@@ -382,6 +423,9 @@ static error_t parse_opt(int key, char *arg, struct argp_state *argp_state) | |
case 'p': | ||
POI_import_path = arg; | ||
break; | ||
case 's': | ||
show_POI_path = arg; | ||
break; | ||
case 'l': | ||
license_dir = arg; | ||
break; | ||
|
@@ -392,7 +436,7 @@ static error_t parse_opt(int key, char *arg, struct argp_state *argp_state) | |
vid_in_path = arg; | ||
break; | ||
case ARGP_KEY_END: | ||
if (license_dir.empty() && vid_in_path.empty()) | ||
if (license_dir.empty() && vid_in_path.empty() && show_POI_path.empty()) | ||
argp_error(argp_state, "Need path to directory with WIC license file, or path to input video."); | ||
break; | ||
default: | ||
|
@@ -405,6 +449,7 @@ static error_t parse_opt(int key, char *arg, struct argp_state *argp_state) | |
static struct argp_option options[] = { | ||
{ "enter_poi", 'e', "FILE", OPTION_ARG_OPTIONAL, "Enter Points of interest by hand, optionally save them to json file at supplied path." }, | ||
{ "poi_path", 'p', "FILE", 0, "Path to config file containing saved POIs." }, | ||
{ "show-poi", 's', "FILE", 0, "Show camera image taken at saving POIs." }, | ||
{ "license_dir", 'l', "FILE", 0, "Path to directory containing WIC license file." }, | ||
{ "record_video", 'r', "FILE", 0, "Record video and store it with entered filename"}, | ||
{ "load_video", 'v', "FILE", 0, "Load and process video instead of camera feed"}, | ||
|
@@ -435,6 +480,11 @@ int main(int argc, char **argv) | |
Camera* camera = NULL; | ||
VideoCapture* video = NULL; | ||
|
||
if (!show_POI_path.empty()) { | ||
showPOIImg(show_POI_path); | ||
exit(0); | ||
} | ||
|
||
if (!vid_in_path.empty()) { | ||
video = new VideoCapture(vid_in_path); | ||
} else { | ||
|
@@ -451,9 +501,10 @@ int main(int argc, char **argv) | |
if (!POI_import_path.empty()) | ||
POI = readPOI(POI_import_path); | ||
if (enter_POI) { | ||
inputPOI(camera, &POI, video); | ||
Mat last_img; | ||
inputPOI(camera, &POI, video, last_img); | ||
if (!POI_export_path.empty()) { | ||
writePOI(POI, POI_export_path); | ||
writePOI(POI, last_img, POI_export_path); | ||
cout << "Points saved to " << POI_export_path << endl; | ||
} | ||
} | ||
|
Why do you read the file
path
twice? Wouldn't a single function that reads the JSON and returns both points and img be simpler?