计算速度优化,摄像头读取逻辑改变,分类器更新。
This commit is contained in:
@@ -51,10 +51,11 @@ extern std::map<string, int> prior_red;
|
||||
class LightBlob {
|
||||
public:
|
||||
cv::RotatedRect rect; //灯条位置
|
||||
double areaRatio;
|
||||
double length; //灯条长度
|
||||
uint8_t blob_color; //灯条颜色
|
||||
|
||||
LightBlob(cv::RotatedRect &r, uint8_t color) : rect(r), blob_color(color) {
|
||||
LightBlob(cv::RotatedRect &r, double ratio, uint8_t color) : rect(r), areaRatio(ratio), blob_color(color) {
|
||||
length = max(rect.size.height, rect.size.width);
|
||||
};
|
||||
LightBlob() = default;
|
||||
|
||||
@@ -18,8 +18,8 @@ class Classifier {
|
||||
private:
|
||||
bool state;
|
||||
|
||||
vector<vector<MatrixXd>> conv1_w, conv2_w;
|
||||
vector<double> conv1_b, conv2_b;
|
||||
vector<vector<MatrixXd>> conv1_w, conv2_w, conv3_w;
|
||||
vector<double> conv1_b, conv2_b, conv3_b;
|
||||
MatrixXd fc1_w, fc2_w;
|
||||
VectorXd fc1_b, fc2_b;
|
||||
|
||||
@@ -30,8 +30,10 @@ private:
|
||||
|
||||
MatrixXd softmax(const MatrixXd &input);
|
||||
MatrixXd relu(const MatrixXd &input);
|
||||
MatrixXd leaky_relu(const MatrixXd &input, float alpha);
|
||||
vector<vector<MatrixXd>> apply_bias(const vector<vector<MatrixXd>> &input, const vector<double> &bias);
|
||||
vector<vector<MatrixXd>> relu(const vector<vector<MatrixXd>> &input);
|
||||
vector<vector<MatrixXd>> leaky_relu(const vector<vector<MatrixXd>> &input, float alpha);
|
||||
vector<vector<MatrixXd>> max_pool(const vector<vector<MatrixXd>> &input, int size);
|
||||
vector<vector<MatrixXd>> mean_pool(const vector<vector<MatrixXd>> &input, int size);
|
||||
vector<vector<MatrixXd>> pand(const vector<vector<MatrixXd>> &input, int val);
|
||||
|
||||
@@ -3,12 +3,9 @@
|
||||
//
|
||||
|
||||
#include <armor_finder/armor_finder.h>
|
||||
#include <additions/additions.h>
|
||||
#include <log.h>
|
||||
|
||||
static double getTimeIntervalms(const timeval& now, const timeval &last){
|
||||
return (now.tv_sec-last.tv_sec)*1000.0 + (now.tv_usec-last.tv_usec)/1000.0;
|
||||
}
|
||||
|
||||
void ArmorFinder::antiTop() {
|
||||
static double top_periodms = 0;
|
||||
static double last_top_periodms = 0;
|
||||
|
||||
@@ -58,8 +58,8 @@ ArmorFinder::ArmorFinder(uint8_t &color, Serial &u, const string ¶s_folder,
|
||||
}
|
||||
|
||||
void ArmorFinder::run(cv::Mat &src) {
|
||||
// stateSearchingTarget(src); // for debug
|
||||
// goto end;
|
||||
stateSearchingTarget(src); // for debug
|
||||
goto end;
|
||||
switch (state) {
|
||||
case SEARCHING_STATE:
|
||||
if (stateSearchingTarget(src)) {
|
||||
|
||||
@@ -162,6 +162,12 @@ MatrixXd Classifier::relu(const MatrixXd &input){
|
||||
});
|
||||
}
|
||||
|
||||
MatrixXd Classifier::leaky_relu(const MatrixXd &input, float alpha){
|
||||
return input.unaryExpr([&](double val){
|
||||
return (val>0)?(val):(alpha*val);
|
||||
});
|
||||
}
|
||||
|
||||
vector<vector<MatrixXd>> Classifier::relu(const vector<vector<MatrixXd>> &input){
|
||||
vector<vector<MatrixXd>> result;
|
||||
for(int samples=0; samples<input.size(); samples++){
|
||||
@@ -174,6 +180,18 @@ vector<vector<MatrixXd>> Classifier::relu(const vector<vector<MatrixXd>> &input)
|
||||
return result;
|
||||
}
|
||||
|
||||
vector<vector<MatrixXd>> Classifier::leaky_relu(const vector<vector<MatrixXd>> &input, float alpha){
|
||||
vector<vector<MatrixXd>> result;
|
||||
for(int samples=0; samples<input.size(); samples++){
|
||||
vector<MatrixXd> sub;
|
||||
for(int channels=0; channels<input[0].size(); channels++){
|
||||
sub.emplace_back(leaky_relu(input[samples][channels], alpha));
|
||||
}
|
||||
result.emplace_back(sub);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
vector<vector<MatrixXd>> Classifier::pand(const vector<vector<MatrixXd>> &input, int val){
|
||||
vector<vector<MatrixXd>> result;
|
||||
for(int sample=0; sample<input.size(); sample++){
|
||||
@@ -254,6 +272,8 @@ Classifier::Classifier(const string &folder) : state(true){
|
||||
conv1_b = load_conv_b(folder+"conv1_b");
|
||||
conv2_w = load_conv_w(folder+"conv2_w");
|
||||
conv2_b = load_conv_b(folder+"conv2_b");
|
||||
conv3_w = load_conv_w(folder+"conv3_w");
|
||||
conv3_b = load_conv_b(folder+"conv3_b");
|
||||
fc1_w = load_fc_w(folder+"fc1_w");
|
||||
fc1_b = load_fc_b(folder+"fc1_b");
|
||||
fc2_w = load_fc_w(folder+"fc2_w");
|
||||
@@ -273,7 +293,8 @@ MatrixXd Classifier::calculate(const vector<vector<MatrixXd>> &input) {
|
||||
vector<vector<MatrixXd>> pool1_result = mean_pool(conv1_result, 2);
|
||||
vector<vector<MatrixXd>> conv2_result = relu(apply_bias(conv2(conv2_w, pool1_result), conv2_b));
|
||||
vector<vector<MatrixXd>> pool2_result = mean_pool(conv2_result, 2);
|
||||
MatrixXd flattened = flatten(pool2_result);
|
||||
vector<vector<MatrixXd>> conv3_result = relu(apply_bias(conv2(conv3_w, pool2_result), conv3_b));
|
||||
MatrixXd flattened = flatten(conv3_result);
|
||||
MatrixXd y1 = fc1_w * flattened;
|
||||
y1.colwise() += fc1_b;
|
||||
MatrixXd fc1 = relu(y1);
|
||||
@@ -303,7 +324,7 @@ int Classifier::operator()(const cv::Mat &image) {
|
||||
// cout << result << "==============" <<endl;
|
||||
MatrixXd::Index minRow, minCol;
|
||||
result.maxCoeff(&minRow, &minCol);
|
||||
if(result(minRow, minCol) > 0.9){
|
||||
if(result(minRow, minCol) > 0.90){
|
||||
return minRow;
|
||||
}else{
|
||||
return 0;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <show_images/show_images.h>
|
||||
#include <options/options.h>
|
||||
#include <opencv2/highgui.hpp>
|
||||
#define DO_NOT_CNT_TIME
|
||||
#include <log.h>
|
||||
|
||||
|
||||
@@ -27,7 +28,7 @@ static bool lengthJudge(const LightBlob &light_blob_i, const LightBlob &light_bl
|
||||
double side_length;
|
||||
cv::Point2f centers = light_blob_i.rect.center - light_blob_j.rect.center;
|
||||
side_length = sqrt(centers.ddot(centers));
|
||||
return (side_length / light_blob_i.length < 8 && side_length / light_blob_i.length > 0.5);
|
||||
return (side_length / light_blob_i.length < 10 && side_length / light_blob_i.length > 0.5);
|
||||
}
|
||||
|
||||
static bool lengthRatioJudge(const LightBlob &light_blob_i, const LightBlob &light_blob_j) {
|
||||
@@ -99,6 +100,7 @@ bool matchArmorBoxes(const cv::Mat &src, const LightBlobs &light_blobs, ArmorBox
|
||||
if (min_x < 0 || max_x > src.cols || min_y < 0 || max_y > src.rows) {
|
||||
continue;
|
||||
}
|
||||
if((max_x-min_x)/(max_y-min_y) < 0.8) continue;
|
||||
LightBlobs pair_blobs = {light_blobs.at(i), light_blobs.at(j)};
|
||||
armor_boxes.emplace_back(
|
||||
cv::Rect2d(min_x, min_y, max_x - min_x, max_y - min_y),
|
||||
@@ -116,31 +118,35 @@ bool ArmorFinder::findArmorBox(const cv::Mat &src, ArmorBox &box) {
|
||||
|
||||
box.rect = cv::Rect2d(0, 0, 0, 0);
|
||||
box.id = -1;
|
||||
|
||||
if (!findLightBlobs(src, light_blobs)) {
|
||||
return false;
|
||||
}
|
||||
CNT_TIME("blob", {
|
||||
if (!findLightBlobs(src, light_blobs)) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
if (show_light_blobs && src.size() == cv::Size(640, 480)) {
|
||||
showLightBlobs("light_blobs", src, light_blobs);
|
||||
cv::waitKey(1);
|
||||
}
|
||||
|
||||
if (!matchArmorBoxes(src, light_blobs, armor_boxes, enemy_color)) {
|
||||
// cout << "Box fail!" << endl;
|
||||
return false;
|
||||
}
|
||||
CNT_TIME("boxes",{
|
||||
if (!matchArmorBoxes(src, light_blobs, armor_boxes, enemy_color)) {
|
||||
// cout << "Box fail!" << endl;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
if (show_armor_boxes && src.size() == cv::Size(640, 480)) {
|
||||
showArmorBoxes("boxes", src, armor_boxes);
|
||||
cv::waitKey(1);
|
||||
}
|
||||
|
||||
if (classifier && use_classifier) {
|
||||
for (auto &armor_box : armor_boxes) {
|
||||
cv::Mat roi = src(armor_box.rect).clone();
|
||||
cv::resize(roi, roi, cv::Size(48, 36));
|
||||
int c = classifier(roi);
|
||||
armor_box.id = c;
|
||||
}
|
||||
CNT_TIME("classify: %d", {
|
||||
for (auto &armor_box : armor_boxes) {
|
||||
cv::Mat roi = src(armor_box.rect).clone();
|
||||
cv::resize(roi, roi, cv::Size(48, 36));
|
||||
int c = classifier(roi);
|
||||
armor_box.id = c;
|
||||
}
|
||||
}, armor_boxes.size());
|
||||
sort(armor_boxes.begin(), armor_boxes.end());
|
||||
if(armor_boxes[0].id != 0){
|
||||
box = armor_boxes[0];
|
||||
|
||||
@@ -13,14 +13,14 @@ static double lw_rate(const cv::RotatedRect &rect) {
|
||||
}
|
||||
|
||||
|
||||
static double areaRatio(const std::vector<cv::Point> &contour, const cv::RotatedRect &rect){
|
||||
static double areaRatio(const std::vector<cv::Point> &contour, const cv::RotatedRect &rect) {
|
||||
return cv::contourArea(contour) / rect.size.area();
|
||||
}
|
||||
|
||||
static bool isValidLightBlob(const std::vector<cv::Point> &contour, const cv::RotatedRect &rect) {
|
||||
return (1.5 < lw_rate(rect) && lw_rate(rect) < 10) &&
|
||||
// (rect.size.area() < 3000) &&
|
||||
((rect.size.area() < 50 && areaRatio(contour, rect) > 0.4) ||
|
||||
// (rect.size.area() < 3000) &&
|
||||
((rect.size.area() < 50 && areaRatio(contour, rect) > 0.4) ||
|
||||
(rect.size.area() >= 50 && areaRatio(contour, rect) > 0.6));
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ static float linePointX(const cv::Point2f &p1, const cv::Point2f &p2, int y) {
|
||||
|
||||
/// Todo:性能优化后的函数(还有点问题)
|
||||
static double get_blob_color_opt(const cv::Mat &src, cv::RotatedRect blobPos) {
|
||||
int blue_cnt=0, red_cnt=0;
|
||||
int blue_cnt = 0, red_cnt = 0;
|
||||
blobPos.size.height *= 1.05;
|
||||
blobPos.size.width *= 1.1;
|
||||
cv::Point2f corners[4];
|
||||
@@ -95,6 +95,11 @@ static double get_blob_color_opt(const cv::Mat &src, cv::RotatedRect blobPos) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool isSameBlob(LightBlob blob1, LightBlob blob2) {
|
||||
auto dist = blob1.rect.center - blob2.rect.center;
|
||||
return (dist.x * dist.x + dist.y * dist.y) < 9;
|
||||
}
|
||||
|
||||
static void imagePreProcess(cv::Mat &src) {
|
||||
static cv::Mat kernel_erode = getStructuringElement(cv::MORPH_RECT, cv::Size(3, 5));
|
||||
erode(src, src, kernel_erode);
|
||||
@@ -119,41 +124,76 @@ bool ArmorFinder::findLightBlobs(const cv::Mat &src, LightBlobs &light_blobs) {
|
||||
std::vector<cv::Mat> channels; // 通道拆分
|
||||
|
||||
cv::split(src, channels); /************************/
|
||||
if (enemy_color == ENEMY_BLUE){ /* */
|
||||
if (enemy_color == ENEMY_BLUE) { /* */
|
||||
color_channel = channels[0]; /* 根据目标颜色进行通道提取 */
|
||||
}else if (enemy_color == ENEMY_RED){ /* */
|
||||
} else if (enemy_color == ENEMY_RED) { /* */
|
||||
color_channel = channels[2]; /************************/
|
||||
}
|
||||
|
||||
|
||||
|
||||
cv::threshold(color_channel, src_bin_light, 200, 255, CV_THRESH_BINARY); // 二值化对应通道
|
||||
if(src_bin_light.empty()) return false;
|
||||
if (src_bin_light.empty()) return false;
|
||||
imagePreProcess(src_bin_light); // 开闭运算
|
||||
|
||||
cv::threshold(color_channel, src_bin_dim, 140, 255, CV_THRESH_BINARY); // 二值化对应通道
|
||||
if(src_bin_dim.empty()) return false;
|
||||
if (src_bin_dim.empty()) return false;
|
||||
imagePreProcess(src_bin_dim); // 开闭运算
|
||||
|
||||
if(src_bin_light.size() == cv::Size(640, 480) && show_light_blobs) {
|
||||
if (src_bin_light.size() == cv::Size(640, 480) && show_light_blobs) {
|
||||
imshow("bin_light", src_bin_light);
|
||||
imshow("bin_dim", src_bin_dim);
|
||||
}
|
||||
|
||||
std::vector<std::vector<cv::Point> > light_contours_light, light_contours_dim;
|
||||
cv::findContours(src_bin_light, light_contours_light, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
|
||||
cv::findContours(src_bin_dim, light_contours_dim, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
|
||||
for (auto &light_contour : light_contours_light) {
|
||||
cv::RotatedRect rect = cv::minAreaRect(light_contour);
|
||||
if (isValidLightBlob(light_contour, rect)) {
|
||||
light_blobs.emplace_back(rect, get_blob_color(src, rect));
|
||||
std::vector<std::vector<cv::Point>> light_contours_light, light_contours_dim;
|
||||
LightBlobs light_blobs_light, light_blobs_dim;
|
||||
std::vector<cv::Vec4i> hierarchy_light, hierarchy_dim;
|
||||
cv::findContours(src_bin_light, light_contours_light, hierarchy_light, CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE);
|
||||
cv::findContours(src_bin_dim, light_contours_dim, hierarchy_dim, CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE);
|
||||
for (int i = 0; i < light_contours_light.size(); i++) {
|
||||
if (hierarchy_light[i][2] == -1) {
|
||||
cv::RotatedRect rect = cv::minAreaRect(light_contours_light[i]);
|
||||
if (isValidLightBlob(light_contours_light[i], rect)) {
|
||||
light_blobs_light.emplace_back(
|
||||
rect, areaRatio(light_contours_light[i], rect), get_blob_color(src, rect)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto &light_contour : light_contours_dim) {
|
||||
cv::RotatedRect rect = cv::minAreaRect(light_contour);
|
||||
if (isValidLightBlob(light_contour, rect)) {
|
||||
light_blobs.emplace_back(rect, get_blob_color(src, rect));
|
||||
for (int i = 0; i < light_contours_dim.size(); i++) {
|
||||
if (hierarchy_dim[i][2] == -1) {
|
||||
cv::RotatedRect rect = cv::minAreaRect(light_contours_dim[i]);
|
||||
if (isValidLightBlob(light_contours_dim[i], rect)) {
|
||||
light_blobs_dim.emplace_back(
|
||||
rect, areaRatio(light_contours_dim[i], rect), get_blob_color(src, rect)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
vector<int> light_to_remove, dim_to_remove;
|
||||
for (int l = 0; l != light_blobs_light.size(); l++) {
|
||||
for (int d = 0; d != light_blobs_dim.size(); d++) {
|
||||
if (isSameBlob(light_blobs_light[l], light_blobs_dim[d])) {
|
||||
if (light_blobs_light[l].areaRatio > light_blobs_dim[d].areaRatio) {
|
||||
dim_to_remove.emplace_back(d);
|
||||
} else {
|
||||
light_to_remove.emplace_back(l);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sort(light_to_remove.begin(), light_to_remove.end(), [](int a, int b) { return a > b; });
|
||||
sort(dim_to_remove.begin(), dim_to_remove.end(), [](int a, int b) { return a > b; });
|
||||
for (auto x : light_to_remove) {
|
||||
light_blobs_light.erase(light_blobs_light.begin() + x);
|
||||
}
|
||||
for (auto x : dim_to_remove) {
|
||||
light_blobs_dim.erase(light_blobs_dim.begin() + x);
|
||||
}
|
||||
for (const auto &light : light_blobs_light) {
|
||||
light_blobs.emplace_back(light);
|
||||
}
|
||||
for (const auto &dim : light_blobs_dim) {
|
||||
light_blobs.emplace_back(dim);
|
||||
}
|
||||
return light_blobs.size() >= 2;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user