当前位置:   article > 正文

OpenCV计算机视觉实战(Python版)_07-图像金字塔与轮廓检测_np.asarray(contours).shape

np.asarray(contours).shape

图像金字塔 cv2.pyrDown(x) cv2.pyrUp(x)

  • 高斯金字塔
  • 拉普拉斯金字塔

金字塔的每一层特征可以采取不同的方式获得,这样每一层的特征都不同。

图像金字塔是一组图像的集合,集合中的所有图像都是通过对某一图像连续降采样得到的一组图像序列。

  • cv2.pyrUp: 上采样

  • cv2.pyrDown: 下采样

  • 有两种经典的金字塔:高斯金字塔和拉普拉斯金字塔,前者采用向下采样,后者是向上采样需要的缺失的信息。

  • 向下采样(生成高斯金字塔)的具体操作为: 从大到小

  •     1. 对图像进行高斯卷积

  •     2. 删除所有的偶数行和偶数列

  • 向上采样的缺失信息(生成拉普拉斯金字塔)的具体操作为:从小到大

  •     1. 首先将维数扩大两倍

  •     2. 将扩大位的值置为0

  •     3. 对新的图像进行高斯卷积

  •     4. 用新的层次的高斯金字塔减去 3 中形成的图像

高斯金字塔:向下采样方法(缩小)

高斯金字塔:向上采样方法(放大)

高斯金字塔程序

  1. import cv2
  2. img = cv2.imread("D:/WeChat.picture/AM.png")
  3. cv_show(img ,"img")
  4. print(img.shape)
  1. up = cv2.pyrUp(img)
  2. cv_show(up ,"up")
  3. print(up.shape)
  1. down = cv2.pyrDown(up)
  2. cv_show(down ,"down")
  3. print(down.shape)
  1. import numpy as np
  2. import cv2
  3. img = cv2.imread("D:/WeChat.picture/lufei.jpg")
  4. up_down = cv2.pyrUp(img)
  5. up_down = cv2.pyrDown(up_down)
  6. # res = np.hstack((img , up_down))
  7. cv_show(np.hstack((img , up_down)) , "res")

拉普拉斯金字塔

拉普拉斯程序

  1. import numpy as np # 在 pyrUp or pyrDown 的过程中 会损失一些数据 (亮度等)
  2. import cv2
  3. img = cv2.imread("D:/WeChat.picture/AM.png",cv2.IMREAD_GRAYSCALE)
  4. up_down = cv2.pyrUp(img)
  5. up_down = cv2.pyrDown(up_down)
  6. # res = np.hstack((img , up_down))
  7. #cv_show(np.hstack((img , up_down)) , "res")
  8. l_1=img-up_down
  9. cv_show(l_1,'l_1')

 

图像轮廓

轮廓检索

  • cv2.findContours(img,mode,method)

    • img: 二值图像
    • mode: 轮廓检索模式
  • 1 RETR_EXTERNAL :只检索最外面的轮廓;

  • 2 RETR_LIST:检索所有的轮廓,并将其保存到一条链表当中;

  • 3 RETR_CCOMP:检索所有的轮廓,并将他们组织为两层:顶层是各部分的外部边界,第二层是空洞的边界;

  • 4 RETR_TREE:检索所有的轮廓,并重构嵌套轮廓的整个层次; (通常选这个)

method:轮廓逼近方法

  • CHAIN_APPROX_NONE:以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列)。
  • CHAIN_APPROX_SIMPLE:压缩水平的、垂直的和斜的部分,也就是,函数只保留他们的终点部分。

返回值

  • contours 是一个list,list中每个元素都是图像中的一个轮廓,用numpy中的ndarray表示
  • hierarchy 是一个ndarray,其中的元素个数和轮廓个数相同,每个轮廓contours[i]对应4个hierarchy元素hierarchy[i][0]~hierarchy[i][3],分别表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号,如果没有对应项,则该值为负数 如果报错

为了更高的准确率,使用二值图像

  1. def cv_show( img ,name): # 做二值结果 是为更好的 做边缘检测
  2. cv2.imshow(name , img)
  3. cv2.waitKey(0)
  4. cv2.destroyAllWindows()
  5. import cv2
  6. img = cv2.imread("D:/WeChat.picture/contours.png")
  7. gray = cv2.cvtColor(img , cv2.COLOR_BGR2GRAY)
  8. ret , thresh = cv2.threshold(gray , 127 , 255 ,cv2.THRESH_BINARY)
  9. cv_show(thresh , "thresh")
  • OpenCV旧版,返回三个参数:
  • binary , contours , hierarchy = cv2.findContours( thresh , cv2.RETR_TREE , cv2.CHAIN_APPROX_NONE )
  • OpenCV 新版调用,返回两个参数:
  1. #hierarchy 层次,等级
  2. # contours 轮廓线,保存的是轮廓信息,是一个list值,可以用np.array(contours).shape查看
  3. import numpy as np
  4. contours , hierarchy=cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
np.array(contours).shape  # 如果您打算这样做,则在创建ndarray时必须指定‘dtype=object’。“”启动IPython内核的入口点

绘制轮廓

  1. def cv_show( img ,name):
  2. cv2.imshow(name , img)
  3. cv2.waitKey(0)
  4. cv2.destroyAllWindows()
  5. import cv2
  6. img = cv2.imread("D:/WeChat.picture/contours.png")
  7. cv_show(img ,"img")
  1. draw_img = img.copy() # 保存原图需要 copy 进行浅拷贝
  2. draw = cv2.drawContours(draw_img , contours , -1 ,(0 , 0 ,255), 2) # -1 表示 all in
  3. # (B , G ,R) 2 表示 penszie
  4. cv_show(draw , "draw")

轮廓特征

cnt = contours[1]
  1. # 面积
  2. cv2.contourArea(cnt)
  1. # 周长 ,True 表示闭合
  2. cv2.arcLength(cnt ,True)

轮廓近似

  1. def cv_show(img ,name):
  2. cv2.imshow(name , img)
  3. cv2.waitKey(0)
  4. cv2.destroyAllWindows()
  5. import cv2
  6. import numpy as np
  7. img1 = cv2.imread("D:/WeChat.picture/contours2.png")
  8. cv_show(img1 , "img")

近似函数:受函数控制

  • epsilon一般与轮廓的周长有关系,再乘以比例系数,一般用0.1即可,越大边缘细节越弱
 cv_show(img1 , "img")
  1. img = cv2.imread("D:/WeChat.picture/contours2.png")
  2. gray = cv2.cvtColor(img , cv2.COLOR_BGR2GRAY) # 不是 ( img ,cv2.IMREAD_GRAYSCALE)
  3. ret , thresh =cv2.threshold( gray ,127 , 255 , cv2.THRESH_BINARY)
  4. contours , hierarachy = cv2.findContours(thresh , cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) # 二值化
  5. cnt = contours[0]
  6. res = cv2.drawContours(draw_img , cnt , -1 , (0 ,0 ,255) , 2)
  7. cv_show(res , "res")
  8. #边缘近似
  9. epsilon = 0.01 * cv2.arcLength(cnt , True)
  10. approx = cv2.approxPolyDP( cnt , epsilon , True)
  11. draw_img = img.copy() # copy 少了括号 () “DrawContess”>过载解决方案失败:
  12. # -Image不是Numpy数组,也不是标量>-预期PTR<cv::UMAT>用于参数“图像”
  13. res = cv2.drawContours(draw_img , [approx] , -1 , (0 , 0, 255) , 2)
  14. cv_show(res , "res")
  1. img = cv2.imread("D:/WeChat.picture/contours2.png") #读图
  2. gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #转成灰度图
  3. ret,thresh=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)#二值化
  4. #边缘检测
  5. contours,hierarchy=cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
  6. cnt=contours[0]
  7. draw_img=img.copy() #.copy是复制另存
  8. res=cv2.drawContours(draw_img,[cnt],-1,(0,0,255),2)
  9. # -1 是所有轮廓都画进来,可以改 (0,0,255)B,G,R的颜色,红色
  10. cv_show(res,'res')
  11. #边缘近似
  12. epsilon=0.1*cv2.arcLength(cnt,True)#0.1倍周长,指定的越小,变化程度越小
  13. #cv2.approxPolyDP(),近似函数,cnt:轮廓,epsilon:周长百分比作为比较
  14. approx=cv2.approxPolyDP(cnt,epsilon,True)
  15. draw_img=img.copy()
  16. res=cv2.drawContours(draw_img,[approx],-1,(0,0,255),2)
  17. # -1 是所有轮廓都画进来,可以改 (0,0,255)B,G,R的颜色,红色
  18. cv_show(res,'res')

外接矩形

  1. img = cv2.imread("D:/WeChat.picture/contours.png")
  2. gray = cv2.cvtColor(img , cv2.COLOR_BGR2GRAY)
  3. ret , thresh =cv2.threshold ( gray , 127 , 255 ,cv2.THRESH_BINARY)
  4. contours , hierarchy = cv2.findContours(thresh , cv2.RETR_TREE , cv2.CHAIN_APPROX_NONE)
  5. cnt = contours[4]
  6. x ,y ,w ,h =cv2.boundingRect(cnt)
  7. img = cv2.rectangle(img , (x ,y) ,(x+w ,y+h) ,(0 ,225 ,0) ,2)
  8. cv_show(img , "img")
  1. area = cv2.contourArea(cnt)
  2. x , y ,w ,h = cv2.boundingRect(cnt)
  3. rect_area = w * h
  4. extent = float(area) / rect_area
  5. print("轮廓面积与边界形比", extent)
轮廓面积与边界形比 0.520365296803653

外接圆 

  1. (x ,y) ,radius = cv2.minEnclosingCircle(cnt) # 没有 maxEnclosingcircle()
  2. center = (int(x),int(y))
  3. radius = int(radius)
  4. img = cv2.circle(img , center , radius , (0 , 255 ,0) ,2)
  5. cv_show(img , "img")

 

匹配方法

  • TM_SQDIFF:计算平方不同,计算出来的值越小,越相关
  • TM_CCORR:计算相关性,计算出来的值越大,越相关
  • TM_CCOEFF:计算相关系数,计算出来的值越大,越相关
  • TM_SQDIFF_NORMED:计算归一化平方不同,计算出来的值越接近0,越相关
  • TM_CCORR_NORMED:计算归一化相关性,计算出来的值越接近1,越相关
  • TM_CCOEFF_NORMED:计算归一化相关系数,计算出来的值越接近1,越相关

模板匹配

模板匹配与卷积原理很像,模板在原图像从原点开始滑动,计算模板与(图像被模板覆盖的地方)的差别程度,这个差别程度的计算方法在opencv里有6种,然后将每次计算的结果放入一个矩阵里,作为结果输出。加入原图形式AB大小,而模板是ab大小,则输出结果矩阵是(A-a+1)*(B-b+1)

def cv_show( img ,name): cv2.imshow(name , img) cv2.waitKey(0) cv2.destroyAllWindows() import cv2 img_1 = cv2.imread("D:/WeChat.picture/lena.png",0) template = cv2.imread("D:/WeChat.picture/face.jpg",0) cv_show(img_1 , "img_1") cv_show(template , "img_2") img_1.shape ,template .shape # 并排才能都输出

methods = ["cv2.TM_SQDIFF" , "cv2.TM_CCORR" , "cv2.TM_CCOEFF" , "cv2.TM_SQDIFF_NORMED" , "cv2.TM_CCORR_NORMED" , "cv2.TM_CCOEFF_NORMED"]
  1. res = cv2.matchTemplate(img_1, template ,1) # cv2.matchTemplate(img_1, template ,cv2.TM_SQDIFF)
  2. res.shape
  1. def cv_show( img ,name):
  2. cv2.imshow(name , img)
  3. cv2.waitKey(0)
  4. cv2.destroyAllWindows()
  5. import cv2
  6. import matplotlib.pyplot as plt
  7. img_1 = cv2.imread("D:/WeChat.picture/lena.png",0)
  8. template = cv2.imread("D:/WeChat.picture/face.jpg",0)
  9. h ,w = template.shape[:2] # 这一步不可以少
  10. methods = ["cv2.TM_SQDIFF" , "cv2.TM_CCORR" , "cv2.TM_CCOEFF" , "cv2.TM_SQDIFF_NORMED" , "cv2.TM_CCORR_NORMED" , "cv2.TM_CCOEFF_NORMED"]
  11. for meth in methods:
  12. img_2 = img_1.copy()
  13. # 匹配方法
  14. method = eval(meth)
  15. print(method)
  16. res = cv2.matchTemplate(img_1, template ,1) # 1 表示采用什么方法 尽量使用归一化的办法 这里只用到了一种方法 所以结果与下面大不相同
  17. min_val , max_val , min_loc , max_loc = cv2.minMaxLoc(res) # 采用小值(左上角) 因为其存在的差异小
  18. # 如果是平方差匹配TM_SQDIEF或归一化平方差匹配TM_SQDIEF_NORMED 取最小值
  19. if method in [ cv2.TM_SQDIFF , cv2.TM_SQDIFF_NORMED]:
  20. top_left = min_loc # 坐标
  21. else:
  22. top_left = max_loc
  23. bottom_right = (top_left[0] + w ,top_left[1] + h) # top_left[0]是左上角横坐标
  24. #画矩形
  25. cv2.rectangle(img_2 , top_left , bottom_right , 255 ,2 )
  26. plt.subplot(121), plt.imshow(res ,cmap = "gray")
  27. plt.xticks([]), plt.yticks([]) #隐藏坐标
  28. plt.subplot(122), plt.imshow(img_2 ,cmap = "gray")
  29. plt.xticks([]), plt.yticks([]) #隐藏坐标
  30. plt.suptitle(meth)
  31. plt.show()
0

2

4

1

3

5

Comparesion

  1. def cv_show( img ,name):
  2. cv2.imshow(name , img)
  3. cv2.waitKey(0)
  4. cv2.destroyAllWindows()
  5. import cv2
  6. import matplotlib.pyplot as plt
  7. img_1 = cv2.imread("D:/WeChat.picture/lena.png",0)
  8. template1 = cv2.imread("D:/WeChat.picture/face.jpg",0)
  9. h ,w = template1.shape[:2] # 这一步不可以少
  10. methods = ["cv2.TM_SQDIFF" , "cv2.TM_CCORR" , "cv2.TM_CCOEFF" , "cv2.TM_SQDIFF_NORMED" , "cv2.TM_CCORR_NORMED" , "cv2.TM_CCOEFF_NORMED"]
  11. for meth in methods:
  12. img_2 = img_1.copy()
  13. # 匹配方法的真值
  14. method = eval(meth)
  15. print (method)
  16. res = cv2.matchTemplate(img_1, template1, method)
  17. min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
  18. # 如果是平方差匹配TM_SQDIFF或归一化平方差匹配TM_SQDIFF_NORMED,取最小值
  19. if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
  20. top_left = min_loc
  21. else:
  22. top_left = max_loc
  23. bottom_right = (top_left[0] + w, top_left[1] + h)
  24. # 画矩形
  25. cv2.rectangle(img_2, top_left, bottom_right, 255, 2)
  26. plt.subplot(121), plt.imshow(res, cmap='gray')
  27. plt.xticks([]), plt.yticks([]) # 隐藏坐标轴
  28. plt.subplot(122), plt.imshow(img_2, cmap='gray')
  29. plt.xticks([]), plt.yticks([])
  30. plt.suptitle(meth)
  31. plt.show()

 

0

2

4

1

3

5

 匹配多个对象

  1. def cv_show( img ,name):
  2. cv2.imshow(name , img)
  3. cv2.waitKey(0)
  4. cv2.destroyAllWindows()
  5. import cv2
  6. import numpy as np
  7. img_1 = cv2.imread("D:/WeChat.picture/mario.jpg")
  8. img_gray = cv2.cvtColor(img_1 , cv2.COLOR_BGR2GRAY)
  9. template = cv2.imread("D:/WeChat.picture/mario_coin.jpg",0)
  10. h ,w = template.shape[:2] # h ,w = template[:2] 出现- Can't parse 'pt2'. Sequence item with index 0 has a wrong type
  11. # 无法解析“pt2”。索引0的序列项类型错误。
  12. res = cv2.matchTemplate(img_gray , template , cv2.TM_CCOEFF_NORMED)
  13. threshold = 0.8
  14. #匹配程度大于80%的坐标
  15. loc = np.where( res >= threshold)
  16. for pt in zip (*loc[::-1]): # *表示可选参数
  17. bottom_right = (pt[0] + w , pt[1] + h)
  18. cv2.rectangle(img_1 , pt , bottom_right ,( 0,0 ,255) , 2)
  19. cv_show(img_1 , "img")
  1. import matplotlib.pyplot as plt
  2. img_rgb = cv2.imread("D:/WeChat.picture/mario.jpg")
  3. img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
  4. template = cv2.imread("D:/WeChat.picture/mario_coin.jpg", 0)
  5. h, w = template.shape[:2]
  6. res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
  7. threshold = 0.8
  8. # 取匹配程度大于%80的坐标
  9. loc = np.where(res >= threshold)
  10. for pt in zip(*loc[::-1]): # *号表示可选参数
  11. bottom_right = (pt[0] + w, pt[1] + h)
  12. cv2.rectangle(img_rgb, pt, bottom_right, (0, 0, 255), 2)
  13. cv2.imshow('img_rgb', img_rgb)
  14. cv2.waitKey(0)
  15. cv2.destroyAllWindows()
  16. plt.imshow(img_rgb)
  17. plt.show()

  • 1 opencv: 从左到右, 从上到下
  • 2 如果是模板匹配的差异性,越小越好;尽量用归一化的匹配方式
  • 3 多匹配:需要设置阈值

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/611139
推荐阅读
相关标签
  

闽ICP备14008679号