[blog 项目实战派]压板识别项目分析

压板识别项目

零、相关说明:

首先进行一下相关说明。在“jsxyhelu.cnblogs.com/项目实战派”栏目里面出现的需求、图片和其他资源,都是我在浏览威客网站、论坛等网站的时候通过正规渠道获得的真实需求。个人觉得比较感兴趣,但是由于时间或者工作的冲突自己没有去接这些项目。但是由于这些需求都很有实现价值,所以过了一段时间,仍然拿出来练一练手,并且实现了核心模块。希望能够给浏览者一些启发。如果你认为这些图片和资源放在这里不合适,请及时联系我([email protected]),我会及时处理的。此外,我会将核心代码和技术细节尽可能将清楚,我认为这样才是最有价值的方式。如果需要原始代码,也可以和我联系。

一、原始需求/图片:

1.图片为保护压板正常方式投入,要求图像识别能正确判断,并将保护压板投退状态显示出来。

2.保护压板漏投(误投),要求图像识别能发现报警,并显示出是哪些保护压板漏投。

3.保护压板有投退异常现象,要求图像识别能发现报警,并显示出是哪些保护压板异常。

4.通过保护盘二维码(或条形码),要能识别出来保护盘柜名称

(正常情况下的图片)

(存在问题的图片1)

(存在问题的图片2)

二、初步分析:

其实需求主要是两个方面,一个是识别出压板的情况,二个是识别条码。

2.1识别压板:

常见的图像初步处理(换色彩域->OSTU->投影分析),对于初始的三幅图像,都能够得到比较干净的结果。但是这种情况过于理想了,在实

际项目中,需要考虑到由于其他原因引起的噪音,可能需要采用一定的方法去除噪音。此外,第5和第9个开关,采用的是和背景颜色比

较接近的压板,在实际项目中容易混乱,但是这个结果是原始需求直接关注的结果,可能要采用其他方法来强化  。

(预处理结果)

(投影运算结果)

   

////第一个部分,获得各个压板区域的位置////

//经过ostu运算,得到质量比较好的图像
    threshold(matSplit[1],ostu,100,255,THRESH_OTSU);
    dstclone = ostu.clone();
    // 做竖直的投影。这里由于更关心截断的情况,而不关心具体升降,所以是画出截断线而不是画波形
    for (int i=0;i<ostu.cols;i++)
    {
        Mat data = ostu.col(i);
        int itmp = countNonZero(data);
        vectorV.push_back(itmp);
    }
    //上波形为VUpper,下波形为VDown
    for (int i=1;i<vectorV.size();i++)
    {
        if (vectorV[i-1] == 0 && vectorV[i]>0)
        {
            VUpper.push_back(i);
        }
        if (vectorV[i-1]>0 && vectorV[i] == 0)
        {
            VDown.push_back(i);
        }
    }
    
    //计算结果
    for (int i=0;i<VUpper.size();i++)
    {
        Mat roitmp = ostu(Rect(VUpper[i],0,VDown[i]-VUpper[i],ostu.rows));
        dilate(roitmp,roitmp,Mat());//对ostu的结果适当膨胀
        int uppertimes = 0;
        for (int j=0;j<ostu.rows;j++)
        {
            Mat data = roitmp.row(j);
            int itmp = countNonZero(data);
            vectorH.push_back(itmp);
        }
        for (int j=0;j<vectorH.size()-1;j++)
        {   
            if (vectorH[j]>0 && vectorH[j+1] == 0)
            {
                HDower.push_back(j);
            }
            if (vectorH[j] == 0 && vectorH[j+1]>0)
            {
                HUpper.push_back(j);
            }
        }
        if (HUpper.size() <= 1)
        {
            result[i] = 1;
            //printf("结果为连在一起的\n");
        }
        else
        {   
            int iresult = 0;
            for (int j=0;j<HDower.size()-1;j++)
            {
                //得出之间空白的区域
                int iwidth = HUpper[j+1] - HDower[j];
                if (iwidth > 10)
                {
                    iresult = iresult +1;
                }
            }
            if (iresult > 0 )
            {
                result[i] = 0;
               // printf("结果为断开的\n");
            }
            else
            {
                result[i] = 1;
                //printf("结果为连在一起的\n");
            }
            iresult = 0;
        }
        vectorH.clear();
        HUpper.clear();
        HDower.clear();
        uppertimes = 0;
    }

    2.2条码识别:

一般条码识别都依赖于现有的库(包括二维码,可以参考以前写过的一篇‘单向图像信息传输系统’和‘ZXing一维二维编码解码‘),图像处理方面需要做的主要是把条码区域抠出来。由于条码它本身在设计的时候就是在竖直方向具备了冗余性,所以可以根据这个特性,采用形态学的方法将需要的区域采集出来。

(canny处理并且经过形态学强化)

(最终取出来的结果)

(条码解码)

////第二个部分,获得条码区域////

Mat sobel;

Mat canny;

Mat canny_output;

int imax = 0;

int imaxcontour = -1;

std::vector<std::vector<cv::Point>>contours;

Mat cannyClone= Mat::zeros(Size(gray.cols,gray.rows),gray.type());

Canny(gray,canny,100,255);

Mat element = getStructuringElement(MORPH_ELLIPSE,Size(7,3));

morphologyEx(canny,canny,CV_MOP_DILATE,element);

morphologyEx(canny,canny,CV_MOP_ERODE ,element);

findContours(canny,contours,CV_RETR_TREE,CV_CHAIN_APPROX_NONE);

for (int i=0;i<contours.size();i++)

{

int itmp =  contourArea(contours[i]);

if (imaxcontour < itmp )

{

imax = i;

imaxcontour = itmp;

}

}

//找到轮廓的处理

Rect boundRect;//最小外接矩形

drawContours(cannyClone,contours,imax,Scalar(255),-1);

boundRect = boundingRect(Mat(contours[imax]));

Mat srcRoi = src(boundRect);

imwrite("barcode.jpg",srcRoi);

三、难点攻关:

3.1第5和第9压板的特殊情况。

由于第5和第9压板的颜色和背景颜色非常接近,所以采用特殊的方法来进行处理。通过观察,结合常理。压板打开之后,必然带来的结果就

是下垂并且将下面的字符牌遮挡。那么可以通过反过来判断字符牌是否被遮盖来判断压板是否被打了下来。

    

(字符遮挡)

//将第5和第9条单独取出来

Mat roi05 = src(Rect(6*VUpper[4],0,6*(VDown[4]-VUpper[4]),src.rows));

Mat roi09 = src(Rect(6*VUpper[8],0,6*(VDown[8]-VUpper[8]),src.rows));

cvtColor(roi05,roi05,CV_BGR2GRAY);

cvtColor(roi09,roi09,CV_BGR2GRAY);

threshold(roi05,roi05,100,255,THRESH_OTSU);

threshold(roi09,roi09,100,255,THRESH_OTSU);

threshold(roi05,roi05,0,255,THRESH_BINARY_INV);

threshold(roi09,roi09,0,255,THRESH_BINARY_INV);

std::vector<std::vector<cv::Point>>contours2;

findContours(roi05,contours2,CV_RETR_LIST,CV_CHAIN_APPROX_SIMPLE);

int imax2 = 0;

int imaxcontour2 = -1;

for (int i=0;i<contours2.size();i++)

{

int itmp =  contourArea(contours2[i]);

if (imaxcontour2 < itmp )

{

imax2 = i;

imaxcontour2 = itmp;

}

}

Rect boundRect2;//最小外接矩形

boundRect2 = boundingRect(Mat(contours2[imax2]));

if (boundRect2.y+boundRect2.height >750)

{

//printf("第5个为打开的\n");

result[4] = 0;

}

else

{

//printf("第5个为关闭的\n");

result[4] = 1;

}

contours2.clear();

findContours(roi09,contours2,CV_RETR_LIST,CV_CHAIN_APPROX_SIMPLE);

imax2 = 0;

imaxcontour2 = -1;

for (int i=0;i<contours2.size();i++)

{

int itmp =  contourArea(contours2[i]);

if (imaxcontour2 < itmp )

{

imax2 = i;

imaxcontour2 = itmp;

}

}

boundRect2 = boundingRect(Mat(contours2[imax2]));

if (boundRect2.y+boundRect2.height >750)

{

//printf("第9个为打开的\n");

result[8] = 0;

}

else

{

//printf("第9个为关闭的\n");

result[8] = 1;

}

3.2倾斜情况下,条码识别错误

受到摄像头分辨率的限制,使得图像中条形码在倾斜的时候,受到插值算法的影响,边缘变得模糊。虽然尝试了许多方法,但是都无法达到

能够让zxing识别的程度。这个问题不知道哪位有更好的方法,如果可以的话,希望能够告之。

四、系统集成:

由于目前还没有很好地将zxing集成到mfc的环境中来。由于我对“csharp通过dll方式调用console程序”比较熟悉,所以这里尝试采用的是"csharp通过程序调用console的形式"。也就是主要图像处理的部分还是写的console程序,并且运算出相应的结果和图片,而后在csharp的程序中合并得到最后的结果。过程中发现这种方法的问题还是比较多的,包括参数的传递、程序重复运行时的控制等,应该说不是一种很成熟的方法,在以后面对类似的问题的时候,最好是能够直接将代码集成到mfc中,否则就要采用“csharp通过dll方式调用console程序”的方式。

最后的结果如下,并且可以多次测试都没有问题:

五、设计小结:

工作完成了,那么除了对代码进行重构并且提取出可以被重复使用的函数外,对于思路的小结也非常重要。在本例中:

5.1 提出了具有创造性的一个想法:采取分析下面的字符牌是否被遮挡的方式来判断开关闭合情况。逆向思维取得了稳定的结果;

5.2 对于色彩空间转换、对于投影的灵活运用构成了识别的主体。

不足的地方

5.3 对于一维/二维码识别没有构建稳定的库或解决方案,现在使用的zxing可以解决一部分问题,但是不过不了解原理,遇到不能解决的问题就无法继续优化;目前提取条码的方法应该被提出出来。

5.4 验证了"csharp通过程序调用console的形式"是不合算的。

来自为知笔记(Wiz)

时间: 2024-08-01 10:44:57

[blog 项目实战派]压板识别项目分析的相关文章

[blog 项目实战派]钢管识别项目1

钢管识别项目1 零.相关说明: 首先进行一下相关说明.在"jsxyhelu.cnblogs.com/项目实战派"栏目里面出现的需求.图片和其他资源,都是我在浏览威客网站.论坛等网站的时候通过正规渠道获得的真实需求.个人觉得比较感兴趣,但是由于时间或者工作的冲突自己没有去接这些项目.但是由于这些需求都很有实现价值,所以过了一段时间,仍然拿出来练一练手,并且实现了核心模块.希望能够给浏览者一些启发.如果你认为这些图片和资源放在这里不合适,请及时联系我([email protected]),

[blog 项目实战派]钢管识别项目2

钢管识别项目2 零.相关说明: 首先进行一下相关说明.在"jsxyhelu.cnblogs.com/项目实战派"栏目里面出现的需求.图片和其他资源,都是我在浏览威客网站.论坛等网站的时候通过正规渠道获得的真实需求.个人觉得比较感兴趣,但是由于时间或者工作的冲突自己没有去接这些项目.但是由于这些需求都很有实现价值,所以过了一段时间,仍然拿出来练一练手,并且实现了核心模块.希望能够给浏览者一些启发.如果你认为这些图片和资源放在这里不合适,请及时联系我([email protected]),

[blog 项目实战派]csharp通过dll调用opencv函数

[blog 项目实战派]opencv通过dll调用matlab函数,图片作为参数 前文介绍了如何“csharp通过dll调用opencv函数,图片作为参数”.而在实际的代码编写过程中,很多时候想把已经写好的matlab函数融合进去,但是依然是将图片作为参数传递比较成为问题.这里我经过一段时间的研究解决了这个问题(目前只解决了灰度图片下的图片传递问题).这个问题包含几个难点,一个是mxmatrix的使用,一个是matlab和opencv对于图片的格式处理是不一样的. 本次这个项目,是opencv通

[blog 项目实战派]csharp通过dll调用opencv函数,图片作为参数

?一直想做着方面的研究,但是因为这个方面的知识过于小众,也是由于自己找资料的能力比较弱,知道今天才找到了比较好的资料.一个是thinimage,一个是basework,里面都实现了这里的“csharp通过dll调用opencv函数,并且采用图片作为参数”.这里小结如下. 关于如何“csharp通过dll调用opencv函数”,请参考前面博文,这里主要说如何“采用图片为参数”. 在编写图像识别/增强/机器视觉等项目的时候,一般会将算法打包成dll文件给客户,如果界面是用mfc写的话,是很好实现这个

【项目实战派】触摸屏程序设计要点

[项目实战派]触摸屏程序设计要点            触摸屏作为一种更为直接的人机交互方式,现在广泛运用于智能手机.工业控制.场景展示等许多场合.作为程序员,如何理解触摸屏程序设计?如何做好的触摸屏程序设计?现在已经有的资源包括那些?借着项目牵引,我对这个问题进行一定探索,经验有限,欢迎批评交流. 一.如何理解触摸屏程序设计 操作系统层面已经实现了基础功能,基于触摸屏的界面,从本质上来说和普通的GuI界面是没有区别的.程序的界面设计需要服务于程序的功能,为客户提供直观.易用.体验效果较好的界面

【项目实战派】图像处理项目硬件选型

[项目实战派]图像处理项目的硬件平台选型 一直以来我都对嵌入式系统比较感兴趣,因为感到图像处理最终还是要走向便携式.移动化的.这里讲自己对图像处理项目的硬件平台选型这块的想法进行交流,欢迎交流.批评. 一.典型图像处理系统构建 ①相机与镜头--这部分属于成像器件,通常的视觉系统都是由一套或者多套这样的成像系统组成,如果有多路相机,可能由图像卡切换来获取图像数据,也可能由同步控制同时获取多相机通道的数据.根据应用的需要相机可能是输出标准的单色视频(RS-170/CCIR).复合信号(Y/C).RG

机器学习进阶-项目实战-信用卡数字识别 1.cv2.findContour(找出轮廓) 2.cv2.boudingRect(轮廓外接矩阵位置) 3.cv2.threshold(图片二值化操作) 4.cv2.MORPH_TOPHAT(礼帽运算突出线条) 5.cv2.MORPH_CLOSE(闭运算图片内部膨胀) 6. cv2.resize(改变图像大小) 7.cv2.putText(在图片上放上文本)

7. cv2.putText(img, text, loc, text_font, font_scale, color, linestick) # 参数说明:img表示输入图片,text表示需要填写的文本str格式,loc表示文本在图中的位置,font_size可以使用cv2.FONT_HERSHEY_SIMPLEX, font_scale表示文本的规格,color表示文本颜色,linestick表示线条大小 信用卡数字识别: 信用卡      数字模板涉及到的内容:主要是采用模板匹配的思想 思

[项目实战派]花40分钟写一个-CBIR引擎-代码公开

浏览网页的时候发现一篇不错的文章"用Python和OpenCV创建一个图片搜索引擎的完整指南"http://python.jobbole.com/80860/.作者在浏览自己旅游的照片的时候,发现照片太多了分类不过来,一时技痒写了个分类软件,虽然简单但是有用.关键的是我发现他在原文中使用了半个小时就写出来了. 蛮快的嘛,我想.那么我要用多长时间写出来了,毕竟对于CBIR也是研究过的. 那么立即来做,首先我要找到是图片.我没有那么多旅游图片(汗),但是别人的照片也是可以一样用的.找到了之

人脸识别完整项目实战(14):实时人脸特征点标定程序设计

一.前言 本文是<人脸识别完整项目实战>系列博文第14章<实时人脸特征点标定程序设计>,本章内容详细介绍Win10 环境下,基于Visual Studio 2015 + Opencv + Dlib开发环境,如何实现实时视频流人脸特征点标定程序的设计.本文内容已经同步录制成视频课程,课程地址:<人脸识别完整项目实战> 二.正文 2.1 界面设计 人脸特征点标定程序沿用之前的界面设计,新增人脸特征点标定按钮,界面设计如下图所示: 2.2 执行结果 人脸特征点标定程序运行后,