资讯专栏INFORMATION COLUMN

备份笔记

jsyzchen / 1234人阅读

摘要:步骤高斯平滑去噪计算梯度强度及方向非极大抑制在每一点上,首先将梯度近似为四个方向,然后将领域中心与沿着其对应的梯度方向的两个像素相比,若中心像素为最大值,则保留,否则中心置,这样可以抑制非极大值,保留局部梯度最大的点,以得到细化的边缘。

之前的OpenCV笔记


图像的获取

  • .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包
  • 上面的这些函数,你能看到一些相同的参数:
    • img:你想画的图片
    • color:形状的颜色,如 BGR,它是一个元组,例如:蓝色(255,0,0)。对于灰度图,只需传一个标量值。
    • thickness: 线或圆等的厚度。如果传 -1 就是像圆的闭合图形,它将填充形状。_ 默认 thickness = 1_
    • lineType:线条类型,如 8 连接,抗锯齿线等。默认情况下,它是 8 连接。cv.LINE_AA 画出抗锯齿线,非常好看的曲线。

鼠标事件

  • 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-定义要添加的边框类型的标志。它可以是以下类型:

      • 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 执行仿射变换

      • src - 输入图像。
        M - 变换矩阵。
        dsize - 输出图像的大小。
        flags - 插值方法的组合(int 类型!)
        borderMode - 边界像素模式(int 类型!)
        borderValue - (重点!)边界填充值; 默认情况下,它为0
    • .GetPerspectiveTransform(src, dst) 透视变换(Perspective Transformation)是将成像投影到一个新的视平面(Viewing Plane),也称作投影映射(Projective Mapping)。

      • src:源图像中待测矩形的四点坐标
      • sdt:目标图像中矩形的四点坐标
    • cv2.warpPerspective(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]]) → dst#获取变换矩阵

      参数为:

      • src:输入图像
      • M:变换矩阵
      • dsize:目标图像shape
      • flags:插值方式,interpolation方法INTER_LINEAR或INTER_NEAREST
      • borderMode:边界补偿方式,BORDER_CONSTANT or BORDER_REPLICATE
      • borderValue:边界补偿大小,常值,默认为0
  • 图像阈值

    • retVal, thresh = cv2.threshold(需要处理的图像,阈值,分配的值,阈值处理模式选择)

      • 参数1,需要处理的图像:注意,需要处理的图像需要被转成灰度图像(后面小试一下部分会讲解)

        参数2,阈值:设定阈值,分界值

        参数3,分配的值:如果一个像素的灰度值,大于或者小于(取决于参数4的选择)阈值,会被赋予分配的值

        参数4,

        • cv2.THRESH_BINARY
        • cv2.THRESH_BINARY_INV
        • cv2.THRESH_TRUNC
        • cv2.THRESH_TOZERO
        • cv2.THRESH_TOZERO_INV
      • 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]])
        • src:输入图像
        • d:过滤时周围每个像素领域的直径
        • sigmaColor:在color space中过滤sigma。参数越大,临近像素将会在越远的地方mix。
        • sigmaSpace:在coordinate space中过滤sigma。参数越大,那些颜色足够相近的的颜色的影响越大。
      • 保留边缘的消噪,绝绝子,但是速度慢
  • 形态转换了佳人们

    • .erode(img,kernel,iterations = 1) 腐蚀操作
      • 内核在图像内移动,只有内核所在位置均为1时才会为1,否则均为0
      • 有助于消除小的白色噪音(如我们在“颜色空间”一章中所看到的),分离两个连接的对象等
    • .dilate(img,kernel,iterations = 1) 膨胀操作
      • 如果内核下至少有一个像素为“1”,则像素元素为“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 ,
      • 矩形:MORPH_RECT;
      • 交叉形:MORPH_CROSS;
      • 椭圆形:MORPH_ELLIPSE;
  • 隔着整梯度算法是吧

    • Sobel

      • dst = cv2.Sobel(src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]])

        • 第一个参数是需要处理的图像;
        • 第二个参数是图像的深度,-1表示采用的是与原图像相同的深度。目标图像的深度必须大于等于原图像的深度,一般为.CV_**
        • dx和dy表示的是求导的阶数,0表示这个方向上没有求导,一般为0、1、2
      • 原理:图像中的边缘区域,像素值会发生“跳跃”,对这些像素求导,在其一阶导数在边缘位置为极值,这就是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]]]]])
        • ksize是算子的大小,必须为1、3、5、7。默认为1。
          scale是缩放导数的比例常数,默认情况下没有伸缩系数;
          delta是一个可选的增量,将会加到最终的dst中,同样,默认情况下没有额外的值加到dst中;
          borderType是判断图像边界的模式。这个参数默认值为cv2.BORDER_DEFAULT。
      • 原理:如果对像素值求二阶导数,会发现边缘处的导数值为0,Laplace函数实现的方法是先用Sobel 算子计算二阶x和y导数,再求和
    • Canny

      • 非常的好用 .Canny() 第一个参数为原图像,第二个和第三个参数分别是我们的 minVal 和 maxVal。第四个参数是 aperture_size。它是用于查找图像渐变的 Sobel 内核的大小。默认情况下,它是 3.最后一个参数是 L2gradient,它指定用于查找梯度幅度的等式。

      • 步骤

        • 1.高斯平滑去噪

        • 2.计算梯度强度及方向(非极大抑制

          • 在每一点上,首先将梯度近似为四个方向,然后将领域中心 x 与沿着其对应的梯度方向的两个像素相比,若中心像素为最大值,则保留,否则中心置0,这样可以抑制非极大值,保留局部梯度最大的点,以得到细化的边缘。
        • 3.经过非极大抑制后图像中仍然有很多噪声点。Canny算法中应用了一种叫双阈值的技术。即设定一个阈值上界和阈值下界(opencv中通常由人为指定的),图像中的像素点如果大于阈值上界则认为必然是边界(称为强边界,strong edge),小于阈值下界则认为必然不是边界,两者之间的则认为是候选项(称为弱边界,weak edge),需进行进一步处理。

        • 4.和强边界相连的弱边界认为是边界,其他的弱边界则被抑制。

    • 轮廓

      • 为了找轮廓一般用二值图像,因此需要先阈值或者Canny
      • contours, hierarchy = cv.findContours( image, mode, method[, contours[, hierarchy[, offset]]] )
        • 参数1:源图像
        • 参数2:轮廓的检索方式一般用 .RETR_TREE ,详细见此处)
        • 参数3:一般用 cv.CHAIN_APPROX_SIMPLE,就表示用尽可能少的像素点表示轮廓
        • contours:图像轮廓坐标,是一个链表
        • hierarchy:[Next, Previous, First Child, Parent],文中有详细解释
    • 轮廓操作

      • 绘制轮廓 .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]]])

        • points: 就是我们传入的轮廓。
        • hull: 是输出,通常我们避免它。
        • clockwise:方向标记。如果为True,则输出凸包为顺时针方向。否则,其方向为逆时针方向。
        • returnPoints:默认情况下为True。然后返回船体点的坐标。如果为False,则返回与船体点相对应的轮廓点的索引。
      • 凸包的定义

        • 换句话,对于空间中的对象.如果对象中的任意两个点构成的线段,也包含在对象内,则称对象是凸的。
      • 凸包外观看起来与轮廓逼近相似,但并非如此(在某些情况下两者可能提供相同的结果)

      • .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)
      • 点多边形测试(点与轮廓位置)

相关文章

  • 2021年10月6日 软考中级笔记---软件设计师(B站视频笔记

    摘要:死锁问题可以预防,可以解决死锁年月日数据库的完整性约束实体完整性约束定义主键。主键不能为空,不能重复参照完整性约束外键。系统需要进行多次连接,才能进行查询操作,是的系统效率大大下降。 ...

    superPershing 评论0 收藏0
  • Linux云计算笔记(一)

    摘要:的备份和恢复的过程是可以被终端然后后继续的,无须冻结文件系统。甚至提供了高性能的多线程备份操作,它把一次拆分多个数据流,每个数据流可以被发往不同的目的地。 基本网络知识 ifconfig 用来配置网络或查看当前网络接口的状态 临时修改网卡IP地址 ifconfig 网卡名称 IP地址 直接修改网卡的IP地址,重启失效 说明:修改后当前终端会终端,需要重新使用新的I...

    yintaolaowanzi 评论0 收藏0
  • mongo备份笔记

    摘要:转载请注明出处原文排版地址点击跳转全局的备份恢复备份迁移到本机恢复复制到这个文件夹进入进入指定集合的导入导出导出数据库中指定集合的数据导出集合中指定字段的数据,导出的文件格式为根据条件导出数据 转载请注明出处 http://www.paraller.com 原文排版地址 点击跳转 全局的备份恢复 备份 mongodump -d yea -o /data/db/3.1_2017_07...

    Jiavan 评论0 收藏0
  • mysql笔记

    摘要:遇到的问题安装指令注意事项按照上面的指令安装是傻瓜式的安装,而且不容易出问题,另外还有其他的安装方法,可以通过的下载的安装包,然后通过指令解压,前提是你下载的安装包是压缩包。 遇到的mysql问题 1 、安装mysql 指令 shellyum install mysql yum -y install mysql-server service mysqld start mysql ...

    xushaojieaaa 评论0 收藏0
  • 备份一点笔记, 关于用 escodegen 将 JavaScript AST 转化为代码

    摘要:这是项目相关的代码就是把代码变换成代码当前版本的用的是手工转化代码是比较乱的虽然也比较有效其中支持导致代码的复杂性难以降低而且实际上我当前写的几个项目都是没有开启因为提升并不明显另一个原因是代码和几乎是对应的在对所有文件都打包的前提下查看源 这是 Cirru 项目相关的代码, 就是把 Cirru 代码变换成 JavaScript 代码 当前版本的 CirruScript 用的是手工转化...

    novo 评论0 收藏0
  • 免费网易有道云笔记支持跨平台多设备同步云端笔记

    摘要:有道云笔记支持电脑客户端软件和手机客户端,也可以在线,可以实现多端同步管理。老蒋觉得有道云笔记的写作体验是比较好的。以前我们是否也有记日记的习惯?或者喜欢到每年年底准备新年的笔记本用来记录新的一年中的事儿或者日常的文档笔记。但是,随着电脑的普及,我们很多事情基本上都在电脑上完成,除了我们上学时候用到本子和笔的,工作之后能电脑代替的,可能很少会用到写字,于是乎原本记日记、写写随笔之类的可能也丢...

    Winer 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<