图像处理(image processing),用计算机对图像进行分析,以达到所需结果的技术。又称影像处理。图像处理一般指数字图像处理。数字图像是指用工业相机、摄像机、扫描仪等设备经过拍摄得到的一个大的二维数组,该数组的元素称为像素,其值称为灰度值。图像处理技术一般包括图像压缩,增强和复原,匹配、描述和识别3个部分。
数字化:通过取样和量化过程将一个以自然形式存在的图像变换为适合计算机处理的数字形式。图像在计算机内部被表示为一个数字矩阵,矩阵中每一元素称为像素。图像数字化需要专门的设备,常见的有各种电子的和光学的扫描设备,还有机电扫描设备和手工操作的数字化仪。
图像增强 使图像清晰或将其转换为更适合人或机器分析的形式。与图像复原不同,图像增强并不要求忠实地反映原始图像。相反,含有某种失真(例如突出轮廓线)的图像可能比无失真的原始图像更为清晰。常用的图像增强方法有:①灰度等级直方图处理:使加工后的图像在某一灰度范围内有更好的对比度;②干扰抑制:通过低通滤波、多图像平均、施行某类空间域算子等处理,抑制叠加在图像上的随机性干扰;③边缘锐化:通过高通滤波、差分运算或某种变换,使图形的轮廓线增强;④伪彩色处理:将黑白图像转换为彩色图像,从而使人们易于分析和检测图像包含的信息。
图像复原 除去或减少在获得图像过程中因各种原因产生的退化。这类原因可能是光学系统的像差或离焦、摄像系统与被摄物之间的相对运动、电子或光学系统的噪声和介于摄像系统与被摄像物间的大气湍流等。图像复原常用二种方法。当不知道图像本身的性质时,可以建立退化源的数学模型,然后施行复原算法除去或减少退化源的影响。当有了关于图像本身的先验知识时,可以建立原始图像的模型,然后在观测到的退化图像中通过检测原始图像而复原图像。
图像分割将图像划分为一些互不重叠的区域,每一区域是像素的一个连续集。通常采用把像素分入特定区域的区域法和寻求区域之间边界的境界法。区域法根据被分割对象与背景的对比度进行阈值运算,将对象从背景中分割出来。
opencv图像处理基础实战
OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉和机器学习软件库,可以运行在Linux、Windows、Android和Mac OS操作系统上。 它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。OpenCV用C++语言编写,它具有C ++,Python,Java和MATLAB接口,并支持Windows,Linux,Android和Mac OS,OpenCV主要倾向于实时视觉应用,并在可用时利用MMX和SSE指令, 如今也提供对于C#、Ch、Ruby,GO的支持。下面的工作是基于Python进行编码的。
import cv2
from matplotlib import pyplot as plt
import numpy as np
导入opencv常用的基本库。
图1、高速公路图原图
img_path = "C:\\Users\\Lijian\\Desktop\\timg.jpg"
img = cv2.imread(img_path)
img.shape
运行上段代码的结果:
(511, 860, 3)
想将图像转换为黑白图像,则使用cvtColor函数。
gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
通过matplotlib中的imshow函数查看灰度图像。
注意如果直接使用plt显示图像,它默认使用三通道进行显示,会度图像如图2图像所示。
图2 plt直接显示图像
正确显示灰度图像的方法
gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
plt.imshow(gray_image,cmap="gray")
plt.axis('off')
print(gray_image.shape)
图3正确显示灰度图像
如图3所示,我们已将图像转换为黑白图像。当我们检查其尺寸时,不再有3个尺寸,仅为(511, 860)的矩阵。
(thresh, blackAndWhiteImage) = cv2.threshold(gray_image, 200, 255, cv2.THRESH_BINARY)
(thresh, blackAndWhiteImage) = cv2.threshold(gray_image, 80, 255, cv2.THRESH_BINARY)
(thresh, blackAndWhiteImage) = cv2.threshold(gray_image, 160, 255, cv2.THRESH_BINARY)
(thresh, blackAndWhiteImage) = cv2.threshold(gray_image, 200, 255, cv2.THRESH_BINARY)
plt.imshow(blackAndWhiteImage,cmap="gray")
plt.axis('off')
plt.show()
通过不同阈值获取灰度图像如图4所示
a(20,255) b(80,255)
c(160,255) d(200,255)
图4不同阈值处理后的灰度图像结果
OpenCV中阈值功能所需的第一个参数是要处理的图像。以下参数是阈值。第三个参数是我们要分配超出阈值的矩阵元素的值。可以在图3中看到四个不同阈值的影响。在第一张图像(图像1)中,该阈值确定为20.将20之上的所有值分配给255.其余值为设置为0。这仅允许黑色或非常深的颜色为黑色,而所有其他阴影直接为白色。图像2和图像3的阈值分别为80和160.最后,在图像4中将阈值确定为200.与图像1不同,白色和非常浅的颜色被指定为255,而所有在图4中将剩余值设置为0。
图像处理中常用的一种方法是图像模糊,如下所示
output2 = cv2.blur(gray_image, (10, 10))
plt.imshow(output2,cmap="gray")
plt.axis('off')
plt.show()
output2 = cv2.GaussianBlur(gray_image, (9, 9), 5)
plt.imshow(output2,cmap="gray")
plt.axis('off')
plt.show()
a均值滤波 b高斯滤波
图5 图像滤波结果
导向滤波代码:
import numpy as np
import cv2
def guideFilter(I, p, winSize, eps):
mean_I = cv2.blur(I, winSize) # I的均值平滑
mean_p = cv2.blur(p, winSize) # p的均值平滑
mean_II = cv2.blur(I * I, winSize) # I*I的均值平滑
mean_Ip = cv2.blur(I * p, winSize) # I*p的均值平滑
var_I = mean_II - mean_I * mean_I # 方差
cov_Ip = mean_Ip - mean_I * mean_p # 协方差
a = cov_Ip / (var_I + eps) # 相关因子a
b = mean_p - a * mean_I # 相关因子b
mean_a = cv2.blur(a, winSize) # 对a进行均值平滑
mean_b = cv2.blur(b, winSize) # 对b进行均值平滑
q = mean_a * I + mean_b
return q
if __name__ == '__main__':
eps = 0.01
winSize = (5,5)
image = cv2.imread("C:\\Users\\Lijian\\Desktop\\timg.jpg", cv2.IMREAD_ANYCOLOR)
image = cv2.resize(image, None,fx=0.7, fy=0.7, interpolation=cv2.INTER_CUBIC)
I = image/255.0 #将图像归一化
p =I
guideFilter_img = guideFilter(I, p, winSize, eps)
# 保存导向滤波结果
guideFilter_img = guideFilter_img * 255
guideFilter_img [guideFilter_img > 255] = 255
guideFilter_img = np.round(guideFilter_img )
guideFilter_img = guideFilter_img.astype(np.uint8)
cv2.imshow("image",image)
cv2.imshow("winSize_5", guideFilter_img )
cv2.waitKey(0)
cv2.destroyAllWindows()
图67彩色图像导向滤波后结果
图像的滤波包括均值滤波,中值滤波,高斯滤波,导向滤波,双边滤波,最小二乘滤波,以及SWF滤波等,图像的滤波过程通常用于消除图像中的噪声点。
对于一些拍摄歪曲的图像,我们可以利用opencv中的getRotationMatrix2D函数校正图像。
(h, w) = img.shape[:2]
center = (w / 2, h / 2)
M = cv2.getRotationMatrix2D(center, 13, scale =1.1)
rotated = cv2.warpAffine(gray_image, M, (w, h))
plt.imshow(rotated,cmap="gray")
plt.axis('off')
plt.show()
图7getRotationMatrix2D函数进行图像的旋转
可以先通过确定图像的中心,并以中心为基准进行旋转。getRotationMatrix2D函数的第一个参数是计算出的中心值。第二个参数是角度值。最后,第三个参数是旋转后要应用的缩放比例值。如果将此值设置为1,它将仅根据给定的角度旋转同一图像,而不会进行任何缩放。
项目一
高速公路车道检测
第一步:边缘检测
canny算子
(h, w) = img.shape[:2]
center = (w / 2, h / 2)
M = cv2.getRotationMatrix2D(center, 13, scale =1.1)
rotated = cv2.warpAffine(gray_image, M, (w, h))
plt.imshow(rotated,cmap="gray")
plt.axis('off')
plt.show()
sobel算子
img = cv2.imread(img_path)
gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
(thresh, output2) = cv2.threshold(gray_image, 200, 255, cv2.THRESH_BINARY)
output2 = cv2.GaussianBlur(output2, (5, 5), 3)
output2 = cv2.Sobel(output2,cv2.CV_16S,1,0)
plt.imshow(output2,cmap="gray")
plt.axis('off')
plt.show()
图8边缘检测
a.canny算子 b.sobel算子
Canny边缘检测算子是一种多级检测算法。1986年由John F. Canny提出,同时提出了边缘检测的三大准则:
- 低错误率的边缘检测:检测算法应该精确地找到图像中的尽可能多的边缘,尽可能的减少漏检和误检。
- 最优定位:检测的边缘点应该精确地定位于边缘的中心。
- 图像中的任意边缘应该只被标记一次,同时图像噪声不应产生伪边缘。
Canny算法出现以后一直是作为一种标准的边缘检测算法,此后也出现了各种基于Canny算法的改进算法。时至今日,Canny算法及其各种变种依旧是一种优秀的边缘检测算法。而且除非前提条件很适合,你很难找到一种边缘检测算子能显著地比Canny算子做的更好。
关于各种差分算子,还有Canny算子的简单介绍,这里就不罗嗦了,网上都可以找得到。直接进入Canny算法的实现。Canny算法分为以下几步。
1. 高斯模糊。2. 计算梯度幅值和方向。3. 非最大值抑制。4. 双阀值。5. 滞后边界跟踪。
canny算子调整参数进一步细化
img = cv2.imread(img_path)
gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
(thresh, output2) = cv2.threshold(gray_image, 245, 255, cv2.THRESH_BINARY)
output2 = cv2.Canny(output2, 180, 255)
plt.imshow(output2,cmap="gray")
plt.axis('off')
plt.show()
图9细化后的边缘检测算子
如果高速图像未实现高斯滤波,则会在图9中出现大量噪声,这会影响后面的检测结果。在该阶段之后,基于确定的边缘在真实(标准)图像上执行处理。为此使用HoughLinesP和line函数。
lines = cv2.HoughLinesP(output2, 1, np.pi/180,30)
for line in lines:
x1,y1,x2,y2 = line[0]
cv2.line(img,(x1,y1),(x2,y2),(0,255,0),4)
cv2.imshow("image",img)
cv2.waitKey(0)
cv2.destroyAllWindows()
图10运用HoughLinesP后图像
如图10所示,可以较好的实现道路边界和车道,但是也会出现一些噪声点,错把别的边界当成路,可以通过掩膜的方法来解决该问题。
def mask_of_image(image):
height = image.shape[0]
polygons = np.array([[(0,height),(2200,height),(250,100)]])
mask = np.zeros_like(image)
cv2.fillPoly(mask,polygons,255)
masked_image = cv2.bitwise_and(image,mask)
return masked_image
out=mask_of_image(output2)
cv2.imshow("image",out)
cv2.waitKey(0)
cv2.destroyAllWindows()
图11掩膜区域
经过掩膜后得到的结果
lines = cv2.HoughLinesP(out, 1, np.pi/180,30)
for line in lines:
x1,y1,x2,y2 = line[0]
cv2.line(img,(x1,y1),(x2,y2),(0,255,0),4)
cv2.imshow("image",img)
cv2.waitKey(0)
cv2.destroyAllWindows()
上面结果可能还需要进一步细化达到更好的结果。
上面是从一个公众号看到的公众号链接如下: