![c091fede431fc3f93bbae0a797c1bb99.png](https://i-blog.csdnimg.cn/blog_migrate/5cc17bcbef32c894cfb145039677f2a6.jpeg)
个人学习笔记:用sobel算子将RGB图片的轮廓提取出来
分成两个步骤:
1、将RGB转为灰度图:
分别对三个通道进行计算,RGB代表红绿蓝三种颜色,这个公式的含义就是对三种颜色进行加权处理,获得最后的灰度图(opencv提供了RGB2GRAY的功能,可以作为对比)
![aa884fb273d9d753ab7599c68217bc5f.png](https://i-blog.csdnimg.cn/blog_migrate/9a0134a24c630c1153e545a5d2ecad96.png)
import numpy as np
import imageio
def rgb2gray(rgb):
"""
convert rgb image into gray
Args:
rgb: grb image with numpy type
Returns:
gray: gray image
"""
gray = rgb[:, :, 0] * 0.299 + rgb[:, :, 1] * 0.587 + rgb[:, :, 2] * 0.114
return gray
image_in = imageio.imread("desk.jpg")
gray = rgb2gray(image_in)
imageio.imsave(im=gray.astype(np.uint8), uri="gray_image.jpg")
下面首先来看一下原始的RGB图(上自习的时候拍的,水平和垂直边缘都很多啊):
![60f92aeee1157950c4aff846c45e72f7.png](https://i-blog.csdnimg.cn/blog_migrate/765b16ac34afe18e8c721c3174a528c3.jpeg)
然后就是转换以后的灰度图,现在只能感受到亮度差,看不出来颜色是什么了:
![03f825585eaaf3bbaf4175504c4517fd.png](https://i-blog.csdnimg.cn/blog_migrate/3ddbbbe5b876550f4ec2a957d0a28ec8.jpeg)
2、将灰度图用sobel算子处理
sobel算子可以用来提取图片的边缘,那么什么是图片的边缘呢?我的认为,就是比如颜色图片或者是物体的轮廓(纯粹个人理解)。据说啊,sobel算子并没有发表在论文中,仅仅是在一次博士生讨论会中提出来的,这么厉害的东西居然没有发论文,要是引用的时候参考文献怎么写?有点跑题。。。
sobel模板就是3x3的矩阵,分为水平检测和垂直检测。之前看数字图像处理就感觉很玄幻,不知道为什么下面这种卷积核就能把图像的边缘找到:
![86e7fdc5a88a9409cd3386ea6f7b5f0b.png](https://i-blog.csdnimg.cn/blog_migrate/1569927e413e982ef6bf4acb480903b0.jpeg)
把这个3x3的卷积核与灰度图进行卷积计算,就能得到边缘了。
现在想想,还是不太懂。感觉上看,就是右边的像素减去左边的像素:如果左边和右边的像素值越接近(同一物体或者同一颜色或者没有任何断层),那么差值就越小,也就是没有边缘;反之,如果右边和左边不是连续的,那么减法获得的结果就会很大,也就出现了轮廓。
def sobel(image):
"""
implement sobel compute on a single gray image
Args:
image: a gray image
Returns:
the image that have been processd by sobel
Raises:
ValueError: the input's shape image must bigger than sobel(3x3)
"""
# change the data type of input image into np.uint8(cheaper compute cost)
image = image.astype(np.uint8)
assert len(image.shape) == 2
if image.shape[0] < 3 or image.shape[1] < 3:
raise ValueError("The width and height of input image must bigger than 3")
# create temp image container
sobel_image_x = np.zeros(shape=image.shape)
sobel_image_y = np.zeros(shape=image.shape)
# create sobel
sobel_x = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])
sobel_y = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]])
for i in range(image.shape[0]-2):
for j in range(image.shape[1]-2):
# have to use np.abs() to make sure the value is positive
sobel_image_x[i, j] = np.abs(np.sum(image[i:i+3, j:j+3] * sobel_x))
sobel_image_y[i, j] = np.abs(np.sum(image[i:i+3, j:j+3] * sobel_y))
sobel_image = np.sqrt(sobel_image_x*sobel_image_x + sobel_image_y*sobel_image_y).astype(np.uint8)
return sobel_image
上面的代码流程如下:
(1)数据类型转换与输入数据尺寸检测
(2)创建X和Y方向的边缘图像容器,定义sobel算子
(3)卷积(求abs,也就是绝对值,是因为差值可能是负数)
image_in = imageio.imread("desk.jpg")
rgb = rgb2gray(image_in)
sobel_image = sobel(rgb)
imageio.imsave(im=sobel_image, uri="sobel_image.jpg")
处理前后 对比 :
![1d73755b60cdff4f10aa8a36312e348f.png](https://i-blog.csdnimg.cn/blog_migrate/ad5df2c217004078a4b633a6a3406936.jpeg)