一种清淤机器人分拣识别系统的C/Python语言实现

Part 1.项目背景

许多城市历史悠久,排水系统老旧、结构复杂,在暴雨频发的时期,因破损或淤积不畅,造成城市道路内涝频发,不仅对交通造成严重阻塞,还大大增加了发生安全事故的风险。人工清淤工作环境恶劣,在排水管道内存在毒气、尖锐杂物等不可控的危险因素,因此,能取代人工操作进行清淤工作的清淤机器人的应用前景广泛而需求迫切。本课程设计对清淤机器人的图像识别与淤积物分拣技术进行研究,以软件的形式实现对硬质积淤物和有色垃圾的分拣处理,达到减少清淤仪器损害并高效、低成本清淤的目的。

Part 2.整体设计

本清淤机器人的用途为检查小口径管道内部情况(通过传感器和图像识别技术反馈有毒气体、内部淤积物形态、管道结构等信息),将其运动方向前方的淤积物铲入机身,在机身内将淤积物进行初步拆解分散,识别易沉积、体积较大的固体物质(如石块、泥沙集团),并将其分拣入存储室内,将易流通的杂质(如可溶有机物、细小泥沙)排至机器人运动方向的后方。待机器人走向另一端井口时,工作人员将其取上地面,然后对管道剩余淤积物进行冲刷,在机器人的存储室经过清理后方可继续使用。

机器人大致结构图如下所示,手绘较丑,可以凑合看看(说来惭愧,初中差点走上美术生的道路):

一种清淤机器人分拣识别系统的C/Python语言实现_第1张图片

然后让同组的Partner用CAD画了一张正经点的图:

一种清淤机器人分拣识别系统的C/Python语言实现_第2张图片

OK,机器人到手了,可以开始干活了,本文主要讲解机器人检测横截面为方形或者可以近似方形的下水管道的横截面积,系统根据横截面积大小,结合工作人员(软件用户)对积淤物分拣的要求(指令)进行分拣,对硬质积淤物含量和白色垃圾含量在设定分拣范围内的积淤物分拣入机器人存储室内,对含量不在设定分拣范围内的积淤物直接排放回管道。

刚开始接触这份课设,本想将题目定为基于深度学习的分拣识别系统(名字高大上,看起来牛逼),然后基于图像识别,使用深度学习技术找出符合要求的积淤物特征,然后通过训练、拟合……(老方法啦)。然鹅,对于我们课设所关注的硬质积淤物,上面往往覆盖油污、泥土等物质,怎么能够通过视觉的方式去检测呢?对于有色垃圾,尤其是城市排水管道常见的有色塑料袋,在混杂与其他积淤物的情况下,形态都是未知数,即使是人脸,如果只用一张照片作为训练集,想通过同一个人不同夸张表情的照片确定他的身份,也是有难度的,更何况垃圾的形态跟人的表情相比,更是千奇百怪,难以捕捉特征。

一种清淤机器人分拣识别系统的C/Python语言实现_第3张图片

所以,最终选定的方案无需使用深度学习这么麻烦 ,系统也是越简单越好:

首先是测量工作:清淤机器人中部有摄像机,它具有接收光学信息的作用,定义机器人进入的垂直管道口一端为始端,机器人走过行径路线之后被工作人员捞取的垂直管道口为终端。当机器人进入始端的横向管道口后,工作人员在终端管道口插入一个激光发射装置,如图所示,在发出激光后,若清淤机器人的摄像头没有接收到光源信息,则说明管道存在高度超过管道半径50%的堆积物,将此信息和有毒有害气体监测信息传给地面工作人员,工作人员可根据摄像头拍摄到的管道具体情况酌情发送指令给机器人,让其继续操作或者停止操作。若清淤机器人可接收激光信息,则说明管道不存在高度超过管道半径50%的堆积物,工作人员使用机械装置将堵塞装置塞入始端和末端的横向管道,避免流入污水和淤积物干扰清理工作。

一种清淤机器人分拣识别系统的C/Python语言实现_第4张图片

1).大型硬质积淤物(砖头、钢筋等)的识别:基于接触式传感识别方法,采用的传感器是一个矩形板,板上附有密集的弹簧击针,传感器位于机身顶面,在积淤物进入机身后,传感器向下压积淤物,直至压至最大限度,若是软质物,弹簧击针很少发生弹性形变,而硬质物会使弹簧击针发生较大形变。记录传感器每个弹簧击针该次下压所得到的最大形变位移(硬物高度),多个弹簧击针所组成的形状即为硬物俯视图面积,由此,可计算出硬物的体积,若淤积物中硬物体积偏大,则将此次收集到的积淤物通过机械臂推入分拣物存储器;体积小则可忽视存在硬物的因素。使用这种类似蒙特卡洛法的检测手段,不仅可大致得到整体的硬物体积信息,同时,也具有松散泥沙的作用,有助于被排出泥沙的高压冲洗工作。

一种清淤机器人分拣识别系统的C/Python语言实现_第5张图片

2).白色垃圾(有色塑料袋等)的识别:仅有淤泥、石块等天然物质的淤积物颜色往往呈褐色、黑色、灰色或土黄色,而塑料袋、瓶罐包装等塑料制品会因消费美观的营销考量,被设计为色彩丰富的亮色,如红色、蛋黄色、蓝色、绿色等,对于非自然物带有的特征颜色,将它们转化为RGB值范围。在机身上方四周布置白光照射装置,淤积物反射光线到摄像装置形成图像,读取图像每个像素的RGB值,若其RGB值在特征颜色的RGB值范围,考虑到噪声干扰,符合特征颜色的像素还要具有面积大的特点时,才能认定含有塑料垃圾,若在大型淤积物识别时未将积淤物推入存储室,则将此次收集的淤积物分拣入存储室。 

Part 3.C语言代码实战

上文已写出大致设计思路,但我们还需要一个模型去模拟积淤物的形态特性,考虑到正态分布有极其广泛的实际背景,生产与科学实验中很多随机变量的概率分布都可以近似地用正态分布来描述,因此我们采用高斯(正态)分布模型对单位面积硬质积淤物的高度进行随机模拟。首先上场的是我们的C语言,下面参照这个博客的老哥写的高斯分布随机数生成函数:

https://blog.csdn.net/z_feng12489/article/details/102861094?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522160662342719724818076376%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=160662342719724818076376&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~baidu_landing_v2~default-3-102861094.pc_v2_rank_blog_default&utm_term=C%E8%AF%AD%E8%A8%80%E7%94%9F%E6%88%90%E6%AD%A3%E6%80%81%E5%88%86%E5%B8%83

这个博客上的高斯函数代码写的非常好,美中不足的是,您在不改变期望值、标准差的前提下多次运行后会发现——数据咋都是一样哒???其实是因为这位老哥忘了使用种子随机数,随着程序运行时间的不同而产生不同随机数,我们在写C语言代码的时候要加上。

首先放上头文件,声明高斯模型的两个子函数,声明两个宏定义——矩形传感器上的击针点分布是40*50的,对应矩形板尺寸是40cm*50cm,即每个传感击针负责1cm^2单位面积的检测

#include
#include
#include
#include
const int N = 40; //宽边取40个单位检测点
const int n = 50; //长边取50个单位检测点
float gaussrand_NORMAL();
float gaussrand(float Ex, float sigma);

OK,准备把机器人放入管道了,进入管道前,清淤机器人内部弹簧压缩至最小,进入管道后,弹簧伸长至机器人上下滑动轮分别紧贴管道上下内壁 ,根据弹簧伸展情况,测量机器人分拣室高度h,加上机器人外壳的高度30cm,则管道的高度为(30+h)cm。然后用机器人内在的红外激光测量仪测量管道宽度和管道长度(在程序中使用随机数模拟),并将测量结果传输给地面工作人员。

int main(){
	srand((unsigned)time(NULL));//设定种子随机数,使随机数随时间改变
	//分拣室具体高度h往往为浮点数,取20cm<=h<=50cm
	float h = 20.0+(rand()%3)*10+rand()%10+(rand()%10)/(float)10+(rand()%10)/(float)100;
	//管道宽度40cm<=wide<70cm
	float wide = 40.0+(rand()%3)*10+rand()%10+(rand()%10)/(float)10+(rand()%10)/(float)100;
	//用随机数模拟机器人分拣室高度h,20cm<=h<50cm
	float length = 1000.0+(rand()%2)*1000+(rand()%10)*100+(rand()%10)*10+rand()%10+(rand()%10)/(float)10+(rand()%10)/(float)100;
	//管道长度10m<=length<30m 
	printf("———----—-—管道数据——-—----—---\n"); 
	printf("分拣室高度:%.3f cm\n",h);
	printf("管道长度:%.3f cm\n",length);
	printf("管道高度:%.3f cm\n",h + 30.0); //管道高度=分拣室高度+30cm
	printf("管道宽度:%.3f cm\n",wide);
	printf("管道横截面积:%.3f cm^2\n",(h + 30.0)*wide);
	float V = 0.0; //初始化硬物总体积
	//单位面积为1cm^2

一种清淤机器人分拣识别系统的C/Python语言实现_第6张图片

然后,先列一下刚才提到的高斯分布生成随机数函数,值得注意的是,这两个函数是写在main函数外面的:

float gaussrand_NORMAL() {
	static float V1, V2, S;
	static int phase = 0;
	float X;
	if (phase == 0) {
		do {
			float U1 = (float) rand() / RAND_MAX;
			float U2 = (float) rand() / RAND_MAX;
			V1 = 2 * U1 - 1;
			V2 = 2 * U2 - 1;
			S = V1 * V1 + V2 * V2;
		} while (S >= 1 || S == 0);
		X = V1 * sqrt(-2 * log(S) / S);
	} else
		X = V2 * sqrt(-2 * log(S) / S);
	phase = 1 - phase;
	return X;
}
float gaussrand(float Ex, float sigma) {
	return Ex + gaussrand_NORMAL() * sigma;
}

基于这两个函数,系统用户可以选择直接让计算机模拟正态分布,或者用户手动输入期望值(硬质积淤物平均高度)和标准差值,计算机根据用户设定的参数运行。既然符合正态分布,那么模拟的过程中总会有负数或者超出分拣室高度的数字吧?不必担心,首先,系统里有防呆措施,即如果所输的期望值超出当前符合实际的范围,系统会提醒用户“输入错误,请重新输入!”,对于生成的所有随机数,均会在取绝对值后,取分拣室高度(强制转化为int型)余数,这样就保证了模拟结果均在实际范围内。

printf("———----—-—模型参数——-—----—---\n");
	//生成符合高斯分布、期望值为Ex、标准差为sigma、长度为N*n的一维数组Z
	bool Foolproof = false; //防呆判别变量
	int choice;
	float Ex,sigma; //期望值,标准差 
	printf("请选择模拟方式:\n1.计算机模拟 2.手动输入数据\n");
	scanf("%d",&choice); 
	if(choice==1){
		Ex = 20.0+(rand()%2)*10+rand()%10+(rand()%10)/(float)10+(rand()%10)/(float)100; //Ex在20~40之间取随机值
		sigma = rand()%10+(rand()%10)/(float)10+(rand()%10)/(float)100; //sigma在0~10之间取随机值
    	printf("期望值Ex:%.3f\n",Ex);
    	printf("标准差sigma:%.3f\n",sigma);
	}
	else{
		while(Foolproof==false){
    	    printf("请输入硬质积淤物高度期望值(<=h):");
            scanf("%f",&Ex);
            if(Ex < 0.0||Ex > h)printf("输入错误,请重新输入!\n");
            else Foolproof = true;
	    }
	    printf("请输入标准差值:");
	    scanf("%f",&sigma);
	} 
	Foolproof = false;//初始化

 1).全程由计算机模拟:

一种清淤机器人分拣识别系统的C/Python语言实现_第7张图片

2).用户手动输入数据:

一种清淤机器人分拣识别系统的C/Python语言实现_第8张图片

由于使用Dev C++并无法将数据可视化,因此我们将运行结果导入一个很常用的数据库中——EXCEL表格:

//按照计算机随机值或用户输入参数进行模拟
	float Z[N][n]; //生成的图像中Z轴高度,即每个检测点检测到的硬质积淤物高度 
	FILE *fp;
	fp=fopen("积淤物数据采集.xls","w");
	for(int i=0; i

打开cpp文件同一目录下的文档/桌面,选择“积淤物数据采集.xls”文件:

打开后全选里面的数据,插入图表,考虑到可视化程度,推荐选择以下2种图表:

1).三维直方图:

一种清淤机器人分拣识别系统的C/Python语言实现_第9张图片

2). 三维曲面图:

一种清淤机器人分拣识别系统的C/Python语言实现_第10张图片

 最后,用户输入分拣条件:

printf("———----—请输入分拣条件———----—\n");
    float scale,h_max; 
    while(Foolproof == false){
    	printf("直接排放的体积占比上限(0.0~1.0):");
    	scanf("%f",&scale);
    	if(scale >= 0.0 && scale <= 1.0)Foolproof = true;
        else printf("输入错误,请重新输入!\n");
	}
    Foolproof = false; //初始化
    //考虑到某些硬物体积小但长度大的情况
    while(Foolproof == false){
    	printf("允许直接排放的最大高度:");
    	scanf("%f",&h_max);
    	if(h_max >= 0.0 && h_max <= h)Foolproof = true;
        else printf("输入错误,请重新输入!\n");
	}

同样,当用户输入参数时,系统都会有防呆措施: 

一种清淤机器人分拣识别系统的C/Python语言实现_第11张图片

最后,根据用户要求的分拣条件,机器人选择将积淤物分拣入存储室,或者直接将积淤物排放至其行进方向的后方。

    printf("———----—-—处理方案———----—-—\n");
    bool Judge = false; //判断条件,True表示分拣入室,False表示直接排放
    for(int i=0;i= (h+30) *wide *N *scale)Judge = true;
	      //硬物最大高度小于设定高度界限,且硬物体积占比小于管道横截面积*机器人分拣室长度*设定比重 
    if(Judge == true)printf("分拣入室\n");
    else printf("直接排放\n"); //硬质淤积物体积占管道比例过小,不至于造成阻塞则直接排放
    return 0;
}

 1).直接将积淤物排放至其行进方向的后方:

 2).将积淤物分拣入存储室:

Part 4.Python语言代码实战

C语言运行是蛮快的,但复杂程度也比脚本语言高很多,比如生成符合高斯分布的随机数时,Python直接可以省略那30多行函数代码,直接调用函数几行代码就能解决。更何况,本渣使用的C语言IDE并无法实现读取图像RGB值的功能,还是不得不使用Python。

首先,将刚才的硬质积淤物分拣程序直接放上吧,思路基本一致,不过绘图不必导入EXCEL那么麻烦,直接导入matplotlib库的绘图函数Axes3D,然后将X、Y、Z轴检测到的高度点数组作为形参传入函数,接着加一句plt.show()就能画出散点图。考虑到散点图的看起来比较散乱,因此我们对分拣室高度的0~1/3、1/3~2/3、2/3~3/3分别采用黄色、蓝色、红色进行标记,将可视化的效果变得更好。在程序运行过程中会弹出散点图,若想继续执行程序,关闭散点图弹框即可。

一种清淤机器人分拣识别系统的C/Python语言实现_第12张图片

 

import random
import numpy as np
#进入管道前,清淤机器人内部弹簧压缩至最小
#进入管道后,弹簧伸长至机器人上下滑动轮分别紧贴管道上下内壁 
#根据弹簧伸展情况,测量机器人分拣室高度h
#分拣室具体高度h往往为浮点数,取20cm<=h<=50cm
h=random.uniform(20.0,50.0) #分拣室高度
wide=random.uniform(40.0,70.0) #管道宽度
length=random.uniform(1000.0,3000.0)
print("———----—-—管道数据——-—----—---")
print("管道长度:",round(length,3),"cm")
print("分拣室高度:",round(h,3),"cm")
print("管道高度:",round(h,3)+30.0,"cm") #管道高度=分拣室高度+30cm
print("管道横截面积:",round(length*(round(h,3)+30.0),3),"cm")
V = 0.0 #初始化硬物总体积
N = 40 #宽边取40个单位检测点
n = 50 #长边取50个单位检测点
#单位面积为1cm^2
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
#定义坐标轴
fig = plt.figure()
ax1 = plt.axes(projection='3d')
#定义三维数据
X = np.zeros(N*n)
Y = np.zeros(n*N)
Z = np.zeros(N*n)
k=0
for i in range(0, N, 1):
    for j in range(0, n, 1):
        X[k] = i
        k=k+1
k=0
for i in range(0, N, 1):
    for j in range(0, n, 1):
        Y[k] = j
        k=k+1
print("———----—-—模型参数——-—----—---")
#生成符合高斯分布、期望值为Ex、标准差为sigma、长度为N*n的一维数组Z
Foolproof = False #防呆判别变量
print("请选择模拟方式:1.计算机模拟 2.手动输入数据")
choice = int(input())
if choice == 1:
    Ex = random.uniform(20.0, h) #Ex在20~40之间取随机值
    print("期望值Ex:",round(Ex,3))
    sigma = random.uniform(0, 10.0) #sigma在0~10之间取随机值
    print("标准差sigma:",round(sigma,3))
else:
    while Foolproof == False:
        Ex = float(input("请输入硬质积淤物高度期望值(<=h):"))
        if Ex < 0.0 or Ex > h:
            print("输入错误,请重新输入!")
        else:
            Foolproof = True
    sigma = float(input("请输入标准差值:"))
Foolproof = False #初始化
#按照计算机随机值或用户输入参数进行模拟
Z = np.random.normal(Ex,sigma,N*n)%int(h) + np.random.randn(N*n)%10/10
#生成的高度值收敛于50
print("———----—积淤物形态模型———----—")
#单位面积所检测到的硬物高度Z收敛于h
#作图
for i in range(0, N*n, 1):
    if Z[i]= 0.0 and scale <= 1.0:
        Foolproof = True
    else:
        print("输入错误,请重新输入!")
Foolproof = False #初始化
#硬质淤积物体积占管道比例过小,不至于造成阻塞则直接排放
while Foolproof == False:
    h_max = float(input("允许直接排放的最大高度:"))
    if h_max >= 0.0 and h_max <= h:
        Foolproof = True
    else:
        print("输入错误,请重新输入!")
#考虑到某些硬物体积小但长度大的情况
print("———----—-—处理方案———----—-—")
Judge = False #判断条件,True表示分拣入室,False表示直接排放
for i in range(0, N*n, 1):
    if h_max < Z[i]:
        Judge = True
if V >= (h+30) * wide * scale: #管道高度=分拣室高度+30cm
    Judge = True
if Judge == True:
    print("分拣入室")
else:
    print("直接排放")

一种清淤机器人分拣识别系统的C/Python语言实现_第13张图片

接着,就要加上识别白色垃圾的代码了,本文不直接提供白色垃圾的识别代码,给读者更多的发挥空间去思考程序设计方案。识别的大致思路可谓朴实无华且枯燥:对色彩鲜艳的颜色,如红色、蛋黄色、蓝色、绿色等非自然物带有的特征颜色,读取图像的每个像素的RGB值,若像素值在这些特征颜色的像素值范围,则纳入统计,若统计出来的“人造颜色”像素数量与图片总像素量之比足够大,则可以排除出现这些颜色是因为噪声干扰等原因,从而将该次识别结果判定为“白色垃圾”占比过大,并将积淤物分拣入存储室而不直接排放。

可以参考处理图像RGB值的博客:

C++版本:Opencv图像处理:判断图片里某个颜色值占的比例_xiaolong1126626497的专栏-CSDN博客

Python版本:Python3 识别判断图片主要颜色,提取指定颜色的方法_python深度学习笔记,一起学习的加QQ2737499951-CSDN博客_python颜色识别

最后,感谢耐心观看,祝所有阅读者快乐且暴富QAQ~

你可能感兴趣的:(测试技术)