一种更快的高斯拉普拉斯算子方法
A faster approach to Laplacian of Gaussian
我目前正在优化我的代码以提高图像处理效率。我的第一个问题是 vision.VideoFileReader
和 step
需要很长时间才能打开每一帧。我通过将我的灰度图像压缩为 1 个 RGB 帧中的 3 个帧来加速我的代码。这样我就可以使用 vid.step()
加载 1 个 RGB 帧,并导入 3 个帧以供处理。
现在我的代码在高斯拉普拉斯 (LoG) 滤波上 运行 很慢。我读到使用函数 imfilter
可用于执行 LoG,但它似乎是下一个速率限制步骤。
进一步阅读后,imfilter
似乎不是提高速度的最佳选择。显然 MATLAB 引入了 LoG function 但它是在 R2016b 中引入的,不幸的是我正在使用 R2016a。
是否有加快速度的方法imfilter
或者是否有更好的函数可用于执行 LoG 过滤?
我应该打电话给python来加快进程吗?
代码:
Hei = gh.Video.reader.info.VideoSize(2);
Wid = gh.Video.reader.info.VideoSize(1);
Log_filter = fspecial('log', filterdot, thresh); % fspecial creat predefined filter.Return a filter.
% 25X25 Gaussian filter with SD =25 is created.
tic
ii = 1;
bkgd = zeros(Hei,Wid,3);
bkgd(:,:,1) = gh.Bkgd;
bkgd(:,:,2) = gh.Bkgd;
bkgd(:,:,3) = gh.Bkgd;
bkgdmod = reshape(bkgd,720,[]);
while ~isDone(gh.Video.reader)
frame = gh.readFrame();
img_temp = double(frame);
img_temp2 = reshape(img_temp,720,[]);
subbk = img_temp2 - bkgdmod;
img_LOG = imfilter(subbk, Log_filter, 'symmetric', 'conv');
img_LOG = imbinarize(img_LOG,.002);
[~, centroids, ~] = gh.Video.blobAnalyser.step(img_LOG);
toc
end
高斯的拉普拉斯不能直接分离成两个一维核。因此,imfilter
会做一个全卷积,这是相当昂贵的。但我们可以手动将其分离成更简单的过滤器。
高斯拉普拉斯定义为高斯的两个二阶导数之和:
LoG = d²/dx² G + d²/dy² G
高斯本身及其导数,are separable。因此,可以使用 4 个 1D 卷积计算上述内容,这比单个 2D 卷积便宜得多,除非内核非常小(例如,如果内核是 7x7,我们需要 49 个乘法和加法每个像素用于 2D 内核,或者 4 *7=4 个一维核的每个像素有 28 次乘法和加法;这种差异随着核变大而增加)。计算结果为:
sigma = 3;
cutoff = ceil(3*sigma);
G = fspecial('gaussian',[1,2*cutoff+1],sigma);
d2G = G .* ((-cutoff:cutoff).^2 - sigma^2)/ (sigma^4);
dxx = conv2(d2G,G,img,'same');
dyy = conv2(G,d2G,img,'same');
LoG = dxx + dyy;
如果你真的很赶时间,又不关心精度,你可以将 cutoff
设置为 2*sigma
(对于较小的内核),但这并不理想。
另一种不太精确的方法是以不同方式分离操作:
LoG * f = ( d²/dx² G + d²/dy² G ) * f
= ( d²/dx² * G + d²/dy² * G ) * f
= ( d²/dx^2 + d²/dy² ) * G * f
(其中 *
表示卷积,而 Dirac delta,卷积相当于乘以 1)。 d²/dx² + d²/dy²
运算符在离散世界中并不真正存在,但您可以采用有限差分近似,从而得出著名的 3x3 拉普拉斯核:
[ 1 1 1 [ 0 1 0
1 -8 1 or: 1 -4 1
1 1 1 ] 0 1 0 ]
现在我们得到了一个更粗略的近似值,但计算速度更快(2 个 1D 卷积,以及一个具有普通 3x3 内核的卷积):
sigma = 3;
cutoff = ceil(3*sigma);
G = fspecial('gaussian',[1,2*cutoff+1],sigma);
tmp = conv2(G,G,img,'same');
h = fspecial('laplacian',0);
LoG = conv2(tmp,h,'same'); % or use imfilter
我目前正在优化我的代码以提高图像处理效率。我的第一个问题是 vision.VideoFileReader
和 step
需要很长时间才能打开每一帧。我通过将我的灰度图像压缩为 1 个 RGB 帧中的 3 个帧来加速我的代码。这样我就可以使用 vid.step()
加载 1 个 RGB 帧,并导入 3 个帧以供处理。
现在我的代码在高斯拉普拉斯 (LoG) 滤波上 运行 很慢。我读到使用函数 imfilter
可用于执行 LoG,但它似乎是下一个速率限制步骤。
进一步阅读后,imfilter
似乎不是提高速度的最佳选择。显然 MATLAB 引入了 LoG function 但它是在 R2016b 中引入的,不幸的是我正在使用 R2016a。
是否有加快速度的方法imfilter
或者是否有更好的函数可用于执行 LoG 过滤?
我应该打电话给python来加快进程吗?
代码:
Hei = gh.Video.reader.info.VideoSize(2);
Wid = gh.Video.reader.info.VideoSize(1);
Log_filter = fspecial('log', filterdot, thresh); % fspecial creat predefined filter.Return a filter.
% 25X25 Gaussian filter with SD =25 is created.
tic
ii = 1;
bkgd = zeros(Hei,Wid,3);
bkgd(:,:,1) = gh.Bkgd;
bkgd(:,:,2) = gh.Bkgd;
bkgd(:,:,3) = gh.Bkgd;
bkgdmod = reshape(bkgd,720,[]);
while ~isDone(gh.Video.reader)
frame = gh.readFrame();
img_temp = double(frame);
img_temp2 = reshape(img_temp,720,[]);
subbk = img_temp2 - bkgdmod;
img_LOG = imfilter(subbk, Log_filter, 'symmetric', 'conv');
img_LOG = imbinarize(img_LOG,.002);
[~, centroids, ~] = gh.Video.blobAnalyser.step(img_LOG);
toc
end
高斯的拉普拉斯不能直接分离成两个一维核。因此,imfilter
会做一个全卷积,这是相当昂贵的。但我们可以手动将其分离成更简单的过滤器。
高斯拉普拉斯定义为高斯的两个二阶导数之和:
LoG = d²/dx² G + d²/dy² G
高斯本身及其导数,are separable。因此,可以使用 4 个 1D 卷积计算上述内容,这比单个 2D 卷积便宜得多,除非内核非常小(例如,如果内核是 7x7,我们需要 49 个乘法和加法每个像素用于 2D 内核,或者 4 *7=4 个一维核的每个像素有 28 次乘法和加法;这种差异随着核变大而增加)。计算结果为:
sigma = 3;
cutoff = ceil(3*sigma);
G = fspecial('gaussian',[1,2*cutoff+1],sigma);
d2G = G .* ((-cutoff:cutoff).^2 - sigma^2)/ (sigma^4);
dxx = conv2(d2G,G,img,'same');
dyy = conv2(G,d2G,img,'same');
LoG = dxx + dyy;
如果你真的很赶时间,又不关心精度,你可以将 cutoff
设置为 2*sigma
(对于较小的内核),但这并不理想。
另一种不太精确的方法是以不同方式分离操作:
LoG * f = ( d²/dx² G + d²/dy² G ) * f
= ( d²/dx² * G + d²/dy² * G ) * f
= ( d²/dx^2 + d²/dy² ) * G * f
(其中 *
表示卷积,而 Dirac delta,卷积相当于乘以 1)。 d²/dx² + d²/dy²
运算符在离散世界中并不真正存在,但您可以采用有限差分近似,从而得出著名的 3x3 拉普拉斯核:
[ 1 1 1 [ 0 1 0
1 -8 1 or: 1 -4 1
1 1 1 ] 0 1 0 ]
现在我们得到了一个更粗略的近似值,但计算速度更快(2 个 1D 卷积,以及一个具有普通 3x3 内核的卷积):
sigma = 3;
cutoff = ceil(3*sigma);
G = fspecial('gaussian',[1,2*cutoff+1],sigma);
tmp = conv2(G,G,img,'same');
h = fspecial('laplacian',0);
LoG = conv2(tmp,h,'same'); % or use imfilter