我的胡子一周能长多久?
一个令人费解的冒险故事。有点令人不快的故事。
今天的客座博主是Rob Holt,他在马萨诸塞州Natick的MathWorks工作。
Rob目前在MathWorks担任生物科学经理。他是生物学、生物技术和制药应用的协调员和合作者。在此之前,Rob在Konica Minolta公司Invicro担任了五年的高级科学家,在那里他设计、实现和交流了药物发现和开发的图像分析算法。Rob在达特茅斯学院获得博士学位,在那里他专注于通过多模态医学图像合成进行分子癌症成像。继续关注Robÿs的更多滑稽动作
他的推特
而且
他的LinkedIn
.
上个周末我在修胡子。当我因为缺少计算设备而神游时,我在想“我的胡子长得有多快?”这是我无法消除的想法之一。所以我开始计划。
我想我可以让它生长一个月,然后用尺子测量,但这样我可能就不得不从刮得干干净净变成蓬头垢面,牺牲了我所保留的专业精神。
然后灵感来了。修剪胡子,让它生长整整一周,然后把胡子修剪成同样的长度。如果我们有一张修剪过的头发的图片,并且图片中的某些东西是已知大小的,我们可以提取某种长度信息。辉煌!
阅读并显示图像
%加载图像
imname =“mySink.jpg”;
Im = imread(imname);
图;
imshow (im);
标题(原始图像的);
注意,视野中有一个便士。我把它扔进水槽的原因是一便士的直径被定义为19.05毫米。这可以作为稍后确定像素大小的已知参考。这也是我能负担得起的。
使用便士获得像素大小
裁剪关于便士的图片
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))
分割头发
现在我们有了像素大小,我们可以分割毛发并尝试找出它们的长度。为了使事情更简单,让我们裁剪出一个只有头发的部分。
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))
标题(《白发细部》);
希望这是我未来几年里唯一的一根白头发。
thresh = graythresh(grayHair);
hairSeg = ~ imbinalize (grayHair,thresh);
图;
次要情节(121)
imshow (hairSeg);
标题(“头发分割”);
次要情节(122)
imshow (hairSeg (150:500,900:1350));
标题(“头发分割细节”)
尽量保持头发不结块
现在我们有了所有的毛发。其中一些是簇状的,但大多数看起来是独立的。对于第一次评估,让我们删除较大的集群,以及较小的集群,留下大部分独特的毛发。
除去边缘被剪掉的毛发。
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);
总结与讨论
当然,这个模型并不完美。长度计算可以更准确地为每根头发拟合曲线。如果我们能找到一种方法来分离更多更大的毛发,分割就会更准确。但对于大多数实际目的,这是一个很好的估计值。
这种工作流程也可以应用于其他图像处理方案。例如,在生命科学研究中测量毛毛虫或蠕虫的长度,或在工业制造质量控制中测量碎片长度。
The MathWorks, Inc.版权所有