罗兰谈MATLAB的艺术

将想法转化为MATLAB

请注意

罗兰谈MATLAB的艺术已退役,不会更新。

我的胡子一周能长多久?

一个令人费解的冒险故事。有点令人不快的故事。
今天的客座博主是Rob Holt,他在马萨诸塞州Natick的MathWorks工作。
Rob目前在MathWorks担任生物科学经理。他是生物学、生物技术和制药应用的协调员和合作者。在此之前,Rob在Konica Minolta公司Invicro担任了五年的高级科学家,在那里他设计、实现和交流了药物发现和开发的图像分析算法。Rob在达特茅斯学院获得博士学位,在那里他专注于通过多模态医学图像合成进行分子癌症成像。继续关注Robÿs的更多滑稽动作 他的推特 而且 他的LinkedIn
上个周末我在修胡子。当我因为缺少计算设备而神游时,我在想“我的胡子长得有多快?”这是我无法消除的想法之一。所以我开始计划。
我想我可以让它生长一个月,然后用尺子测量,但这样我可能就不得不从刮得干干净净变成蓬头垢面,牺牲了我所保留的专业精神。
然后灵感来了。修剪胡子,让它生长整整一周,然后把胡子修剪成同样的长度。如果我们有一张修剪过的头发的图片,并且图片中的某些东西是已知大小的,我们可以提取某种长度信息。辉煌!

阅读并显示图像

%加载图像
imname =“mySink.jpg”
Im = imread(imname);
图;
imshow (im);
标题(原始图像的);
注意,视野中有一个便士。我把它扔进水槽的原因是一便士的直径被定义为19.05毫米。这可以作为稍后确定像素大小的已知参考。这也是我能负担得起的。

使用便士获得像素大小

这个函数 imfindcircles 可用于在视场中查找圆形物体。注意,我对半径范围有一个粗略的估计,因为硬币比背景暗,我们将物体的极性设置为暗。
裁剪关于便士的图片
pennyImage = im(1400:1800,1000:1500,:);
稍微过滤一下硬币图像。
pennyImageFilt = medfilt3(pennyImage,[15 15 1]);
%使用imfindcircles函数找到硬币
Radrange = [100 300];
[centers, radii] = imfindcircles(pennyImageFilt,radrange,...
“ObjectPolarity”“黑暗”);
可视化所有找到的圆
图;
imshow (pennyImage)
viscircles(中心、半径、“EdgeColor”“b”);
标题(“带有圆圈注释的便士细节”);
从硬币的半径计算像素大小
%使用毫米直径/像素直径
pSize = 19.05/(半径(1)*2);%像素大小(单位:mm)
流('像素大小为%d微米\n'而圆(pSize * 1000))
像素大小为62微米

分割头发

现在我们有了像素大小,我们可以分割毛发并尝试找出它们的长度。为了使事情更简单,让我们裁剪出一个只有头发的部分。
justHair = im(500:1800,1500:3000,:);
图;
次要情节(121)
imshow (justHair);
标题(“只是头发”);
次要情节(122)
imshow (justHair (150:500,900:1350:));
标题(“头发细节”);
现在我们需要从背景中分割头发。因为头发是黑色的,背景是白色的,这是相当直接的。这也可以在灰度图像上完成,因为颜色并没有真正地为这个任务添加任何信息。
grayHair = rgb2gray(justHair);
图;
次要情节(121)
imshow (grayHair);
标题(《我的白发》);
次要情节(122)
imshow (grayHair (150:500,900:1350))
标题(《白发细部》);
希望这是我未来几年里唯一的一根白头发。
现在我们可以使用经典的大津阈值,它根据强度自动将图像分为两类。这可以使用命令来完成 graythresh ,它确定了根据强度将两类分开的阈值,以及 imbinarize ,它使用该阈值生成二值图像。
thresh = graythresh(grayHair);
hairSeg = ~ imbinalize (grayHair,thresh);
图;
次要情节(121)
imshow (hairSeg);
标题(“头发分割”);
次要情节(122)
imshow (hairSeg (150:500,900:1350));
标题(“头发分割细节”
在这种情况下, imbinarize 使明亮的部分为真,所以 就是顺理成章地把它翻过来做成头发的一部分 hairSeg ,对头发的分割,待 真正的

尽量保持头发不结块

现在我们有了所有的毛发。其中一些是簇状的,但大多数看起来是独立的。对于第一次评估,让我们删除较大的集群,以及较小的集群,留下大部分独特的毛发。
除去边缘被剪掉的毛发。
hairSeg = imclearborder(hairSeg);
%删除任何太小的集群
hairSeg = bwareaopen(hairSeg,30);
%移除太大的集群
hairSeg = hairSeg & ~ bwareaopen(hairSeg,300);
图;
次要情节(121)
imshow (hairSeg)
标题(“检查头发长度”);
次要情节(122)
imshow (hairSeg (150:500,900:1350))
标题(“头发长度检查细节”);

估计所有毛发的长度

我们现在有一份最好的毛发切片供我们检查。要估计它们的长度,我们首先要做的是骨架化(使每根头发最多一个像素宽),然后计算每根骨架化头发中的像素。这是使用属性“area”完成的,但由于每根头发都是一个像素宽,所以面积大致等于头发的长度。
把头发做成骨架
hairSkel = bwskel(hairSeg);
%显示骨架
图;
次要情节(121)
imshow (hairSkel);
标题(“头发骨架化”);
次要情节(122)
imshow (hairSkel (150:500,900:1350));
标题(“头发骨架化细节”);
计算所有毛发的长度
stats = regionprops(hairSkel,“区域”);
从结构中得到区域
hairLengthInPixels = cat(1,stats.Area);
%转换为真实世界的长度
hairLength = hairLengthInPixels*pSize;

计算平均头发长度

现在我们有了所有毛发长度的列表。因此,我们可以可视化直方图以及计算平均长度。
图;
直方图(hairLength);
包含(“头发长度(毫米)”);
ylabel (“头发数量”);
meanHairLength = mean(hairLength);
流('平均头发长度:%.1fmm\n', meanHairLength);
平均头发长度:2.2mm

总结与讨论

就是这样!我的胡子每周长2.2毫米,每天长0.31毫米。这非常接近 吉列的估计是每天0.27毫米
当然,这个模型并不完美。长度计算可以更准确地为每根头发拟合曲线。如果我们能找到一种方法来分离更多更大的毛发,分割就会更准确。但对于大多数实际目的,这是一个很好的估计值。
这种工作流程也可以应用于其他图像处理方案。例如,在生命科学研究中测量毛毛虫或蠕虫的长度,或在工业制造质量控制中测量碎片长度。
你最近在做什么奇怪的项目吗?你们知道可以用MATLAB来解决这类问题吗?你觉得我胡子的高分辨率照片不合适吗?请在评论中分享你的想法和观点 在这里
The MathWorks, Inc.版权所有
|