import cv2
import numpy as np
img=cv2.pyrDown(cv2.imread("../image/test2.jpg",cv2.IMREAD_UNCHANGED))
ret,thresh = cv2.threshold(cv2.cvtColor(img.copy(),cv2.COLOR_BGR2GRAY),127,255,cv2.THRESH_BINARY)
contours,hierarchy =cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
#查找边界框坐标
x,y,w,h = cv2.boundingRect(c)
cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
#查找最小区域
rect = cv2.minAreaRect(c)
#计算最小面积矩形的坐标
box = cv2.boxPoints(rect)
#将坐标标准化为整数
box =np.int0(box)
#绘制等高线
cv2.drawContours(img,[box],0,(0,0,255),3)
#计算最小封闭圆的中心和半径
(x,y),radius = cv2.minEnclosingCircle(c)
#转换为整数
center = (int(x),int(y))
radius = int(radius)
#画圆
img = cv2.circle(img,center,radius,(0,255,0),2)
cv2.drawContours(img,contours,-1,(255,0,0),1)
cv2.imshow("contours",img)
cv2.waitKey()
cv2.destroyWindow()
img=cv2.pyrDown(cv2.imread("../image/test2.jpg",cv2.IMREAD_UNCHANGED))
摘自《OpenCV官方教程中文版(For Python)段力辉 译》
一般情况下,我们要处理是一副具有固定分辨率的图像。但是有些情况下,
我们需要对同一图像的不同分辨率的子图像进行处理。比如,我们要在一幅图
像中查找某个目标,比如脸,我们不知道目标在图像中的尺寸大小。这种情况
下,我们需要创建创建一组图像,这些图像是具有不同分辨率的原始图像。我
们把这组图像叫做图像金字塔(简单来说就是同一图像的不同分辨率的子图集
合)。如果我们把最大的图像放在底部,最小的放在顶部,看起来像一座金字
塔,故而得名图像金字塔。
有两类图像金字塔:高斯金字塔和拉普拉斯金字塔。
高斯金字塔的顶部是通过将底部图像中的连续的行和列去除得到的。顶
部图像中的每个像素值等于下一层图像中 5 个像素的高斯加权平均值。这样
操作一次一个 MxN 的图像就变成了一个 M/2xN/2 的图像。所以这幅图像
的面积就变为原来图像面积的四分之一。这被称为 Octave。连续进行这样
的操作我们就会得到一个分辨率不断下降的图像金字塔。我们可以使用函数
cv2.pyrDown() 和 cv2.pyrUp() 构建图像金字塔。
函数 cv2.pyrDown() 从一个高分辨率大尺寸的图像向上构建一个金子塔
(尺寸变小,分辨率降低)。
img = cv2.imread('messi5.jpg')
lower_reso = cv2.pyrDown(higher_reso
函数cv2.pyrUp() 从一个低分辨率小尺寸的图像向下构建一个金子塔(尺
寸变大,但分辨率不会增加)。
higher_reso2 = cv2.pyrUp(lower_reso)
你要记住的是是 higher_reso2 和 higher_reso 是不同的。因为一旦使
用 cv2.pyrDown(),图像的分辨率就会降低,信息就会被丢失。下图就是
从 cv2.pyrDown() 产生的图像金字塔的(由下到上)第三层图像使用函数
cv2.pyrUp() 得到的图像,与原图像相比分辨率差了很多。
拉普拉斯金字塔可以有高斯金字塔计算得来,公式如下:
Li = Gi − P yrUp (Gi+1)
拉普拉金字塔的图像看起来就像边界图,其中很多像素都是 0。他们经常
被用在图像压缩中。下图就是一个三层的拉普拉斯金字塔:
ret,thresh = cv2.threshold(cv2.cvtColor(img.copy(),cv2.COLOR_BGR2GRAY),127,255,cv2.THRESH_BINARY)
简单阈值
与名字一样,这种方法非常简单。但像素值高于阈值时,我们给这个像素
赋予一个新值(可能是白色),否则我们给它赋予另外一种颜色(也许是黑色)。
这个函数就是 cv2.threshhold()。这个函数的第一个参数就是原图像,原图
像应该是灰度图。第二个参数就是用来对像素值进行分类的阈值。第三个参数
就是当像素值高于(有时是小于)阈值时应该被赋予的新的像素值。 OpenCV
提供了多种不同的阈值方法,这是有第四个参数来决定的。这些方法包括:
• cv2.THRESH_BINARY
• cv2.THRESH_BINARY_INV
• cv2.THRESH_TRUNC
• cv2.THRESH_TOZERO
• cv2.THRESH_TOZERO_INV
contours,hierarchy =cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
轮廓可以简单认为成将连续的点(连着边界)连在一起的曲线,具有相同
的颜色或者灰度。轮廓在形状分析和物体的检测和识别中很有用。
• 为了更加准确,要使用二值化图像。在寻找轮廓之前,要进行阈值化处理
或者 Canny 边界检测。
• 查找轮廓的函数会修改原始图像。如果你在找到轮廓之后还想使用原始图
像的话,你应该将原始图像存储到其他变量中。
• 在 OpenCV 中,查找轮廓就像在黑色背景中超白色物体。你应该记住,
要找的物体应该是白色而背景应该是黑色。
让我们看看如何在一个二值图像中查找轮廓:
函数 cv2.findContours() 有三个输入参数:
第一个是输入图像,第二个是 轮廓检索模式,第三个是轮廓近似方法。
返回值有两个:
第一个是轮廓本身,第二个 是轮廓对应属性
轮廓(第二个返回值)是一个Python 列表,其中存储这图像中的所有轮廓。每一个轮廓都是一个 Numpy 数组,包 含对象边界点( x, y)的坐标。
注:opencv3会返回三个值,分别是img, countours, hierarchy
#查找边界框坐标
x,y,w,h = cv2.boundingRect(c)
有两类边界矩形。
直边界矩形
一个直矩形(就是没有旋转的矩形)。它不会考虑对象是否旋转。 所以边界矩形的面积不是最小的。可以使用函数 cv2.boundingRect() 查 找得到。 ( x, y)为矩形左上角的坐标,( w, h)是矩形的宽和高。
x,y,w,h = cv2.boundingRect(cnt)
img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
旋转的边界矩形
这个边界矩形是面积最小的,因为它考虑了对象的旋转。用
到的函数为 cv2.minAreaRect()。返回的是一个 Box2D 结构,其中包含
矩形左上角角点的坐标( x, y),矩形的宽和高( w, h),以及旋转角度。但是
要绘制这个矩形需要矩形的 4 个角点,可以通过函数 cv2.boxPoints() 获得
x,y,w,h = cv2.boundingRect(cnt)
img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
函数 cv2.drawContours() 可以被用来绘制轮廓。它可以根据你提供
的边界点绘制任何形状。它的第一个参数是原始图像,第二个参数是轮廓,一
个 Python 列表。第三个参数是轮廓的索引(在绘制独立轮廓是很有用,当设
置为 -1 时绘制所有轮廓)。接下来的参数是轮廓的颜色和厚度等。
在一幅图像上绘制所有的轮廓:
# -*- coding: utf-8 -*-
"""
Created on Sun Jan 12 18:05:52 2014
@author: duan
"""
import numpy as np
import cv2
im = cv2.imread('test.jpg')
imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imgray,127,255,0)
image, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
绘制独立轮廓,如第四个轮廓:
img = cv2.drawContour(img, contours, -1, (0,255,0), 3)
但是大多数时候,下面的方法更有用:
img = cv2.drawContours(img, contours, 3, (0,255,0), 3)
函数 cv2.minEnclosingCircle() 可以帮我们找到一个对象的外切圆。
它是所有能够包括对象的圆中面积最小的一个。
(x,y),radius = cv2.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
img = cv2.circle(img,center,radius,(0,255,0),2)
要画圆的话,只需要指定圆形的中心点坐标和半径大小。我们在上面的矩
形中画一个圆。
cv2.circle(img,(447,63), 63, (0,0,255), -1)