本帖最后由 血阳 于 2019-8-15 20:54 编辑
处理一个题目,先把题目描述一遍吧:
一家使用瓶子盛装各种工业化学药品的公司雇佣你来设计一种检测瓶子未装满的方法。瓶子在传送带上移动并通过自动装填和封盖机时的情形如图所示。当液位低于瓶颈底部和盘子肩部的中间点时,则认为瓶子未装满。瓶子横断面的侧面与倾斜面的区域定义为瓶子的肩部。瓶子在不断移动,但该公司有一个成像系统,该系统装备了一个前端照明闪光灯,可有效地停止瓶子的移动,所以你可以得到非常接近于下图显示的样例图像。基于上述资料,请你提出一个检测未完全装满瓶子的解决方案,编程实现该算法。
最后结果图:
个人思路:思路比较简单,就是找出瓶子上方的白色区域,然后再找到他们轮廓,找到连通区域,对区域面积进行判断,对于满足要求的地方(瓶未满)上色,其他地方删除,最后与原图叠加就行。
不多说,上程序: #include <opencv2/opencv.hpp>
#include <iostream>
#include <string>
using namespace cv;
using namespace std;
int main()
{
Mat img, grayimg,dstimg;
Mat cannyimg,openimg1;
vector<vector< Point>> contours;
vector<Vec4i> hierarchy;
int h, w;
int a[6] = { 0 }, b = 0;
img= imread("1.jpg"); //读取图片
imshow("原图",img); //显示原图
cvtColor(img, grayimg, COLOR_BGR2GRAY);    //将图片转化为灰度图
imshow("灰度图",grayimg); //显示灰度图
blur(grayimg, grayimg, Size(9, 9));        //对图片进行平滑处理
imshow("平滑处理后的灰度图",grayimg); //显示平滑处理后的灰度图
Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));
morphologyEx(grayimg, openimg1, MORPH_OPEN, element); // 对图片进行开运算
imshow("开运算图",openimg1); ///显示开运算后的图
dstimg.create(openimg1.size(),openimg1.type()); //创建一个和开运算图片一样大小,类型的矩阵
    /////下面是对图片进行二值化处理(二值化就是把有灰度的图直接转换为黑白图)
uchar *p = openimg1.data;  //定义一个指针,指向图片矩阵第一个元素
h = openimg1.rows;        //赋值图片的高给h
w = openimg1.cols;        //赋值图片的宽给w
for (unsigned int i = 0; i < h*w; i++) //遍历图片所有元素
{
if (*p >170)
{
*p = 255;             //对于元素值大于170的赋值给元素255,即为白色
}
else *p = 0; //其他情况,设为黑色
*p++;
}
imshow("二值图",openimg1);
////////////////////////////
/////设置一个相框
uchar *q = 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 = 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 *pa = openimg1.data;
uchar *qa = dstimg.data;
for (unsigned int i = 0; i < w*h; i++)
{
*pa = (*pa)*(*qa);
*pa++;
*qa++;
}
imshow("加相框图",openimg1);
Canny(openimg1,cannyimg,3,9,3);   ///对图片进行边缘检测
imshow("边缘检测", cannyimg); //显示边缘检测的图结果
findContours(cannyimg, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE,Point(0, 0));  //提取图片轮廓
Mat drawing = 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 color = Scalar(255, 255, 0);     //定义一个颜色
drawContours(drawing, contours, i, color, FILLED, 8, hierarchy, 0,  Point()); //对于满足要求的区域进行填充颜色
}
else
{
Scalar color=Scalar(0,0,0);            //定义黑色
drawContours(drawing, contours, i, color,2, 8, hierarchy, 0,  Point());  //对不满足要求的区域删除(元素值全部为零,黑色)
}
}   //最后会得到一个只有不满足要求区域的图
imshow("提取后的图",drawing); //显示上面操作所得到的图
drawing = img - drawing;    //用原图减去处理说得的图即可标记处相应的区域
imshow("最终结果", drawing); //显示最终结果
waitKey(0);
}
最后,给上整个过程中出现的图吧:
这是灰度图:
这是灰度图开运算后的图:
这是二值图:
这是加了一个边界相框后的图:
这是边缘检测图:
这是提取轮廓,并排除其他,给特征轮廓上色的图:
最后这是结果图:
|