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)