正文之前
最近新开了一门课,我十分感兴趣,或者是说老早就想接触类似方面的学习,但是一直没有真正着手,所以说,其实上课还是很有必要的,很多时候你想做的事情但是你根本没法开始,所以需要一个推动力,当一点点的作业加上完成学分的压力压在你的肩头,配合你早就蓄势待发的兴趣使然,就会爆发很大的热情去学习。就好比这门,机器视觉与图像处理技术, 我很感兴趣,所以昨天坐火车的时候我都在火车上把我们这门课的第一次作业做出来了。
正文
我们的第一次作业,是把下图中的这个风扇扇叶一个叶片的角度计算出来。
我一开始还苦思冥想,不知道怎么才能提取出来这个因素,所以很是烦恼不知道该如何是好,但是昨天看了下群里面的说法,我瞬间就理通了。只要转变下思维,把图像看成一个二维数组配上每个元素的大小不同代表着颜色深浅的想法就好了
他已经做到了这一步,剩下的就是不知道如何处理这个图形的元素,但是,我虽然目前还是个菜鸡,但是我好歹也是要念计算机的博士的人啊!!!怎么会被这种小问题难到??不存在的!!下面请看我的表演:
然后,想法有了。手段也有了。对数组的处理,尤其是一堆的只是bool量的二维数组,简直不要太简单好么?都不需要for嵌套了,直接取两个X坐标作为定值定量的检测这两行的数据,不就好了?下面是那位同学的想法:
:我觉得,这样是给自己增加了工作量,反而让matlab变轻松了啊。怎么能这样呢?不存在的!!所以还是直接让matlab去计算吧,直接用两点确定一条直线的方式,给两条直线分别求出来斜率,然后在视觉的绝对坐标系下转化为角度,最后就得到咯~~:
这之间还发生了一个小插曲,那就是我给我的MATLAB爸爸跪舔的时候,直接被打脸了
这脸打的啪啪响!!
所以,最后这就是我的代码咯~~
pic=imread('/Users/zhangzhaobo/program/MATLAB/First_work_angles.jpg'); %读取照片作为一个对象读入matlab 而不是简单的打开bw=im2bw(pic); % 我们需要的不是一个RGB图像,而是一个二值化图像就好了。至于什么是二值化,就是说黑白照咯,一个像素点,要不就是黑的要不就是白的,所以就很好整!!bw=edge(bw,'canny'); % 边缘提取,一个一直困扰我的地方,因为我还没看到这些点!%下面的变量分别就是我取点的列数,至于Y1 Y2 就是行数,因为读取出来的图像有点问题first_dot1=0;first_dot2=0;second_dot1=0;second_dot1=0;Y1=400;Y2=450;% 从400行第一个点到第2440个点,分别取值,为了防止噪声干扰,我还特意的给了一个范围以及限制。for i=1:2440 if 700<1600 if bw(Y1,i)==1 if first_dot1>0 second_dot1=i else first_dot1=i end end endend% 从450行第一个点到第2440个点,分别取值,为了防止噪声干扰,我还特意的给了一个范围以及限制。for i=1:2440 if 700<1600 if bw(Y2,i)==1 if first_dot2>0 second_dot2=i else first_dot2=i end end endend%算出斜率,然后斜率转为角度,最后角度之差就是叶片的角度啦!XieLv1=(first_dot1-first_dot2)/(Y1-Y2)XieLv2=(second_dot1-second_dot2)/(Y1-Y2)Angle=atan(XieLv1)*180/pi-atan(XieLv2)*180/pi复制代码
我知道肯定还有很多可以优化的地方,但是目前来说么。实现了测试角度就好了么~~我现在在小妹子这儿的图书馆陪她过双十一,美滋滋啊,图书馆人好多,但是排插好少,而且灯光是昏黄的,让人想睡觉!中评吧!
最后得出来的角度是44.4190°
之后我也测试了别的行数的数据,基本是形成了45°左右的正态分布,至于更大的数据,我就懒得算了,其实也可以写个小函数,统计下各个行数的时候会形成很多个值,然后求个平均 mean就好了!
还别说,偏差真的很大,我在想要不要真的写个统计函数,然后画个图给老师看?搞不好有加分?
或者把很多点存起来,来个线性回归分析???but ,我还是先看书吧,这些都是随便查得到的东西,就先不玩了!反正还没到交作业的时候不是。
正文之后
有木有人要资源啊,matlab的或者别的都行哦,我现在看不完了。mmp,感觉自己真是个盗版文化的传播者,but这些都是老掉牙的东西了。最新的都是2013的书了。再不找点人看估计都会灭绝吧!
书名我都给你准备好了。就怕你搜不到~
(PS:当然,上面都是没法下载的,只是给你看看简介而已,要的点了喜欢后评论发邮箱,不过分吧?~~)
=========修改版========
Find_Angle.m
function [y]=Find_Angle(Y1,Y2,bw)%下面省略的原因是一开始只准备测试一个角度,所以就单纯的在一个m文件里面导入对象,后来需要另外封装下传入边缘检测后的bw对象作为实参%pic=imread('/Users/zhangzhaobo/program/MATLAB/First_work_angles.jpg');% bw=im2bw(pic);% bw=edge(bw,'canny'); % 按照我的四点构成两直线的做法,下面分别是四个点的列数,行数在形参中传入first_dot1=0;first_dot2=0;second_dot1=0;second_dot2=0;% 遍历给定行所有的item,然后查找400-1300之间的元素(取点不可能在此范围外),取两点for i=1:1600 if (400 < i) && (i < 1300) if bw(Y1,i)==1 if first_dot1>0 % 如果已经取过第一个点;那么就取第二个同一行内的点 second_dot1=i; else first_dot1=i; % 如果没有取过第一个点,那么就记录第一个点 end end endend% 相同步骤取第二行中的数据for i=1:1600 if (400 < i) && (i < 1300) if bw(Y2,i)==1 if first_dot2>0 second_dot2=i; else first_dot2=i; end end endend% 直接两点求斜率XieLv1=(first_dot1-first_dot2)/(Y1-Y2);XieLv2=(second_dot1-second_dot2)/(Y1-Y2);% 绝对坐标系中由斜率算出绝对角度,然后相减得到相对角度Angle=atan(XieLv1)*180/pi-atan(XieLv2)*180/pi;% 判断Angle是否合理,配合调用此函数的内容可以进行筛选if (Angle>49) || (Angle<43) y=0;else y=Angle;end复制代码
Average.m
function [angle]=Average(pic) % 此函数用于求同一个扇叶的多次取点求直线夹角的过程angle=0; %初始化角度count=0; % 计数,用于最后的求平均for i=(380:450) % 我取 400行到500行之间的两行,间隔最小20 最大50 ,间隔步长为2 for j=(20:2:50) if Find_Angle(i,i+j,pic)==0 % 如果求出很大偏差的角度,直接剔除 continue; else angle=angle+Find_Angle(i,i+j,pic); count=count+1; end endendangle=angle/count; % 求平均,完成一个扇叶的角度平均 1050次复制代码
Find_4_Angles.m
clear; % 这个是总函数,类似于main 所以事前清除其他变量很有必要。%读取对象并且进行最有阈值的筛选,二值化,边缘提取,删掉边缘利于旋转叶片pic=imread('First_work_angles.jpg');thresh=graythresh(pic);bw=im2bw(pic,thresh);bw=edge(bw,'canny'); BW=bw(100:1700,420:2020);%建立角度数组,存储四个叶片的角度Angle=[0,0,0,0];%每次求得角度后转过90°再次求平均值for i = 0:3 BW=imrotate(BW,i*90); Angle(i+1)=Average(BW);end% 精度精确至3位有效数组,即0.1°digits(3)Angles=vpa(Angle,3)复制代码
文件结构如图:
运行的时候直接输入Find_4_Angles即可!