前两天看了一篇硕士学位论文,但是在知网上被引用了13次,下载了700多次。是相关主题中相对最有价值的一篇论文。
论文题目:细胞图像的分割与计数
作者:王筱(xiao)艳(四川大学)生物医学工程专业,生物医学图像研究方向
论文设计了一个软件,可以进行细胞图像的分割、自动识别、统计分析的功能。高效准确且使用方便。
在我看完这篇论文后,我发现最重要的是她解决了链式粘连以及非链式粘连细胞的分割。
在这里主要说她利用线长直方图估计等效直径这个想法十分出彩。
轮到我自己进行实践的时候,也想到提取线长直方图,结果发现网上所有有关opencv直方图提取的全是灰度直方图。。。
这就很恼火,所以我准备自己写一个。
首先了解一下线长直方图(以线段长度为横轴,以线长出现的次数为纵轴。)
粘连越严重的细胞图像,其线长直方图最高峰越往右移,因此通过最高峰估计出来的等效直径要根据粘连严重程度做一个修正,这个修正值应该凭经验选择。这里就不管什么修正了。
重点是实现:
以下为代码:
void my_Hist(Mat Gray_img){
//绘制直方图图像
int hist_height=500;
double max_val=500; //直方图的最大值
int scale = 2; //直方图的宽度
int hist[500] = {0};
// at方法遍历图片
int data=0;
int length=0;//长度计数
for(int i=0;i<Gray_img.rows;i++) //遍历行
{
for(int j=0;j<Gray_img.cols;j++) //遍历列
{
data = Gray_img.at<uchar>(i,j);
if(data!=0)
length++;
else
{
if(length!=0)
{
hist[length]++;
length=0;
}
}
}
length=0;
}
/*for(int p=0;p<80;p++)
cout<<hist[p]<<endl;*/
max_val=max(hist,500);
Mat hist_img = Mat::zeros(hist_height,500*scale, CV_8UC3); //创建一个直方图图像并初始化为0
int bin_val=0;int intensity=0;
//在直方图图像中写入直方图数据
for(int i=0;i<500;i++)
{
bin_val = hist[i]; // 第i灰度级上的数
intensity = cvRound(bin_val*hist_height/max_val); //要绘制的高度
//填充第i灰度级的数据
rectangle(hist_img,Point(i*scale,hist_height-1),
Point((i+1)*scale - 1, hist_height - intensity),
CV_RGB(255,255,255));
}
imshow( "Histogram", hist_img );
imwrite("Histogram.bmp", hist_img);
}
我在写这部分代码的时候,借鉴了灰度直方图显示直方图图片的方法,用一维数组代替了原本的MatND格式的hist,成功实现了横向线长直方图的提取。
至于怎么调用这段代码只需要当作一个函数调用就好了,输入是Mat的灰度图
以下是原图以及结果图
2017.3.31加:
后来添加了纵向上线段长度的统计,也就是把上面行列顺序换一下,效果好了不少。
接下来考虑了统计方法进行优化,比如每五个取均值之类的,能够让效果好很多。图就懒得放了。