1 Star 0 Fork 0

王哲King/Yolo_mark

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
main.cpp 37.80 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014
#include <cstdio>
#include <iostream>
#include <vector>
#include <numeric>
#include <chrono>
#include <atomic>
#include <locale>
#include <future> // C++11: async(); feature<>;
#include <iostream>
#include <iomanip>
#include <fstream> // std::ofstream
#include <algorithm> // std::unique
#include <opencv2/opencv.hpp> // C++
#include <opencv2/core/version.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
//#include <opencv2/optflow.hpp>
#include <opencv2/video/tracking.hpp>
#ifdef _DEBUG
#define LIB_SUFFIX "d.lib"
#else
#define LIB_SUFFIX ".lib"
#endif // DEBUG
#ifndef CV_VERSION_EPOCH
#include "opencv2/videoio/videoio.hpp"
#define OPENCV_VERSION CVAUX_STR(CV_VERSION_MAJOR)"" CVAUX_STR(CV_VERSION_MINOR)"" CVAUX_STR(CV_VERSION_REVISION)
#pragma comment(lib, "opencv_world" OPENCV_VERSION LIB_SUFFIX)
#else
#define OPENCV_VERSION CVAUX_STR(CV_VERSION_EPOCH)"" CVAUX_STR(CV_VERSION_MAJOR)"" CVAUX_STR(CV_VERSION_MINOR)
#pragma comment(lib, "opencv_core" OPENCV_VERSION LIB_SUFFIX)
#pragma comment(lib, "opencv_imgproc" OPENCV_VERSION LIB_SUFFIX)
#pragma comment(lib, "opencv_highgui" OPENCV_VERSION LIB_SUFFIX)
#endif
#ifndef CV_FILLED
#define CV_FILLED cv::FILLED
#endif
using namespace cv;
// label coordinates
struct coord_t {
cv::Rect_<float> abs_rect;
int id;
};
class Tracker_optflow {
public:
const int flow_error;
Tracker_optflow(int win_size = 15, int max_level = 3, int iterations = 8000, int _flow_error = -1) :
flow_error((_flow_error > 0) ? _flow_error : (win_size * 4))
{
sync_PyrLKOpticalFlow = cv::SparsePyrLKOpticalFlow::create();
sync_PyrLKOpticalFlow->setWinSize(cv::Size(win_size, win_size)); // 9, 15, 21, 31
sync_PyrLKOpticalFlow->setMaxLevel(max_level); // +- 3 pt
}
// just to avoid extra allocations
cv::Mat dst_grey;
cv::Mat prev_pts_flow, cur_pts_flow;
cv::Mat status, err;
cv::Mat src_grey; // used in both functions
cv::Ptr<cv::SparsePyrLKOpticalFlow> sync_PyrLKOpticalFlow;
std::vector<coord_t> cur_bbox_vec;
std::vector<bool> good_bbox_vec_flags;
void update_cur_bbox_vec(std::vector<coord_t> _cur_bbox_vec)
{
cur_bbox_vec = _cur_bbox_vec;
good_bbox_vec_flags = std::vector<bool>(cur_bbox_vec.size(), true);
cv::Mat prev_pts, cur_pts_flow;
for (auto &i : cur_bbox_vec) {
float x_center = (i.abs_rect.x + i.abs_rect.width / 2.0F);
float y_center = (i.abs_rect.y + i.abs_rect.height / 2.0F);
prev_pts.push_back(cv::Point2f(x_center, y_center));
}
if (prev_pts.rows == 0)
prev_pts_flow = cv::Mat();
else
cv::transpose(prev_pts, prev_pts_flow);
}
void update_tracking_flow(cv::Mat new_src_mat, std::vector<coord_t> _cur_bbox_vec)
{
if (new_src_mat.channels() == 1) {
src_grey = new_src_mat.clone();
}
else if (new_src_mat.channels() == 3) {
cv::cvtColor(new_src_mat, src_grey, cv::COLOR_BGR2GRAY, 1);
}
else if (new_src_mat.channels() == 4) {
cv::cvtColor(new_src_mat, src_grey, cv::COLOR_BGRA2GRAY, 1);
}
else {
std::cerr << " Warning: new_src_mat.channels() is not: 1, 3 or 4. It is = " << new_src_mat.channels() << " \n";
return;
}
update_cur_bbox_vec(_cur_bbox_vec);
}
std::vector<coord_t> tracking_flow(cv::Mat new_dst_mat, bool check_error = true)
{
if (sync_PyrLKOpticalFlow.empty()) {
std::cout << "sync_PyrLKOpticalFlow isn't initialized \n";
return cur_bbox_vec;
}
cv::cvtColor(new_dst_mat, dst_grey, cv::COLOR_BGR2GRAY, 1);
if (src_grey.rows != dst_grey.rows || src_grey.cols != dst_grey.cols) {
src_grey = dst_grey.clone();
//std::cerr << " Warning: src_grey.rows != dst_grey.rows || src_grey.cols != dst_grey.cols \n";
return cur_bbox_vec;
}
if (prev_pts_flow.cols < 1) {
return cur_bbox_vec;
}
////sync_PyrLKOpticalFlow_gpu.sparse(src_grey_gpu, dst_grey_gpu, prev_pts_flow_gpu, cur_pts_flow_gpu, status_gpu, &err_gpu); // OpenCV 2.4.x
sync_PyrLKOpticalFlow->calc(src_grey, dst_grey, prev_pts_flow, cur_pts_flow, status, err); // OpenCV 3.x
dst_grey.copyTo(src_grey);
std::vector<coord_t> result_bbox_vec;
if (err.rows == cur_bbox_vec.size() && status.rows == cur_bbox_vec.size())
{
for (size_t i = 0; i < cur_bbox_vec.size(); ++i)
{
cv::Point2f cur_key_pt = cur_pts_flow.at<cv::Point2f>(0, i);
cv::Point2f prev_key_pt = prev_pts_flow.at<cv::Point2f>(0, i);
float moved_x = cur_key_pt.x - prev_key_pt.x;
float moved_y = cur_key_pt.y - prev_key_pt.y;
if (abs(moved_x) < 100 && abs(moved_y) < 100 && good_bbox_vec_flags[i])
if (err.at<float>(0, i) < flow_error && status.at<unsigned char>(0, i) != 0 &&
((float)cur_bbox_vec[i].abs_rect.x + moved_x) > 0 && ((float)cur_bbox_vec[i].abs_rect.y + moved_y) > 0)
{
cur_bbox_vec[i].abs_rect.x += moved_x;// +0.5;
cur_bbox_vec[i].abs_rect.y += moved_y;// +0.5;
result_bbox_vec.push_back(cur_bbox_vec[i]);
}
else good_bbox_vec_flags[i] = false;
else good_bbox_vec_flags[i] = false;
//if(!check_error && !good_bbox_vec_flags[i]) result_bbox_vec.push_back(cur_bbox_vec[i]);
}
}
prev_pts_flow = cur_pts_flow.clone();
return result_bbox_vec;
}
};
std::atomic<bool> right_button_click;
std::atomic<int> move_rect_id;
std::atomic<bool> move_rect;
std::atomic<bool> clear_marks;
std::atomic<bool> copy_previous_marks(false);
std::atomic<bool> tracker_copy_previous_marks(false);
std::atomic<bool> show_help;
std::atomic<bool> exit_flag(false);
std::atomic<int> mark_line_width(2); // default mark line width is 2 pixels.
const int MAX_MARK_LINE_WIDTH = 3;
std::atomic<bool> show_mark_class(true);
std::atomic<bool> delete_selected(false);
std::atomic<int> x_start, y_start;
std::atomic<int> x_end, y_end;
std::atomic<int> x_size, y_size;
std::atomic<bool> draw_select, selected, undo;
std::atomic<int> add_id_img;
Rect prev_img_rect(0, 0, 50, 100);
Rect next_img_rect(1280 - 50, 0, 50, 100);
void callback_mouse_click(int event, int x, int y, int flags, void* user_data)
{
if (event == cv::EVENT_LBUTTONDBLCLK)
{
std::cout << "cv::EVENT_LBUTTONDBLCLK \n";
}
else if (event == cv::EVENT_LBUTTONDOWN)
{
draw_select = true;
selected = false;
x_start = x;
y_start = y;
if (prev_img_rect.contains(Point2i(x, y))) add_id_img = -1;
else if (next_img_rect.contains(Point2i(x, y))) add_id_img = 1;
else add_id_img = 0;
//std::cout << "cv::EVENT_LBUTTONDOWN \n";
}
else if (event == cv::EVENT_LBUTTONUP)
{
x_size = abs(x - x_start);
y_size = abs(y - y_start);
x_end = max(x, 0);
y_end = max(y, 0);
draw_select = false;
selected = true;
//std::cout << "cv::EVENT_LBUTTONUP \n";
}
else if (event == cv::EVENT_RBUTTONDOWN)
{
right_button_click = true;
x_start = x;
y_start = y;
std::cout << "cv::EVENT_RBUTTONDOWN \n";
}
else if (event == cv::EVENT_RBUTTONUP)
{
right_button_click = false;
move_rect = true;
}
if (event == cv::EVENT_RBUTTONDBLCLK)
{
std::cout << "cv::EVENT_RBUTTONDBLCLK \n";
}
else if (event == cv::EVENT_MOUSEMOVE)
{
x_end = max(x, 0);
y_end = max(y, 0);
}
}
class comma : public std::numpunct<char> {
public:
comma() : std::numpunct<char>() {}
protected:
char do_decimal_point() const { return '.'; }
};
int main(int argc, char *argv[])
{
try
{
std::locale loccomma(std::locale::classic(), new comma);
std::locale::global(loccomma);
std::string images_path = "./";
if (argc >= 2) {
images_path = std::string(argv[1]); // path to images, train and synset
}
else {
std::cout << "Usage: [path_to_images] [train.txt] [obj.names] \n";
return 0;
}
std::string train_filename = images_path + "train.txt";
std::string synset_filename = images_path + "obj.names";
if (argc >= 3) {
train_filename = std::string(argv[2]); // file containing: list of images
}
if (argc >= 4) {
synset_filename = std::string(argv[3]); // file containing: object names
}
// optical flow tracker
Tracker_optflow tracker_optflow;
cv::Mat optflow_img;
// capture frames from video file - 1 frame per 3 seconds of video
if (argc >= 4 && (train_filename == "cap_video" || train_filename == "cap_video_backward")) {
const std::string videofile = synset_filename;
cv::VideoCapture cap(videofile);
#ifndef CV_VERSION_EPOCH // OpenCV 3.x
const int fps = cap.get(cv::CAP_PROP_FPS);
#else // OpenCV 2.x
const int fps = cap.get(CV_CAP_PROP_FPS);
#endif
int frame_counter = 0, image_counter = 0;
int backward = (train_filename == "cap_video_backward") ? 1 : 0;
if (backward) image_counter = 99999999; // 99M
float save_each_frames = 50;
if (argc >= 5) save_each_frames = std::stoul(std::string(argv[4]));
int pos_filename = 0;
if ((1 + videofile.find_last_of("\\")) < videofile.length()) pos_filename = 1 + videofile.find_last_of("\\");
if ((1 + videofile.find_last_of("/")) < videofile.length()) pos_filename = std::max(pos_filename, 1 + (int)videofile.find_last_of("/"));
std::string const filename = videofile.substr(pos_filename);
std::string const filename_without_ext = filename.substr(0, filename.find_last_of("."));
for (cv::Mat frame; cap >> frame, cap.isOpened() && !frame.empty();) {
cv::imshow("video cap to frames", frame);
#ifndef CV_VERSION_EPOCH
int pressed_key = cv::waitKeyEx(20); // OpenCV 3.x
#else
int pressed_key = cv::waitKey(20); // OpenCV 2.x
#endif
if (pressed_key == 27 || pressed_key == 1048603) break; // ESC - exit (OpenCV 2.x / 3.x)
if (frame_counter++ >= save_each_frames) { // save frame for each 3 second
frame_counter = 0;
std::stringstream image_counter_ss;
image_counter_ss << std::setw(8) << std::setfill('0') << image_counter;
if (backward) image_counter--;
else image_counter++;
std::string img_name = images_path + "/" + filename_without_ext + "_" + image_counter_ss.str() + ".jpg";
std::cout << "saved " << img_name << std::endl;
cv::imwrite(img_name, frame);
}
}
exit(0);
}
bool show_mouse_coords = false;
std::vector<std::string> filenames_in_folder;
//glob(images_path, filenames_in_folder); // void glob(String pattern, std::vector<String>& result, bool recursive = false);
cv::String images_path_cv = images_path;
std::vector<cv::String> filenames_in_folder_cv;
glob(images_path_cv, filenames_in_folder_cv); // void glob(String pattern, std::vector<String>& result, bool recursive = false);
for (auto &i : filenames_in_folder_cv)
filenames_in_folder.push_back(i);
std::vector<std::string> jpg_filenames_path;
std::vector<std::string> jpg_filenames;
std::vector<std::string> jpg_filenames_without_ext;
std::vector<std::string> image_ext;
std::vector<std::string> txt_filenames;
std::vector<std::string> jpg_in_train;
std::vector<std::string> synset_txt;
// image-paths to txt-paths
for (auto &i : filenames_in_folder)
{
int pos_filename = 0;
if ((1 + i.find_last_of("\\")) < i.length()) pos_filename = 1 + i.find_last_of("\\");
if ((1 + i.find_last_of("/")) < i.length()) pos_filename = std::max(pos_filename, 1 + (int)i.find_last_of("/"));
std::string const filename = i.substr(pos_filename);
std::string const ext = i.substr(i.find_last_of(".") + 1);
std::string const filename_without_ext = filename.substr(0, filename.find_last_of("."));
if (ext == "jpg" || ext == "JPG" ||
ext == "jpeg" || ext == "JPEG" ||
ext == "bmp" || ext == "BMP" ||
ext == "png" || ext == "PNG" ||
ext == "ppm" || ext == "PPM")
{
jpg_filenames_without_ext.push_back(filename_without_ext);
image_ext.push_back(ext);
jpg_filenames.push_back(filename);
jpg_filenames_path.push_back(i);
}
if (ext == "txt") {
txt_filenames.push_back(filename_without_ext);
}
}
std::sort(jpg_filenames.begin(), jpg_filenames.end());
std::sort(jpg_filenames_path.begin(), jpg_filenames_path.end());
std::sort(txt_filenames.begin(), txt_filenames.end());
if (jpg_filenames.size() == 0) {
std::cout << "Error: Image files not found by path: " << images_path << std::endl;
return 0;
}
// check whether there are files with the same names (but different extensions)
{
auto sorted_names_without_ext = jpg_filenames_without_ext;
std::sort(sorted_names_without_ext.begin(), sorted_names_without_ext.end());
for (size_t i = 1; i < sorted_names_without_ext.size(); ++i) {
if (sorted_names_without_ext[i - 1] == sorted_names_without_ext[i]) {
std::cout << "Error: Can't create " << sorted_names_without_ext[i] <<
".txt file for several images with different extensions but with the same filename: "
<< sorted_names_without_ext[i] << std::endl;
// print duplicate images
for (size_t k = 0; k < jpg_filenames_without_ext.size(); ++k) {
if (jpg_filenames_without_ext[k] == sorted_names_without_ext[i]) {
std::cout << jpg_filenames_without_ext[k] << "." << image_ext[k] << std::endl;
}
}
return 0;
}
}
}
// intersect jpg & txt
std::vector<std::string> intersect_filenames(jpg_filenames.size());
std::vector<std::string> difference_filenames(jpg_filenames.size());
std::vector<std::string> intersect_ext;
std::vector<std::string> difference_ext;
auto dif_it_end = std::set_difference(jpg_filenames_without_ext.begin(), jpg_filenames_without_ext.end(),
txt_filenames.begin(), txt_filenames.end(),
difference_filenames.begin());
difference_filenames.resize(dif_it_end - difference_filenames.begin());
auto inter_it_end = std::set_intersection(jpg_filenames_without_ext.begin(), jpg_filenames_without_ext.end(),
txt_filenames.begin(), txt_filenames.end(),
intersect_filenames.begin());
intersect_filenames.resize(inter_it_end - intersect_filenames.begin());
// get intersect extensions for intersect_filenames
for (auto &i : intersect_filenames) {
size_t ext_index = find(jpg_filenames_without_ext.begin(), jpg_filenames_without_ext.end(), i) - jpg_filenames_without_ext.begin();
intersect_ext.push_back(image_ext[ext_index]);
}
// get difference extensions for intersect_filenames
for (auto &i : difference_filenames) {
size_t ext_index = find(jpg_filenames_without_ext.begin(), jpg_filenames_without_ext.end(), i) - jpg_filenames_without_ext.begin();
difference_ext.push_back(image_ext[ext_index]);
}
txt_filenames.clear();
for (auto &i : intersect_filenames) {
txt_filenames.push_back(i + ".txt");
}
int image_list_count = max(1, (int)jpg_filenames_path.size() - 1);
// store train.txt
std::ofstream ofs_train(train_filename, std::ios::out | std::ios::trunc);
if (!ofs_train.is_open()) {
throw(std::runtime_error("Can't open file: " + train_filename));
}
for (size_t i = 0; i < intersect_filenames.size(); ++i) {
ofs_train << images_path << "/" << intersect_filenames[i] << "." << intersect_ext[i] << std::endl;
}
ofs_train.flush();
std::cout << "File opened for output: " << train_filename << std::endl;
// load synset.txt
{
std::ifstream ifs(synset_filename);
if (!ifs.is_open()) {
throw(std::runtime_error("Can't open file: " + synset_filename));
}
for (std::string line; getline(ifs, line);)
synset_txt.push_back(line);
}
std::cout << "File loaded: " << synset_filename << std::endl;
Mat preview(Size(100, 100), CV_8UC3);
Mat full_image(Size(1280, 720), CV_8UC3);
Mat frame(Size(full_image.cols, full_image.rows + preview.rows), CV_8UC3);
Rect full_rect_dst(Point2i(0, preview.rows), Size(frame.cols, frame.rows - preview.rows));
Mat full_image_roi = frame(full_rect_dst);
size_t const preview_number = frame.cols / preview.cols;
// labels on the current image
std::vector<coord_t> current_coord_vec;
Size current_img_size;
std::string const window_name = "Marking images";
namedWindow(window_name, WINDOW_NORMAL);
resizeWindow(window_name, 1280, 720);
imshow(window_name, frame);
moveWindow(window_name, 0, 0);
setMouseCallback(window_name, callback_mouse_click);
bool next_by_click = false;
bool marks_changed = false;
int old_trackbar_value = -1, trackbar_value = 0;
std::string const trackbar_name = "image num";
int tb_res = createTrackbar(trackbar_name, window_name, &trackbar_value, image_list_count);
int old_current_obj_id = -1, current_obj_id = 0;
std::string const trackbar_name_2 = "object id";
int const max_object_id = (synset_txt.size() > 0) ? synset_txt.size() : 20;
int tb_res_2 = createTrackbar(trackbar_name_2, window_name, &current_obj_id, max_object_id);
do {
//trackbar_value = min(max(0, trackbar_value), (int)jpg_filenames_path.size() - 1);
// selected new image
if (old_trackbar_value != trackbar_value || exit_flag)
{
trackbar_value = min(max(0, trackbar_value), (int)jpg_filenames_path.size() - 1);
setTrackbarPos(trackbar_name, window_name, trackbar_value);
frame(Rect(0, 0, frame.cols, preview.rows)) = Scalar::all(0);
move_rect_id = -1;
// save current coords
if (old_trackbar_value >= 0) // && current_coord_vec.size() > 0) // Yolo v2 can processes background-image without objects
{
try
{
std::string const jpg_filename = jpg_filenames[old_trackbar_value];
std::string const filename_without_ext = jpg_filename.substr(0, jpg_filename.find_last_of("."));
std::string const txt_filename = filename_without_ext + ".txt";
std::string const txt_filename_path = images_path + "/" + txt_filename;
std::cout << "txt_filename_path = " << txt_filename_path << std::endl;
std::ofstream ofs(txt_filename_path, std::ios::out | std::ios::trunc);
ofs << std::fixed;
// store coords to [image name].txt
for (auto &i : current_coord_vec)
{
float const relative_center_x = (float)(i.abs_rect.x + i.abs_rect.width / 2) / full_image_roi.cols;
float const relative_center_y = (float)(i.abs_rect.y + i.abs_rect.height / 2) / full_image_roi.rows;
float const relative_width = (float)i.abs_rect.width / full_image_roi.cols;
float const relative_height = (float)i.abs_rect.height / full_image_roi.rows;
if (relative_width <= 0) continue;
if (relative_height <= 0) continue;
if (relative_center_x <= 0) continue;
if (relative_center_y <= 0) continue;
ofs << i.id << " " <<
relative_center_x << " " << relative_center_y << " " <<
relative_width << " " << relative_height << std::endl;
}
// store [path/image name.jpg] to train.txt
auto it = std::find(difference_filenames.begin(), difference_filenames.end(), filename_without_ext);
if (it != difference_filenames.end())
{
ofs_train << images_path << "/" << jpg_filename << std::endl;
ofs_train.flush();
size_t new_size = std::remove(difference_filenames.begin(), difference_filenames.end(), filename_without_ext) -
difference_filenames.begin();
difference_filenames.resize(new_size);
}
}
catch (...) { std::cout << " Exception when try to write txt-file \n"; }
}
// show preview images
for (size_t i = 0; i < preview_number && (i + trackbar_value) < jpg_filenames_path.size(); ++i)
{
Mat img = imread(jpg_filenames_path[trackbar_value + i]);
// check if the image has been loaded successful to prevent crash
if (img.cols == 0)
{
continue;
}
resize(img, preview, preview.size());
int const x_shift = i*preview.cols + prev_img_rect.width;
Rect rect_dst(Point2i(x_shift, 0), preview.size());
Mat dst_roi = frame(rect_dst);
preview.copyTo(dst_roi);
//rectangle(frame, rect_dst, Scalar(200, 150, 200), 2);
putText(dst_roi, jpg_filenames[trackbar_value + i], Point2i(0, 10), FONT_HERSHEY_COMPLEX_SMALL, 0.5, Scalar::all(255));
if (i == 0)
{
optflow_img = img;
resize(img, full_image, full_rect_dst.size());
full_image.copyTo(full_image_roi);
current_img_size = img.size();
try {
std::string const jpg_filename = jpg_filenames[trackbar_value];
std::string const txt_filename = jpg_filename.substr(0, jpg_filename.find_last_of(".")) + ".txt";
//std::cout << (images_path + "/" + txt_filename) << std::endl;
std::ifstream ifs(images_path + "/" + txt_filename);
if (copy_previous_marks) copy_previous_marks = false;
else if (tracker_copy_previous_marks) {
tracker_copy_previous_marks = false;
current_coord_vec = tracker_optflow.tracking_flow(img, false);
}
else current_coord_vec.clear();
for (std::string line; getline(ifs, line);)
{
std::stringstream ss(line);
coord_t coord;
coord.id = -1;
ss >> coord.id;
if (coord.id < 0) continue;
float relative_coord[4] = { -1, -1, -1, -1 }; // rel_center_x, rel_center_y, rel_width, rel_height
for (size_t i = 0; i < 4; i++) if(!(ss >> relative_coord[i])) continue;
for (size_t i = 0; i < 4; i++) if (relative_coord[i] < 0) continue;
coord.abs_rect.x = (relative_coord[0] - relative_coord[2] / 2) * (float)full_image_roi.cols;
coord.abs_rect.y = (relative_coord[1] - relative_coord[3] / 2) * (float)full_image_roi.rows;
coord.abs_rect.width = relative_coord[2] * (float)full_image_roi.cols;
coord.abs_rect.height = relative_coord[3] * (float)full_image_roi.rows;
current_coord_vec.push_back(coord);
}
}
catch (...) { std::cout << " Exception when try to read txt-file \n"; }
}
std::string const jpg_filename = jpg_filenames[trackbar_value + i];
std::string const filename_without_ext = jpg_filename.substr(0, jpg_filename.find_last_of("."));
// green check-mark on the preview image if there is a lebel txt-file for this image
if (!std::binary_search(difference_filenames.begin(), difference_filenames.end(), filename_without_ext))
{
line(dst_roi, Point2i(80, 88), Point2i(85, 93), Scalar(20, 70, 20), 5);
line(dst_roi, Point2i(85, 93), Point2i(93, 85), Scalar(20, 70, 20), 5);
line(dst_roi, Point2i(80, 88), Point2i(85, 93), Scalar(50, 200, 100), 2);
line(dst_roi, Point2i(85, 93), Point2i(93, 85), Scalar(50, 200, 100), 2);
}
}
std::cout << " trackbar_value = " << trackbar_value << std::endl;
old_trackbar_value = trackbar_value;
marks_changed = false;
rectangle(frame, prev_img_rect, Scalar(100, 100, 100), CV_FILLED);
rectangle(frame, next_img_rect, Scalar(100, 100, 100), CV_FILLED);
}
trackbar_value = min(max(0, trackbar_value), (int)jpg_filenames_path.size() - 1);
// highlight prev img
for (size_t i = 0; i < preview_number && (i + trackbar_value) < jpg_filenames_path.size(); ++i)
{
int const x_shift = i*preview.cols + prev_img_rect.width;
Rect rect_dst(Point2i(x_shift, 0), Size(preview.cols - 2, preview.rows));
Scalar color(100, 70, 100);
if (i == 0) color = Scalar(250, 120, 150);
if (y_end < preview.rows && i == (x_end - prev_img_rect.width) / preview.cols) color = Scalar(250, 200, 200);
rectangle(frame, rect_dst, color, 2);
}
if (undo) {
undo = false;
if(current_coord_vec.size() > 0) {
full_image.copyTo(full_image_roi);
current_coord_vec.pop_back();
}
}
// marking is completed (left mouse button is OFF)
if (selected)
{
selected = false;
full_image.copyTo(full_image_roi);
if (y_end < preview.rows && x_end > prev_img_rect.width && x_end < (full_image.cols - prev_img_rect.width) &&
y_start < preview.rows)
{
int const i = (x_end - prev_img_rect.width) / preview.cols;
trackbar_value += i;
}
else if (y_end >= preview.rows)
{
if (next_by_click) {
++trackbar_value;
current_coord_vec.clear();
}
Rect selected_rect(
Point2i((int)min(x_start, x_end), (int)min(y_start, y_end)),
Size(x_size, y_size));
selected_rect &= full_rect_dst;
selected_rect.y -= (int)prev_img_rect.height;
coord_t coord;
coord.abs_rect = selected_rect;
coord.id = current_obj_id;
current_coord_vec.push_back(coord);
marks_changed = true;
}
}
std::string current_synset_name;
if (current_obj_id < synset_txt.size()) current_synset_name = " - " + synset_txt[current_obj_id];
// show X and Y coords of mouse
if (show_mouse_coords) {
full_image.copyTo(full_image_roi);
int const x_inside = std::min((int)x_end, full_image_roi.cols);
int const y_inside = std::min(std::max(0, y_end - (int)prev_img_rect.height), full_image_roi.rows);
float const relative_center_x = (float)(x_inside) / full_image_roi.cols;
float const relative_center_y = (float)(y_inside) / full_image_roi.rows;
int const abs_x = relative_center_x*current_img_size.width;
int const abs_y = relative_center_y*current_img_size.height;
char buff[100];
snprintf(buff, 100, "Abs: %d x %d Rel: %.3f x %.3f", abs_x, abs_y, relative_center_x, relative_center_y);
//putText(full_image_roi, buff, Point2i(800, 20), FONT_HERSHEY_SIMPLEX, 0.7, Scalar(50, 10, 10), 3);
putText(full_image_roi, buff, Point2i(800, 20), FONT_HERSHEY_SIMPLEX, 0.7, Scalar(100, 50, 50), 2);
putText(full_image_roi, buff, Point2i(800, 20), FONT_HERSHEY_SIMPLEX, 0.7, Scalar(220, 120, 120), 1);
}
else
{
full_image.copyTo(full_image_roi);
//std::string text = "Show mouse coordinates - press M";
//putText(full_image_roi, text, Point2i(800, 20), FONT_HERSHEY_SIMPLEX, 0.7, Scalar(100, 50, 50), 2);
//putText(full_image_roi, text, Point2i(800, 20), FONT_HERSHEY_SIMPLEX, 0.7, Scalar(220, 120, 120), 1);
}
// marking is in progress (left mouse button is ON)
if (draw_select)
{
if (add_id_img != 0) trackbar_value += add_id_img;
if (y_start >= preview.rows)
{
//full_image.copyTo(full_image_roi);
Rect selected_rect(
Point2i(max(0, (int)min(x_start, x_end)), max(preview.rows, (int)min(y_start, y_end))),
Point2i(max(x_start, x_end), max(y_start, y_end)));
rectangle(frame, selected_rect, Scalar(150, 200, 150));
if (show_mark_class)
{
putText(frame, std::to_string(current_obj_id) + current_synset_name,
selected_rect.tl() + Point2i(2, 22), FONT_HERSHEY_SIMPLEX, 0.8, Scalar(150, 200, 150), 2);
}
}
}
// Draw crosshair
{
const int offset = preview.rows; // Vertical offset
// Only draw crosshair, if mouse is over image area
if (y_end >= offset)
{
const bool bit_high = true;
const bool bit_low = false;
const int mouse_offset = 25;
const int ver_min = draw_select ? std::min(x_end - mouse_offset, x_start - mouse_offset) : x_end - mouse_offset;
const int ver_max = draw_select ? std::max(x_end + mouse_offset, x_start + mouse_offset) : x_end + mouse_offset;
const int hor_min = draw_select ? std::min(y_end - mouse_offset, y_start - mouse_offset) : y_end - mouse_offset;
const int hor_max = draw_select ? std::max(y_end + mouse_offset, y_start + mouse_offset) : y_end + mouse_offset;
// Draw crosshair onto empty canvas (draws high bits on low-bit-canvas)
cv::Mat crosshair_mask(frame.size(), CV_8UC1, cv::Scalar(bit_low));
cv::line(crosshair_mask, cv::Point(0, y_end), cv::Point(ver_min, y_end), cv::Scalar(bit_high)); // Horizontal, left to mouse
cv::line(crosshair_mask, cv::Point(ver_max, y_end), cv::Point(crosshair_mask.size().width, y_end), cv::Scalar(bit_high)); // Horizontal, mouse to right
cv::line(crosshair_mask, cv::Point(x_end, offset), cv::Point(x_end, std::max(offset, hor_min)), cv::Scalar(bit_high)); // Vertical, top to mouse
cv::line(crosshair_mask, cv::Point(x_end, hor_max), cv::Point(x_end, crosshair_mask.size().height), cv::Scalar(bit_high)); // Vertical, mouse to bottom
// Draw crosshair onto frame copy
cv::Mat crosshair_frame(frame.size(), frame.type());
frame.copyTo(crosshair_frame);
cv::bitwise_not(crosshair_frame, crosshair_frame, crosshair_mask);
// Fade-in frame copy with crosshair into original frame (for alpha)
const double alpha = 0.7;
cv::addWeighted(crosshair_frame, alpha, frame, 1 - alpha, 0.0, frame);
}
}
// remove all labels from this image
if (clear_marks == true)
{
clear_marks = false;
marks_changed = true;
full_image.copyTo(full_image_roi);
current_coord_vec.clear();
}
if (old_current_obj_id != current_obj_id)
{
full_image.copyTo(full_image_roi);
old_current_obj_id = current_obj_id;
setTrackbarPos(trackbar_name_2, window_name, current_obj_id);
}
int selected_id = -1;
// draw all labels
//for (auto &i : current_coord_vec)
for(size_t k = 0; k < current_coord_vec.size(); ++k)
{
auto &i = current_coord_vec.at(k);
std::string synset_name;
if (i.id < synset_txt.size()) synset_name = " - " + synset_txt[i.id];
int offset = i.id * 25;
int red = (offset + 0) % 255 * ((i.id + 2) % 3);
int green = (offset + 70) % 255 * ((i.id + 1) % 3);
int blue = (offset + 140) % 255 * ((i.id + 0) % 3);
Scalar color_rect(red, green, blue); // Scalar color_rect(100, 200, 100);
// selected rect
if (i.abs_rect.x < x_end && (i.abs_rect.x + i.abs_rect.width) > x_end &&
(i.abs_rect.y + preview.rows) < y_end && (i.abs_rect.y + i.abs_rect.height + preview.rows) > y_end)
{
if (selected_id < 0) {
color_rect = Scalar(100, 200, 300);
selected_id = k;
rectangle(full_image_roi, i.abs_rect, color_rect, mark_line_width*2);
}
}
if (show_mark_class)
{
putText(full_image_roi, std::to_string(i.id) + synset_name,
i.abs_rect.tl() + Point2f(2, 22), FONT_HERSHEY_SIMPLEX, 0.8, color_rect, 2);
}
rectangle(full_image_roi, i.abs_rect, color_rect, mark_line_width);
}
// remove selected rect
if (delete_selected) {
delete_selected = false;
if (selected_id >= 0) current_coord_vec.erase(current_coord_vec.begin() + selected_id);
}
// show moving rect
if (right_button_click == true)
{
if (move_rect_id < 0) move_rect_id = selected_id;
int x_delta = x_end - x_start;
int y_delta = y_end - y_start;
auto rect = current_coord_vec[move_rect_id].abs_rect;
rect.x += x_delta;
rect.y += y_delta;
Scalar color_rect = Scalar(300, 200, 100);
rectangle(full_image_roi, rect, color_rect, mark_line_width);
}
// complete moving label rect
if (move_rect && move_rect_id >= 0) {
int x_delta = x_end - x_start;
int y_delta = y_end - y_start;
current_coord_vec[move_rect_id].abs_rect.x += x_delta;
current_coord_vec[move_rect_id].abs_rect.y += y_delta;
move_rect = false;
move_rect_id = -1;
}
if (next_by_click) {
putText(full_image_roi, "Mode: 1 mark per image (next by click)",
Point2i(850, 20), FONT_HERSHEY_SIMPLEX, 0.6, Scalar(50, 170, 100), 2);
}
{
std::string const obj_str = "Object id: " + std::to_string(current_obj_id) + current_synset_name;
putText(full_image_roi, obj_str, Point2i(0, 21), FONT_HERSHEY_DUPLEX, 0.8, Scalar(10, 50, 10), 3);
putText(full_image_roi, obj_str, Point2i(0, 21), FONT_HERSHEY_DUPLEX, 0.8, Scalar(20, 120, 60), 2);
putText(full_image_roi, obj_str, Point2i(0, 21), FONT_HERSHEY_DUPLEX, 0.8, Scalar(50, 200, 100), 1);
}
if (show_help)
{
putText(full_image_roi,
"<- prev_img -> next_img c - clear_marks n - one_object_per_img 0-9 - obj_id m - show coords ESC - exit",
Point2i(0, 45), FONT_HERSHEY_SIMPLEX, 0.6, Scalar(50, 10, 10), 2);
putText(full_image_roi,
"w - line width k - hide obj_name p - copy previous o - track objects r - delete selected R-mouse - move box", // h - disable help",
Point2i(0, 80), FONT_HERSHEY_SIMPLEX, 0.6, Scalar(50, 10, 10), 2);
}
else
{
putText(full_image_roi,
"h - show help",
Point2i(0, 45), FONT_HERSHEY_SIMPLEX, 0.6, Scalar(50, 10, 10), 2);
}
// arrows
{
Scalar prev_arrow_color(200, 150, 100);
Scalar next_arrow_color = prev_arrow_color;
if (prev_img_rect.contains(Point2i(x_end, y_end))) prev_arrow_color = Scalar(220, 190, 170);
if (next_img_rect.contains(Point2i(x_end, y_end))) next_arrow_color = Scalar(220, 190, 170);
std::vector<Point> prev_triangle_pts = { Point(5, 50), Point(40, 90), Point(40, 10), Point(5, 50) };
Mat prev_roi = frame(prev_img_rect);
line(prev_roi, prev_triangle_pts[0], prev_triangle_pts[1], prev_arrow_color, 5);
line(prev_roi, prev_triangle_pts[1], prev_triangle_pts[2], prev_arrow_color, 5);
line(prev_roi, prev_triangle_pts[2], prev_triangle_pts[3], prev_arrow_color, 5);
line(prev_roi, prev_triangle_pts[3], prev_triangle_pts[0], prev_arrow_color, 5);
std::vector<Point> next_triangle_pts = { Point(10, 10), Point(10, 90), Point(45, 50), Point(10, 10) };
Mat next_roi = frame(next_img_rect);
line(next_roi, next_triangle_pts[0], next_triangle_pts[1], next_arrow_color, 5);
line(next_roi, next_triangle_pts[1], next_triangle_pts[2], next_arrow_color, 5);
line(next_roi, next_triangle_pts[2], next_triangle_pts[3], next_arrow_color, 5);
line(next_roi, next_triangle_pts[3], next_triangle_pts[0], next_arrow_color, 5);
}
imshow(window_name, frame);
#ifndef CV_VERSION_EPOCH
int pressed_key = cv::waitKeyEx(20); // OpenCV 3.x
#else
int pressed_key = cv::waitKey(20); // OpenCV 2.x
#endif
if (pressed_key >= 0)
for (int i = 0; i < 5; ++i) cv::waitKey(1);
if (exit_flag) break; // exit after saving
if (pressed_key == 27 || pressed_key == 1048603) exit_flag = true;// break; // ESC - save & exit
if (pressed_key >= '0' && pressed_key <= '9') current_obj_id = pressed_key - '0'; // 0 - 9
if (pressed_key >= 1048624 && pressed_key <= 1048633) current_obj_id = pressed_key - 1048624; // 0 - 9
switch (pressed_key)
{
//case 'z': // z
//case 1048698: // z
// undo = true;
// break;
case 'p': // p
case 1048688: // p
copy_previous_marks = 1;
++trackbar_value;
break;
case 'o': // o
case 1048687: // o
tracker_copy_previous_marks = 1;
++trackbar_value;
break;
case 32: // SPACE
case 1048608: // SPACE
++trackbar_value;
break;
case 2424832: // <-
case 65361: // <-
case 91: // [
--trackbar_value;
break;
case 2555904: // ->
case 65363: // ->
case 93: // ]
++trackbar_value;
break;
case 'c': // c
case 1048675: // c
clear_marks = true;
break;
case 'm': // m
case 1048685: // m
show_mouse_coords = !show_mouse_coords;
full_image.copyTo(full_image_roi);
break;
case 'n': // n
case 1048686: // n
next_by_click = !next_by_click;
full_image.copyTo(full_image_roi);
break;
case 'w': // w
case 1048695: // w
mark_line_width = mark_line_width % MAX_MARK_LINE_WIDTH + 1;
break;
case 'h': // h
case 1048680: // h
show_help = !show_help;
break;
case 'k':
case 1048683:
show_mark_class = !show_mark_class;
break;
case 'r': // r
case 1048690: // r
delete_selected = true;
break;
default:
;
}
if(tracker_copy_previous_marks)
tracker_optflow.update_tracking_flow(optflow_img, current_coord_vec);
//if (pressed_key >= 0) std::cout << "pressed_key = " << (int)pressed_key << std::endl;
} while (true);
}
catch (std::exception &e) {
std::cout << "exception: " << e.what() << std::endl;
}
catch (...) {
std::cout << "unknown exception \n";
}
return 0;
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/wangzheking/Yolo_mark.git
git@gitee.com:wangzheking/Yolo_mark.git
wangzheking
Yolo_mark
Yolo_mark
master

搜索帮助