极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 10707|回复: 12

瓶子液体装满与否判断opencv3.0

[复制链接]
发表于 2015-10-23 12:47:40 | 显示全部楼层 |阅读模式
本帖最后由 血阳 于 2019-8-15 20:54 编辑

处理一个题目,先把题目描述一遍吧:
       一家使用瓶子盛装各种工业化学药品的公司雇佣你来设计一种检测瓶子未装满的方法。瓶子在传送带上移动并通过自动装填和封盖机时的情形如图所示。当液位低于瓶颈底部和盘子肩部的中间点时,则认为瓶子未装满。瓶子横断面的侧面与倾斜面的区域定义为瓶子的肩部。瓶子在不断移动,但该公司有一个成像系统,该系统装备了一个前端照明闪光灯,可有效地停止瓶子的移动,所以你可以得到非常接近于下图显示的样例图像。基于上述资料,请你提出一个检测未完全装满瓶子的解决方案,编程实现该算法。

原图

原图

最后结果图:

个人思路:思路比较简单,就是找出瓶子上方的白色区域,然后再找到他们轮廓,找到连通区域,对区域面积进行判断,对于满足要求的地方(瓶未满)上色,其他地方删除,最后与原图叠加就行。
不多说,上程序:
#include&#160;<opencv2/opencv.hpp>
#include&#160;<iostream>
#include&#160;<string>
using&#160;namespace&#160;cv;
using&#160;namespace&#160;std;
int main()
{
        Mat&#160;img,&#160;grayimg,dstimg;
        Mat&#160;cannyimg,openimg1;
        vector<vector< Point>>&#160;contours;
        vector<Vec4i>&#160;hierarchy;
        int h, w;
        int a[6] = { 0 }, b = 0;
        img=&#160;imread("1.jpg");                       //读取图片
        imshow("原图",img);                        //显示原图
        cvtColor(img,&#160;grayimg,&#160;COLOR_BGR2GRAY);&#160;&#160;&#160;&#160;//将图片转化为灰度图
        imshow("灰度图",grayimg);                  //显示灰度图
        blur(grayimg,&#160;grayimg,&#160;Size(9,&#160;9));&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;//对图片进行平滑处理
        imshow("平滑处理后的灰度图",grayimg);      //显示平滑处理后的灰度图
        Mat&#160;element&#160;=&#160;getStructuringElement(MORPH_RECT,&#160;Size(15,&#160;15));
        morphologyEx(grayimg,&#160;openimg1,&#160;MORPH_OPEN,&#160;element);&#160;// 对图片进行开运算
        imshow("开运算图",openimg1);  ///显示开运算后的图
        dstimg.create(openimg1.size(),openimg1.type());  //创建一个和开运算图片一样大小,类型的矩阵

&#160;&#160;&#160;&#160;/////下面是对图片进行二值化处理(二值化就是把有灰度的图直接转换为黑白图)
        uchar&#160;*p&#160;=&#160;openimg1.data;&#160;&#160;//定义一个指针,指向图片矩阵第一个元素
        h&#160;=&#160;openimg1.rows;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;//赋值图片的高给h
        w&#160;=&#160;openimg1.cols;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;//赋值图片的宽给w
        for (unsigned int i = 0; i < h*w; i++)  //遍历图片所有元素
        {
                if (*p >170)
                {
                        *p&#160;=&#160;255;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;//对于元素值大于170的赋值给元素255,即为白色
                }
                else *p = 0;             //其他情况,设为黑色
                *p++;
        }
        imshow("二值图",openimg1);
        ////////////////////////////

        /////设置一个相框
        uchar&#160;*q&#160;=&#160;dstimg.data;
        for (unsigned int i=0; i < h; i++)
        {
                if (i < 5||i>h-5)
                {
                        for (unsigned int j = 0; j < w; j++)
                        {
                                *q&#160;=&#160;0;
                                *q++;
                        }
                }
                else
                {
                        for (unsigned int n = 0; n < w; n++)
                        {
                                if (n<5 || n>w - 5) *q = 0;
                                else *q = 1;
                                *q++;
                        }
                }
        }
        //imshow("creat",dstimg);
        /////用相框与处理的开运算图进行叠加
        uchar&#160;*pa&#160;=&#160;openimg1.data;
        uchar&#160;*qa&#160;=&#160;dstimg.data;
        for (unsigned int i = 0; i < w*h; i++)
        {
                *pa&#160;=&#160;(*pa)*(*qa);
                *pa++;
                *qa++;
        }
        imshow("加相框图",openimg1);
        Canny(openimg1,cannyimg,3,9,3);&#160;&#160;&#160;///对图片进行边缘检测
        imshow("边缘检测", cannyimg);     //显示边缘检测的图结果

        findContours(cannyimg,&#160;contours,&#160;hierarchy,&#160;RETR_EXTERNAL,&#160;CHAIN_APPROX_SIMPLE,Point(0,&#160;0));&#160;&#160;//提取图片轮廓
        Mat&#160;drawing&#160;=&#160;Mat::zeros(cannyimg.size(),CV_8UC3);  //定义一个三通道的和原图尺寸一样大小的矩阵,方便上色

        printf("图片尺寸为高h=%d    宽w=%d    \n", h, w);
        for (unsigned int i = 0; i < contours.size(); i++)  //遍历连通区域的个数
        {
                if (contourArea(contours[i] ) > 10000)        // 判断连通区域的面积是否大于10000
                {
                        Scalar&#160;color&#160;=&#160;Scalar(255,&#160;255,&#160;0);&#160;&#160;&#160;&#160;&#160;//定义一个颜色
                        drawContours(drawing,&#160;contours,&#160;i,&#160;color,&#160;FILLED,&#160;8,&#160;hierarchy,&#160;0,&#160; Point());&#160;//对于满足要求的区域进行填充颜色
                }
                else
                {
                        Scalar&#160;color=Scalar(0,0,0);&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;//定义黑色
                        drawContours(drawing,&#160;contours,&#160;i,&#160;color,2,&#160;8,&#160;hierarchy,&#160;0,&#160; Point());&#160;&#160;//对不满足要求的区域删除(元素值全部为零,黑色)
                }
        }&#160;&#160;&#160;//最后会得到一个只有不满足要求区域的图
        imshow("提取后的图",drawing); //显示上面操作所得到的图
        drawing&#160;=&#160;img&#160;-&#160;drawing;&#160;&#160;&#160;&#160;//用原图减去处理说得的图即可标记处相应的区域
        imshow("最终结果", drawing);  //显示最终结果

        waitKey(0);
}

最后,给上整个过程中出现的图吧:
这是灰度图:

灰度图

灰度图

这是灰度图开运算后的图:

开运算图

开运算图

这是二值图:

二值图

二值图

这是加了一个边界相框后的图:

加相框图

加相框图

这是边缘检测图:

边缘检测

边缘检测

这是提取轮廓,并排除其他,给特征轮廓上色的图:

提取后的图

提取后的图

最后这是结果图:


回复

使用道具 举报

发表于 2015-10-23 13:07:54 | 显示全部楼层
赞,我也想学opencv
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-10-23 13:14:52 | 显示全部楼层
davidce 发表于 2015-10-23 13:07
赞,我也想学opencv

opencv不难,就是一个函数库。有编程基础的学一学就会,主要是知道里面的函数,然后会一些方法就可以入门了。
回复 支持 反对

使用道具 举报

发表于 2015-10-23 17:43:04 | 显示全部楼层
这个图的背景是怎么处理掉的?
回复 支持 反对

使用道具 举报

发表于 2015-10-23 18:22:25 | 显示全部楼层
用一排光敏电阻,对面发出均匀强光。瓶子从光和电阻中间穿过。不满的阻值和满的阻值相差较大,一下子就分辨出来了……
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-10-23 22:05:53 | 显示全部楼层
hp198969 发表于 2015-10-23 18:22
用一排光敏电阻,对面发出均匀强光。瓶子从光和电阻中间穿过。不满的阻值和满的阻值相差较大,一下子就分辨 ...

呃……我写这个的主要目的不是在通过什么方法能更好地解决这个问题。
最主要的目的是练习opencv。学习opencv。
你说的方法当然好啦,只是我们的目的不一样罢啦。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-10-23 22:10:00 | 显示全部楼层
davidce 发表于 2015-10-23 17:43
这个图的背景是怎么处理掉的?

什么意思?图的背景?不就是黑色的吗?
回复 支持 反对

使用道具 举报

发表于 2015-10-24 10:06:47 | 显示全部楼层
哇~~~~有高手在写OPENCV耶。。。本菜最近也是刚刚接触,好强大的说
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-10-24 10:49:05 | 显示全部楼层
迷你强 发表于 2015-10-24 10:06
哇~~~~有高手在写OPENCV耶。。。本菜最近也是刚刚接触,好强大的说

{:2_39:}我也是菜鸟一只,只是花了点时间了解了几个函数的意思并且应用而已o(╯□╰)o。。。opencv学习之路还很漫长啊。。。。
回复 支持 反对

使用道具 举报

发表于 2015-10-24 13:43:21 | 显示全部楼层
是用PROCESSING来做的么
回复 支持 反对

使用道具 举报

发表于 2015-10-24 17:00:23 | 显示全部楼层
这个比较牛!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-10-24 22:27:21 | 显示全部楼层
mikeliujia 发表于 2015-10-24 17:00
这个比较牛!

我也还只是个菜鸟。还需要学习。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-10-24 22:30:40 | 显示全部楼层
darkorigin 发表于 2015-10-24 13:43
是用PROCESSING来做的么

用的是opencv3.0做的,编译器的VS2013.
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|联系我们|极客工坊 ( 浙ICP备09023225号 )

GMT+8, 2020-9-23 18:16 , Processed in 0.054004 second(s), 27 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表