光学显微镜自动聚焦之找出聚焦图像位置

想起高中物理课上讲过:在光学显微镜下观察及操控一个对象,第一步就是要进行对焦。这里实验室要做一个关于显微镜自动对焦的系统。

简而言之,大致分为以下三个方面:

A. 设计一个机构,将电机连接到显微镜的细准焦螺旋,用电机代替手工调焦。这是实现自动化必备的基础,这里用的是步进电机。

B. 控制电机部分,主要涉及电机的驱动、控制以及与电脑端之间的通信。

C. 视觉反馈部分,通过对显微镜采集到的图像进行视觉评估找出聚焦图片的位置,从而通过通信操作电机到指定位置。

这里,我们主要介绍第3部分。即在得到一个显微镜采集到的包含“离焦-聚焦-离焦”过程的连续图像后,如何找到聚焦图像的位置。
一. 理论介绍
大部分人都应该有经验,离焦情况下图像都比较模糊,而聚焦情况下图像边缘更为清晰。据此,大概有以下几种评估方法:

  1. 使用图像的灰度方差函数对图像进行评估

图像灰度方差的大小表示图像像素灰度分布的离散程度:当图像完全模糊时,图像像素点的灰度值分布离散程度较小,对应的灰度方差较小;而当图像较清晰时,图像像素点的灰度值分布离散程度较大,对应的灰度方差较大。

2.使用Laplace找图像边缘从而对图像进行评估
图像越清晰,边缘越明晰。因此可以通过找边缘的方式对图像进行聚焦评估,这里使用拉普拉斯算子找图像边缘。

3.使用使用图像的灰度熵(Gray entropy )作为评价函数
了解点信息论的应该清楚,对于一个事物知道的信息越多,确定性就越大,熵越小。对应于图像,图像越模糊,确定性越小,熵越大;反之越小。

4.空间域图像转换到频域,通过高频部分对图像进行评估
频域图像中,高频部分对应图像边缘信息,跟方法2类似,通过高频部分值的大小来评估图像清晰度。

二. 动手实践
介绍完理论部分,下面分别给出四中方法对应的MATLAB代码,代码不长,仅供参考。
//autofocus.m 程序主运行

videoname = '47.avi';
framefolder = video_to_frame(videoname);  %视频转化为图片
tic;  %与toc配合用于计算时间
var_index = im_var_evaluation(framefolder);  %以下分别采用4中评估方法
toc
fprintf('var_index:%d \n', var_index);
tic;
laplace_index = im_laplace_evaluation(framefolder);
toc
fprintf('laplace_index:%d \n', laplace_index);
tic;
fft_index = im_fft_evaluation(framefolder);
toc
fprintf('fft_index:%d \n', fft_index);
tic;
entropy_index = im_entropy_evaluation(framefolder);
toc
fprintf('ventropy_index:%d \n', entropy_index);

//video_to_frame.m

function [figurefolder] = video_to_frame(videoname)
% IMGETFRAMEANDHISTFROMVIDEO     从视频中获取每一帧图像
%   语法:
%       imgetframeandhistfromvideo(filename);
%   这个函数没有返回值,filename为视的路径加文件名, 视频必须在当前工作目录下
%   注意更改工作路径到当前文件路径

obj = VideoReader(videoname);%加载视频
numFrames = obj.NumberOfFrames; %帧的总数
figurefolder = [videoname(1:end-4), 'figure'];
[s,mess,messid] = mkdir(figurefolder);%创建文件夹
for k = 1 : numFrames %读取数据
    frame = read(obj, k);%读取第k帧图片
    figurePath = sprintf(['.\\', figurefolder, '\\%d.jpg'], k);
    imwrite(frame, figurePath); %保存帧
end

end

//im_var_evaluation.m

function [maxindex, maxvalue] = im_var_evaluation(foldername)
% IMGETMEANSANDVAR     从文件夹中所有图片的方差,并利用方差进行清晰度评估

finf = dir(strcat(foldername, '\\*.jpg')); %列出该文件夹下所有后缀名为jpg文件的属性
n = length(finf);  %获取文件的个数
resultdata = zeros(n, 1);
for k = 1:n
    filename = strcat(foldername, '\\', int2str(k), '.jpg');
    originalImage = imread(filename);
    grayImage = rgb2gray(originalImage);
    resultdata(k, 1) = (std2(grayImage))^2;  %计算方差
end
xlswrite([ foldername(1:end-6), 'var.xls'], resultdata, 1);
% 得到最大的方差值及其索引
[maxvalue, maxindex] = max(resultdata(:, 1));
xlswrite([ foldername(1:end-6), 'var.xls'], [maxvalue, maxindex], 1, 'D1');

end

//im_laplace_evaluation.m

function [maxindex, maxvalue ] = im_laplace_evaluation( foldername )
%UNTITLED Summary of this function goes here
%   利用梯度拉普拉斯变换对图像进行聚焦离焦评估
finf = dir(strcat(foldername, '\\*.jpg')); %列出该文件夹下所有后缀名为jpg文件的属性
n = length(finf);  %获取文件的个数
M = [-1, -4, -1; -4, 20, -4; -1, -4, -1];
resultdata = zeros(n, 1);
for k = 1:n
    filename = strcat(foldername, '\\', int2str(k), '.jpg');
    originalImage = imread(filename);
    grayImage = rgb2gray(originalImage);
    img = imfilter(grayImage, M);
    %此处可以设阈值为X的的高频边缘像素的个数
%    figurePath = sprintf(['.\\', '47laplace', '\\%d.jpg'], k);
%    imwrite(img, figurePath); %保存帧 
    resultdata(k, 1) = mean2(img);  %计算均值
end
xlswrite([ foldername(1:end-6), 'laplace.xls'], resultdata, 1);
% 得到最大的方差值及其索引
[maxvalue, maxindex] = max(resultdata(:, 1));
xlswrite([ foldername(1:end-6), 'laplace.xls'], [maxvalue, maxindex], 1, 'D1');

end

//im_fft_evaluation.m

function [maxindex, maxvalue ] = im_fft_evaluation( foldername )
%UNTITLED3 Summary of this function goes here
%   利用傅里叶变换
finf = dir(strcat(foldername, '\\*.jpg')); %列出该文件夹下所有后缀名为jpg文件的属性
n = length(finf);  %获取文件的个数
resultdata = zeros(n, 1);

I = imread(strcat(foldername, '\\', '1', '.jpg'));
row = size(I,1);
col = size(I,2);

for k = 1:n
    filename = strcat(foldername, '\\', int2str(k), '.jpg');
    originalImage = imread(filename);
    grayImage = rgb2gray(originalImage);
    fcoef = fft2(double(grayImage));
    spectrum = fftshift(fcoef);
    tmp2 = log(1+abs(spectrum));
    tmp2((row/2-20):(row/2+20), (col/2-20):(col/2+20)) = 0;  %将频域图像中低频部分的数据去掉(也可以说是置为常数)
    tmp = im2uint8(mat2gray(tmp2)); %数据转换为图片
%    figurePath = sprintf(['.\\', '47bfft', '\\%d.jpg'], k);
%    imwrite(tmp, figurePath); %保存
    resultdata(k, 1) = mean2(tmp);  %计算均值
end 

xlswrite([ foldername(1:end-6), 'fft.xls'], resultdata, 1);
% 得到最大的方差值及其索引
[maxvalue, maxindex] = max(resultdata(:, 1));
xlswrite([ foldername(1:end-6), 'fft.xls'], [maxvalue, maxindex], 1, 'D1');

end

//im_entropy_evaluation.m

function [maxindex, maxvalue ] = im_entropy_evaluation( foldername )
%UNTITLED2 Summary of this function goes here
%   Detailed explanation goes here
finf = dir(strcat(foldername, '\\*.jpg')); %列出该文件夹下所有后缀名为jpg文件的属性
n = length(finf);  %获取文件的个数
resultdata = zeros(n, 1);
for k = 1:n
    filename = strcat(foldername, '\\', int2str(k), '.jpg');
    originalImage = imread(filename);
    grayImage = rgb2gray(originalImage);
    [m, n] = size(grayImage);
    [counts, x] = imhist(grayImage, 32);
    p = counts/m/n;
    resultdata(k, 1) = -p(p>0)' * log2(p(p>0));  %计算方差
end
xlswrite([ foldername(1:end-6), 'entropy.xls'], resultdata, 1);
% 找出信息熵最小即为最清晰的图片
[maxvalue, maxindex] = min(resultdata(:, 1));
xlswrite([ foldername(1:end-6), 'entropy.xls'], [maxvalue, maxindex], 1, 'D1');

end

大致代码部分就是这样,仅供参考。

三. 结果分析与改进
结果分析,可以将同一个视频序列用不同的方法评估,结果进行对比。
传视频不方便,这里贴几张视频中的图片(整个视频是从离焦到聚焦再到离焦的过程):

对于这样一个序列,不同方法的结果对比:
光学显微镜自动聚焦之找出聚焦图像位置_第1张图片
对结果进行归一化的MATLAB程序:
//draw_curve_graph.m

%绘制xlsx第一列数据的曲线图
%   Detailed explanation goes here
var = xlsread('48var.xls');  %读取excel中的数据
laplace = xlsread('48laplace.xls');
fft = xlsread('48fft.xls');
entropy = xlsread('48entropy.xls');

var_raw=var(:, 1);  %提取第一列数据
laplace_raw=laplace(:, 1);
fft_raw=fft(:, 1);
entropy_raw=entropy(:, 1);
%数据作归一化处理
var_norm=0.1+(var_raw-min(var_raw))/(max(var_raw)-min(var_raw))*(0.9-0.1);
laplace_norm=0.1+(laplace_raw-min(laplace_raw))/(max(laplace_raw)-min(laplace_raw))*(0.9-0.1);
fft_norm=0.1+(fft_raw-min(fft_raw))/(max(fft_raw)-min(fft_raw))*(0.9-0.1);
entropy_norm=0.9-(entropy_raw-min(entropy_raw))/(max(entropy_raw)-min(entropy_raw))*(0.9-0.1);
%画图
plot(var_norm, 'b-');
hold on;
plot(laplace_norm, 'g-');
hold on;
plot(entropy_norm, 'r-');
hold on;
plot(fft_norm, 'c-');
xlabel('frames');ylabel('evluations');  
title('The comparison for several algorithms of autofocus');
legend('Gray variance','Gradient', 'Gray entropy', 'Frequency domain');
axis([0 ceil(size(var_raw,1)/10)*10 0 1]);

综合多次试验结果来看,使用灰度方差函数的方法应该是比较好的,首先它比较平滑,很好的模拟了“离焦——》聚焦——》离焦”的过程,还有它的运算时间也比较短。使用离散傅里叶在频域中处理的方法不太稳定。laplace、fft和entropy曲线看起来总是比较对称,观察一下最初的数据,发现可能是由于他们数据的range比较小导致的。

对于上述有需要改进的地方:
1.目前是使用整张图片做评估,下一步可以只选择target的邻域来进行处理,这样会抗干扰性更强一点。MATLAB中选ROI的方法:http://www.ilovematlab.cn/thread-111922-1-2.html

参考:
1.《面向细胞生长支架组装的微纳操作机器人多探针识别与
跟踪》
2.《纺织纤维显微图像的自动聚焦以及多焦面问题的研究》_丁喻洋

你可能感兴趣的:(计算机视觉,MATLAB)