摘要:步骤高斯平滑去噪计算梯度强度及方向非极大抑制在每一点上,首先将梯度近似为四个方向,然后将领域中心与沿着其对应的梯度方向的两个像素相比,若中心像素为最大值,则保留,否则中心置,这样可以抑制非极大值,保留局部梯度最大的点,以得到细化的边缘。
.VideoCapture()
获取视频流 cap
.isOpened()
返回是否打开
.read()
读取一张照片,一帧一帧读,而不是抽帧读
.get(propId)
获取视频特征, .set(propId, value)
修改值
import numpy as npimport cv2 as cvcap = cv.VideoCapture(0)while(True): # 一帧一帧捕捉 ret, frame = cap.read() # 我们对帧的操作在这里 gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY) # 显示返回的每帧 cv.imshow("frame",gray) if cv.waitKey(1) & 0xFF == ord("q"): break# 当所有事完成,释放 VideoCapture 对象cap.release()cv.destroyAllWindows()
.imread()
读取图片
.line()
.circle()
.rectangle()
.ellipse()
画椭圆.putText()
写中文的话要改调用 PIL包import numpy as npimport cv2 as cv# 鼠标回调函数def draw_circle(event,x,y,flags,param): if event == cv.EVENT_LBUTTONDBLCLK: cv.circle(img,(x,y),100,(255,0,0),-1)# 创建一个黑色图像,一个窗口,然后和回调绑定img = np.zeros((512,512,3), np.uint8)cv.namedWindow("image")cv.setMouseCallback("image",draw_circle)while(1): cv.imshow("image",img) if cv.waitKey(20) & 0xFF == 27: breakcv.destroyAllWindows()
其中 cv2.EVENT_LBUTTONDOWN
等属性可以判断一直按下等操作
Numpy 是一个用于快速阵列计算的优化库。因此,简单地访问每个像素值并对其进行修改将非常缓慢,并不鼓励这样做。
img.dtype
获取图像数据类型
合并与拆分
>>>b,g,r = cv.spilt(img) #拆分,速度慢>>>img = cv.merge((b,g,r))#合并,一般BGR
制作边界
.copyMakeBorder()
src-输入的图像
top,bottom,left,right-上下左右四个方向上的边界拓宽的值
borderType-定义要添加的边框类型的标志。它可以是以下类型:
- cv.BORDER_CONSTANT- 添加一个恒定的彩色边框。该值应作为下一个参数value给出。
- cv.BORDER_REFLECT-边框将是边框元素的镜像反射,如下所示:fedcba|abcdefgh|hgfedcb
- cv.BORDER_REFLECT_101或者 cv.BORDER_DEFAULT-与上面相同,但略有改动,如下所示: gfedcb | abcdefgh | gfedcba
- cv.BORDER_REPLICATE -最后一个元素被复制,如下所示: aaaaaa | abcdefgh | hhhhhhh
- cv.BORDER_WRAP-不好解释,它看起来像这样: cdefgh | abcdefgh | abcdefg
value- 如果边框类型为cv.BORDER_CONSTANT,则这个值即为要设置的边框颜色
图像加法
找不同:
>>> x = np.uint8([250])>>> y = np.uint8([10])>>> print(cv.add(x,y)) #250 + 10 =260 => 255[[255]]>>> print(x + y)[4]
addWeighted(img1,0.7,img2,0.3,0)
权重相加
img1 = cv.imread("messi5.jpg")e1 = cv.getTickCount()#返回执行程序此时时钟数for i in xrange(5,49,2): img1 = cv.medianBlur(img1,i)e2 = cv.getTickCount()#返回执行程序此时时钟数t = (e2 - e1)/cv.getTickFrequency()#除每秒时钟数print( t )# 得到的结果是 0.521107655 秒
OpenCV自带默认优化,可以使用 cv.useOptimized() 来检查它是否已启用/禁用,并使用 cv.setUseOptimized() 来启用/禁用它
.cvtColor(input_image, flag)
更改颜色空间
flag
为 .COLOR_
开头一般更改完颜色空间后使用 .inRange()
返回指定范围内颜色
.getAffineTransform()
仿射变换(Affine Transformation)是指在向量空间中进行一次线性变换(乘以一个矩阵)和一次平移(加上一个向量),变换到另一个向量空间的过程。变换矩阵存为 np.float32 类型的 numpy 数组
.warpAffine(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]]) → dst
执行仿射变换
.GetPerspectiveTransform(src, dst)
透视变换(Perspective Transformation)是将成像投影到一个新的视平面(Viewing Plane),也称作投影映射(Projective Mapping)。
cv2.warpPerspective(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]]) → dst#获取变换矩阵
参数为:
图像阈值
retVal, thresh = cv2.threshold(需要处理的图像,阈值,分配的值,阈值处理模式选择)
参数1,需要处理的图像:注意,需要处理的图像需要被转成灰度图像(后面小试一下
部分会讲解)
参数2,阈值:设定阈值,分界值
参数3,分配的值:如果一个像素的灰度值,大于或者小于(取决于参数4的选择)阈值,会被赋予分配的值
参数4,
def adaptiveThreshold(src,maxValue,adaptiveMethod,thresholdType,blockSize,C,dst=None)
maxval:Double类型的,阈值的最大值
adaptiveMethod:Int类型的,这里有两种选择
1 —— ADAPTIVE_THRESH_MEAN_C(通过平均的方法取得平均值)
2 —— ADAPTIVE_THRESH_GAUSSIAN_C(通过高斯取得高斯值)
不过这两种方法最后得到的结果要减掉参数里面的C值
thresholdType:Int类型的,方法如下:
THRESH_BINARY 二进制阈值化 -> 大于阈值为1 小于阈值为0
THRESH_BINARY_INV 反二进制阈值化 -> 大于阈值为0 小于阈值为1
THRESH_TRUNC 截断阈值化 -> 大于阈值为阈值,小于阈值不变
THRESH_TOZERO 阈值化为0 -> 大于阈值的不变,小于阈值的全为0
THRESH_TOZERO_INV 反阈值化为0 -> 大于阈值为0,小于阈值不变
blockSize:Int类型的,这个值来决定像素的邻域块有多大。
注意:这里的blockSize的值要为奇数,否则会给出这样的提示:
Assertion failed (blockSize % 2 == 1 && blockSize > 1) in cv::adaptiveThreshold
C:偏移值调整量,计算adaptiveMethod用到的参数。
实验中,我阈值的type选择第一种,来演示这两种方式得出的结果
当blockSize的值比较小的时候,两种方法得到的结果的差异不是很大
当blockSize的值比较大的时候,就会发现,平均的这种会将整体的轮廓加深的程度大于高斯
直接看图:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K6gQJd6p-1633572209561)(https://opencv.apachecn.org/docs/4.0.0/img/Image_Thresholding_2.png)]
我图片上虽然显示的blockSize为10,不过我在程序里面做了判断,当为偶数的情况,就让它+1变成奇数。
Otus二值化
import cv2 as cvimport numpy as npfrom matplotlib import pyplot as pltimg = cv.imread("noisy2.png",0)# 全局阈值ret1,th1 = cv.threshold(img,127,255,cv.THRESH_BINARY)# Otsu 阈值ret2,th2 = cv.threshold(img,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)# 经过高斯滤波的 Otsu 阈值blur = cv.GaussianBlur(img,(5,5),0)ret3,th3 = cv.threshold(blur,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)# 画出所有的图像和他们的直方图images = [img, 0, th1, img, 0, th2, blur, 0, th3]titles = ["Original Noisy Image","Histogram","Global Thresholding (v=127)", "Original Noisy Image","Histogram","Otsu"s Thresholding", "Gaussian filtered Image","Histogram","Otsu"s Thresholding"]for i in xrange(3): plt.subplot(3,3,i*3+1),plt.imshow(images[i*3],"gray") plt.title(titles[i*3]), plt.xticks([]), plt.yticks([]) plt.subplot(3,3,i*3+2),plt.hist(images[i*3].ravel(),256) plt.title(titles[i*3+1]), plt.xticks([]), plt.yticks([]) plt.subplot(3,3,i*3+3),plt.imshow(images[i*3+2],"gray") plt.title(titles[i*3+2]), plt.xticks([]), plt.yticks([])plt.show()
图像模糊
.blur()
默认3*3均值滤波.boxFliter()
不使用3*3的滤波.GaussianBlur(img,(5,5),0)
正态分布的卷积核,消除高斯噪声.medianBlur(img,5)
像素点所在5*5范围内中间值替换该像素,可有效降低噪声.bilateralFilter(src, d, sigmaColor, sigmaSpace[, dst[, borderType]])
形态转换了佳人们
.erode(img,kernel,iterations = 1)
腐蚀操作 .dilate(img,kernel,iterations = 1)
膨胀操作 .morphologyEx(img, cv.MORPH_OPEN, kernel)
先腐蚀后膨胀.morphologyEx(img, cv.MORPH_CLOSE, kernel)
先膨胀后腐蚀.morphologyEx(img, cv.MORPH_GRADIENT, kernel)
膨胀和腐蚀间的差值.morphologyEx(img, cv.MORPH_TOPHAT, kernel)
原图像和开运算结果的差值.morphologyEx(img, cv.MORPH_BLACKHAT, kernel)
原图像和闭运算结果差值.getStructuringElement(cv2.MORPH_CROSS,(5,5))
获取各个形状的原图的 kernel , 隔着整梯度算法是吧
Sobel
dst = cv2.Sobel(src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]])
.CV_**
原理:图像中的边缘区域,像素值会发生“跳跃”,对这些像素求导,在其一阶导数在边缘位置为极值,这就是Sobel算子使用的原理——极值处就是边缘。
输出数据类型是 cv.CV_8U或 np.uint8。但这有一个小问题。黑白过渡为正斜率(有正值),而白黑过渡为负斜率(有负值)。所以当你把数据转换成 np.uint8 时,所有的负斜率都变成零。简单来说,你失去了边缘。
如果要检测两条边,更好的选择是将输出数据类型保留为更高的格式,如 cv.CV_16S、cv.CV_64F 等,取其绝对值,然后转换回 cv.CV_8U。下面的代码演示了水平 Sobel滤波器的过程以及结果差异。
Scharr
.Scharr(src, ddepth, dx, dy)
Sobel 算子虽然可以有效的提取图像边缘,但是对图像中较弱的边缘提取效果较差。
这是由于 Sobel 算子在计算相对较小的核的时候,其近似计算导数的精度比较低,例如一个 3 * 3
的 Sobel 算子,在梯度角度接近水平或垂直方向时,其不精确性就非常明显。
因此引入 Scharr 算子。 Scharr 算子是对 Sobel 算子差异性的增强,两者之间的在检测图像边缘的原理和使用方式上相同。
Laplacian
dst = cv2.Laplacian(src, ddepth[, dst[, ksize[, scale[, delta[, borderType]]]]])
Canny
非常的好用 .Canny()
第一个参数为原图像,第二个和第三个参数分别是我们的 minVal 和 maxVal。第四个参数是 aperture_size。它是用于查找图像渐变的 Sobel 内核的大小。默认情况下,它是 3.最后一个参数是 L2gradient,它指定用于查找梯度幅度的等式。
步骤
1.高斯平滑去噪
2.计算梯度强度及方向(非极大抑制)
3.经过非极大抑制后图像中仍然有很多噪声点。Canny算法中应用了一种叫双阈值的技术。即设定一个阈值上界和阈值下界(opencv中通常由人为指定的),图像中的像素点如果大于阈值上界则认为必然是边界(称为强边界,strong edge),小于阈值下界则认为必然不是边界,两者之间的则认为是候选项(称为弱边界,weak edge),需进行进一步处理。
4.和强边界相连的弱边界认为是边界,其他的弱边界则被抑制。
轮廓
contours, hierarchy = cv.findContours( image, mode, method[, contours[, hierarchy[, offset]]] )
.RETR_TREE
,详细见此处)轮廓操作
绘制轮廓 .drawContours(img, contours, -1, (0,255,0), 3)
图像的矩
图像矩可用来计算某些特征,例如物体的重心,物体的面积等,可以用 .moments(cnt)
得到所有矩
可以用图像的矩计算出重心:
Cannot read property "type" of undefined
轮廓面积 .contourArea()
轮廓周长 .arcLength()
轮廓近似
获取轮廓外围
设置精度(从轮廓到近似轮廓的最大距离)
获取近似轮廓
绘制轮廓
#参照值:决定是否将一段曲线近为直线epsilon=0.1*cv2.arcLength(cnt,True)#近似轮廓approx=cv2.approxPolyDP(cnt,epsilon,True)#将近似出来的轮廓画在复制出来的图片上res=cv2.drawContours(draw_img,[approx],-1,(0,0,255),1)
凸包
hull = cv.convexHull(points[, hull[, clockwise[, returnPoints]]])
凸包的定义
凸包外观看起来与轮廓逼近相似,但并非如此(在某些情况下两者可能提供相同的结果)
.isContourConvex(cnt)
返回曲线是否是凸多边形
矩形
直角矩形
x,y,w,h = cv.boundingRect(cnt)cv.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
旋转矩形
rect = cv.minAreaRect(cnt)#返回一个Box2D结构,其中包含以下细节-(中心(x,y),(宽度,高度),旋转角度)box = cv.boxPoints(rect)#返回矩形的4个角box = np.int0(box)cv.drawContours(img,[box],0,(0,0,255),2)
圆
(x,y),radius = cv.minEnclosingCircle(cnt)center = (int(x),int(y))radius = int(radius)cv.circle(img,center,radius,(0,255,0),2)
拟合线
rows,cols = img.shape[:2][vx,vy,x,y] = cv.fitLine(cnt, cv.DIST_L2,0,0.01,0.01)lefty = int((-x*vy/vx) + y)righty = int(((cols-x)*vy/vx)+y)cv.line(img,(cols-1,righty),(0,lefty),(0,255,0),2)
轮廓属性
长宽比:对象边界矩形的宽度与高度的比率
x,y,w,h = cv.boundingRect(cnt)aspect_ratio = float(w)/h
范围:轮廓区域与边界矩形区域的比率
area = cv.contourArea(cnt)x,y,w,h = cv.boundingRect(cnt)rect_area = w*hextent = float(area)/rect_area
固实性:轮廓面积与其凸包面积的比率
area = cv.contourArea(cnt)hull = cv.convexHull(cnt)hull_area = cv.contourArea(hull)solidity = float(area)/hull_area
等效直径是面积与轮廓面积相同的圆的直径
area = cv.contourArea(cnt)equi_diameter = np.sqrt(4*area/np.pi)
方向是物体指向的角度。以下方法还给出了主轴和副轴的长度
(x,y),(MA,ma),angle = cv.fitEllipse(cnt)
在某些情况下,我们可能需要构成该对象的所有点。可以按照以下步骤完成:
mask = np.zeros(imgray.shape,np.uint8)cv.drawContours(mask,[cnt],0,255,-1)pixelpoints = np.transpose(np.nonzero(mask))# pixelpoints = cv.findNonZero(mask)
给出了两种方法,一种使用Numpy函数,另一种使用OpenCV函数(最后注释的行)执行相同的操作。结果也相同,但略有不同。Numpy以(行,列)格式给出坐标,而OpenCV以(x,y)格式给出坐标。因此,基本上答案是可以互换的。注意,row = x,column = y
最大值、最小值及其位置
min_val, max_val, min_loc, max_loc = cv.minMaxLoc(imgray,mask = mask)
平均颜色
mean_val = cv.mean(im,mask = mask)
极点是指对象的最顶部,最底部,最右侧和最左侧的点
leftmost = tuple(cnt[cnt[:,:,0].argmin()][0])rightmost = tuple(cnt[cnt[:,:,0].argmax()][0])topmost = tuple(cnt[cnt[:,:,1].argmin()][0])bottommost = tuple(cnt[cnt[:,:,1].argmax()][0])
凸包缺陷
凸包缺陷就是凸包与轮廓间的部分
img = cv2.imread("图片名")gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)ret,binary= cv2.threshold(gray,127,255,cv2.THRESH_BINARY)contours,h= cv2.findContours(binary,cv2.RETR_LIST,/ cv2.CHAIN_APPROX_SIMPLE)#获取凸包hull= cv2.convexHull(contours[0],returnPoints= False)#一定要写returnPoints= Falsedf= cv2.convexityDefects(contours[0],hull)
点多边形测试(点与轮廓位置)
查找图像中的点与轮廓之间的最短距离。它返回的距离为:当点在轮廓外时为负;当点在轮廓内时为正;如果点在轮廓上,则返回零。
dist = cv.pointPolygonTest(cnt,(50,50)
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/121808.html
摘要:死锁问题可以预防,可以解决死锁年月日数据库的完整性约束实体完整性约束定义主键。主键不能为空,不能重复参照完整性约束外键。系统需要进行多次连接,才能进行查询操作,是的系统效率大大下降。 ...
摘要:的备份和恢复的过程是可以被终端然后后继续的,无须冻结文件系统。甚至提供了高性能的多线程备份操作,它把一次拆分多个数据流,每个数据流可以被发往不同的目的地。 基本网络知识 ifconfig 用来配置网络或查看当前网络接口的状态 临时修改网卡IP地址 ifconfig 网卡名称 IP地址 直接修改网卡的IP地址,重启失效 说明:修改后当前终端会终端,需要重新使用新的I...
摘要:遇到的问题安装指令注意事项按照上面的指令安装是傻瓜式的安装,而且不容易出问题,另外还有其他的安装方法,可以通过的下载的安装包,然后通过指令解压,前提是你下载的安装包是压缩包。 遇到的mysql问题 1 、安装mysql 指令 shellyum install mysql yum -y install mysql-server service mysqld start mysql ...
摘要:这是项目相关的代码就是把代码变换成代码当前版本的用的是手工转化代码是比较乱的虽然也比较有效其中支持导致代码的复杂性难以降低而且实际上我当前写的几个项目都是没有开启因为提升并不明显另一个原因是代码和几乎是对应的在对所有文件都打包的前提下查看源 这是 Cirru 项目相关的代码, 就是把 Cirru 代码变换成 JavaScript 代码 当前版本的 CirruScript 用的是手工转化...
摘要:有道云笔记支持电脑客户端软件和手机客户端,也可以在线,可以实现多端同步管理。老蒋觉得有道云笔记的写作体验是比较好的。以前我们是否也有记日记的习惯?或者喜欢到每年年底准备新年的笔记本用来记录新的一年中的事儿或者日常的文档笔记。但是,随着电脑的普及,我们很多事情基本上都在电脑上完成,除了我们上学时候用到本子和笔的,工作之后能电脑代替的,可能很少会用到写字,于是乎原本记日记、写写随笔之类的可能也丢...
阅读 2523·2023-04-26 01:47
阅读 3405·2023-04-25 23:45
阅读 2076·2021-10-13 09:39
阅读 421·2021-10-09 09:44
阅读 1235·2021-10-08 10:05
阅读 1550·2021-09-22 15:59
阅读 2418·2021-09-13 10:33
阅读 1470·2021-09-03 10:30