cv六

1.图像轮廓发现

 1 # 图像轮廓发现
 2 # 轮廓发现是基于边缘提取的基础寻找对象轮廓的方法
 3 # 所以边缘提取的阈值选定会影响最终轮廓发现结果
 4 # findContour发现轮廓  在发现轮廓的时候,可以直接使用二值化的图像也可以使用边缘提取的图像,用哪个分析实际情景
 5 # drawContours绘制轮廓
 6 
 7 
 8 import cv2 as cv
 9 import numpy as np
10 
11 
12 def edge_demo(image):
13     blurred = cv.GaussianBlur(image, (3, 3), 0)
14     gray = cv.cvtColor(blurred, cv.COLOR_BGR2GRAY)
15 
16     grad_x = cv.Sobel(gray, cv.CV_16SC1, 1, 0)
17     grad_y = cv.Sobel(gray, cv.CV_16SC1, 0, 1)
18 
19     # edge_output = cv.Canny(grad_x, grad_y, 30, 150)
20     edge_output = cv.Canny(gray, 50, 150)
21     return edge_output
22 
23 
24 def contours_demo(image):
25     """
26     . 轮廓可以简单认为成将连续的点(连着边界)连在一起的曲线,具有相同 的颜色或者灰度。
27     轮廓在形状分析和物体的检测和识别中很有用。
28     . 为了更加准确,要使用二值化图像。在寻找轮廓之前,要进行阈值化处理或者 Canny 边界检测
29     . 查找轮廓的函数会修改原始图像。如果你在找到轮廓之后还想使用原始图像的话,
30     你应该将原始图像存储到其他变量中.
31     . 在 OpenCV 中,查找轮廓就像在黑色背景中超白色物体。要找的物体应该是白色而背景应该是黑色。
32     """
33     # dst = cv.GaussianBlur(image, (3, 3), 0)
34     # gray = cv.cvtColor(dst, cv.COLOR_BGR2GRAY)
35     # ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
36     # cv.imshow("binary image", binary)
37     binary = edge_demo(image)
38     """
39     • 函数 cv2.findContours() 有三个参数, 第一个是输入图像,第二个是轮廓检索模式,第三个是轮廓近似方法。
40     • 检索模式:
41         • CV_RETR_EXTERNAL - 只提取外层的轮廓  
42         • CV_RETR_LIST - 提取所有轮廓,并且放置在 list 中  
43         • CV_RETR_CCOMP - 提取所有轮廓,并且将其组织为两层的 hierarchy: 
44             顶层为连通域的 外围边界,次层为洞的内层边界。  
45         • CV_RETR_TREE - 提取所有轮廓,并且重构嵌套轮廓的全部 hierarchy
46     • 逼近方法 (对所有节点, 不包括使用内部逼近的 CV_RETR_RUNS).  点的存贮情况,是不是都被存贮
47         • CV_CHAIN_CODE - Freeman 链码的输出轮廓. 其它方法输出多边形(定点序列).  
48         • CV_CHAIN_APPROX_NONE - 将所有点由链码形式翻译为点序列形式  
49         • CV_CHAIN_APPROX_SIMPLE - 压缩水平、垂直和对角分割,即函数只保留末端的象素 点;  
50         • CV_CHAIN_APPROX_TC89_L1,  CV_CHAIN_APPROX_TC89_KCOS - 应用 Teh-Chin 链逼近算法.  
51         • CV_LINK_RUNS - 通过连接为 1 的水平碎片使用完全不同的轮廓提取算法。仅有 CV_RETR_LIST 提取模式可以在本方法中应用.  
52     • offset:每一个轮廓点的偏移量. 当轮廓是从图像 ROI 中提取出来的时候,使用偏移量有用,因为可以从整个图像上下文来对轮廓做分析. 
53     • 返回值有三个,第一个是图像,第二个是轮廓,第三个是(轮廓的)层析结构。
54         轮廓(第二个返回值)是一个 Python 列表,其中存储这图像中的所有轮廓。
55         每一个轮廓都是一个 Numpy 数组,包含对象边界点(x,y)的坐标。
56     """
57     contours, hierarchy= cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
58     for i, contour in enumerate(contours):
59         # 函数 cv2.drawContours() 可以被用来绘制轮廓。它可以根据你提供的边界点绘制任何形状。
60         # 它的第一个参数是原始图像,第二个参数是轮廓,一个 Python 列表。
61         # 第三个参数是轮廓的索引(在绘制独立轮廓是很有用,当设 置为 -1 时绘制所有轮廓)。
62         # 接下来的参数是轮廓的颜色和厚度等。
63         cv.drawContours(image, contours, i, (0, 0, 255), 2)  # 2为像素大小,-1时填充轮廓
64         print(i)
65     cv.imshow("detect contours", image)
66 
67 
68 def main():
69     src = cv.imread("../images/circle.png")
70     cv.imshow("demo",src)
71     contours_demo(src)
72     cv.waitKey(0)  # 等有键输入或者1000ms后自动将窗口消除,0表示只用键输入结束窗口
73     cv.destroyAllWindows()  # 关闭所有窗口
74 
75 
76 if __name__ == '__main__':
77     main()

2.对象测量

 1 # 对象测量
 2 # 测量对象的弧长与面积,多边形拟合,几何矩计算
 3 
 4 
 5 import cv2 as cv
 6 import numpy as np
 7 
 8 
 9 def measure_object(image):
10     gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
11     ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV | cv.THRESH_OTSU)
12     print("threshold value: %s"%ret)
13     cv.imshow("binary image", binary)
14 
15     contours, hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
16     for i, contour in enumerate(contours):
17         cv.drawContours(image, contours, i, (0, 255, 255), 1)  # 用黄色线条画出轮廓
18 
19         area = cv.contourArea(contour)  # 计算轮廓面积
20         print("contour area:", area)
21 
22         # 轮廓周长,第二参数可以用来指定对象的形状是闭合的(True),还是打开的(一条曲线)。
23         perimeter = cv.arcLength(contour, True)
24 
25         print("contour perimeter:", perimeter)
26 
27         x, y, w, h = cv.boundingRect(contour)  # 计算轮廓的外接矩形
28         cv.rectangle(image, (x, y), (x + w, y + h), (0, 0, 255), 2)
29 
30         rate = min(w, h)/max(w, h)  # 计算矩阵宽高比
31         print("rectangle rate",rate)
32 
33         mm = cv.moments(contour)  # 计算几何矩,函数 cv2.moments() 会将计算得到的几何矩以一个字典的形式返回
34         # 计算出对象的重心
35         cx = mm['m10']/mm['m00']
36         cy = mm['m01']/mm['m00']
37         cv.circle(image, (np.int(cx), np.int(cy)), 2, (0, 255, 255), -1)  # 用实心圆画出重心
38 
39     cv.imshow("measure_object", image)
40 
41 
42 def contour_approx(image):
43     gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
44     ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
45     print("threshold value: %s" % ret)
46     cv.imshow("binary image", binary)
47 
48     contours, hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
49     for i, contour in enumerate(contours):
50         cv.drawContours(image, contours, i, (0, 0, 255), 2)  # 用红色线条画出轮廓
51 
52         """cv.approxPolyDP(contour, epsilon, True) 参数解释
53             .   @param curve Input vector of a 2D point stored in std::vector or Mat
54             .   @param approxCurve Result of the approximation. The type should match the type of the input curve.
55             .   @param epsilon Parameter specifying the approximation accuracy. This is the maximum distance
56             .   between the original curve and its approximation.
57             .   @param closed If true, the approximated curve is closed (its first and last vertices are
58             .   connected). Otherwise, it is not closed.
59         """
60         # 将轮廓形状近似到另外一种由更少点组成的轮廓形状,新轮廓的点的数目由我们设定的准确度来决定。
61         # 为了帮助理解,假设从一幅图像中查找一个矩形,但是由于图像的种种原因,我们不能得到一个完美的矩形,
62         # 而是一个“坏形状”(如下图所示)。
63         # 现在你就可以使用这个函数来近似这个形状()了。
64         # 这个函数的第二个参数叫 epsilon,它是从原始轮廓到近似轮廓的最大距离。
65         # 它是一个准确度参数。选 择一个好的 epsilon 对于得到满意结果非常重要。
66 
67         epsilon = 0.01 * cv.arcLength(contour, True)
68         approx = cv.approxPolyDP(contour, epsilon, True)
69         if approx.shape[0] > 6:
70             cv.drawContours(binary, contour, i, (0, 255, 0), 2)
71         if approx.shape[0] == 4:
72             cv.drawContours(binary, contour, i, (0, 0, 255), 2)
73         if approx.shape[0] == 3:
74             cv.drawContours(binary, contour, i, (255, 0, 0), 2)
75         cv.drawContours(image, approx, -1, (255, 0, 0), 10)
76 
77     cv.imshow("contour_approx", image)
78 
79 
80 def main():
81     # src = cv.imread("../images/handwriting.jpg")
82     # cv.imshow("demo",src)
83     # measure_object(src)
84 
85     img = cv.imread("../images/approximate.png")
86     contour_approx(img)
87     cv.waitKey(0)  # 等有键输入或者1000ms后自动将窗口消除,0表示只用键输入结束窗口
88     cv.destroyAllWindows()  # 关闭所有窗口
89 
90 
91 if __name__ == '__main__':
92     main()

3.膨胀与腐蚀

 1 # 图像形态学两个基本内容:膨胀与腐蚀
 2 # 膨胀:是使用模板下的元素最大值来替换中心像素
 3 # 腐蚀:是使用模板下的元素最小值来替换中心像素
 4 
 5 
 6 import cv2 as cv
 7 import numpy as np
 8 
 9 
10 """
11 形态学操作是根据图像形状进行的简单操作。一般情况下对二值化图像进行的操作。
12 需要输入两个参数,一个是原始图像,第二个被称为结构化元素或 核,它是用来决定操作的性质的。
13 两个基本的形态学操作是腐蚀和膨胀。他们 的变体构成了开运算,闭运算,梯度等
14 """
15 
16 
17 def erode_demo(image):
18     """
19     就像土壤侵蚀一样,这个操作会把前景物体的边界腐蚀掉(但是前景仍然 是白色)。
20     卷积核沿着图像滑动,如果与卷积核对应的原图像的所有像素值都是 1,
21     那么中心元素就保持原来的像素值,否则就变为零。
22     这回产生什么影响呢?根据卷积核的大小靠近前景的所有像素都会被腐蚀掉(变为 0),
23     所以前景物体会变小,整幅图像的白色区域会减少。
24     这对于去除白噪声很有用,也可以用来断开两个连在一块的物体等。
25     """
26     print(image.shape)
27     gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
28     ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
29     cv.imshow("binary", binary)
30 
31     kernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))  # 得到结构元素或说是模板
32     dst = cv.erode(binary, kernel=kernel)  # 腐蚀
33     cv.imshow("erode_demo", dst)
34 
35 
36 def dilate_demo(image):
37     """
38     与腐蚀相反,与卷积核对应的原图像的像素值中只要有一个是 1,中心元 素的像素值就是 1。
39     所以这个操作会增加图像中的白色区域(前景)。一般在去 噪声时先用腐蚀再用膨胀。
40     因为腐蚀在去掉白噪声的同时,也会使前景对象变 小。所以我们再对他进行膨胀。
41     这时噪声已经被去除了,不会再回来了,但是 前景还在并会增加。
42     膨胀也可以用来连接两个分开的物体。
43     """
44     print(image.shape)
45     gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
46     ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
47     cv.imshow("binary", binary)
48 
49     kernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))
50     dst = cv.dilate(binary, kernel=kernel)  # 膨胀
51     cv.imshow("dilate_demo", dst)
52 
53 
54 def main():
55     src = cv.imread("../images/01.jpg")
56     # erode_demo(src)
57     # dilate_demo(src)
58 
59     # 彩色图像腐蚀,膨胀
60     img = cv.imread("../images/lena.jpg")
61     cv.imshow("img", img)
62     kernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))
63     # dst = cv.dilate(img, kernel=kernel)
64     dst = cv.erode(img, kernel=kernel)  # 也可以直接对彩色图像进行膨胀和腐蚀
65     cv.imshow("dilate", dst)
66     cv.waitKey(0)  # 等有键输入或者1000ms后自动将窗口消除,0表示只用键输入结束窗口
67     cv.destroyAllWindows()  # 关闭所有窗口
68 
69 
70 if __name__ == '__main__':
71     main()

4.开操作与闭操作

 1 # 图像形态学重要操作:开操作和闭操作
 2 # 开操作 = 腐蚀+膨胀,可以去除小的干扰块
 3 # 闭操作 = 膨胀+腐蚀,填充闭合区域
 4 # 水平或者垂直线的提取
 5 
 6 
 7 import cv2 as cv
 8 import numpy as np
 9 
10 
11 """
12 开运算:先进性腐蚀再进行膨胀就叫做开运算,它被用来去除噪声。
13 闭运算:先膨胀再腐蚀。它经常被用来填充前景物体中的小洞,或者前景物体上的小黑点。
14 这里我们用到的函数是 cv2.morphologyEx()。
15 开闭操作作用:
16 1. 去除小的干扰块-开操作
17 2. 填充闭合区间-闭操作
18 3. 水平或垂直线提取,调整kernel的row,col值差异。
19 比如:采用开操作,kernel为(1, 15),提取垂直线,kernel为(15, 1),提取水平线,
20 """
21 
22 """
23 其他形态学操作:
24 顶帽:原图像与开操作之间的差值图像
25 黑帽:比操作与原图像直接的差值图像
26 形态学梯度:其实就是一幅图像膨胀与腐蚀的差别。 结果看上去就像前景物体的轮廓
27 基本梯度:膨胀后图像减去腐蚀后图像得到的差值图像。
28 内部梯度:用原图减去腐蚀图像得到的差值图像。
29 外部梯度:膨胀后图像减去原图像得到的差值图像。
30 """
31 
32 
33 def open_demo(image):
34     print(image.shape)
35     gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
36     ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
37     cv.imshow("binary", binary)
38     """
39     在前面的例子中我们使用Numpy构建了结构化元素,它是正方形的。
40     但有时我们需要构建一个椭圆形 / 圆形的核。为了实现这种要求,提供了OpenCV
41     函数cv2.getStructuringElement()。你只需要告诉他你需要的核的形状和大小。
42     """
43     kernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))
44     dst = cv.morphologyEx(binary, cv.MORPH_OPEN, kernel=kernel)  # MORPH_OPEN 开操作,MORPH_ELLIPSE会保留所有圆的区域
45     cv.imshow("open_demo", dst)
46 
47 
48 def close_demo(image):
49     print(image.shape)
50     gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
51     ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
52     cv.imshow("binary", binary)
53 
54     kernel = cv.getStructuringElement(cv.MORPH_RECT, (15, 5))  # 15是水平 5的垂直
55     dst = cv.morphologyEx(binary, cv.MORPH_CLOSE, kernel=kernel)  # MORPH_CLOSE 闭操作
56     cv.imshow("open_demo", dst)
57 
58 
59 def other_morphology_demo(image):
60     gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
61     kernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))
62     dst = cv.morphologyEx(gray, cv.MORPH_BLACKHAT, kernel=kernel)
63     cimg = np.array(gray.shape, np.uint8)
64     cimg = 100
65     dst = cv.add(dst, cimg)
66 
67     cv.imshow("top_hat_demo", dst)
68 
69 
70 def main():
71     src = cv.imread("../images/lena.jpg")
72     open_demo(src)
73     # close_demo(src)
74 
75     # # 彩色图像腐蚀,膨胀
76     # img = cv.imread("../images/lena.jpg")
77     # cv.imshow("img", img)
78     # kernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))
79     # # dst = cv.dilate(img, kernel=kernel)
80     # dst = cv.erode(img, kernel=kernel)
81     # cv.imshow("dilate", dst)
82 
83     # # tophat, blackhat
84     #
85     # top_hat_demo(src)
86 
87     cv.waitKey(0)  # 等有键输入或者1000ms后自动将窗口消除,0表示只用键输入结束窗口
88     cv.destroyAllWindows()  # 关闭所有窗口
89 
90 
91 if __name__ == '__main__':
92     main()

5.其它形态学操作

 1 '''其他形态学操作:
 2 顶帽:原图像与开操作之间的差值图像
 3 黑帽:比操作与原图像直接的差值图像
 4 形态学梯度:其实就是一幅图像膨胀与腐蚀的差别。 结果看上去就像前景物体的轮廓
 5 基本梯度:膨胀后图像减去腐蚀后图像得到的差值图像。
 6 内部梯度:用原图减去腐蚀图像得到的差值图像。
 7 外部梯度:膨胀后图像减去原图像得到的差值图像。'''
 8 
 9 import cv2 as cv
10 import numpy as np
11 
12 
13 def hat_fray_demo(image):  # 对灰度图像
14     gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
15     kernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))
16     dst1 = cv.morphologyEx(gray, cv.MORPH_TOPHAT, kernel=kernel)  # MORPH_TOPHAT顶帽
17     dst2 = cv.morphologyEx(gray, cv.MORPH_BLACKHAT, kernel=kernel)  # BLACKHAT黑帽
18     cimage = np.array(gray.shape, np.uint8)
19     cimage = 100
20     cv.add(dst1, cimage)  # 每个值加100
21     cv.add(dst2, cimage)  # 每个值加100
22     cv.imshow('topHat', dst1)
23     cv.imshow('topHat', dst2)
24 
25 
26 def hat_binary_demo(image):  # 对二值图像
27     gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
28     ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
29     kernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))
30     dst1 = cv.morphologyEx(binary, cv.MORPH_TOPHAT, kernel=kernel)  # MORPH_TOPHAT顶帽
31     dst2 = cv.morphologyEx(binary, cv.MORPH_BLACKHAT, kernel=kernel)  # BLACKHAT黑帽
32     dst3 = cv.morphologyEx(binary, cv.MORPH_GRADIENT, kernel=kernel)  # GRADIENT基本梯度
33     cv.imshow('topHat', dst1)
34     cv.imshow('topHat', dst2)
35 
36 
37 def gradient_demo(image):  # 内梯度和外梯度
38     kernel = cv.getStructuringElement(cv.MORPH_RECT, (3, 3))
39     dm = cv.dilate(image, kernel)
40     em = cv.erode(image, kernel)
41     dst1 =cv.subtract(image, em)  # 内部梯度
42     dst2 =cv.subtract(dm, image)  # 外部梯度
43     cv.imshow('topHat', dst1)
44     cv.imshow('topHat', dst2)

 

posted @ 2020-06-26 12:43  liang哥哥  阅读(278)  评论(0)    收藏  举报