最近在看Udacity的一门免费课程:Introduction to Computer Vision。
2A-L5 Edge Detection: Gradients
- Sodel 算子
用于图像的边检测,具体原理自行百度,这里给出模板:
下面以X方向的模板为例,探究它的性质。
- 单个模板边缘检测
用octave(matlab),首先导入一张八边形图片:
因为我是在视频中截取的图片,所以虽然看起来是灰度图,其实是3通道的,要进行灰度处理。归一化后,白色的部分是0, 黑色是1。
img = double(imread('octagon.png')) / 255.;
img = rgb2gray(img);
imshow(img); % assumes [0, 1] range for double images
接下来计算x, y方向的梯度:
%% Compute x, y gradients
[gx gy] = imgradientxy(img, 'sobel'); % Note: gx, gy are not normalized
imshow(gx)
% imshow((gx + 4) / 8)
- 方向
可以看到,水平的边缘和左边部分的都没有(梯度值<=0), 这是由的性质决定的。
水平方向好理解,因为边缘分割的是上下区域,左右可以看作对称的,而左右也是对称的,所以运算过后结果为0(黑色),和均匀区域一样。
对于八边形左侧,当移动到左上角边缘时:
灰色部分×0.5,白色×1,-1+0.5-2+2-0.5+0.5=-0.5,也显示为灰色。左下角同理,左边的值为负,右边为正,所以当边界左边颜色浅(趋近1),右边深(趋近0)时,得到的结果小于0,不进行归一化就看不到边界了。
- 归一化
imshow((gx + 4) / 8)
运算结果的区间为[-4, 4], 要映射到[0, 1],所以(gx + 4) / 8:
根据上一步的分析可以看出,左边的部分梯度值最小。
- 两个方向边缘检测
[gmag gdir] = imgradient(gx, gy); % gmag大小 gdir方向
imshow(gmag / (4 * sqrt(2))); % mag = sqrt(gx^2 + gy^2), so [0, (4 * sqrt(2))]
%imshow((gdir + 180.0) / 360.0); % angle in degrees [-180, 180]
综合两个算子,各个方向的边缘都可以检测出来了。
因为是截图,所以角度计算的有些偏差:
实际效果是这样的:
为什么gmag的线条比gdir的细呢?我觉得可能是因为平方和开根号的运算和反三角函数的运算性质导致的吧。
- 寻找特定角度的边缘
function result = select_gdir(gmag, gdir, mag_min, angle_low, angle_high)
% TODO Find and return pixels that fall within the desired mag, angle range
result = gmag >= mag_min & angle_low <= gdir & gdir <= angle_high;
endfunction
得到30度到60度之间的梯度大于1的边缘:
- 全部代码
pkg load image; % Gradient Direction function result = select_gdir(gmag, gdir, mag_min, angle_low, angle_high) % TODO Find and return pixels that fall within the desired mag, angle range result = gmag >= mag_min & angle_low <= gdir & gdir <= angle_high; endfunction %% Load and convert image to double type, range [0, 1] for convenience img = double(imread('octagon.png')) / 255.; img = rgb2gray(img); %imshow(img); % assumes [0, 1] range for double images %% Compute x, y gradients [gx gy] = imgradientxy(img, 'sobel'); % Note: gx, gy are not normalized % imshow(gx) % imshow((gx + 4) / 8) %% Obtain gradient magnitude and direction [gmag gdir] = imgradient(gx, gy); % imshow(gmag / (4 * sqrt(2))); % mag = sqrt(gx^2 + gy^2), so [0, (4 * sqrt(2))] %imshow((gdir + 180.0) / 360.0); % angle in degrees [-180, 180] %% Find pixels with desired gradient direction my_grad = select_gdir(gmag, gdir, 1, 45, 90); % 45 +/- 15 imshow(my_grad); % NOTE: enable after you've implemented select_gdir