美文网首页
解决目标检测可视化文字重叠

解决目标检测可视化文字重叠

作者: leon0514 | 来源:发表于2023-11-20 14:02 被阅读0次

说明

在目标检测算法应用中,需要在图片上画位置框以及对应的类别。一旦画面中的目标比集中,文字会出现重叠现象,不易观察。故提出一种方法用于减少文字重叠现象。

思路

  1. 先规划一个目标框位置附近所有可以画图的区域。
  2. 对可选区域和已经写下文字的区域做iou,找到iou为0或者iou最小的可选区域作为写文字区域并加入已写入文字区域。

说明

在写文字的时候最好将目标框按照面积有小到大排序。优先画面积比较小的框的文字。对于面积比较大的框有比较多的选择空间。

代码

hpp

#ifndef POSITION_HPP
#define POSITION_HPP
#include <vector>
#include <tuple>

namespace ptn{

struct PutTextBox{
    int xmin_;
    int ymin_;
    int xmax_;
    int ymax_;
    PutTextBox () = default;
    PutTextBox(int xmin, int ymin, int xmax, int ymax) : xmin_(xmin), ymin_(ymin), xmax_(xmax), ymax_(ymax) {}
};

float area_percent(const PutTextBox& a, const PutTextBox& b);
float iou(const PutTextBox& a, const PutTextBox& b);

class Position{
public:
    std::vector<std::tuple<int, int>> calculate_all(
        std::vector<PutTextBox> all_boxes, 
        int width, 
        int height, 
        int text_width, 
        int text_height, 
        int baseline);
        
    std::tuple<int, int> calculate(
        PutTextBox box, 
        int width, 
        int height, 
        int text_width, 
        int text_height, 
        int baseline);
    void clear();

    std::vector<PutTextBox> find_all_draw_postion(
        PutTextBox& box, 
        int width, 
        int height,
        int text_width, 
        int text_height);

    void cal_suitable_position(
        std::vector<PutTextBox>& suitable_position,
        int& x, 
        int& y);

private:
    std::vector<PutTextBox> mark_position;
    int zero_box_num = 1;

};

}

#endif

cpp

#include "position.hpp"
#include <iostream>

namespace ptn{

float area_percent(const PutTextBox& a, const PutTextBox& b)
{       
    int b_area = (b.ymax_ - b.ymin_) * (b.xmax_ - b.xmin_);
        
    int xmin = std::max(a.xmin_, b.xmin_);
    int xmax = std::min(a.xmax_, b.xmax_);
    int ymin = std::max(a.ymin_, b.ymin_);
    int ymax = std::min(a.ymax_, b.ymax_);
    int w = std::max(std::min(a.xmax_, b.xmax_) - std::max(a.xmin_, b.xmin_), 0);
    int h = std::max(std::min(a.ymax_, b.ymax_) - std::max(a.ymin_, b.ymin_), 0);
    int over_area = w * h;
    if (b_area == 0 || over_area == 0)
    {
        return 0;
    }
    return 1.0 * over_area / b_area * 100;
}
float iou(const PutTextBox& a, const PutTextBox& b)
{       
    int a_area = (a.ymax_ - a.ymin_) * (a.xmax_ - a.xmin_);
    int b_area = (b.ymax_ - b.ymin_) * (b.xmax_ - b.xmin_);
        
    int xmin = std::max(a.xmin_, b.xmin_);
    int xmax = std::min(a.xmax_, b.xmax_);
    int ymin = std::max(a.ymin_, b.ymin_);
    int ymax = std::min(a.ymax_, b.ymax_);
    int w = std::max(std::min(a.xmax_, b.xmax_) - std::max(a.xmin_, b.xmin_), 0);
    int h = std::max(std::min(a.ymax_, b.ymax_) - std::max(a.ymin_, b.ymin_), 0);
    int over_area = w * h;
    if (a_area == 0 || b_area == 0 || over_area == 0)
    {
        return 0.f;
    }
    return 1.0 * over_area / (b_area + a_area - over_area) * 100;
}


std::vector<PutTextBox> Position::find_all_draw_postion(
    PutTextBox& box, 
    int width, 
    int height,
    int text_width, 
    int text_height)
{
    std::vector<PutTextBox> suitable_position;

    int xmin = std::max(0, box.xmin_);
    int ymin = std::max(0, box.ymin_);
    int xmax = std::min(width, box.xmax_);
    int ymax = std::min(height, box.ymax_);

    PutTextBox all{0, 0, width, height};

    int btwl = std::max(xmax - xmin, text_width);
    PutTextBox top_left(xmin, ymin - text_height, xmin + btwl, ymax);
    PutTextBox bottom_left(xmin, ymin, xmin + btwl, ymax + text_height);

    int btwr = std::min(xmax - xmin - text_width, 0);
    PutTextBox top_right(xmin + btwr, ymin - text_height, xmax, ymax);
    PutTextBox bottom_right(xmin + btwr, ymin, xmax, ymax + text_height);
    
    int lrh = std::max(ymax - ymin, text_height);
    PutTextBox left(xmin - text_width, ymin, xmax, ymin + lrh);
    PutTextBox right(xmin, ymin, xmax + text_width, ymin + lrh);
    if (area_percent(all, top_left) == 100)
    {
        int bxmin = top_left.xmin_;
        int bymin = top_left.ymin_;
        int bxmax = top_left.xmin_ + text_width;
        int bymax = top_left.ymin_ + text_height;
        suitable_position.emplace_back(std::move(PutTextBox(bxmin, bymin, bxmax, bymax)));
    }
    if (area_percent(all, top_right) == 100)
    {
        int bxmin = top_right.xmin_;
        int bymin = top_right.ymin_;
        int bxmax = top_right.xmin_ + text_width;
        int bymax = top_right.ymin_ + text_height;
        suitable_position.emplace_back(std::move(PutTextBox(bxmin, bymin, bxmax, bymax)));
    }
    if (area_percent(all, right) == 100)
    {
        int box_height = ymax - ymin;
        int num = box_height / text_height;
        for (int i = 0; i < num; i++)
        {
            int bxmin = right.xmax_ - text_width;
            int bymin = right.ymin_ + i * text_height;
            int bxmax = right.xmax_;
            int bymax = right.ymin_ + i * text_height + text_height;
            suitable_position.emplace_back(std::move(PutTextBox(bxmin, bymin, bxmax, bymax)));
        }
    }
    if (area_percent(all, left) == 100)
    {
        int box_height = ymax - ymin;
        int num = box_height / text_height;
        for (int i = 0; i < num; i++)
        {
            int bxmin = left.xmin_;
            int bymin = left.ymin_ + i * text_height;
            int bxmax = left.xmin_ + text_width;
            int bymax = left.ymin_ + i * text_height + text_height;
            suitable_position.emplace_back(std::move(PutTextBox(bxmin, bymin, bxmax, bymax)));
        }
    }
    if (area_percent(all, bottom_left) == 100)
    {
        int bxmin = bottom_left.xmin_;
        int bymin = bottom_left.ymax_ - text_height;
        int bxmax = bottom_left.xmin_ + text_width;
        int bymax = bottom_left.ymax_;
        suitable_position.emplace_back(std::move(PutTextBox(bxmin, bymin, bxmax, bymax)));
    }
    if (area_percent(all, bottom_right) == 100)
    {
        int bxmin = bottom_right.xmin_;
        int bymin = bottom_right.ymax_ - text_height;
        int bxmax = bottom_right.xmin_ + text_width;
        int bymax = bottom_right.ymax_;
        suitable_position.emplace_back(std::move(PutTextBox(bxmin, bymin, bxmax, bymax)));
    }
    if (suitable_position.size() == 0)
    {
        int bxmin = xmin;
        int bymin = ymin;
        int bxmax = xmin + text_width;
        int bymax = ymin + text_height;
        suitable_position.emplace_back(std::move(PutTextBox(bxmin, bymin, bxmax, bymax)));
    }
    return suitable_position;
}

void Position::cal_suitable_position(
    std::vector<PutTextBox>& suitable_position,
    int& x, 
    int& y)
{
    if (mark_position.size() == 0)
    {
        mark_position.push_back(suitable_position[0]);
        x = suitable_position[0].xmin_;
        y = suitable_position[0].ymin_;
        return;
    }
    PutTextBox box;
    float all_max_iou = 0.f;
    for (const auto& sp : suitable_position)
    {
        float max_iou = 0.f;
        for (const auto& mp : mark_position)
        {
            float percent = iou(sp, mp);
            if (percent > max_iou)
            {
                max_iou = percent;
            }
        }
        /**
         * 遍历完所有已经标记过的地区,最大iou依然为0,说明这个地方可以写文字
        */
        if (max_iou == 0)
        {
            box = sp;
            break;
        }
        else
        {
            if (max_iou > all_max_iou)
            {
                all_max_iou = max_iou;
                box = sp;
            }
        }
    }
    x = box.xmin_;
    y = box.ymin_;
    mark_position.push_back(box);
}

std::vector<std::tuple<int, int>> Position::calculate_all(
    std::vector<PutTextBox> all_boxes, 
    int width, 
    int height, 
    int text_width, 
    int text_height, 
    int baseline)
{
    std::vector<std::tuple<int, int>> result;
    int zero_box_num = 1;
    for (auto& box : all_boxes)
    {
        result.push_back(calculate(box, width, height, text_width, text_height, baseline));
    }
    clear();
    return result;
}

std::tuple<int, int> Position::calculate(PutTextBox box, int width, int height, int text_width, int text_height, int baseline)
{
    std::tuple<int, int> result;
    if (box.xmax_ < box.xmin_ || box.ymax_ < box.ymin_)
    {
        result = std::make_tuple(-1, -1);
    }
    else if (box.xmin_ == 0 && box.ymin_ == 0 && box.xmax_ == 0 && box.ymax_ == 0)
    {
        int x = (width - text_width) / 2;
        int y = 0 + zero_box_num * text_height;
        zero_box_num += 1;
        result = std::make_tuple(x, y);
    }
    else
    {
        std::vector<PutTextBox> draw_positions = find_all_draw_postion(box, width, height, text_width, text_height + baseline);
        int x = 0;
        int y = 0;
        cal_suitable_position(draw_positions, x, y);
        result = std::make_tuple(x, y + text_height);
    }
    return result;
}

void Position::clear()
{
    std::vector<PutTextBox>().swap(mark_position);
    zero_box_num  = 1;
}

}

相关文章

网友评论

      本文标题:解决目标检测可视化文字重叠

      本文链接:https://www.haomeiwen.com/subject/xfevwdtx.html