美文网首页
图像轮廓(2)

图像轮廓(2)

作者: Tsukinousag | 来源:发表于2021-11-03 22:23 被阅读0次

    1. 凸包

    凸缺陷可以用来处理手势识别问题

    Hull = cv2.convexHull(points,clockwise,returnPoints)
    

    points:轮廓
    clockwise:True:凸包按顺时针方向排列;False:凸包按逆时针排列
    returnPoints:True:返回凸包角点(x,y)坐标 ;False:返回轮廓中凸包角点的索引

    import cv2
    
    img=cv2.imread("D:/part12/part12_8.bmp")
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    ret,binary=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
    contours,hierarchy=cv2.findContours(binary,
                                        cv2.RETR_LIST,
                                        cv2.CHAIN_APPROX_SIMPLE)
    
    hull1=cv2.convexHull(contours[0])
    print("默认是False,hull的值",hull1)
    
    hull2=cv2.convexHull(contours[0],returnPoints=False)
    print("是True,hull的值",hull2)
    
    默认是False,hull的值 [[[256  28]]
    
     [[260  29]]
    
     [[319  45]]
    
     [[392  91]]
    
    ...
    是True,hull的值 [[526]
     [524]
     [428]
     [347]
    ...
    

    绘制凸包

    import cv2
    
    img=cv2.imread("D:/part12/part12_8.bmp")
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    ret,binary=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
    contours,hierarchy=cv2.findContours(binary,
                                        cv2.RETR_LIST,
                                        cv2.CHAIN_APPROX_SIMPLE)
    
    hull=cv2.convexHull(contours[0])
    
    cv2.polylines(img,[hull],True,(0,255,0),2)
    
    cv2.imshow("img",img)
    
    cv2.waitKey(0)
    cv2.destroyWindow()
    

    2. 凸缺陷

    凸包与轮廓间的部分称为凸缺陷

    convexityDefects=cv2.convexityDefects(contour,convexhull)
    

    返回值:[起点,终点,轮廓上距离凸包最远的点,最远点的近似距离]

    前三个值是轮廓点的索引

    参数:contour是轮廓;convexhull是凸包

    因为用到的是轮廓点的索引,所以cv2.convexHull的参数returnPoints的值必须是False

    import cv2
    
    img=cv2.imread("D:/part12/part12_8.bmp")
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    ret,binary=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
    contours,hierarchy=cv2.findContours(binary,
                                        cv2.RETR_LIST,
                                        cv2.CHAIN_APPROX_SIMPLE)
    
    cnt=contours[0]
    
    hull=cv2.convexHull(cnt,returnPoints=False)
    
    defects=cv2.convexityDefects(cnt,hull)
    
    print("defects:\n",defects)
    
    ##构造凸缺陷
    for i in range(defects.shape[0]):
        s,e,f,d=defects[i,0]
        start=tuple(cnt[s][0])
        end=tuple(cnt[e][0])
        far=tuple(cnt[f][0])
        cv2.line(img,start,end,[0,0,255],2)
        cv2.circle(img,far,5,(255,0,0),-1)
    
    
    cv2.imshow("img",img)
    
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    defects:
     [[[    0   102    46 29796]]
    
     [[  102   105   104   284]]
    
     [[  106   166   133 17825]]
    
     [[  167   173   170   225]]
    
     [[  173   181   180   262]]
    
     [[  181   189   188   208]]
    
     [[  189   248   238  5027]]
    
     [[  250   344   267  3672]]
    
     [[  345   347   346   114]]
    
     [[  347   428   390 20365]]
    
     [[  428   524   479 28489]]
    
     [[  524   526   525   186]]]
    

    cnt=contours[0]
    #print(cnt) 随机图片会出现的问题,很小,捕捉不到凸包
    #[[[256 366]]
    
    # [[255 367]]]
    

    3. 几何学测试

    检测轮廓是否是凸形

    retval=cv2.isContourConvex(contour)
    

    retval: bool类型
    contour:需要判断的轮廓

    import cv2
    
    img=cv2.imread("D:/part12/part12_8.bmp")
    
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    ret,binary=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
    contours,hierarchy=cv2.findContours(binary,
                                        cv2.RETR_LIST,
                                        cv2.CHAIN_APPROX_SIMPLE)
    #-----------------凸包
    
    image1=img.copy()
    hull=cv2.convexHull(contours[0])
    cv2.polylines(image1,[hull],True,[0,255,0],2)
    print("使用函数cv2.convexHull()构造的多边形是否是凸形的:",cv2.isContourConvex(hull))
    cv2.imshow("result1",image1)
    
    #-------------------逼近多边形
    image2=img.copy()
    epsilon=0.01*cv2.arcLength(contours[0],True)
    approx=cv2.approxPolyDP(contours[0],epsilon,True)
    image2=cv2.drawContours(image2,[approx],0,(0,0,255),2)
    print("使用函数cv2.approxPolyDP()构造的多边形是否是凸形:",cv2.isContourConvex(approx))
    cv2.imshow("result2",image2)
    
    #-----------------------
    cv2.waitKey(0)
    cv2.destroyWindow()
    
    使用函数cv2.convexHull()构造的多边形是否是凸形的: True
    使用函数cv2.approxPolyDP()构造的多边形是否是凸形: False
    

    点到轮廓的距离

    用来计算点到多边形(轮廓)的最短距离,也就是垂线距离

    retval=cv2.pointPolygonTest(contour,pt,measureDist)
    

    pt: 为待判定的点
    measureDist:True(距离,内正,上0,外负);False(相对位置关系,1,-1,0)

    import cv2
    
    img=cv2.imread("D:/part12/part12_6.bmp")
    
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    ret,binary=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
    contours,hierarchy=cv2.findContours(binary,
                                        cv2.RETR_LIST,
                                        cv2.CHAIN_APPROX_SIMPLE)
    
    #---------------获取凸包
    image1=img.copy()
    hull=cv2.convexHull(contours[0])
    cv2.polylines(image1,[hull],True,(0,255,0),2)
    #print(hull)
    
    #------------------内部点A到轮廓的距离
    distA=cv2.pointPolygonTest(hull,(320,50),True)
    font=cv2.FONT_HERSHEY_SIMPLEX
    cv2.putText(image1,'A',(320,50),font,1,(0,255,0),3)
    print("distA=",distA)
    
    #-----------------轮廓上点B到轮廓的距离
    distB=cv2.pointPolygonTest(hull,(432,100),True)
    font=cv2.FONT_HERSHEY_SIMPLEX
    cv2.putText(image1,'B',(432,100),font,1,(0,255,0),3)
    print("distB=",distB)
    
    #-----------------轮廓外点C到轮廓的距离
    distC=cv2.pointPolygonTest(hull,(432,150),True)
    font=cv2.FONT_HERSHEY_SIMPLEX
    cv2.putText(image1,'C',(432,150),font,1,(0,255,0),3)
    print("distC=",distC)
    
    cv2.imshow("image1",image1)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    distA= 19.27341155003588
    distB= -0.0
    distC= -27.164164493555205
    

    点与轮廓的位置判断

    将参数改为False

    distA= 1.0
    distB= 0.0
    distC= -1.0
    

    4. 轮廓的特征值

    1.宽高比

    import cv2
    
    img=cv2.imread("D:/part12/part12_1.bmp")
    
    cv2.imshow("result",img)
    
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    ret,binary=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
    contours,hierarchy=cv2.findContours(binary,
                                        cv2.RETR_LIST,
                                        cv2.CHAIN_APPROX_SIMPLE)
    
    x,y,w,h=cv2.boundingRect(contours[0])
    cv2.rectangle(img,(x,y),(x+w,y+h),(255,255,255),3)
    aspectRatio=float(w)/h
    print(aspectRatio)
    cv2.imshow("result",img)
    cv2.waitKey(0)
    cv2.destroyWindow()
    
    
    1.6503067484662577
    

    2. Extent

    轮廓面积(对象面积)/矩形边界面积

    import cv2
    
    img=cv2.imread("D:/part12/part12_1.bmp")
    
    cv2.imshow("result",img)
    
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    ret,binary=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
    contours,hierarchy=cv2.findContours(binary,
                                        cv2.RETR_LIST,
                                        cv2.CHAIN_APPROX_SIMPLE)
    
    x,y,w,h=cv2.boundingRect(contours[0])
    cv2.drawContours(img,contours[0],-1,(0,0,255),3)
    cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),3)
    rectArea=w*h
    cntArea=cv2.contourArea(contours[0])
    extend=float(cntArea)/rectArea
    print(extend)
    cv2.imshow("result",img)
    cv2.waitKey(0)
    cv2.destroyWindow()
    
    0.6662371427919812
    

    3. Solidity

    轮廓面积/凸包面积

    import cv2
    
    img=cv2.imread("D:/part12/part12_6.bmp")
    
    cv2.imshow("result",img)
    
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    ret,binary=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
    contours,hierarchy=cv2.findContours(binary,
                                        cv2.RETR_LIST,
                                        cv2.CHAIN_APPROX_SIMPLE)
    
    cv2.drawContours(img,contours[0],-1,(0,255,255),3)
    
    hull=cv2.convexHull(contours[0])
    cntArea=cv2.contourArea(contours[0])
    hullArea=cv2.contourArea(hull)
    
    cv2.polylines(img,[hull],True,(0,255,0),2)
    
    solidity=float(cntArea)/hullArea
    
    print(solidity)
    cv2.imshow("result",img)
    cv2.waitKey(0)
    cv2.destroyWindow()
    
    0.7329527393863876
    

    4. 等效直径

    该值是与轮廓面积相等的圆形的直径

    import cv2
    import numpy as np
    
    img=cv2.imread("D:/part12/part12_1.bmp")
    
    cv2.imshow("img",img)
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    ret,binary=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
    contours,hierarchy=cv2.findContours(binary,
                                        cv2.RETR_LIST,
                                        cv2.CHAIN_APPROX_SIMPLE)
    
    cv2.drawContours(img,contours[0],-1,(0,0,255),3)
    cntArea=cv2.contourArea(contours[0])
    equiDiameter=np.sqrt(4*cntArea/np.pi)
    
    print(equiDiameter)
    cv2.circle(img,(100,100),int(equiDiameter/2),(0,0,255),3)
    cv2.imshow("result",img)
    
    cv2.waitKey(0)
    cv2.destroyWindow()
    
    192.85878305271953
    

    5. 方向

    (x,y),(MA,ma),angle=cv2.fitEllipse(cnt)
    

    其中:
    (x,y):椭圆的中心点
    (MA,ma) :椭圆水平方向轴和垂直方向轴的长度
    angle:椭圆的旋转角度

    import cv2
    
    img=cv2.imread("D:/part12/part12_1.bmp")
    
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    ret,binary=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
    contours,hierarchy=cv2.findContours(binary,
                                        cv2.RETR_LIST,
                                        cv2.CHAIN_APPROX_SIMPLE)
    
    ellipse=cv2.fitEllipse(contours[0])
    retval=cv2.fitEllipse(contours[0])
    
    print("单个返回形式:")
    print("retval=\n",retval)
    print("三个返回形式:")
    (x,y),(MA,ma),angle=cv2.fitEllipse(contours[0])
    
    print("(x,y)=(",x,y,")")
    print("(MA,ma)=(",MA,ma,")")
    print("angle=",angle)
    
    cv2.ellipse(img,ellipse,(0,0,255),2)
    cv2.imshow("img",img)
    cv2.waitKey(0)
    cv2.destroyWindow()
    
    单个返回形式:
    retval=
     ((246.05667114257812, 185.529541015625), (141.45005798339844, 282.24273681640625), 77.81553649902344)
    三个返回形式:
    (x,y)=( 246.05667114257812 185.529541015625 )
    (MA,ma)=( 141.45005798339844 282.24273681640625 )
    angle= 77.81553649902344
    

    6. 掩模和像素点

    6.1 使用Numpy函数获取轮廓像素点

    cv2.drawContours()轮廓宽度参数thickness设置为“-1”,即可获取特定对象的实心轮廓,即特定对象的掩模

    numpy.nonzero()
    #返回数组内非零元素的位置,但其返回的是行,列分别显示的
    
    numpy.transpose()
    #处理上述返回值,则得到这些点的(x,y)形式的坐标
    
    import numpy as np
    
    a=np.zeros((5,5),dtype=np.uint8)
    
    for time in range(10):
        i=np.random.randint(0,5)
        j=np.random.randint(0,5)
        a[i,j]=1
    
    print("a=\n",a)
    loc=np.transpose(np.nonzero(a))
    
    print("a内非零位置",loc)
    
    a=
     [[1 0 0 0 0]
     [1 0 0 0 1]
     [0 1 0 0 1]
     [1 1 1 1 0]
     [0 0 0 0 0]]
    a内非零位置 [[0 0]
     [1 0]
     [1 4]
     [2 1]
     [2 4]
     [3 0]
     [3 1]
     [3 2]
     [3 3]]
    

    使用numpy获取一个图像内的轮廓点位置

    import cv2
    import numpy as np
    
    img=cv2.imread("D:/part12/part12_1.bmp")
    
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    ret,binary=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
    contours,hierarchy=cv2.findContours(binary,
                                        cv2.RETR_LIST,
                                        cv2.CHAIN_APPROX_SIMPLE)
    
    cnt=contours[0]
    
    #-----------------------------------------绘制空心轮廓
    mask1=np.zeros(gray.shape,np.uint8)
    cv2.drawContours(mask1,[cnt],0,(255,255,255),2)
    pixelpoints1=np.transpose(np.nonzero(mask1))
    print("pixelpoints1.shape:",pixelpoints1.shape)
    print("pixelpoints1:\n",pixelpoints1)
    cv2.imshow("mask1",mask1)
    
    #-----------------------------------------绘制实心轮廓
    mask2=np.zeros(gray.shape,np.uint8)
    cv2.drawContours(mask2,[cnt],0,(255,255,255),-1)
    pixelpoints2=np.transpose(np.nonzero(mask2))
    print("pixelpoints2.shape:",pixelpoints2.shape)
    print("pixelpoints2:\n",pixelpoints2)
    cv2.imshow("mask2",mask2)
    
    cv2.waitKey(0)
    cv2.destroyWindow()
    
    
    cv2.waitKey(0)
    cv2.destroyWindow()
    
    pixelpoints1.shape: (2708, 2)
    pixelpoints1:
     [[111 276]
     [111 277]
     [111 278]
     ...
     [275 150]
     [275 151]
     [275 152]]
    pixelpoints2.shape: (29571, 2)
    pixelpoints2:
     [[112 277]
     [112 278]
     [112 279]
     ...
     [274 149]
     [274 150]
     [274 151]]
    
    6.1 使用Opencv函数获取轮廓像素点
    import cv2
    import numpy as np
    
    a=np.zeros((5,5),dtype=np.uint8)
    
    for time in range(5):
        i=np.random.randint(0,5)
        j=np.random.randint(0,5)
        a[i,j]=1
    
    print("a=\n",a)
    
    loc=cv2.findNonZero(a)
    
    print("a内非零值得位置:\n",loc)
    
    a=
     [[0 0 0 0 0]
     [0 0 1 0 0]
     [0 1 0 0 0]
     [0 0 0 0 0]
     [1 1 0 0 0]]
    a内非零值得位置:
     [[[2 1]]
    
     [[1 2]]
    
     [[0 4]]
    
     [[1 4]]]
    
    import cv2
    import numpy as np
    
    img=cv2.imread("D:/part12/part12_1.bmp")
    
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    ret,binary=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
    contours,hierarchy=cv2.findContours(binary,
                                        cv2.RETR_LIST,
                                        cv2.CHAIN_APPROX_SIMPLE)
    
    
    cnt=contours[0]
    
    #----------------绘制空心轮廓
    mask1=np.zeros(gray.shape,dtype=np.uint8)
    cv2.drawContours(mask1,[cnt],0,255,2)
    pixelpoints1=cv2.findNonZero(mask1)
    print("pixelpoints.shape",pixelpoints1.shape)
    print("pixelpoints",pixelpoints1)
    cv2.imshow("mask1",mask1)
    #----------------绘制实心轮廓
    mask2=np.zeros(gray.shape,dtype=np.uint8)
    cv2.drawContours(mask2,[cnt],0,255,-1)
    pixelpoints2=cv2.findNonZero(mask2)
    print("pixelpoints.shape",pixelpoints2.shape)
    print("pixelpoints",pixelpoints2)
    cv2.imshow("mask2",mask2)
    
    cv2.waitKey(0)
    cv2.destroyWindow()
    

    最大值和最小值以及其位置

    minval,maxval,minloc,maxloc=cv2.minMaxLoc(imgray,mask)
    

    指定的对象内查找最大值,最小值以及其位置

    import cv2
    import numpy as np
    
    img=cv2.imread("D:/101.bmp")
    
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    ret,binary=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
    contours,hierarchy=cv2.findContours(binary,
                                        cv2.RETR_LIST,
                                        cv2.CHAIN_APPROX_SIMPLE)
    
    cnt=contours[2]
    
    mask=np.zeros(gray.shape,dtype=np.uint8)
    mask=cv2.drawContours(mask,[cnt],-1,255,-1)
    
    cv2.imshow("mask",mask)
    
    minval,maxval,minloc,maxloc=cv2.minMaxLoc(gray,mask=mask)
    
    print("minval:\n",minval)
    print("maxval:\n",maxval)
    print("minloc:\n",minloc)
    print("maxloc:\n",maxloc)
    
    #构造掩模获取感兴趣区域
    masko=np.zeros(img.shape,dtype=np.uint8)
    masko=cv2.drawContours(masko,[cnt],-1,(255,255,255),-1)
    loc=cv2.bitwise_and(img,masko)
    
    cv2.imshow("loc",loc)
    
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    minval:
     127.0
    maxval:
     255.0
    minloc:
     (271, 148)
    maxloc:
     (271, 147)
    

    6. 平均颜色及灰度

    mean_val=cv2.mean(in,mask=mask)
    
    import cv2
    import numpy as np
    
    img=cv2.imread("D:/101.bmp")
    
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    ret,binary=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
    contours,hierarchy=cv2.findContours(binary,
                                        cv2.RETR_LIST,
                                        cv2.CHAIN_APPROX_SIMPLE)
    
    cnt=contours[2]
    
    mask=np.zeros(gray.shape,dtype=np.uint8)
    cv2.drawContours(mask,[cnt],0,255,-1)
    mean=cv2.mean(img,mask=mask)
    print("mean=:",mean)
    mask2=np.zeros(img.shape,dtype=np.uint8)
    cv2.drawContours(mask2,[cnt],0,(255,255,255),-1)
    loc=cv2.bitwise_and(img,mask2)
    
    cv2.imshow("loc",loc)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    mean=: (133.34867032503166, 133.34867032503166, 133.34867032503166, 0.0)
    

    7. 极点

    获取某个对象内的极点,例如最左端,最右端,最上端,最下端

    leftmost=tuple(cnt[cnt[:,:,0].argmin()][0])
    rightmost=tuple(cnt[cnt[:,:,0].argmax()][0])
    topmost=tuple(cnt[cnt[:,:,1].argmax()][0])
    bottommost=tuple(cnt[cnt[:,:,1].argmin()][0])
    
    import cv2
    import numpy as np
    
    img=cv2.imread("D:/part12/part12_6.bmp")
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    ret,binary=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
    contours,hierarchy=cv2.findContours(binary,
                                        cv2.RETR_LIST,
                                        cv2.CHAIN_APPROX_SIMPLE)
    
    cnt=contours[0]
    mask=np.zeros(gray.shape,dtype=np.uint8)
    cv2.drawContours(mask,[cnt],0,255,-1)
    #---------------------------------计算极值
    leftmost=tuple(cnt[cnt[:,:,0].argmin()][0])
    rightmost=tuple(cnt[cnt[:,:,0].argmax()][0])
    topmost=tuple(cnt[cnt[:,:,1].argmax()][0])
    bottommost=tuple(cnt[cnt[:,:,1].argmin()][0])
    #---------------------------------打印极值
    print("leftmost:",leftmost)
    print("rightmost:",rightmost)
    print("topmost",topmost)
    print("bottommost",bottommost)
    #---------------------------------绘制说明文字
    font=cv2.FONT_HERSHEY_SIMPLEX
    cv2.putText(img,'A',leftmost,font,1,(0,0,255),2)
    cv2.putText(img,'B',rightmost,font,1,(0,0,255),2)
    cv2.putText(img,'C',topmost,font,1,(0,0,255),2)
    cv2.putText(img,'D',bottommost,font,1,(0,0,255),2)
    
    #----------------------------------绘制图像
    cv2.imshow("img",img)
    
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    leftmost: (104, 159)
    rightmost: (434, 111)
    topmost (126, 237)
    bottommost (322, 27)
    

    相关文章

      网友评论

          本文标题:图像轮廓(2)

          本文链接:https://www.haomeiwen.com/subject/piayaltx.html