精华内容
下载资源
问答
  • 指针式仪表识别(MFC)

    2018-03-15 15:56:04
    图像处理的指针式仪表识别,利用OPENCV库,MFC对话框程序
  • OPENCV与VC++指针式仪表识别,识别圆形指针仪表,并读数,内含测试图片,鲁棒性好,识别精度高,正在解决识别非圆形电压表的问题,等解决问题,放出源码,和大家共享
  • 随着电力系统行业对自动化程度的要求不断提高,关于指针式仪表识别技术有待进一步改进。传统检测常常忽视阴影的影响,速度及准确性也常常不能满足要求,文章提出一种实用性强的识别算法。首先通过HSV空间变换操作...
  • 基于三次样条插值的指针式仪表图像分割方法,首先提取包含指针的圆形区域作为信息图,对信息图进行中值滤波、灰度拉伸;其次使用16个固定的阈值对信息图进行分割,并统计指针的长度和面积;最后使用三次样条插值法对...
  • MATLAB图像处理 控制策略
  • 本文将介绍如何利用OpenCV,提取图片中的矩形轮廓特征并进行图片的倾斜校正。...但是由于仪表上存在指针,所以图片在经过轮廓提取直线检测后,会误检出很多条直线。demo程序中主要的算法就是从含有噪声...

    本文将介绍如何利用OpenCV,提取图片中的矩形轮廓特征并进行图片的倾斜校正。完成demo程序可以至:基于轮廓的倾斜仪表校正

    本demo所处理的图片是一张仪表(如下图),欲实现的功能是将图片中倾斜的PCB校正为水平。基本的思路是检测PCB的边缘直线,而后根据边缘直线的斜率旋转图片。但是由于仪表上存在指针,所以图片在经过轮廓提取直线检测后,会误检出很多条直线。demo程序中主要的算法就是从含有噪声的直线簇中提取出直线中相互垂直的直线。 
        

    Step1: 直线检测。OpenCV提供了一个检测直线的函数HoughLinesP(),关于此函数的API介绍,可以参考HoughLinesP。此步骤主要程序如下:

    Mat imgOrigion = imread(IMAGE_PATH);
    Mat imgScale;
    float scaleFactor = COLSLIMIT / imgOrigion.cols;
    resize(imgOrigion, imgScale, Size(imgOrigion.cols * scaleFactor, imgOrigion.rows * scaleFactor));  // reduce image size to speed up calculation
    
    Mat imgGray;
    cvtColor(imgScale, imgGray, COLOR_BGR2GRAY);  // gray scale
    Mat imgCanny;
    Canny(imgGray, imgCanny, 100, 200);  // use canny operator to detect contour
    imshow("Contour detection", imgCanny);
    
    std::vector<Vec4i> lineAll;
    HoughLinesP(imgCanny, lineAll, 1, CV_PI / 180, 30, 50, 4);
    // draw all lines detected
    Mat imgAllLines;
    imgScale.copyTo(imgAllLines);
    for (int i = 0, steps = lineAll.size(); i < steps; i++)
    {
        line(imgAllLines, Point(lineAll[i][0], lineAll[i][1]), Point(lineAll[i][2], lineAll[i][3]), Scalar(255, 255, 255), 3, 8);
    }
    imshow("All lines detected", imgAllLines);
    

        

    上图为使用Canny算子检测出的边缘。仪表板上的轮廓使得算法检测出了丰富的轮廓信息。对此轮廓图进行直线检测,结果如下图所示,除了仪表的边缘直线被检测出来, 算法还误检出了很多的直线。因此,下一步算法的目的就是提取边缘直线,滤出仪表盘内的误检直线。

      

     

    Step2:直线滤波。仪表边缘直线与误检直线所具有的一个不同特征是边缘直线相互垂直,误检直线不一定能找到与其相垂直的直线。算法利用此特征对所有检测出的直线进行滤波

    std::list<Vec4i> linesList;
    for (std::vector<Vec4i>::iterator itor = lineAll.begin(); itor != lineAll.end(); ++itor)
    {
        linesList.push_back(*itor);
    }
    std::vector<Vec4i> lineFiltered;
    for (std::list<Vec4i>::iterator itorOuter = linesList.begin(); itorOuter != linesList.end();)
    {
        for (std::list<Vec4i>::iterator itorInner = linesList.begin(); itorInner != linesList.end(); ++itorInner)
        {
            if (abs(angleOfLines(*itorOuter, *itorInner) - 90) < 1)
            {
                // take out the current two perpendicular lines to reduce the size of linesList
                lineFiltered.push_back(*itorOuter);
                lineFiltered.push_back(*itorInner);
                itorInner = linesList.erase(itorInner);
                itorOuter = linesList.erase(itorOuter);
                break;
            }
    
            if (itorInner == --linesList.end())
            {
                if (linesList.size() > 2)
                {
                    itorOuter = linesList.erase(itorOuter);  // erase current element when there is no other line perpendicular to it.
                }
                else
                {
                    itorOuter = linesList.end();
                    break;
                }
            }
        }
    }
    
    Mat imgLinesFiltered;
    imgScale.copyTo(imgLinesFiltered);
    // draw lines after filtering
    for (int i = 0, steps = lineFiltered.size(); i < steps; i++)
    {
        line(imgLinesFiltered, Point(lineFiltered[i][0], lineFiltered[i][1]), Point(lineFiltered[i][2], lineFiltered[i][3]), Scalar(255, 0, 0), 3, 8);
    }
    imshow("Lines after filtering", imgLinesFiltered);
    
    /**
    * @brief calculate the angle of two lines by using vector angle formula: cos(thea) = (a*b) / (|a||b|)
    * @param line1
    * @param line2
    * @return result ranges from 0 to pi
    */
    double angleOfLines(const cv::Vec4i& line1, const cv::Vec4i& line2)
    {
        double moduleLine1 = sqrt(pow(line1[0] - line1[2], 2) + pow(line1[1] - line1[3], 2));
        double moduleLine2 = sqrt(pow(line2[0] - line2[2], 2) + pow(line2[1] - line2[3], 2));
        double dotProduct = (line1[2] - line1[0])*(line2[2] - line2[0]) + (line1[3] - line1[1])*(line2[3] - line2[1]);
    
        return acos(dotProduct / moduleLine1 / moduleLine2) * 180 / CV_PI;
    }
    

        

     

    Step3:倾角计算。 
    滤波后的直线簇中可能会存在与边缘直线相平行的直线,因此通过对std::vector lineFiltered进行四次排序,提取出最靠图像边界的直线。排序规则即为分别对线段中点坐标x,y的值升序降序排列。注意,在图像坐标系中,原点是图像的最左上角。 
    计算边缘直线的斜率。下面的程序中angleForCorrect()函数返回的是图像最终需要旋转的角度。
     

    double correctAngle = 0.0;  // average tilt angle of PCB 
    if (lineFiltered.size() > 0)
    {
        // find edge lines of PCB
        std::vector<Vec4i> lineEdge;
        sort(lineFiltered.begin(), lineFiltered.end(), getMinMidX);  // get the line at the far left of the image
        lineEdge.push_back(lineFiltered[0]);
        sort(lineFiltered.begin(), lineFiltered.end(), getMaxMidX);  // get the line at the far right of the image
        lineEdge.push_back(lineFiltered[0]);
        sort(lineFiltered.begin(), lineFiltered.end(), getMinMidY);  // get the line at the top of the image
        lineEdge.push_back(lineFiltered[0]);
        sort(lineFiltered.begin(), lineFiltered.end(), getMaxMidY);  // get the line at the buttom of the image
        lineEdge.push_back(lineFiltered[0]);
    
        Mat imgLinesEdge;
        imgScale.copyTo(imgLinesEdge);
        // draw lines after filtering
        for (int i = 0, steps = lineEdge.size(); i < steps; i++)
        {
            line(imgLinesEdge, Point(lineEdge[i][0], lineEdge[i][1]), Point(lineEdge[i][2], lineEdge[i][3]), Scalar(0, 0, 255), 3, 8);
        }
        imshow("PCB edge lines", imgLinesEdge);
    
        for (int i = 0, step = lineEdge.size(); i < step; i++)   // calcualte averge tilt angle of PCB edge lines
        {
            correctAngle += angleForCorrect(lineEdge[i]);
        }
        correctAngle /= lineEdge.size();
    }
    
    /**
    * @brief comparison function for sort, sort vector<Vec4i> from small to large accodoring to x of the midpoint of each element
    * @param line1
    * @param line2
    * @return
    */
    bool getMinMidX(const cv::Vec4i& line1, const cv::Vec4i& line2)
    {
        return (line1[0] + line1[2]) < (line2[0] + line2[2]); // Although middle point compared, there is no need to divide 2
    }
    
    /**
    * @brief comparison function for sort, sort vector<Vec4i> from large to small accodoring to x of the midpoint of each element
    * @param line1
    * @param line2
    * @return
    */
    bool getMaxMidX(const cv::Vec4i& line1, const cv::Vec4i& line2)
    {
        return (line1[0] + line1[2]) > (line2[0] + line2[2]);
    }
    
    /**
    * @brief comparison function for sort, sort vector<Vec4i> from small to large accodoring to y of the midpoint of each element
    * @param line1
    * @param line2
    * @return
    */
    bool getMinMidY(const cv::Vec4i& line1, const cv::Vec4i& line2)
    {
        return (line1[1] + line1[3]) < (line2[1] + line2[3]);
    }
    
    /**
    * @brief comparison function for sort, sort vector<Vec4i> from large to small accodoring to y of the midpoint of each element
    * @param line1
    * @param line2
    * @return
    */
    bool getMaxMidY(const cv::Vec4i& line1, const cv::Vec4i& line2)
    {
        return (line1[1] + line1[3]) > (line2[1] + line2[3]);
    }
    
    /**
    * @brief rotation angle in degrees for correcting tilt
    * @param line: for cv::Vec4i& line, [0] is always smaller than [2]
    * @return The symbol of the result represnts the direction of rotation to correct tilt.
    *         Positive values mean counter-clockwise rotation (the coordinate origin is assumed to be the top-left corner).
    */
    double angleForCorrect(const cv::Vec4i& line)
    {
        Vec4i unitXVector(0, 0, 1, 0);
        double angle = angleOfLines(unitXVector, line);  // here angle belongs to [0, pi/2]
        // @attention: the increment direction of X and Y axis of OpenCV is different from usual rectangular coordinate system. The origin point is in the upper left corner of the image
        if (angle < 45)
        {
            // consider in the horizontal direction
            if (line[1] > line[3])
            {
                angle = -angle;
            }
        }
        else
        {
            // consider in the vertical direction
            if (line[1] > line[3])
            {
                angle = 90 - angle;
            }
            else
            {
                angle = angle - 90;
            }
        }
    
        return angle;
    }
    

        

     

    Step4:图像旋转。 
    根据上一步得到的倾斜角度,用以下函数旋转图片,校正倾斜。

    void rotateIamge(cv::Mat& src, cv::Mat& dst, double angle)
    {
        cv::Point2f center(src.cols / 2, src.rows / 2);
        cv::Mat rot = getRotationMatrix2D(center, angle, 1);
        cv::Rect box = RotatedRect(center, src.size(), angle).boundingRect(); // get circumscribed rectangle
        cv::warpAffine(src, dst, rot, box.size());
    }
    

        

    得到的图片做进一步的裁剪,得到仪表盘图片,利于下一步做指针式仪表识别。

         

    展开全文
  • 一种指针式仪表的识别方法杨世杰,张平【摘要】当前指针式仪表识别技术日益成熟,其中指针形状和位置的识别大多采用Hough变换算法,传统的Hough变换算法运算时间长、储存空间大,使得识别过程效率低下。针对以上缺点...

    一种指针式仪表的识别方法

    杨世杰,张

    【摘

    要】

    当前指针式仪表识别技术日益成熟,其中指针形状和位置的识别大多

    采用

    Hough

    变换算法,传统的

    Hough

    变换算法运算时间长、储存空间大,使

    得识别过程效率低下。针对以上缺点,提出一种改进型

    Hough

    变换。通过限

    定指针式仪表表盘环形区域、运用差影法确定指针的大致区域、指针通过表盘

    圆心这三个限制条件来缩减

    Hough

    变换扫描的范围,以此缩减

    Hough

    变换算

    法的存储空间和计算量。将改进型

    Hough

    变换算法与传统的

    Hough

    变换算法

    相比较,实验结果表明:改进型

    Hough

    变换可有效地减少算法运行时间,提

    高指针仪表识别的实时性。

    【期刊名称】

    微型机与应用

    【年

    (

    ),

    期】

    2017(036)017

    【总页数】

    3

    【关键词】

    指针识别;

    Hough

    变换;图像处理

    0

    引言

    由于指针式仪表具备性能可靠、工作原理简单、价格低廉、抗干扰能力强等优

    点,在日常生活和工业现场具有广泛的应用。目前大多数指针式仪表不具备数

    据接口,仪表显示数据的识别记录要靠人工来完成,由于人为因素,数据容易

    产生误差,此外有些环境恶劣的工业现场不适合人工抄表记录数据,因而研究

    实现指针式仪表显示数据的自动识别在一些工业现场具有重要的实用意义

    [1-2]

    指针的提取以及识别是指针式仪表数据自动识别的关键技术之一。针对指针的

    识别,已有很多成果。主要包括最小二乘法、传统的

    Hough

    直线变换法、减

    展开全文
  • 指针式仪表自动识别和读数

    万次阅读 多人点赞 2019-03-26 10:52:03
    指针式仪表自动识别和读数》系列文章 本系列文章是关于“指针式仪表的自动读数与识别”,主要内容包括仪表图像预处理、表盘定位、指针定位和读数等,并基于Hough变换(HT)、随机霍夫变换(RHT)等法方,提出了新的圆...

    前言的前言

    因原个人博客废弃,不再维护,防止文章丢失,遂迁移至此。

    鉴于大家对源码的需求较多,遂将源码上传。源码地址见文末。


    前言


    本系列文章是关于“指针式仪表的自动读数与识别”,也是我的毕业设计选题(其实是被选题,老师安排好的,没得选)。主要内容包括仪表图像预处理、表盘定位、指针定位和读数等,并基于Hough变换(HT)、随机霍夫变换(RHT)等法方,提出了新的圆检测以、直线检测以及模板匹配方法,最后用C#实现了一个仪表自动读数的系统。在论文中写的比较偏原理一点,那么在这里就写的偏实践或者说偏代码实现一点。

    本系列文章中使用的工具或者开源库有:

    图像处理库:EmguCV(OpenCV在.NET平台下的封装,用法和OpenCV一样)

    开发语言:C#(因为好写界面,而且对C++不熟,哈哈)

    开发工具:当然是VS了,VS 2017

    本文只是对本人毕设的一个总结,也是对在研究仪表读数过程中遇到的问题、遇到的好的文章或论文、一些方法以及调优的总结,并不涉及高深的算法或内容。


    文章目录

    指针式仪表自动读数与识别(一):前言

    指针式仪表自动读数与识别(二):仪表图像预处理

    指针式仪表自动读数与识别(三):圆形表盘定位

    指针式仪表自动读数与识别(四):非圆形表盘定位

    指针式仪表自动读数与识别(五):刻度线定位与拟合

    指针式仪表自动读数与识别(六):指针定位

    指针式仪表自动读数与识别(七):示数计算

    指针式仪表自动读数与识别(八):仪表自动读数系统设计与开发

    指针式仪表自动读数与识别(九):多仪表自动读数


    源码地址:https://gitee.com/xgpxg/PointerTypeInstrumentIdentification

    展开全文
  • 嵌入式环境指针式仪表快速识别算法研究,曲仁军,徐珍珍,论文在对已有的各种使用图像处理手段进行仪表指针识别方案进行研究的基础上,根据工控环境中指针式仪表所具有特点,设计了基于多
  • 指针式仪表的自动识别,图像处理与图像识别,利用matlab对真个过程进行仿真计算
  • MATLAB识别指针式仪表的示数,所用方法为距离法,经过试验,该方法可以较为准确的识别指针式仪表的示数,代码中有详细的备注,便于读者理解
  • 变电站指针式仪表检测与识别方法.pdf,受限于复杂的电磁环境,变电站中的大量模拟式仪表需要人工读取示数,不利于变电站自动化管理。而目前针对仪表自动读数方法的研究大多基于预先获取到的高质量图像,其中仪表目标...
  • 指针定位作为仪表识别读数识别的重中之重,其定位是否准确直接决定了最终的读数,因此,需要重点分析一下。本文首先介绍一下Hough直线检测的原理及不足之处,然后使用两种新的方法来定位指针:一种是环向模板匹配...

    指针定位作为仪表识别读数识别的重中之重,其定位是否准确直接决定了最终的读数,因此,需要重点分析一下。本文首先介绍一下Hough直线检测的原理及不足之处,然后使用两种新的方法来定位指针:一种是环向模板匹配法(CTM),另一种是径向灰度求和法(RGS),并通过测试来验证其准确性。

    Hough直线检测原理

    Hough直线检测的核心思想是:将在图像空间中的直线检测问题转换到参数空间中对点的检测问题,通过在参数空间里寻找峰值来确定直线。即,对于图像上的任意一点,计算经过该点的直线的可能的斜率(k)和截距(b),当遍历完所有图像上的点后,对k-b进行统计,选出出现次数最多的k-b,有了斜率和截距后就可以确定一条直线。但是由于直角坐标系中垂直x轴方向的直线的斜率不存在,因此需要转化为极坐标系来计算。

    其原理如下:

    对于直角坐标系中的任意一点A(x,y),经过点A的直线满足:

    y=kx+b

    那么在X-Y平面过点**A(x_0,y_0)**的直线簇可以表示为:

    y_0=kx_0+b

    则为了确定唯一的k值和b值,将其转化为参数空间ρ-θ,在极坐标系中表示为

    ρ=x_0×cos⁡θ+y_0×sin⁡θ

    则经过点**(x_0,y_0)的所有可能直线在ρ-θ平面内可用一条曲线表示,图像上的每一个点的所有可能直在ρ-θ**平面内就是一个曲线簇,如下图:

    理论上,一个点对应无数条直线,但在实际应用中,必须限定直线

    展开全文
  • 基于深度学习的指针式仪表自动识别的研究和设计,贺嘉琪,熊永平,随着科技的不断发展,工业信息化、数字化的不断提升,工业生产中对于传统的指针式仪表进行高效的、精确的数据录入变得尤为重要。
  • 基于颜色特征的指针式仪表视频监测识别,阳媛,张申,本文介绍了视频监测系统的功能,描述了针对指针式仪表的视频监测识别流程,并提出了基于几何形状和颜色特征的快速视频图片指针提
  • 巡检机器人中的指针式仪表读数识别系统.pdf,为了解决智能巡检机器人仪表读数识别中易受光照变化影响、识别精度不高等问题,结合高压变电场中常见指针区域的图像特点,建立了指针式仪表读数高精度识别系统。...
  • 指针式仪表的自动读数与识别前言概述步骤概括1.仪表图像预处理2.刻度线提取2.1轮廓查找2.2面积筛选,长宽比,距离2.3刻度线轮廓拟合直线3.指针轮廓提取3.1 霍夫直线检测原理4.结果5.Pyqt55.1功能测试总结检测程序 ...
  • 指针定位作为仪表识别读数识别的重中之重,其定位是否准确直接决定了最终的读数,因此,需要重点分析一下。本文首先介绍一下Hough直线检测的原理及不足之处,然后使用两种新的方法来定位指针:一种是环向模板匹配法...
  • Automatic Recognition of Dial Instrument Based on Deep LearningHE Jiaqi1贺嘉琪(1992-),男,硕士研究生,主要研究方向:计算机视觉、图像识别、机器学习XIONG Yongping1熊永平(1982-),男,副教授,博导,主要...
  • 指针式仪表自动读数与识别(一)

    千次阅读 热门讨论 2020-04-30 20:10:53
    本系列文章是关于“指针式仪表的自动读数与识别”,也是我的毕业设计选题(其实是被选题,老师安排好的,没得选)。主要内容包括仪表图像预处理、表盘定位、指针定位和读数等,并基于Hough变换(HT)、随机霍夫变换...
  • 深度学习的工业应用越来越广,最近用深度学习结合opencv 做了指针仪表识别,鲁棒性很棒,见图 。
  • 仪表自动读数系统是指通过机器视觉等图像处理方法,对摄像头采集到的指针式仪表进行分析,自动识别仪表示数的系统。其主要目的是代替人工读数,减小工作量,提高工作效率,同时能够实施反应设备的工作状态,让其处.....
  • 一、仪表图像预处理 1.预处理操作 在做任何图像处理相关操作之前都要先进行预处理。预处理操作包括: (1) 缩放和变换 缩放操作的主要目的是减小图像大小,减少计算量,缩放操作不是必须的,但是如果系统对输入图像的...
  • 考虑到由于有些仪表并不止一个表盘,所以在摄像头采集到的图像中,一张图像会 包含多个表盘,若是用多个摄像头去拍摄则得不偿失,所以我们使用划分区域的方式进行一个简单的区分,对不同的区域进行独立的检测和识别...
  • DSP通过对采集到的图像进行灰度变换、边沿检测以及Hough变换等处理后,实现对指针式仪表表盘的识别、指针定位和读数计算,以及指针读数的存储和传输。系统可通过串口实现组网测量与数据传输。FPGA接收DSP的指令,...
  • 仪表的最终读数,取决于表盘圆心、指针偏移其实刻度的角度以及量程。在确定表盘圆心、指针方向以及量程后,才可以通过指针偏移角度来计算示数。那这里很重要的一点就是计算起始/终止刻度的位置。 起始/终止刻度的...
  • 针对圆形仪表来说,表盘定位常用的方法是Hough圆检测。 Hough圆检测原理如下: 引用自百度百科: 通过在参数空间里进行简单的累加统计,然后在Hough参数空间寻找累加器峰值的方法检测圆或直线。Hough变换的实质是将...
  • 刻度在仪表自动读数中并不作为计算依据(起始和终止刻度除外),最终读数仅仅依赖指针、表盘位置以及量程,因此在求仪表刻度线时可以允许少量误差,这些误差不会对最终结果造成影响。 对于刻度线的拟合,本质上还是对...
  • 这些仪表没有明显的圆形表盘,因此无法通过直接Hough圆检测来定位表盘圆。观察仪表特点,可以发现虽然表盘不是圆形,但是表盘上的刻度均在同一个圆弧上,所以可以通过刻度线所在圆弧来确定圆弧所在圆的圆心和半径。...

空空如也

空空如也

1 2 3
收藏数 48
精华内容 19
关键字:

指针式仪表识别