《计算机视觉技术与应用》-----第五章 边缘和轮廓

系列文章目录

《计算机视觉技术与应用》-----第二章 图像处理基础

《计算机视觉技术与应用》-----第三章 图形用户界面

《计算机视觉技术与应用》-----第四章 图像变换

《计算机视觉技术与应用》-----第五章 边缘和轮廓

《计算机视觉技术与应用》-----第六章 边缘和轮廓

《计算机视觉技术与应用》-----第七章 边缘和轮廓

《计算机视觉技术与应用》----- 重点复盘


前言

提示:这里可以添加本文要记录的大概内容:

例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


一、Laplacian边缘检测

在这里插入图片描述

#test5-1.py:拉普拉斯边缘检测
import cv2
img=cv2.imread('bee.jpg')  		        #读取图像
cv2.imshow('original',img)  	        #显示原图像
img2=cv2.Laplacian(img,cv2.CV_8U,ksize=1) 	  
img3=cv2.Laplacian(img,-1,ksize=5)   
                                        #边缘检测 ksize ksize是算子的大小,必须为1、3、5、7。默认为1 用于计算二阶导数的滤波器的孔径尺寸,大小必须为正奇数(正奇数才能有中心点)
                                        #cv2.cv_8U,输出图像的深度(数据类型)
                                        #可以使用-1, 与原图像保持一致np.uint8
                                        #数据类型结构: CV_ 【bit_depth】【S/U/F】【C<number_of_channels>】
                                        #CV_8U - 8位无符号整数(0..255)
cv2.imshow('Laplacian2',img2)  	        #显示结果
cv2.imshow('Laplacian3',img3)  	        #显示结果
cv2.waitKey(0)

在这里插入图片描述

opencv:边缘检测之Laplacian算子思想及实现
Opencv学习——边缘检测(Laplacian)

二、Sobel边缘检测

在这里插入图片描述

#test5-2.py:Sobel边缘检测
import cv2
img=cv2.imread('bee.jpg')  	        #读取图像
cv2.imshow('original',img)  	        #显示原图像
img2=cv2.Sobel(img,cv2.CV_8U,0,1)   #边缘检测
                                    #dx和dy指的是求导的阶数,0表示这个方向上没有求导,所填的数一般为0、1、2
                                    #(0表示不求偏导,1表示1阶偏导,2表示2阶偏导)
                                    # dx >= 0 && dy >= 0 && dx+dy > 0
                                    #ksize是Sobel算子的大小,即卷积核的大小,必须为奇数1、3、5、7。如果ksize=-1,就演变成为3x3的Scharr算子,
                                    # scale是缩放导数的比例常数,默认情况为没有伸缩系数。
                                    # borderType是判断图像边界的模式,这个参数默认值为cv2.BORDER_DEFAULT。
img3=cv2.Sobel(img,cv2.CV_8U,0,1,ksize=7)   #sobel内核大小设置为7
img4=cv2.Sobel(img,cv2.CV_8U,0,2)   #dx=0  dy=2 表示对y求二阶偏导

cv2.imshow('Sobel_2',img2)  	        #显示结果
cv2.imshow('Sobel_3',img3)  	        #显示结果
cv2.imshow('Sobel_4',img4)
cv2.waitKey(0)

OpenCV——Sobel边缘检测

三、Canny边缘检测

OpenCV——Canny边缘检测(cv2.Canny())
在这里插入图片描述
Canny()边缘检测步骤
Canny 边缘检测分为如下几个步骤:
步骤 1:去噪。噪声会影响边缘检测的准确性,因此首先要将噪声过滤掉。
步骤 2:计算梯度的幅度与方向。
步骤 3:非极大值抑制,即适当地让边缘“变瘦”。
步骤 4:确定边缘。使用双阈值算法确定最终的边缘信息。

#test5-3.py:Canny边缘检测
import cv2
img=cv2.imread('bee.jpg')  	            #读取图像
cv2.imshow('original',img)  	        #显示原图像
img2=cv2.Canny(img,200,300)             #边缘检测
                                        #threshold1 表示处理过程中的第一个阈值。
                                        #threshold2 表示处理过程中的第二个阈值。
                                        #其中一个为高阈值 maxVal,另一个为低阈值 minVal。
                                        # 根据当前边缘像素的梯度值(指的是梯度幅度,下同)
                                        # 与这两个阈值之间的关系,判断边缘的属性
img3=cv2.Canny(img,100,400)
cv2.imshow('Canny_2',img2)  	            #显示结果
cv2.imshow('Canny_3',img3)  	            #显示结果

cv2.waitKey(0)

应用双阈值确定边缘
完成上述步骤后,图像内的强边缘已经在当前获取的边缘图像内。但是,一些虚边缘可能也在边缘图像内。这些虚边缘可能是真实图像产生的,也可能是由于噪声所产生的。对于后者,必须将其剔除。
设置两个阈值,其中一个为高阈值 maxVal,另一个为低阈值 minVal。根据当前边缘像素的梯度值(指的是梯度幅度,下同)与这两个阈值之间的关系,判断边缘的属性。具体步骤为:
(1)如果当前边缘像素的梯度值大于或等于 maxVal,则将当前边缘像素标记为强边缘。
(2)如果当前边缘像素的梯度值介于 maxVal 与 minVal 之间,则将当前边缘像素标记为虚
边缘(需要保留)。
(3)如果当前边缘像素的梯度值小于或等于 minVal,则抑制当前边缘像素。
在上述过程中,我们得到了虚边缘,需要对其做进一步处理。一般通过判断虚边缘与强边缘是否连接,来确定虚边缘到底属于哪种情况。通常情况下,如果一个虚边缘:
 与强边缘连接,则将该边缘处理为边缘。
 与强边缘无连接,则该边缘为弱边缘,将其抑制。
原文链接:https://blog.csdn.net/m0_51402531/article/details/121066693
OpenCV——Canny边缘检测(cv2.Canny())

四、查找轮廓

报错信息
在这里插入图片描述
报错原因,opencv版本问题,我使用的是opencv3.4.11,升级后(opencv4.5.5)解决该问题
在这里插入图片描述
在这里插入图片描述

#test5-4.py 查找轮廓 
#操作步骤
#1. 首先将原图转为灰度图(cv2.cvtColor())
#2. 将灰度图转换为二值图(cv2.threshold())
#3. 通过查找轮廓函数返回点集合[c可能是列表,也有可能是元组] cv2.findcontours()
#4. 绘制轮廓  polylines() 需要c的点集合

#c,h=cv2.findcontours(img2,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
    #c表示的时轮廓,返回的时列表
    #h是层次,返回的是numpy数组
    #cv2.RETR_TREE 检索所有轮廓并创建完整的层次列表,比如父级,子级
    #cv2.CHAIN_APPROX_SIMPLE:保持水平、垂直、对角线的端点
import cv2
import numpy as np
img = cv2.imread('shapes.jpg')
cv2.imshow('original',img)

gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #转换为灰度图像
ret,img2 = cv2.threshold(gray,125,255,cv2.THRESH_BINARY)#二值化阈值处理,将大于125的像素的值设置为255,
                                                        #小于125的像素设置为0
c,h = cv2.findContours(img2,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) #查找轮廓的函数
print('轮廓:',c)                                        #返回的是列表,但Opencv版本不同,结果可能不同,有可能是元组类型tuple
print('轮廓类型:',type(c))                             
print('轮廓个数:',len(c))
print('层次类型',type(h))
print('层次',h)

for n in(range(3)):
    img3 = np.zeros(img.shape,np.uint8)+255  #按原图大小创建一个白色背景
    cv2.polylines(img3,[c[n]],True,(255,0,0),2) #按照点的集合重新绘制查找到的轮廓 cv2.polylines()函数 44页
                                                #c[n]表示各个轮廓的点集合,c[0]表示第一个轮廓点集
    cv2.imshow('%s'%n,img3)                     #显示轮廓 %s表示占位符 
cv2.waitKey(0)                                            

在这里插入图片描述
参考:opencv:图像轮廓检测 cv2.findContours() 与 cv2.drawContours()

五、绘制轮廓

在这里插入图片描述

#test5-5.py:绘制轮廓
#先查找后绘制,前7行代码与查找轮廓代码一致
import cv2
import numpy as np
img=cv2.imread('shapes.jpg')        #读取图像
cv2.imshow('original',img)  	    #显示原图像
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#转化为灰度图像
ret,img2=cv2.threshold(gray,125,255,cv2.THRESH_BINARY)#二值化阈值处理
c,h=cv2.findContours(img2,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) 

img3=np.zeros(img.shape, np.uint8)+255 	    #按原图大小创建一幅白色图像
#image=cv2.drawContours(image,contours,contourIdx,color,thickness)
#image:原图
#contours为要绘制的轮廓

img3=cv2.drawContours(img3,c,-1,(0,0,255),2)    #绘制轮廓 -1表示绘制所有轮廓
cv2.imshow('Contours',img3)  	                #显示轮廓图像
cv2.waitKey(0)                                  #按任意键结束等待
cv2.destroyAllWindows()                         #关闭所有窗口

六、轮廓特征

1.轮廓的矩
在这里插入图片描述

#test5-6.py:轮廓矩
import cv2
import numpy as np
img=cv2.imread('shape2.jpg')        #读取图像
cv2.imshow('original',img)  	    #显示原图像
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#转化为灰度图像
ret,img2=cv2.threshold(gray,125,255,cv2.THRESH_BINARY)#二值化阈值处理
c,h=cv2.findContours(img2,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) 
img3=np.zeros(img.shape, np.uint8)+255 	    #按原图大小创建一幅白色图像
img3=cv2.drawContours(img3,c,-1,(0,0,255),2)    #绘制轮廓 -1表示绘制所有轮廓
cv2.imshow('Contours',img3)  	                #显示轮廓图像

for n in range(len(c)):
    m=cv2.moments(c[n])                         #cv2.moments()函数用于返回轮廓的矩 
                                                #返回的结果是字典类型 字典的内容在花括号 {} 内,
                                                # 键-值(key-value)之间用冒号 : 分隔,键值对之间用逗号 , 分隔
    print('轮廓%s的矩:'%n,m)   #输出轮廓矩 %s是占位符  
    print('轮廓%s的面积:'%n,m['m00'])   #输出轮廓面积
cv2.waitKey(0)                                  #按任意键结束等待
cv2.destroyAllWindows()                         #关闭所有窗口

2.轮廓面积
在这里插入图片描述

在这里插入图片描述

#test5-7.py:轮廓面积
import cv2
import numpy as np
img=cv2.imread('shape2.jpg')                            #读取图像
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)               #转化为灰度图像
ret,img2=cv2.threshold(gray,125,255,cv2.THRESH_BINARY)  #二值化阈值处理
c,h=cv2.findContours(img2,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)#查找轮廓

for n in range(len(c)):
    m=cv2.contourArea(c[n])             #计算轮廓面积
    print('轮廓%s的面积:'%n,m)          #输出轮廓面积

3.轮廓的长度
在这里插入图片描述

#test5-8.py:轮廓长度
import cv2
import numpy as np
img=cv2.imread('shape2.jpg')                            #读取图像
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)               #转化为灰度图像
ret,img2=cv2.threshold(gray,125,255,cv2.THRESH_BINARY)  #二值化阈值处理
c,h=cv2.findContours(img2,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) #查找轮廓

for n in range(len(c)):
    m=cv2.arcLength(c[n],True)                  #计算轮廓长度 True表示轮廓是封闭的
    print('轮廓%s的长度:'%n,m)                  #输出轮廓长度

4.轮廓的近似多边形
在这里插入图片描述

#test5-9.py:轮廓的近似多边形
import cv2
import numpy as np
img=cv2.imread('shape3.jpg')        #读取图像
cv2.imshow('original',img)  	    #显示原图像
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#转化为灰度图像
ret,img2=cv2.threshold(gray,125,255,cv2.THRESH_BINARY)#二值化阈值处理
c,h=cv2.findContours(img2,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) #查找轮廓

ep=[0.1,0.05,0.01]
arcl=cv2.arcLength(c[0],True)                  #计算轮廓长度
print(arcl)
img3=np.zeros(img.shape, np.uint8)+255 	        #按原图大小创建一幅白色图像
img3=cv2.drawContours(img3,c,-1,(0,0,255),2)    #绘制轮廓
for n in range(3):
    eps=ep[n]*arcl
    img4=img3.copy()
    app=cv2.approxPolyDP(c[0],eps,True)         #获得近似多边形
    img4=cv2.drawContours(img4,[app],-1,(255,0,0),2)    #绘制近似轮廓
    cv2.imshow('appro %.2f' % ep[n],img4)  	                #显示轮廓图像
cv2.waitKey(0)                                  #按任意键结束等待
cv2.destroyAllWindows()                         #关闭所有窗口

5.轮廓的凸包
在这里插入图片描述
在这里插入图片描述

#test5-10.py:轮廓的凸包
import cv2
import numpy as np
img=cv2.imread('shape3.jpg')        #读取图像
cv2.imshow('original',img)  	    #显示原图像
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#转化为灰度图像
ret,img2=cv2.threshold(gray,125,255,cv2.THRESH_BINARY)#二值化阈值处理
c,h=cv2.findContours(img2,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)  #查找轮廓

img3=np.zeros(img.shape, np.uint8)+255 	        #按原图大小创建一幅白色图像
img3=cv2.drawContours(img3,c,-1,(0,0,255),2)    #绘制轮廓

hull = cv2.convexHull(c[0])                     #returnPoints没写出来,则默认值是True,返回的是凸包关键点的坐标
print('returnPoints=True时返回的凸包:\n',hull)
hull2 = cv2.convexHull(c[0],returnPoints=False)
print('returnPoints=False时返回的凸包:\n',hull2)

cv2.polylines(img3,[hull],True,(255,0,0),2)	        #绘制凸包
cv2.imshow('Convex Hull',img3)  	                #显示轮廓图像

cv2.waitKey(0)                                      #按任意键结束等待
cv2.destroyAllWindows()                             #关闭所有窗口

6.轮廓的直边界矩形
在这里插入图片描述
在这里插入图片描述

#test5-11.py:轮廓的直边界矩形
import cv2
import numpy as np
img=cv2.imread('shape4.jpg')                			#读取图像
cv2.imshow('original',img)  	            			#显示原图像
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)   			#转化为灰度图像
ret,img2=cv2.threshold(gray,125,255,cv2.THRESH_BINARY)	#二值化阈值处理
c,h=cv2.findContours(img2,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)  #计算轮廓
img3=np.zeros(img.shape, np.uint8)+255 	        	    #按原图大小创建一幅白色图像
cv2.drawContours(img3,c,-1,(0,0,255),2)         		#绘制轮廓

ret=cv2.boundingRect(c[0])                      		#计算直边矩形 返回值ret是一个四元组
                                                        #(ret[0],ret[1])矩形左上角坐标 ret[2]、ret[3]矩形宽度和高度
print('直边界矩形:',ret)
pt1=(ret[0],ret[1])        
pt2=(ret[0]+ret[2],ret[1]+ret[3])                       #pt1的对角点坐标
cv2.rectangle(img3,pt1,pt2,(255,0,0),2)             	#绘制直边界矩形
cv2.imshow('Rectangle',img3)  	                  	    #显示结果图像
cv2.waitKey(0)                                      	#按任意键结束等待
cv2.destroyAllWindows()                             	#关闭所有窗口

7.轮廓的旋转矩阵
在这里插入图片描述
在这里插入图片描述

#test5-12.py:轮廓的旋转矩形
import cv2
import numpy as np
img=cv2.imread('shape4.jpg')                				#读取图像
cv2.imshow('original',img)  	            				#显示原图像
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)   			#转化为灰度图像
ret,img2=cv2.threshold(gray,125,255,cv2.THRESH_BINARY)	#二值化阈值处理
c,h=cv2.findContours(img2,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)  #计算轮廓
img3=np.zeros(img.shape, np.uint8)+255 	        	#按原图大小创建一幅白色图像
cv2.drawContours(img3,c,-1,(0,0,255),2)         		#绘制轮廓

ret=cv2.minAreaRect(c[0])                      		#计算最小矩形 
                                                    #返回值ret是一个三元组,((矩形中心点坐标x,y),(矩形的w,h),矩形的旋转角度)
print("三元组ret:",ret)
rect=cv2.boxPoints(ret)                             	#计算矩形顶点
print("矩形顶点:",rect)
print("rect类型:",type(rect))
rect=np.int0(rect)                                  	#转换为整数
cv2.drawContours(img3,[rect],0,(255,0,0),2)        	    #绘制旋转矩形
cv2.imshow('Rectangle',img3)  	                  	    	#显示结果图像
cv2.waitKey(0)                                      		#按任意键结束等待
cv2.destroyAllWindows()                             		#关闭所有窗口

8.轮廓的最小外包圆
在这里插入图片描述

#test5-13.py:轮廓的最小圆
import cv2
import numpy as np
img=cv2.imread('shape4.jpg')                				#读取图像
cv2.imshow('original',img)  	            				#显示原图像
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)   			#转化为灰度图像
ret,img2=cv2.threshold(gray,125,255,cv2.THRESH_BINARY)	#二值化阈值处理
c,h=cv2.findContours(img2,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)  #计算轮廓
img3=np.zeros(img.shape, np.uint8)+255 	        	#按原图大小创建一幅白色图像
cv2.drawContours(img3,c,-1,(0,0,255),2)         		#绘制轮廓

(x,y),radius=cv2.minEnclosingCircle(c[0])                #计算可容轮廓的最小外包圆
                                                         #(x,y)表示圆心,radius表示半径
center = (int(x),int(y))                                
radius = int(radius)
cv2.circle(img3,center,radius,(255,0,0),2)               #绘制最小圆
cv2.imshow('Circle',img3)  	                  	    	#显示结果图像
cv2.waitKey(0)                                      		#按任意键结束等待
cv2.destroyAllWindows()                             		#关闭所有窗口

9.轮廓的拟合椭圆
在这里插入图片描述
在这里插入图片描述

#test5-14.py:轮廓的拟合椭圆
import cv2
import numpy as np
img=cv2.imread('shape4.jpg')                				#读取图像
cv2.imshow('original',img)  	            				#显示原图像
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)   			#转化为灰度图像
ret,img2=cv2.threshold(gray,125,255,cv2.THRESH_BINARY)	#二值化阈值处理
c,h=cv2.findContours(img2,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)  #计算轮廓
img3=np.zeros(img.shape, np.uint8)+255 	        	#按原图大小创建一幅白色图像
cv2.drawContours(img3,c,-1,(0,0,255),2)         		#绘制轮廓

ellipse = cv2.fitEllipse(c[0])                           #计算拟合椭圆
print(ellipse)
cv2.ellipse(img3,ellipse,(255,0,0),2)                   #绘制拟合椭圆
cv2.imshow('ellipse',img3)  	                  	    	#显示结果图像
cv2.waitKey(0)                                      		#按任意键结束等待
cv2.destroyAllWindows()                             		#关闭所有窗口

10.轮廓的拟合直线
在这里插入图片描述
参考:opencv-python 中直线拟合函数cv.fitLine()的2D直线拟合(适合小白观看)

5.3 霍夫变换

在这里插入图片描述

5.4 实验

实验1
在这里插入图片描述

#test5-20.py:实验1 执行Canny边缘检测
import cv2
import numpy as np
img=cv2.imread('gate.jpg')                				#读取图像
cv2.imshow('original',img)  	            			#显示原图像
img2=cv2.Canny(img,100,150)                             #执行边缘检测
cv2.imshow('Canny',img2)  	                  	    	#显示结果图像
cv2.waitKey(0)                                          #按任意键结束等待
cv2.destroyAllWindows()                                 #关闭所有窗口

实验2
在这里插入图片描述

#test5-20.py:实验2 查找和绘制轮廓
import cv2
import numpy as np
img=cv2.imread('gate.jpg')       	 				#读取图像
cv2.imshow('original',img)  	    						#显示原图像
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)				#转化为灰度图像
ret,img2=cv2.threshold(gray,125,255,cv2.THRESH_BINARY)	#二值化阈值处理
c,h=cv2.findContours(img2,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) #查找轮廓

img3=np.zeros(img.shape, np.uint8)+255 	    		#按原图大小创建一幅白色图像
img3=cv2.drawContours(img3,c,-1,(0,0,255),2)    	#绘制轮廓 -1表示绘制所有轮廓
cv2.imshow('Contours',img3)  	                		#显示轮廓图像
cv2.waitKey(0)                                  		#按任意键结束等待
cv2.destroyAllWindows()                         		#关闭所有窗口

习题

习题5-1 5-2 5-3
在这里插入图片描述

#选择一幅图像,对其执行Laplacian、Sobel、Canny边缘检测

import cv2
img = cv2.imread('bee.jpg')   
cv2.imshow('original',img)

#Laplacian边缘检测
img2 = cv2.Laplacian(img,cv2.CV_8U,ksize=1) # ddepth参数可以用-1表示(与原图深度一致)
                                            #CV_8U 数据累心结构:CV_【bit_depth】【U】 U表示无符号 
                                            #ksize内核大小设置为1,3,5,7  
#Sobel边缘检测
img3=cv2.Sobel(img,cv2.CV_8U,0,1)   #边缘检测
                                    #dx和dy指的是求导的阶数,0表示这个方向上没有求导,所填的数一般为0、1、2
                                    #(0表示不求偏导,1表示1阶偏导,2表示2阶偏导)
                                    # dx >= 0 && dy >= 0 && dx+dy > 0
                                    #ksize是Sobel算子的大小,即卷积核的大小,必须为奇数1、3、5、7。如果ksize=-1,就演变成为3x3的Scharr算子,
                                    # scale是缩放导数的比例常数,默认情况为没有伸缩系数。
                                    # borderType是判断图像边界的模式,这个参数默认值为cv2.BORDER_DEFAULT。 
img4 = cv2.Canny(img,100,200,apertureSize=3)  #边缘检测 100表示的是最低阈值,200表示最高阈值,这两个阈值自定义设置
                               #注意,这里aperturSize=3表示计算梯度时使用的Sobel算子                                                                                  
cv2.imshow('Laplacian',img2)
cv2.imshow('Sobel',img3)
cv2.imshow('Canny',img4)
cv2.waitKey(0)

总结

提示:这里对文章进行总结:

  1. Laplacian和Sobel边缘检测:ksize是算子的大小,必须为1、3、5、7。默认为1 用于计算二阶导数的滤波器的孔径尺寸,大小必须为正奇数(正奇数才能有中心点)
  2. 数据类型结构: CV_ 【bit_depth】【S/U/F】【C<number_of_channels>】CV_8U - 8位无符号整数(0…255)
  3. Sobel边缘检测中:dx和dy指的是求导的阶数,0表示这个方向上没有求导,所填的数一般为0、1、2(dx >= 0 && dy >= 0 && dx+dy > 0)
  4. Canny边缘检测中:其中一个为高阈值 maxVal,另一个为低阈值 minVal。

猜你喜欢

转载自blog.csdn.net/xiaoren886/article/details/127930809