目录
1. 图片处理
1.1 灰度处理
1.1.1 图像灰度化处理
1.1.2 图像灰度化的算法
1.2 图像二值化
1.3 边缘检测
编辑 2. 绘图
2.1 绘制线段
2.2 绘制矩形
2.3 绘制圆形
2.4 绘制椭圆
2.5 绘制多边形
2.6 绘制文字图片
1. 图片处理
1.1 灰度处理
将彩色图像转化为灰度图像的过程是图像的灰度化处理。彩色图像中的每个像素的颜色
由R,G,B 三个分量决定,而每个分量中可取值0-255,这样一个像素点可以有1600 多万
(256*256*256=1677256)的颜色的变化范围。而灰度图像是R,G,B 三个分量相同的一种
特殊的彩色图像,其中一个像素点的变化范围为256 种,所以在数字图像处理中一般将各种
格式的图像转化为灰度图像以使后续的图像的计算量少一些。灰度图像的描述与彩色图像一
样仍然反映了整副图像的整体和局部的色度和高亮等级的分布和特征。
1.1.1 图像灰度化处理
灰度化处理就是将一幅色彩图像转化为灰度图像的过程。彩色图像分为R,G,B 三个分
量,分别显示出红绿蓝等各种颜色,灰度化就是使彩色的R,G,B 分量相等的过程。灰度值
大的像素点比较亮(像素值最大为255,为白色),反之比较暗(像素最下为0,为黑色)。
图像灰度化核心思想是R = G = B ,这个值也叫灰度值。
1.1.2 图像灰度化的算法
1.最大值法:使转化后的R,G,B 的值等于转化前3 个值中最大的一个,即:R=G=B=max
(R,G,B)。这种方法转换的灰度图亮度很高。
2. 平均值法:是转化后R,G,B 的值为转化前R,G,B 的平均值。即:R=G=B=(R+G+B)/3。
这种方法产生的灰度图像比较柔和。
3. 加权平均值法: 按照一定权值,对R,G,B 的值加权平均, 即:分别为R,G,B的权值,取不同的值形成不同的灰度图像。由于人眼对绿色最为敏感,红色次之,对蓝色的敏感性最低,因此使将得到较易识别的灰度图像。一般得到的灰度图像效果最好。
以下代码中会有四种方法实现灰度化:代码中的4个方法都可以单独拿出来使用,这里为了方便就把四种方法写在一起。
image_path = "./resource/robot.jpg" #待灰度化处理的照片的相对路径,也可以直接使用绝对路径
def gray_image():
# method 1 : use the second parameter of imread() to read image as gray scale.
img_handler = cv2.imread(image_path, cv2.IMREAD_COLOR)
img_handler_gray = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
# methOd 2: cvtColor 颜色空间转换
img_handler_gray = cv2.cvtColor(img_handler, cv2.COLOR_BGR2GRAY)
# # method 3: 平均值法:取R,G,B三者的平均值
height, width, deep = img_handler.shape
gray_img_info = (height, width, deep)
# zeros()第二个参数必须要设置成np.uint8 ,否则灰度化会失败
img_handler_gray = np.zeros(gray_img_info, np.uint8)
print(height, width, deep)
for i in range(0, height):
for j in range(0, width):
# 读取每一个像素点的B,G,R
(b, g, r) = img_handler[i, j]
# 取像素点中B,G,R的平均值
gray = (int(b) + int(g) + int(r))/3
# 将灰度图片中的像素点的B,G,R设置成平均值
img_handler_gray[i, j] = np.uint8(gray)
# method 4 : 加权平均值法
# gray = r*0.299+g*0.587+b*0.114 三个加权值之和必须为1
img_handler = cv2.imread(image_path, cv2.IMREAD_COLOR)
(height, width, deep) = img_handler.shape
img_info = (height, width, deep)
img_handler_gray = np.zeros(img_info, np.uint8)
for i in range(0, height):
for j in range(0, width):
b, g, r = img_handler[i, j]
gray = r * 0.299 + g * 0.587 + b * 0.114
img_handler_gray[i,j] = np.uint8(gray)
cv2.imshow("original_image", img_handler)
cv2.imshow("gray_image", img_handler_gray)
cv2.waitKey(0)
cv2.destroyAllWindows()
代码运行结果:
1.2 图像二值化
图像处理是计算机视觉和图像分析的一个重要领域,其中阈值化是一项常用的图像处理技术之一。在OpenCV中,提供了许多用于图像处理的函数和工具,其中cv2.threshold
函数用于执行图像阈值化操作。
图像阈值化是一种图像处理技术,它根据图像内像素点强度的分布规律设置一个阈值,然后根据像素点强度高于或低于这个阈值来进行一些处理。简单来说,就是通过设置一个阈值,将图像转换为二值图像,即像素点只有两种可能的强度值(通常是0和255)。这种处理技术可以用来突出图像中的特定区域或特征,例如边缘或纹理,从而简化后续的图像分析和处理步骤。
二值化核心思想是设阈值,大于阈值的为0(黑色)或255(白色),使图像称为黑白图。阈值可固定,也可以自适应阈值。自适应阈值一般为一点像素与这点为中序的区域像素平均值或者高斯分布加权和的比较,其中可以设置一个差值也可以不设置。
threshold 的函数如下,
ret, threshold = cv2.threshold(src, thresh, maxval, type)
-
src 为输入的灰度图片
-
threshold 是预设的阈值
-
maxval 像素值超过了阈值(或者小于阈值,取决于阈值类型)所赋予的值
-
type 阈值类型
-
cv2.THRESH_BINARY
:二值化,像素值大于阈值的被赋予maxval
,小于阈值的被赋予0。 -
cv2.THRESH_BINARY_INV
:反二值化,与cv2.THRESH_BINARY
相反,像素值大于阈值的被赋予0,小于阈值的被赋予maxval
。 -
cv2.THRESH_TRUNC
:截断,像素值大于阈值的被赋予阈值,小于阈值的不变。 -
cv2.THRESH_TOZERO
:设置为零,像素值小于阈值的被赋予0,大于阈值的不变。 -
cv2.THRESH_TOZERO_INV
:反设置为零,与cv2.THRESH_TOZERO
相反,像素值小于阈值的不变,大于阈值的被赋予0。 -
cv2.THRESH_OTSU
:这是 Otsu 的二值化方法。这个方法会自动计算最佳阈值,使得两类的类间方差最大。当你使用 Otsu 方法时,设置的阈值(这里是0)会被忽略,Otsu 方法会自动计算一个最佳阈值。
-
-
返回值ret : 二值化使用的阈值,当使用OTSU模式时返回自动计算的最佳阈值
-
返回值threshold: 二值化之后的图像数据
使用不同阈值类型的代码为:每个阈值类型都需要调整预设的阈值,以达到最佳的效果
image_path = "./resource/robot.jpg"
def image_binarization():
img_handler = cv2.imread(image_path,cv2.IMREAD_COLOR)
img_handler_gray = cv2.cvtColor(img_handler,cv2.COLOR_BGR2GRAY)
ret0, threshold0 = cv2.threshold(img_handler_gray,10,255,cv2.THRESH_BINARY)
ret1, threshold1 = cv2.threshold(img_handler_gray, 10, 255, cv2.THRESH_BINARY_INV)
ret2, threshold2 = cv2.threshold(img_handler_gray, 100, 255, cv2.THRESH_TRUNC)
ret3, threshold3= cv2.threshold(img_handler_gray, 10, 255, cv2.THRESH_TOZERO)
ret4, threshold4 = cv2.threshold(img_handler_gray, 100, 255, cv2.THRESH_TOZERO_INV)
ret5, threshold5 = cv2.threshold(img_handler_gray, 0, 255, cv2.THRESH_OTSU)
titles = ["THRESH_BINARY value"+str(ret0),"THRESH_BINARY_INV value"+str(ret1),"THRESH_TRUNC value"+str(ret2),"THRESH_TOZERO value"+str(ret3),
"THRESH_TOZERO_INV value"+str(ret4),"THRESH_OTSU value"+str(ret5)]
threshold_list = [threshold0,threshold1,threshold2,threshold3,threshold4,threshold5]
for i in range(0, len(titles)):
cv2.imshow(titles[i],threshold_list[i])
cv2.waitKey(0)
cv2.destroyAllWindows()
不同阈值类型的二值化效果为(代码中的阈值并不是最佳阈值,所以每个阈值类型的效果不一致)下图中可以看到OTSU自动计算出来的阈值为177,效果是最好的。
1.3 边缘检测
边缘检测的目的是在保留原有图像属性的情况下,显著减少图像的数据规模。目前有多
种算法可以进行边缘检测,虽然Canny 算法年代久远,但可以说它是边缘检测的一种标准算
法,而且仍在研究中广泛使用。
Canny 边缘检测是从不同视觉对象中提取有用的结构信息并大大减少要处理的数据量
的一种技术,目前已广泛应用于各种计算机视觉系统。Canny 发现,在不同视觉系统上对边
缘检测的要求较为类似,因此,可以实现一种具有广泛应用意义的边缘检测技术。
边缘检测的一般标准包括:
以低的错误率检测边缘,也即意味着需要尽可能准确的捕获图像中尽可能多的边缘。
检测到的边缘应精确定位在真实边缘的中心。
图像中给定的边缘应只被标记一次,并且在可能的情况下,图像的噪声不应产生假的边
缘。
为了满足这些要求,Canny 使用了变分法。Canny 检测器中的最优函数使用四个指数项
的和来描述,它可以由高斯函数的一阶导数来近似。
在目前常用的边缘检测方法中,Canny 边缘检测算法是具有严格定义的,可以提供良好
可靠检测的方法之一。由于它具有满足边缘检测的三个标准和实现过程简单的优势,成为边
缘检测最流行的算法之一。
Canny 边缘检测算法可以分为以下5 个步骤:
1、使用高斯滤波器,以平滑图像,滤除噪声。
2、计算图像中每个像素点的梯度强度和方向。
3、应用非极大值(Non-Maximum Suppression)抑制,以消除边缘检测带来的杂散响应。
4、应用双阈值(Double-Threshold)检测来确定真实的和潜在的边缘。
5、通过抑制孤立的弱边缘最终完成边缘检测。
OpenCV里面提供有Canny边缘检测算法,使用代码为:
image_path = "./resource/robot.jpg"
img_handler = cv2.imread(image_path,cv2.IMREAD_COLOR)
imgCanny = cv2.Canny(img_handler, 50, 50)
cv2.imshow("origin_image",img_handler)
cv2.imshow("Canny_edge_detection",imgCanny)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行结果为:
2. 绘图
2.1 绘制线段
OpenCV 中使用line(dst,pt1,pt2,color,thickness=None,lineType=None,shift=None)函数进行线段的绘制。
参数说明:
-
dst:输出图像。
-
pt1,pt2:必选参数。线段的坐标点,分别表示起始点和终止点
-
color:必选参数。用于设置线段的颜色
-
thickness:可选参数。用于设置线段的宽度
-
lineType:可选参数。用于设置线段的类型,可选8(8 邻接连接线-默认)、4(4
邻接连接线)和cv2.LINE_AA 为抗锯齿。
# 1. 绘制直线,可设置线段的颜色的粗细
line(dst,pt1,pt2,color,thickness=None,lineType=None,shift=None)
cv2.line(image,(100,100),(100,200),color=(0,255,255),thickness=cv2.LINE_8,lineType=cv2.LINE_AA) # yellow
cv2.line(image, (200, 100), (200, 200), color=(0, 0, 255), thickness=cv2.LINE_4, lineType=cv2.LINE_AA) #red
运行结果:
2.2 绘制矩形
矩形的确定规则:已知两个对角的顶点坐标,能确定唯一的矩形。
rectangle(img,pt1,pt2,color,thickness=None,lineType=None,shift=None)
参数说明:
-
img:画布或者载体图像
-
pt1,pt2:必选参数。矩形的顶点,分别表示顶点与对角顶点,即矩形的左上角与
右下角(这两个顶点可以确定一个唯一的矩形)
-
color:必选参数。用于设置矩形的颜色
-
thickness:可选参数。用于设置矩形边的宽度,当值为负数时,表示对矩形进行
填充
-
lineType:可选参数。用于设置线段的类型,可选8(8 邻接连接线-默认)、4(4
邻接连接线)和cv2.LINE_AA 为抗锯齿
# 2. 绘制矩形
# rectangle(img,pt1,pt2,color,thickness=None,lineType=None,shift=None)
cv2.rectangle(image,(200,400),(400,200),(0,255,0),1,8)
结果为:
2.3 绘制圆形
圆形的确定规则:圆心坐标和半径可以确定唯一的圆。
cv2.circle(img, center, radius, color[,thickness[,lineType]])
参数说明:
- img:画布或者载体图像
- center:必选参数,为圆心坐标,格式: (50,50)
- radius:必选参数,半径
- color:必选参数,颜色
- thickness: 线条粗细。默认为1.如果-1 则为填充实心。
- lineType:线条类型。默认是8,连接类型。如下表格说明
参数 | 说明 |
cv2.FILLED | 填充 |
cv2.LINE_4 | 4连接类型 |
cv2.LINE_8 | 8连接类型 |
cv2.LINE_AA | 抗锯齿,该参数会让线段更平滑 |
# 3. 绘制圆形
# cv2.circle(img, center, radius, color[,thickness[,lineType]])
cv2.circle(image,(300,300),300,(255,255,0))
运行结果:
2.4 绘制椭圆
cv2.ellipse(img, center, axes, angle, StartAngle, endAngle,color[,thickness[,lineType]])
参数介绍:
- center:椭圆的中心点,(x,y)
- axes:指的是短半径和长半径,(m,n)
- angle:指的是逆时针旋转的角度
- StartAngle:圆弧起始角的角度
- endAngle:圆弧终结角的角度。90,180,360,分别表示1/4椭圆,1/2椭圆,完整椭圆
- img、color 可以参考圆的说明
Note:第五个参数endAngle指的是逆时针开始画图的角度,第六个指的是逆时针结束画图的角度
四五六参数若加上符号,表示的反方向,即顺时针方向
# 4.绘制椭圆
cv2.ellipse(image,center = (300,300),axes= (100,200),angle=0,startAngle=0,endAngle=360,color = (0,255,255),lineType=cv2.LINE_AA)
运行结果
2.5 绘制多边形
cv2.polylines(img,[pts],isClosed, color[,thickness[,lineType]])
参数介绍:
- pts:多边形的顶点
- isClosed:是否闭合。(True/False)
- 其他参数参照圆的绘制参数
绘制多边形要先确定多边形的每一个顶点的坐标,将这些坐标传递给参数pts
#5. 绘制多边形
#point 中为多边形的所有顶点坐标
points = np.array([[150,100],[160,210],[200,300],[300,400],[500,500]],np.int32)
points.reshape((-1,1,2))
cv2.polylines(image,[points],True,color=(255,30,30))
结果为:
上面所有图形绘制的整体代码为:
运行结果:
2.6 绘制文字图片
在图片中标记时会用到文字,这里介绍一下如何在图片中绘制文字。
cv2.putText(img, str, origin, font, size,color,thickness)
各参数依次是:图片,添加的文字,左上角坐标(整数),字体,字体大小,颜色,字体粗细.
在坐标(250,50)处写上文字Test, 实现代码:
# 6.绘制文字
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(image, 'Test', (250, 50), font, 1, (200, 200, 0), 2, cv2.LINE_AA)
运行结果:
上面所有图形绘制的整体代码为:
img_info = (600,600,3) #(height, width, deep)
image = np.zeros(img_info,np.uint8)
# 1. 绘制直线,可设置线段的颜色的粗细
# line(dst,pt1,pt2,color,thickness=None,lineType=None,shift=None)
cv2.line(image,(100,100),(100,200),color=(0,255,255),thickness=cv2.LINE_8,lineType=cv2.LINE_AA) # yellow
cv2.line(image, (200, 100), (200, 200), color=(0, 0, 255), thickness=cv2.LINE_4, lineType=cv2.LINE_AA) #red
# 2. 绘制矩形
# rectangle(img,pt1,pt2,color,thickness=None,lineType=None,shift=None)
cv2.rectangle(image,(200,400),(400,200),(0,255,0),1,8)
# 3. 绘制圆形
# cv2.circle(img, center, radius, color[,thickness[,lineType]])
cv2.circle(image,(300,300),300,(255,255,0),lineType=cv2.LINE_AA)
# # 4.绘制椭圆
cv2.ellipse(image,center = (300,300),axes= (100,200),angle=0,startAngle=0,endAngle=360,color = (0,255,255),lineType=cv2.LINE_AA)
#5. 绘制多边形
points = np.array([[150,100],[160,210],[200,300],[300,400],[500,500]],np.int32)
points.reshape((-1,1,2))
cv2.polylines(image,[points],True,color = (255,30,30))
# 6.绘制文字
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(image, 'Test', (250, 50), font, 1, (200, 200, 0), 2, cv2.LINE_AA)
cv2.imshow("image_line",image)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行结果: