计算机视觉(三)

1、滤波器

傅里叶变换主要作用反应图像各区域像素变化的幅度。

滤波器(核)矩阵:一组权重集合(内部所有值加和为0),作用在源图像的一个区域(滑动),并由此生成目标图像的一个元素。

高通滤波器(HPF):检测图像的某个区域,然后根据像素与周围像素的亮度差值提升该像素的滤波器。如果亮度变化很大,中央像素的亮度会增加(反之则不会)。

(即某个像素比它周围的像素更突出,就会提升它的亮度)

def convolve(input, weights, output=None, mode='reflect', cval=0.0,
             origin=0):       
       return _correlate_or_convolve(input, weights, output, mode, cval,
                              origin, True)

input : array_like         
    Input array to filter.
weights : array_like
    Array of weights, same number of dimensions as input
output : ndarray, optional
    The `output` parameter passes an array in which to store the
    filter output. Output array should have different name as
    compared to input array to avoid aliasing errors.  
mode : {'reflect','constant','nearest','mirror', 'wrap'}, optional
    the `mode` parameter determines how the array borders are
    handled. For 'constant' mode, values beyond borders are set to be
    `cval`. Default is 'reflect'.
cval : scalar, optional
    Value to fill past edges of input if `mode` is 'constant'. Default
    is 0.0
origin : array_like, optional
    The `origin` parameter controls the placement of the filter, 
    relative to the centre of the current element of the input.  
    Default of 0 is equivalent to ``(0,)*input.ndim``.

def GaussianBlur(src, ksize, sigmaX, dst=None, sigmaY=None, borderType=None): # real signature unknown; restored from __doc__
    """ GaussianBlur(src, ksize, sigmaX[, dst[, sigmaY[, borderType]]]) -> dst """
    pass
参数1:源图像

参数2:高斯矩阵尺寸

参数3:标准差

高斯矩阵的尺寸越大,标准差越大,处理过的图像模糊程度越大。


自定义卷积核。

from cv2 import *
import numpy as np
from scipy import ndimage

kernel_3x3=np.array([[-1,-1,-1],
                     [-1,8,-1],
                     [-1,-1,-1]])

kernel_5x5=np.array([[-1,-1,-1,-1,-1],
                     [-1,1,2,1,-1],
                     [-1,2,4,2,-1],
                     [-1,1,2,1,-1],
                     [-1,-1,-1,-1,-1]])

img=imread("D:/temp/1.jpg",0)
img1=ndimage.convolve(img,kernel_3x3)# 注:使用ndimage.convolve()时,滤波核的维度应与原始图像的维度相同,故此采用灰度图
img2=ndimage.convolve(img,kernel_5x5)

blurred=GaussianBlur(img,(11,11),0)
g_hpf=img-blurred

imshow('Pic',img)
imshow('3x3',img1)
imshow('5x5',img2)
imshow('g_hpf',g_hpf)

waitKey()
destroyAllWindows()

低通滤波器(LPF):在像素与周围的亮度差值小于一个特定值时,平滑该像素的亮度,用于去噪和模糊化。如上面的高斯模糊(平滑滤波器)。


2、边缘检测

      OpenCV提供了许多边缘检测滤波函数,包括Laplacian()、Sobel()以及Scharr()。这些滤波函数都会将非边缘区域转为黑色,将边缘区域转为白色或其他饱和的颜色。但是,这些函数都很容易将噪声错误地识别为边缘。缓解这个问题的方法是找到边缘之前对图像进行模糊处理。OpenCV也提供了许多模糊滤波函数,包括blur()(简单的算术平均)、medianBlur()以及GaussianBlur()。边缘检测滤波函数和模糊滤波函数的参数有很多,但总会有一个ksize参数,它是一个奇数,表示滤波器的宽和高(以像素为单位)。

  这里使用medianBlur()作为模糊函数,它对去除数字化的视频噪声非常有效,特别是去除彩色图像的噪声;使用Laplacian()作为边缘检测函数,它会产生明显的边缘线条,灰度图像更是如此。在使用medianBlur()函数之后,将要使用Laplacian()函数之前,需要将图像从BGR色彩空间转为灰度色彩空间。

  在得到Laplacian()函数的结果之后,需要将其转换成黑色边缘和白色背景的图像。然后将其归一化(使它的像素值在0到1之间),并乘以源图像以便能将边缘变黑。

#coding:utf-8
from cv2 import *
import numpy

import distutils

def strokeEdges(src,dst,blurksize=7,edgeksize=5):
    if blurksize>=3:
        blurredsrc=medianBlur(src,blurksize)
        graysrc=cvtColor(blurredsrc,COLOR_BGR2GRAY)
    else:
        graysrc=cvtColor(src,COLOR_BGR2GRAY)  #灰度图
    Laplacian(graysrc,CV_8U,graysrc,ksize=edgeksize)
    #归一化
    normalizedInverseAlpha=(1.0/255)*(255-graysrc)
    channels=split(src) #分离通道

    for channel in channels:
        channel[:]=channel*normalizedInverseAlpha
    merge(channels,dst)
    return dst

img0=imread("D:/temp/1.jpg",1)
dst=img0
dst=filters.strokeEdges(img0,dst,blurksize=7,edgeksize=5)

imshow('dst',dst) #合并通道
    注意,核的大小可由strokeEdges()函数的参数来指定。blurKsize参数会 作为medianBlur()含糊的ksize参数,edgeKsize参数会作为Laplacian()函数的ksize参数。对于作者的摄像头,将blurKsize值设为7,将edgeKsize值设为5会得到最好的效果。但对于较大的ksize(比如7),使用medianBlur()的代价很高。如果在使用strokeEdges()函数时遇到性能问题,可试着减小blurKsize的值。要关闭模糊效果,可以将blurKsize的值设为3以下

Distutils包是标准Python库的一部分;主要特点有两个:
(1)是让用户觉得安装新模块、包和工具的过程是简单、一致又轻松的;
(2)是让开发者觉得创建这些新模块、包和工具的分发包是简单、一致又轻松的;


3、Canny边缘检测

Canny边缘检测算法有5个步骤:使用高斯滤波器对图像进行去噪、计算梯度、在边缘上使用非最大抑制(NMS)、在检测到的边缘上使用双阈值去除假阳性(false positive),最后还会分析所有的边缘及其之间的连接,以保留真正的边缘并消除不明显的边缘。

参考:http://blog.csdn.net/m0_37264397/article/details/70314025

def Canny(image, threshold1, threshold2, edges=None, apertureSize=None, L2gradient=None): # real signature unknown; restored from __doc__
    """ Canny(image, threshold1, threshold2[, edges[, apertureSize[, L2gradient]]]) -> edges """
    pass
from cv2 import *
import numpy as np

img=imread("D:/temp/1.jpg",0)
imwrite('canny.jpg',Canny(img,200,300))
imshow('canny',imread('canny.jpg'))
waitKey()
destroyAllWindows()

4、轮廓检测

在计算机视觉中,轮廓检测不仅用来检测图像或者视频帧中物体的轮廓,而且还有其他操作与轮廓检测有关。如:计算多边形边界、形状逼近和计算感兴趣区域。这是与图像数据交互时的简单操作,因为NumPy中的矩形区域可以使用数组切片(slice)来定义。在物体检测(包括人脸)和物体跟踪时会大量使用。

def threshold(src, thresh, maxval, type, dst=None): # real signature unknown; restored from __doc__
    """ threshold(src, thresh, maxval, type[, dst]) -> retval, dst """
    pass
    threshold()简单阈值
  这个函数有四个参数,第一个原图像,第二个进行分类的阈值,第三个是高于(低于)阈值时赋予的新值,第四个是一个方法选择参数,常用的有: 
    cv2.THRESH_BINARY(黑白二值) 
    cv2.THRESH_BINARY_INV(黑白二值反转) 
    cv2.THRESH_TRUNC (得到的图像为多像素值) 
    cv2.THRESH_TOZERO 
    cv2.THRESH_TOZERO_INV 
该函数有两个返回值,第一个retVal(得到的阈值(在后面一个方法中会用到)),第二个就是阈值化后的图像。

def findContours(image, mode, method, contours=None, hierarchy=None, offset=None): # real signature unknown; restored from __doc__
    """ findContours(image, mode, method[, contours[, hierarchy[, offset]]]) -> image, contours, hierarchy """
    pass
findContours()函数有三个参数:输入图像、层次类型和轮廓逼近方法。
  这个函数会修改输入图像,因此建议使用原始图像的一份拷贝(如:通过img.copy()来作为输入图像)。
  由函数返回的层次树相当重要:cv2.RETR_TREE参数会得到图像中轮廓的整体层次结构,以此来建立轮廓之间的“关系”。如果只想得到最外面的轮廓,可使用cv2.RETR_EXTERNAL。这对消除包含在其他轮廓中的轮廓很有用(如在大多数情形下,不需要检测一个目标包含在另一个与之相同的目标里面)
  findContours()函数有三个返回值:修改后的图像、图像的轮廓以及它们的层次。使用轮廓来画出图像的彩色版本(即把轮廓画成绿色),并显示出来。

画出轮廓:

def drawContours(image, contours, contourIdx, color, thickness=None, lineType=None, hierarchy=None, maxLevel=None, offset=None): # real signature unknown; restored from __doc__
    """ drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]]) -> image """
    pass

from cv2 import *
import  numpy as np

img=np.zeros((200,200),dtype=np.uint8)# 创建一个200x200大小的黑色空白图像
img[50:150,50:150]=255                # 在图像的中央放置一个白色方块

ret,thresh=threshold(img,127,255,0) #对图像进行二值化操作
image,contours,hieraracy=findContours(thresh,RETR_TREE,CHAIN_APPROX_SIMPLE)# 寻找轮廓
color=cvtColor(img,COLOR_GRAY2BGR)# 颜色空间转换

img=drawContours(color,contours,-1,(0,0,255),2)# 画出轮廓,-1,表示所有轮廓,画笔颜色为(0, 0, 255),即Red,粗细为3
imshow('contours',color)
waitKey()
destroyAllWindows()

5. 边界框、最小矩形区域和最小闭圆的轮廓

  可用OpenCV的cv2.findContours函数找到不规则的、歪斜的以及旋转的形状。现实的应用会对目标的边界框、最小矩形面积、最小闭圆特别感兴趣。

高斯金字塔用来向下采样
def pyrDown(src, dst=None, dstsize=None, borderType=None): # real signature unknown; restored from __doc__
    """ pyrDown(src[, dst[, dstsize[, borderType]]]) -> dst """
    pass
从一个高分辨率图像变成低分辨率图

3个参数:

  • tmp: 当前图像,初始化为原图像 src 。
  • dst: 目的图像( 显示图像,为输入图像的一半)
  • Size( tmp.cols/2, tmp.rows/2 ) :目的图像大小, 既然我们是向下采样
def pyrUp(src, dst=None, dstsize=None, borderType=None): # real signature unknown; restored from __doc__
    """ pyrUp(src[, dst[, dstsize[, borderType]]]) -> dst """
    pass

    http://blog.csdn.net/m0_37264397/article/details/70303128

def rectangle(img, pt1, pt2, color, thickness=None, lineType=None, shift=None): # real signature unknown; restored from __doc__
    """ rectangle(img, pt1, pt2, color[, thickness[, lineType[, shift]]]) -> img """
    pass

def boundingRect(points): # real signature unknown; restored from __doc__
    """ boundingRect(points) -> retval """
    pass
  • points:输入点集。
  • 返回最小正矩形

最小矩形区域

def minAreaRect(points): # real signature unknown; restored from __doc__
    """ minAreaRect(points) -> retval """
    pass
points:输入点集。 返回最小斜矩形

def boxPoints(box, points=None): # real signature unknown; restored from __doc__
    """ boxPoints(box[, points]) -> points """
    pass
寻找盒子的顶点

def minEnclosingCircle(points): # real signature unknown; restored from __doc__
    """ minEnclosingCircle(points) -> center, radius """
    pass
  • points:输入点集。
  • center:圆心。
  • radius:半径。
  • 对给定的 2D 点集,寻找最小面积的包围圆形
如下,在摄像(动态图像)中寻找轮廓(动态)。

from cv2 import *
import numpy as np

videocapture=VideoCapture(0)
success,franme=videocapture.read()
while success:
    # image=pyrDown(franme)#下采样降维
    image=pyrUp(franme)#上采样升维
    ret,thresh=threshold(cvtColor(image.copy(),COLOR_BGR2GRAY),127,255,THRESH_BINARY)

    #findContours()函数有三个返回值:修改后的图像、图像的轮廓以及它们的层次。
    img,contiours,hier=findContours(thresh,RETR_EXTERNAL,CHAIN_APPROX_SIMPLE)

    #遍历轮廓中的像素点
    for c in contiours:
        # 现计算出一个简单的边界框
        x,y,w,h=boundingRect(c)

        rectangle(image,(x,y),(x+w,y+h),(0,255,0),2)# 将轮廓信息转换成(x, y)坐标,并加上矩形的高度和宽度

        rect=minAreaRect(c) # 画出矩形

        box=boxPoints(rect)# 计算包围目标的最小矩形区域

        # 注:OpenCV没有函数能直接从轮廓信息中计算出最小矩形顶点的坐标。所以需要计算出最小矩形区域,
        # 然后计算这个矩形的顶点。由于计算出来的顶点坐标是浮点型,但是所得像素的坐标值是整数(不能获取像素的一部分)
        box=np.int0(box)

        # 所以需要做一个转换
        drawContours(image,[box],0,(0,0,255),3)# 画出该矩形

        #圈出目标
        (x,y),radius=minEnclosingCircle(c)

        center=(int(x),int(y)) # 会返回一个二元组,第一个元素为圆心的坐标组成的元组,第二个元素为圆的半径值。

        radius=int(radius)

        image=circle(image,center,radius,(0,0,255),2)

    drawContours(image, contiours, -1, (255, 0, 0), 1)

    imshow('contious', image)
    waitKey(10)
    success, franme = videocapture.read()

6、凸轮廓与Douglas-Peucker算法

  大多数处理轮廓的时候,物体的形状(包括凸形状)都是变化多样的。凸形状内部的任意两点之间的连线都在该形状里面。

  cv2.approxPloyDP是一个OpenCV函数,它用来计算近似的多边形框。该函数有三个参数:

  第一个参数为“轮廓”;

  第二个参数为“ε值”,它表示源轮廓与近似多边形的最大差值(这个值越小,近似多边形与源轮廓越接近);

  第三个参数为“布尔标记”,它表示这个多边形是否闭合。

  ε值对获取有用的轮廓非常重要。是为所得到的近似多边形周长与源轮廓周长之间的最大差值,这个差值越小,近似多边形与源轮廓就越相似。

  可通过OpenCV的cv2.arcLength函数来得到轮廓的周长信息。


ArcLength

计算轮廓周长或曲线长度

double cvArcLength( const void* curve, CvSlice slice=CV_WHOLE_SEQ, int is_closed=-1 );  

 

curve
曲线点集序列或数组
slice
曲线的起始点,缺省是计算整个曲线的长度
is_closed
表示曲线是否闭合,有三种情况:
  • is_closed=0 - 假设曲线不闭合
  • is_closed>0 - 假设曲线闭合
  • is_closed<0 - 若曲线是序列,检查 ((CvSeq*)curve)->flags 中的标识 CV_SEQ_FLAG_CLOSED 来确定曲线是否闭合。否则 (曲线由点集的数组 (CvMat*) 表示) 假设曲线不闭合。

函数 cvArcLength通过依次计算序列点之间的线段长度,并求和来得到曲线的长度。

def approxPolyDP(curve, epsilon, closed, approxCurve=None): # real signature unknown; restored from __doc__
    """ approxPolyDP(curve, epsilon, closed[, approxCurve]) -> approxCurve """
    pass

http://blog.csdn.net/qq_18343569/article/details/47999257

opencv提供了convexHull()函数来查找图像中物体的凸包,起函数定义如下:

void cv::convexHull (   InputArray  points,
                        OutputArray     hull,
                        bool    clockwise = false,
                        bool    returnPoints = true 
)
  • 1
  • 2
  • 3
  • 4
  • 5

def convexHull(points, hull=None, clockwise=None, returnPoints=None): # real signature unknown; restored from __doc__
    """ convexHull(points[, hull[, clockwise[, returnPoints]]]) -> hull """
    pass

参数解释 
points:输入的二维点集,Mat类型数据即可 
hull:输出参数,用于输出函数调用后找到的凸包 
clockwise:操作方向,当标识符为真时,输出凸包为顺时针方向,否则为逆时针方向。 
returnPoints:操作标识符,默认值为true,此时返回各凸包的各个点,否则返回凸包各点的指数,当输出数组时std::vector时,此标识被忽略。

C++ code:http://blog.csdn.net/keith_bb/article/details/70194073
from cv2 import *
import numpy as np

videocapture=VideoCapture(0)
success,franme=videocapture.read()
while success:
    # image=pyrDown(franme)#下采样降维
    # image=pyrUp(franme)#上采样升维
    image=franme
    #对图像进行二值化
    ret,thresh=threshold(cvtColor(image.copy(),COLOR_BGR2GRAY),100,255,THRESH_BINARY)

    #findContours()函数有三个返回值:修改后的图像、图像的轮廓以及它们的层次。
    img,contiours,hier=findContours(thresh,RETR_EXTERNAL,CHAIN_APPROX_NONE)

    #遍历轮廓中的像素点
    for c in contiours:
        epsilon=0.01*arcLength(c,True)

        approx=approxPolyDP(c,epsilon,True)

        #寻找凸包
        hull=convexHull(c)
        drawContours(image,approx, -1, (0,0,255), 3)
        drawContours(image, hull, -1, (0, 0, 255), 3)

    imshow('contious', image)
    waitKey(10)
    success, franme = videocapture.read()

destroyAllWindows()

7、 直线和圆检测

  Hough变换是直线和形状检测背后的理论基础。

绘制直线  

  函数为:cv2.line(img,Point pt1,Point pt2,color,thickness=1,line_type=8 shift=0) 

  有值的代表有默认值,不用给也行。可以看到这个函数主要接受参数为两个点的坐标,线的颜色(彩色图像的话颜色就是一个1*3的数组)

    
直线检测

    直线检测可通过HoughLines和HoughLinesP函数来完成,它们仅有的差别是:第一个函数使用标准的Hough变换,第二个函数使用概率Hough变换。

HoughLinesP函数之所以成为概率版本的Hough变换是因为它只通过分析点的子集并估计这些点都属于一条直线的概率,这是标准Hough变换的优化版本,该函数的计算代价会少一些,执行会变得更快。

def HoughLinesP(image, rho, theta, threshold, lines=None, minLineLength=None, maxLineGap=None): # real signature unknown; restored from __doc__
    """ HoughLinesP(image, rho, theta, threshold[, lines[, minLineLength[, maxLineGap]]]) -> lines """
    pass

第一个参数:输入灰度图像

第二个参数:输出检测的线条

第三个参数:极径

第四个参数:极角

第五个参数:累加平面阈值

第六个参数:最低线段长度

第七个参数:点点之间的最大距离


参考:http://blog.csdn.net/m0_37264397/article/details/72729423
def line(img, pt1, pt2, color, thickness=None, lineType=None, shift=None): # real signature unknown; restored from __doc__
    """ line(img, pt1, pt2, color[, thickness[, lineType[, shift]]]) -> img """
    pass
Demo:
from cv2 import *
import numpy as np

image=imread("D:/temp/1.jpg")
gray=cvtColor(image,COLOR_BGR2GRAY)
edge=Canny(gray,50,120)
minLineLength=20
maxLineGap=5
lines=HoughLinesP(edge,1,np.pi/180,100,minLineLength,maxLineGap)
for x1,y1,x2,y2 in lines[0]:
    line(image,(x1,y1),(x2,y2),(0,255,0),2)

imshow('edge',edge)
imshow('line',image)
waitKey()
destroyAllWindows()
HoughLines函数会接收一个由Canny边缘检测滤波器处理过的单通道二值图像,不一定需要Canny滤波器,但是一个经过去噪并只有边缘的图像当作Hough变换的输入会很不错。

HoughLinesP的参数:

    需要处理的参数;

    线段的几何表示rho和theta,一般分别取1和np.pi/180;

    阈值,低于该阈值的直线会被忽略,Hough变换可以理解为投票箱和投票数之间的关系,每一个投票箱代表一个直线,投票数达到阈值的直线会被保留,其他的会被删除。

    minLineLength和maxLineGap 

问题:

https://stackoverflow.com/questions/16144015/python-typeerror-nonetype-object-has-no-attribute-getitem#comment23064755_16144015
from cv2 import *
import numpy as np

videocapture=VideoCapture(0)

ret,image=videocapture.read()
while ret:
    img=image
    gray=cvtColor(image,COLOR_BGR2GRAY)

    edge=Canny(gray,50,120)
    minLineLength=20
    maxLineGap=5
    lines = (edge, 1, np.pi/180, 20, np.array([]), 10)[0]

    for l in lines:
        line(image, (l[0],l[1]), (l[2],l[3]), (0, 255, 0), 2)
    imshow('line', image)
    imshow('edge',edge)
    imshow('image',img)
    waitKey(10)
    ret, image = videocapture.read()
destroyAllWindows()

 

圆检测

    OpenCV的HoughCircles函数可用来检测圆,它与使用HoughLines函数类似。像用来决定删除或保留直线的两个参数minLineLength和maxLineGap一样,HoughCircles有一个圆心间的最小距离和圆的最小及最大半径。

def medianBlur(src, ksize, dst=None): # real signature unknown; restored from __doc__
    """ medianBlur(src, ksize[, dst]) -> dst """
    pass

def HoughCircles(image, method, dp, minDist, circles=None, param1=None, param2=None, minRadius=None, maxRadius=None): # real signature unknown; restored from __doc__
    """ HoughCircles(image, method, dp, minDist[, circles[, param1[, param2[, minRadius[, maxRadius]]]]]) -> circles """
    pass
   http://blog.csdn.net/m0_37264397/article/details/72729423

Demo1:

from cv2 import *
import numpy as np

image=imread("D:/temp/a2.jpg")
gray=cvtColor(image,COLOR_BGR2GRAY)
img=medianBlur(gray,5)
# cimg=cvtColor(img,COLOR_BGR2GRAY)
circles=HoughCircles(img,HOUGH_GRADIENT,1,120,param1=100,param2=30,minRadius=0,maxRadius=0)
circles=np.uint16(np.around(circles))
for i in circles[0,:]:
    circle(image,(i[0],i[1]),i[2],(0,255,0),2)
    circle(image,(i[0],i[1]),2,(0,0,255),3)

imshow('image',image)

waitKey()
destroyAllWindows()

Demo2:
from cv2 import *
import numpy as np

videocapture=VideoCapture(0)
ret,image=videocapture.read()

while ret:
    gray=cvtColor(image,COLOR_BGR2GRAY)
    img=medianBlur(gray,5)
    cimg=cvtColor(img,COLOR_GRAY2BGR)
    circles = HoughCircles(img, HOUGH_GRADIENT, 1, 120, param1=100, param2 = 30, minRadius = 0,  maxRadius = 0)
    circles = np.uint16(np.around(circles))

    for i in circles[0, :]:
        circle(image, (i[0], i[1]), i[2], (0, 255, 0), 2)
        circle(image, (i[0], i[1]), 2, (0, 0, 255), 3)



    imshow('image',image)
    waitKey(10)
    ret, image = videocapture.read()
destroyAllWindows()

运行出现:AttributeError: 'NoneType' object has no attribute 'rint',暂未解决。

















你可能感兴趣的:(opencv,Python,计算机视觉)