百度飞桨-基于CV的工业读表案例(修改读表范围和数值)

外面的项目需要做一个工业读表的功能,并给发来了百度飞桨的案例链接https://www.paddlepaddle.org.cn/tutorials/projectdetail/3387933。基本的要求是在百度飞桨的基础上进行修改即可,因此主要的工作是修改读表的部分。
由于百度的教程非常详细,所以代码配置问题在此处省略,需要注意的是环境配置必须完全按照教程使用CUDA10.2,否则会导致编译错误,此处只对如何修改读表做出总结。

修改表盘读取范围

打开meter_reader.cpp可以看到63行处有GetMeterReading方法,ctrl+左键点入该方法的所在位置,是在src/reader_postprocess.cpp文件的第233行,而此处也正如教程开始的图片所示。

百度飞桨-基于CV的工业读表案例(修改读表范围和数值)

bool GetMeterReading(
  const std::vector<std::vector<uint8_t>> &seg_label_maps,
  std::vector<float> *readings) {
  for (auto i = 0; i < seg_label_maps.size(); i++) {
    std::vector<uint8_t> rectangle_meter;
    CircleToRectangle(seg_label_maps[i], &rectangle_meter);

    std::vector<int> line_scale;
    std::vector<int> line_pointer;
    RectangleToLine(rectangle_meter, &line_scale, &line_pointer);

    std::vector<int> binaried_scale;
    MeanBinarization(line_scale, &binaried_scale);
    std::vector<int> binaried_pointer;
    MeanBinarization(line_pointer, &binaried_pointer);

    std::vector<float> scale_location;
    LocateScale(binaried_scale, &scale_location);

    float pointer_location;
    LocatePointer(binaried_pointer, &pointer_location);

    MeterResult result;
    GetRelativeLocation(
      scale_location, pointer_location, &result);

    float reading;
    CalculateReading(result, &reading);
    readings->push_back(reading);
  }
  return true;
}

首先将语义分割的结果经过腐蚀处理后输入,之后使用CircleToRectangle将环形表盘展开为矩形图像,这个方法是修改的关键,因为涉及到这个矩形是从何处开始截取的,即表盘的起始点。该方法在前面的57行:


bool CircleToRectangle(
  const std::vector<uint8_t> &seg_label_map,
  std::vector<uint8_t> *rectangle_meter) {
  float theta;
  int rho;
  int image_x;
  int image_y;

  *rectangle_meter =
    std::vector<uint8_t> (RECTANGLE_WIDTH * RECTANGLE_HEIGHT, 0);
  for (int row = 0; row < RECTANGLE_HEIGHT; row++) {
    for (int col = 0; col < RECTANGLE_WIDTH; col++) {

      theta = PI * 2 / RECTANGLE_WIDTH * (col + 1);
      rho = CIRCLE_RADIUS - row - 1;

      int y = static_cast<int>(CIRCLE_CENTER[0] + rho * cos(theta) + 0.5);
      int x = static_cast<int>(CIRCLE_CENTER[1] - rho * sin(theta) + 0.5);
      (*rectangle_meter)[row * RECTANGLE_WIDTH + col] =
        seg_label_map[y * METER_SHAPE[1] + x];
    }
  }
  return true;
}

如果想要将表盘起始点改为数值向上,只需要将y坐标改为:

int y = static_cast<int>(CIRCLE_CENTER[0] - rho * cos(theta) + 0.5);
int x = static_cast<int>(CIRCLE_CENTER[1] + rho * sin(theta) + 0.5);

使得y坐标由小变大再变小,x坐标先变大再变小,自绘示例图对照图片的坐标系便很好理解。

百度飞桨-基于CV的工业读表案例(修改读表范围和数值)

修改读表数值

在修改完读表范围后,读表数值的修改相对简单一些,首先下面是对meter_config.cpp的标注,后续的更改也是基于这个文件。


#include "meter_reader/include/meter_config.h"

std::vector<int> METER_SHAPE = {512, 512};

std::vector<int> CIRCLE_CENTER = {256, 256};

int CIRCLE_RADIUS = 250;
float PI = 3.1415926536;

int RECTANGLE_HEIGHT = 120;
int RECTANGLE_WIDTH = 1570;

int TYPE_THRESHOLD = 40;

std::vector<MeterConfig> METER_CONFIG = {
  MeterConfig(25.0f/50.0f, 25.0f, "(MPa)"),
  MeterConfig(1.6f/32.0f,  1.6f,   "(MPa)"),
  MeterConfig(100.0f/100.0f, 100.0f, "(Kg)")
};

std::map<std::string, uint8_t> SEG_CNAME2CLSID = {
  {"background", 0}, {"pointer", 1}, {"scale", 2}
};

根据GetMeterReading方法可知,CalculateReading即最终读表的数值,在reader_postprocess.cpp的201行。


bool CalculateReading(const MeterResult &result,
                      float *reading) {

  if (result.num_scales_ > TYPE_THRESHOLD) {
    *reading = result.pointed_scale_ * METER_CONFIG[0].scale_interval_value_;
  } else {
    *reading = result.pointed_scale_ * METER_CONFIG[1].scale_interval_value_;
  }
  return true;

此处TYPE_THRESHOLD为刻度线根数,如果有多个不同类型的表盘则至少要保证其刻度线根数不一样,从而可以添加多个TYPE_THRESHOLD,并添加多种类型的表盘。如:

bool CalculateReading(const MeterResult &result,
                      float *reading) {
  if (result.num_scales_ > TYPE_THRESHOLD[0] && result.num_scales_ < TYPE_THRESHOLD[1]) {
    *reading = result.pointed_scale_ * METER_CONFIG[0].scale_interval_value_;
  } else if (result.num_scales_ > TYPE_THRESHOLD[1] && result.num_scales_ < TYPE_THRESHOLD[2]){
    *reading = result.pointed_scale_ * METER_CONFIG[1].scale_interval_value_;
  } else {
    *reading = result.pointed_scale_ * METER_CONFIG[2].scale_interval_value_;
  }
  return true;

小结

得益于百度飞桨内训练好的目标检测和语义分割模型,使得工作的复杂度大大降低。如果需要读取的表盘和刻度与案例相差甚远,则需要重新训练检测和语义分割的模型。此外,该方案需要保证表盘的清晰可见,使用网络高噪点图像做测试时,该方法的读取效果并不佳。
基于该案例做提升的方法有许多,如利用OCR自动获取新表盘的最大量程,使用较小的检测模型进行目标检测以提升速度,通过TCP传输读数做进一步处理等,本文就不再赘述了。

Original: https://blog.csdn.net/Pariya_Official/article/details/124576687
Author: 帕里亚
Title: 百度飞桨-基于CV的工业读表案例(修改读表范围和数值)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/641718/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球