计算速度优化,摄像头读取逻辑改变,分类器更新。

This commit is contained in:
xinyang
2019-07-28 15:59:01 +08:00
parent a5259cbd1f
commit 5a0fdb30af
24 changed files with 17667 additions and 115529 deletions

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -58,8 +58,8 @@ ArmorFinder::ArmorFinder(uint8_t &color, Serial &u, const string &paras_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)) {

View File

@@ -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;

View File

@@ -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];

View File

@@ -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;
}