?本文主要使用Hough变换的方法提取图片中圆形信息。
主要使用了matlab中的imfindcircles函数,功能参数详见其文档。
1)当 radius(或 rmin)的值小于或等于 5 时,imfindcircles 的准确度会受到限制;
2)imfindcircles 找不到圆心位于图像区域之外的圆形;
3)imfindcircles 会预处理二值(逻辑值)图像以提高结果的准确度。在处理真彩色图像之前,它使用 rgb2gray 函数将其转换为灰度图像。
%此程序用来识别和跟踪视频中的颗粒及其轨迹
%% 读取图片信息
% %test;
% RGB= imread('F:\desktop\轨迹熵\实验\目标检测跟踪\granule4.png');
% imshow(RGB)
% 将视频拆解成图片;
video = VideoReader('E:\20220326\125-2fps.avi');
N_Frames = video.NumFrames; %得到帧数
H = video.Height; %得到高度
W = video.Width; %得到宽度
Rate = video.FrameRate;
% Preallocate movie structure.
% mov(1:nFrames) = struct('cdata',zeros(H,W,3,'uint8'),'colormap',[]);
%read one frame every time
% for i = 1:1000
% mov(i).cdata = read(video,i);
% RGB= mov(i).cdata;
% % disp('当前播帧数:'),disp(i);
% % imshow(RGB);
% end
% 由于不需要存储每张图片,所以不需要mov结构来储存数据;
%待将此处化为循环结构;
%
% %test
% i=1156805;
% RGB=read(video,i);
% bw=imbinarize(RGB,'global'); %由于图片本来就是灰度图,直接转为二值图;
% %此处为了提高后续的识别成功率;
% %虽然多出此步骤,但是由于为二值函数,imfindcircles函数的速率也加快,速度总体与之前基本持平;
% bw=bwareaopen(bw,60); %去掉连通像素小于60的区域;
%
% %注意在识别之前,需要先取一个很大的半径范围,进而确认目标是在哪个范围之内,缩小范围,进而节省上述手动划线过程;
% %如果被识别的颗粒直径有变化需要修改此参数!!!!!!!!!!!!!!!
% Rmin = 7;
% Rmax = 16;
% [center, radius]=imfindcircles(bw,[Rmin Rmax],'Sensitivity',0.9,'ObjectPolarity','bright'); %调节ObjectPolarity属性可以实现对不同颜色的区分;
% imshow(bw);
% h=viscircles(center,radius); %显示圆形轮廓;
immatrix=imshow(bw); %将图片化为数值矩阵;
fid_position=fopen('E:\20220326\125-2fps_position.txt','w');
fid_problem=fopen('E:\20220326\125-2fps_position_problem.txt','w');
tic
for i=376841:1:739966
RGB=read(video,i);
bw=imbinarize(RGB,'global'); %由于图片本来就是灰度图,直接转为二值图;
%此处为了提高后续的识别成功率;
%虽然多出此步骤,但是由于为二值函数,imfindcircles函数的速率也加快,速度总体与之前基本持平;
bw=bwareaopen(bw,60); %去掉连通像素小于60的区域;
%注意在识别之前,需要先取一个很大的半径范围,进而确认目标是在哪个范围之内,缩小范围,进而节省上述手动划线过程;
%如果被识别的颗粒直径有变化需要修改此参数!!!!!!!!!!!!!!!
Rmin = 7;
Rmax = 16;
[center, radius]=imfindcircles(bw,[Rmin Rmax],'Sensitivity',0.9,'ObjectPolarity','bright'); %调节ObjectPolarity属性可以实现对不同颜色的区分;
%此处sensitivity的值在0.9附近对结果影响很敏感,0.9为一经验值;
% disp(i);
if length(center)==10
for j=1:1:10
fprintf(fid_position,'%15.10f %15.10f\n',center(j,:));
end
elseif length(center)>10
disp('oh no');
% imshow(bw);
% h=viscircles(center,radius); %显示圆形轮廓;
% drawnow;
disp(i);
disp(center);
%有时识别出的圆的数量大于实际数量,需要剔除多于的圆心数据;
D=pdist(center); %计算行与行之间的欧几里得距离;
Z=squareform(D); %为了方便识别行号和列号,将上述结果转为方阵,第i行j列,即代表center第i行与第j行所代表向量之间的距离;
U=triu(Z); %为了方便识别行号和列号,只取出矩阵的上三角部分;
[row,col]=find(U>0 & U<10); %如果圆心距离大于0小于10,则认为两个圆心重复;如果被识别的颗粒直径有变化需要修改此参数!!!!!!!!
center(row,:)=[]; %任意去掉其中重复的圆心;
if length(center)~=10
disp(['There is a problem with this frame:',num2str(i)]); %以防万一;
disp(center);
fprintf(fid_problem,'%10d\n',i);
else
disp('successful!!!');
disp(center);
for j=1:1:10
fprintf(fid_position,'%15.10f %15.10f\n',center(j,:));
end
end
%有时识别出的圆的数量小于实际数量,暂无更好的办法,此处调节识别圆的sensitivity,但是有风险;
else
disp(['There is a problem with this frame:',num2str(i)]); %以防万一;
disp(center);
fprintf(fid_problem,'%10d\n',i);
end
% imshow(bw)
% h=viscircles(center,radius); %显示圆形轮廓;
% drawnow; %为了连续显示图窗;
end
fclose(fid_position);
fclose(fid_problem);
toc
%注意检查各矩阵是否与实际颗粒的数目是否一样;
%% 将图片转为二值图片,凸显边缘
% % I = rgb2gray(RGB); %图片本来就是灰度图片,不需要再转为灰度图;
% imhist(RGB); %查看图片的灰度分布
% bw = imbinarize(RGB); %由于图片本来就是灰度图,直接转为二值图;
% % imshow(bw)
% imhist(bw); %查看图片的灰度分布
% imwrite(bw,'E:\20220326\125-2fps.png');
%
% % 删除包含少于阈值像素的所有对象
% bw = bwareaopen(bw,60);
% imshow(bw)
% % 填充笔帽中的间隙
% se = strel('disk',2);
% bw = imclose(bw,se);
% imshow(bw)
%
% %填充任何孔洞,以便可以使用 regionprops 来估计每个边界所包围的面积
% bw = imfill(bw,'holes');
% imshow(bw)
% %手动估算颗粒直径的长度
% d = drawline; %在figure图中对颗粒的直径划线
% pos = d.Position;
% diffPos = diff(pos);
% diameter = hypot(diffPos(1),diffPos(2))
- 注意此识别程序并不能完全理想的挑选出所有的圆形,程序中把异常值的情况挑选了出来,输出到了
‘E:\20220326\125-2fps_position_problem.txt’
参考文献:
检测圆形目标
检测和测量图像中的圆形目标
Measuring the Radius of a Roll of Tape
MATLAB: Image Prosessing Toolbox
|