数字图像处理笔记(三):使用OpenCV检测图像特征

1 - 引言

在数字图像处理中还提供了许多检测图像简单特征的方法,例如边缘检测、轮廓检测、直线检测、圆检测等。让我们用OpenCV实现以下这些算法吧

2 - Canny边缘检测

OpenCV提供了一个非常方便的Canny函数(以算法的发明者命名)

import cv2
import numpy as np

img = cv2.imread('images/12.jpg',0)
cv2.imwrite("canny.jpg",cv2.Canny(img,200,300))
cv2.imshow("canny",cv2.imread("canny.jpg"))
cv2.waitKey(0)

原始图片:数字图像处理笔记(三):使用OpenCV检测图像特征_第1张图片
输出图片:
数字图像处理笔记(三):使用OpenCV检测图像特征_第2张图片
Canny边缘检测算法由5个步骤:

  • 高斯滤波器对图像去噪
  • 计算梯度
  • 在边缘上使用非最大抑制
  • 在检测到的边缘上使用双阈值去除假阳性
  • 分析边缘及其之间的连接,以保留真正的边缘并消除不明显的边缘

3 - 轮廓检测

在计算机视觉中,轮廓检测是另一个比较重要的任务,不单是用来检测图像或者视频帧中物体的轮廓,而且还有其他操作与轮廓检测有关。下面给出一个简单的例子来检测出正方形的轮廓

import cv2
import numpy as np

img = np.zeros((200,200),dtype=np.uint8)
img[50:150,50:150]=255

ret,thresh = cv2.threshold(img,127,255,0)
image,contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
color = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)
img = cv2.drawContours(color,contours,-1,(0,255,0),2)

cv2.waitKey(0)

数字图像处理笔记(三):使用OpenCV检测图像特征_第3张图片
找到一个正方形的轮廓很简单,要找到不规则的就需要使用cv2.findContours与其他代码结合起来实现

import cv2
import numpy as np

img = cv2.pyrDown(cv2.imread("images/test.jpg", cv2.IMREAD_UNCHANGED))
# threshold 函数对图像进行二化值处理,由于处理后图像对原图像有所变化,因此img.copy()生成新的图像,cv2.THRESH_BINARY是二化值
ret, thresh = cv2.threshold(cv2.cvtColor(img.copy(), cv2.COLOR_BGR2GRAY), 127, 255, cv2.THRESH_BINARY)
# findContours函数查找图像里的图形轮廓
# 函数参数thresh是图像对象
# 层次类型,参数cv2.RETR_EXTERNAL是获取最外层轮廓,cv2.RETR_TREE是获取轮廓的整体结构
# 轮廓逼近方法
# 输出的返回值,image是原图像、contours是图像的轮廓、hier是层次类型
image, contours, hier = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
    # 轮廓绘制方法一
    # boundingRect函数计算边框值,x,y是坐标值,w,h是矩形的宽和高
    x, y, w, h = cv2.boundingRect(c)
    # 在img图像画出矩形,(x, y), (x + w, y + h)是矩形坐标,(0, 255, 0)设置通道颜色,2是设置线条粗度
    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), 2)
# 显示图像
cv2.imshow("contours", img)
cv2.waitKey()
cv2.destroyAllWindows()


原始图像:数字图像处理笔记(三):使用OpenCV检测图像特征_第4张图片

实验图像:
数字图像处理笔记(三):使用OpenCV检测图像特征_第5张图片

** 凸轮廓与Douglas-Peucker算法**
凸形状内部的任意两点的连线都在该形状里面,使用这个算法后可以画出一个凸包轮廓包围着整个物体。

import cv2
import numpy as np

img = cv2.pyrDown(cv2.imread("images/15.jpg", cv2.IMREAD_UNCHANGED))
ret, thresh = cv2.threshold(cv2.cvtColor(img.copy(), cv2.COLOR_BGR2GRAY) , 127, 255, cv2.THRESH_BINARY)
# findContours函数查找图像里的图形轮廓
# 函数参数thresh是图像对象
# 层次类型,参数cv2.RETR_EXTERNAL是获取最外层轮廓,cv2.RETR_TREE是获取轮廓的整体结构
# 轮廓逼近方法
# 输出的返回值,image是原图像、contours是图像的轮廓、hier是层次类型
image, contours, hier = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 创建新的图像black
black = cv2.cvtColor(np.zeros((img.shape[1], img.shape[0]), dtype=np.uint8), cv2.COLOR_GRAY2BGR)


for cnt in contours:
    # 轮廓周长也被称为弧长。可以使用函数 cv2.arcLength() 计算得到。这个函数的第二参数可以用来指定对象的形状是闭合的(True) ,还是打开的(一条曲线)
    epsilon = 0.01 * cv2.arcLength(cnt, True)
    # 函数approxPolyDP来对指定的点集进行逼近,cnt是图像轮廓,epsilon表示的是精度,越小精度越高,因为表示的意思是是原始曲线与近似曲线之间的最大距离。
    # 第三个函数参数若为true,则说明近似曲线是闭合的,它的首位都是相连,反之,若为false,则断开。
    approx = cv2.approxPolyDP(cnt, epsilon, True)
    # convexHull检查一个曲线的凸性缺陷并进行修正,参数cnt是图像轮廓。
    hull = cv2.convexHull(cnt)
    # 勾画图像原始的轮廓
    cv2.drawContours(black, [cnt], -1, (0, 255, 0), 2)
    # 用多边形勾画轮廓区域
    cv2.drawContours(black, [approx], -1, (255, 255, 0), 2)
    # 修正凸性缺陷的轮廓区域
    cv2.drawContours(black, [hull], -1, (0, 0, 255), 2)
# 显示图像
cv2.imshow("hull", black)
cv2.waitKey()
cv2.destroyAllWindows()

数字图像处理笔记(三):使用OpenCV检测图像特征_第6张图片

4 - 直线检测和圆检测

直线检测

import cv2
import numpy as np

img = cv2.imread('images/louvre_small.jpg')
# 灰度处理
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# canny边缘处理
edges = cv2.Canny(gray,50,120)
line = 100
minLineLength = 20
# HoughLinesP函数是概率直线检测,注意区分HoughLines函数
lines = cv2.HoughLinesP(edges, 1, np.pi/180, 100, lines=line, minLineLength=minLineLength)
# 降维处理
lines1 = lines[:,0,:]
# line 函数勾画直线
# (x1,y1),(x2,y2)坐标位置
# (0,255,0)设置BGR通道颜色
# 2 是设置颜色粗浅度
for x1,y1,x2,y2 in lines1:
    cv2.line(img,(x1,y1),(x2,y2),(0,255,0),2)

# 显示图像
cv2.imshow("edges", edges)
cv2.imshow("lines", img)
cv2.waitKey()
cv2.destroyAllWindows()

实验效果:
数字图像处理笔记(三):使用OpenCV检测图像特征_第7张图片

圆检测

import cv2
import numpy as np

planets = cv2.imread('images/1.jpg')
# 灰度处理
gray_img = cv2.cvtColor(planets, cv2.COLOR_BGR2GRAY)
# medianBlur 平滑(模糊)处理
img = cv2.medianBlur(gray_img, 5)
# 灰度图像转彩色图像
cimg = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)

# 圆检测
circles = cv2.HoughCircles(img, cv2.HOUGH_GRADIENT, 1, 100, param1=100, param2=30, minRadius=50, maxRadius=100)
# 转化整数
circles = np.uint16(np.around(circles))

for i in circles[0,:]:
    # 勾画圆形,planets图像、(i[0],i[1])圆心坐标,i[2]是半径
    cv2.circle(planets,(i[0],i[1]),i[2],(0,255,0),2)
    # 勾画圆心,圆心实质也是一个半径为2的圆形
    cv2.circle(planets,(i[0],i[1]),2,(0,0,255),3)
# 显示图像
cv2.imwrite("planets_circles.jpg", planets)
cv2.imshow("mypic", cimg)
cv2.imshow("HoughCirlces", planets)
cv2.waitKey()
cv2.destroyAllWindows()

数字图像处理笔记(三):使用OpenCV检测图像特征_第8张图片

你可能感兴趣的:(数字图像处理笔记)