first commit
This commit is contained in:
77
nodes/proc/vp_expr_check_node.cpp
Normal file
77
nodes/proc/vp_expr_check_node.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
|
||||
#include "vp_expr_check_node.h"
|
||||
#include "../../third_party/tinyexpr/tinyexpr.h"
|
||||
|
||||
namespace vp_nodes {
|
||||
|
||||
vp_expr_check_node::vp_expr_check_node(std::string node_name):vp_node(node_name) {
|
||||
this->initialized();
|
||||
}
|
||||
|
||||
vp_expr_check_node::~vp_expr_check_node() {
|
||||
deinitialized();
|
||||
}
|
||||
|
||||
std::shared_ptr<vp_objects::vp_meta> vp_expr_check_node::handle_frame_meta(std::shared_ptr<vp_objects::vp_frame_meta> meta) {
|
||||
for (auto& i: meta->text_targets) {
|
||||
auto& text = i->text;
|
||||
auto left_right = vp_utils::string_split(text, '=');
|
||||
|
||||
// only deal with equation such as `1+1=2`, excluding `1+1` or `1+1=` or `=1+1`
|
||||
/*
|
||||
* 1. yes means equation is right
|
||||
* 2. no means equation is wrong
|
||||
* 3. invalid means expression is not valid
|
||||
*/
|
||||
if (left_right.size() == 2) {
|
||||
auto left = left_right[0];
|
||||
auto right = left_right[1];
|
||||
|
||||
// replace specific symbols
|
||||
left = std::regex_replace(left, std::regex("x"), "*");
|
||||
left = std::regex_replace(left, std::regex("÷"), "/");
|
||||
//...
|
||||
|
||||
if (left.empty()) {
|
||||
i->flags = "invalid";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (right.empty()) {
|
||||
i->flags = "invalid";
|
||||
continue;
|
||||
}
|
||||
|
||||
double right_value;
|
||||
try {
|
||||
right_value = std::stod(right);
|
||||
}
|
||||
catch(const std::exception& e) {
|
||||
i->flags = "invalid";
|
||||
continue;
|
||||
}
|
||||
|
||||
// parse and calculate the left part
|
||||
int error;
|
||||
auto cal_value = te_interp(left.c_str(), &error);
|
||||
|
||||
if (error != 0) {
|
||||
i->flags = "invalid";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cal_value == right_value) {
|
||||
i->flags = "yes_" + vp_utils::round_any(cal_value, 2);
|
||||
}
|
||||
else {
|
||||
i->flags = "no_" + vp_utils::round_any(cal_value, 2);
|
||||
}
|
||||
}
|
||||
else {
|
||||
i->flags = "invalid";
|
||||
}
|
||||
}
|
||||
|
||||
return meta;
|
||||
}
|
||||
}
|
||||
17
nodes/proc/vp_expr_check_node.h
Normal file
17
nodes/proc/vp_expr_check_node.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "../vp_node.h"
|
||||
|
||||
namespace vp_nodes {
|
||||
// math expression checker, give right for `1+1=2` and wrong for `sqrt(4)=4`.
|
||||
// note: this node works based on vp_frame_text_target, it will parse expression at the left of `=` and calculate it then compare with the right side of `=` .
|
||||
class vp_expr_check_node: public vp_node
|
||||
{
|
||||
private:
|
||||
protected:
|
||||
virtual std::shared_ptr<vp_objects::vp_meta> handle_frame_meta(std::shared_ptr<vp_objects::vp_frame_meta> meta) override;
|
||||
public:
|
||||
vp_expr_check_node(std::string node_name);
|
||||
~vp_expr_check_node();
|
||||
};
|
||||
}
|
||||
77
nodes/proc/vp_frame_fusion_node.cpp
Normal file
77
nodes/proc/vp_frame_fusion_node.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
|
||||
#include "vp_frame_fusion_node.h"
|
||||
|
||||
namespace vp_nodes {
|
||||
|
||||
vp_frame_fusion_node::vp_frame_fusion_node(std::string node_name,
|
||||
std::vector<vp_objects::vp_point> src_points, // 4 calibration points of the source frame
|
||||
std::vector<vp_objects::vp_point> des_points, // 4 calibration points of the destination frame
|
||||
int src_channel_index,
|
||||
int des_channel_index): vp_node(node_name), src_channel_index(src_channel_index), des_channel_index(des_channel_index) {
|
||||
assert(src_channel_index != des_channel_index);
|
||||
assert(src_points.size() == 4 && des_points.size() == 4); // cv::getPerspectiveTransform(...) need 4 pairs of point
|
||||
|
||||
cv::Point2f src_ps[4], des_ps[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
src_ps[i] = cv::Point2f(src_points[i].x, src_points[i].y);
|
||||
des_ps[i] = cv::Point2f(des_points[i].x, des_points[i].y);
|
||||
}
|
||||
// get transform matrix
|
||||
trans_mat = cv::getPerspectiveTransform(src_ps, des_ps);
|
||||
this->initialized();
|
||||
}
|
||||
|
||||
vp_frame_fusion_node::~vp_frame_fusion_node() {
|
||||
deinitialized();
|
||||
}
|
||||
|
||||
std::shared_ptr<vp_objects::vp_meta> vp_frame_fusion_node::handle_frame_meta(std::shared_ptr<vp_objects::vp_frame_meta> meta) {
|
||||
// ignore for unrelated channels
|
||||
if (meta->channel_index != src_channel_index && meta->channel_index != des_channel_index) {
|
||||
return meta;
|
||||
}
|
||||
|
||||
// for the source channel
|
||||
if (meta->channel_index == src_channel_index) {
|
||||
if (tmp_des == nullptr) {
|
||||
// not ready, return directly
|
||||
return meta;
|
||||
}
|
||||
else {
|
||||
// ready to fuse, put result to osd_frame
|
||||
if (tmp_des->osd_frame.empty()) {
|
||||
tmp_des->osd_frame = tmp_des->frame.clone();
|
||||
}
|
||||
fuse(meta->frame, tmp_des->osd_frame);
|
||||
|
||||
// destination channel first
|
||||
pendding_meta(tmp_des);
|
||||
tmp_des = nullptr;
|
||||
|
||||
// source channel last
|
||||
return meta;
|
||||
}
|
||||
}
|
||||
|
||||
// for the destination channel
|
||||
if (meta->channel_index == des_channel_index) {
|
||||
if (tmp_des != nullptr) {
|
||||
// push previous one to downstream first
|
||||
pendding_meta(tmp_des);
|
||||
}
|
||||
// cache current one
|
||||
tmp_des = meta;
|
||||
// return nullptr since we need fuse next time
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void vp_frame_fusion_node::fuse(cv::Mat& src_canvas, cv::Mat& des_canvas) {
|
||||
// transform source image
|
||||
cv::Mat trans_result;
|
||||
cv::warpPerspective(src_canvas, trans_result, trans_mat, des_canvas.size());
|
||||
|
||||
// merge pixels by weights
|
||||
cv::addWeighted(trans_result, 0.7, des_canvas, 0.3, 0, des_canvas);
|
||||
}
|
||||
}
|
||||
27
nodes/proc/vp_frame_fusion_node.h
Normal file
27
nodes/proc/vp_frame_fusion_node.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include "../vp_node.h"
|
||||
|
||||
namespace vp_nodes {
|
||||
// fuse video frames from 2 channels based on the given calibration points.
|
||||
// only support to fuse 2 channels at the same time so far, fuse the first to second or vice versa, just fuse directly did not check the timestamp of frame.
|
||||
class vp_frame_fusion_node: public vp_node
|
||||
{
|
||||
private:
|
||||
std::shared_ptr<vp_objects::vp_frame_meta> tmp_des = nullptr;
|
||||
cv::Mat trans_mat;
|
||||
int src_channel_index = 0;
|
||||
int des_channel_index = 1;
|
||||
|
||||
void fuse(cv::Mat& src_canvas, cv::Mat& des_canvas);
|
||||
protected:
|
||||
virtual std::shared_ptr<vp_objects::vp_meta> handle_frame_meta(std::shared_ptr<vp_objects::vp_frame_meta> meta) override;
|
||||
public:
|
||||
vp_frame_fusion_node(std::string node_name,
|
||||
std::vector<vp_objects::vp_point> src_points, // 4 calibration points of the source frame
|
||||
std::vector<vp_objects::vp_point> des_points, // 4 calibration points of the destination frame
|
||||
int src_channel_index = 0,
|
||||
int des_channel_index = 1);
|
||||
~vp_frame_fusion_node();
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user