Opencv3.0-python的那些事儿:(一)、Opencv的图像和视频处理基本用法

来源:互联网 发布:淘宝买万艾可怎么购买 编辑:程序博客网 时间:2024/05/01 20:45

        写这篇文章的目的:Opencv已经支持3.0了,这个与python3.4结合绝对是天生的搭配。Opencv主要可以用于图像和视频处理,由于在实际的一些项目需求中也可能会涉及到图像和视频的处理,因此即使抛开项目不谈,做为一个程序员,对自己比较感兴趣的地方做一些探索也是可以的。

      具体如何在Win7 或 Ubuntu下安装Opencv请参看我这两篇文章。

Windows7 64位+python3.4环境下安装opencv3.0的方法

Ubuntu14.04 64位+Python3.4环境下安装opencv3.0的方法


     下面主要是对图像和视频基本用法的一些使用。

# coding: utf-8#学习opencv中基本的图像处理操作import numpy as npimport cv2#读取图像def readImage_my():    #cv2.imread(filename[,flags]),返回图像,作用:加载图像并返回该图像,flags>0:返回3通道颜色,=0:返回灰度图像,<0:返回的图像带有透明度,alpha是灰度通道,记录透明度信息    img = cv2.imread("0_snap.png" , 0)    img = cv2.imread("0_snap.png" , 1)    img = cv2.imread("0_snap.png" , -1)    cv2.imshow("image" , img)    #0表示永久等待键盘输入,waitKey()是键盘绑定函数,时间尺度是毫秒级,特定的几毫秒内,如果有键盘输入,函数会返回按键的ASCII码值    cv2.waitKey(0)    #删除建立的窗口,删除特定的窗口用cv2.destroyWindow(),参数是想删除的窗口名    cv2.destroyAllWindows()#保存图像def imwrite_test():    img = cv2.imread("0_snap.png" , 1)    '''    cv2.imwrrite(filename,img[,params])->返回值,参数:filename是文件名称,img是保存的图像,作用:将图像保存成指定格式的文件,注意这里的params是一个数组    对于JPEG,可以是有质量的保存 CV_IMWRITE_JPEG_QUALITY 从0到100,100表示最高保存质量,默认95    对于WEBP,                  CV_IMWRITE_WEBP_QUALITY    对于PNG,可以是压缩级别     CV_IMWRITE_PNG_COMPRESSION:从0到9,越小表示保存的大小越大,压缩时间越少,默认为3    alpha为0时表示透明,255时表示不透明    '''    #注意cv2.IMWRITE_PNG_COMPRESSION类型为Long,必须转换成int    outimg = cv2.imwrite("0_snap_save_9.png" , img , [ int(cv2.IMWRITE_PNG_COMPRESSION),9 ] )    outimg = cv2.imwrite("0_snap_save_0.png" , img , [ int(cv2.IMWRITE_PNG_COMPRESSION),0 ] )    '''    cv2.imshow("outimg" , outimg)    cv2.waitKey(0)    cv2.destroyWindow("outimg")    '''    '''    如果你用的是 64 位系统,你需要将  k = cv2.waitKey(0) 这行改成    k = cv2.waitKey(0)&0xFF    '''#修改像素值def modifyPixel():    '''    可以根据像素的行和列的坐标获取他的像素值。对于BGR图像而言,返回值为B,G,R的值。对灰度图像而言,会返回灰度值    :return:    '''    img = cv2.imread("./roi.jpg")    #图像可以理解为二维数组,给出行列则得到BGR,注意不是RGB,一个像素是一个三元组    px = img[100,100]    print(px)    #给出img[row , col , index]  ,index=0时,给出蓝色的像素值    blue = img[100,100,0]    print(blue)    green = img[100,100,1]    print(green)    red = img[100,100,2]    red2  = img.item(100,100,2)    print(red)    print(red2)    #给出BGR的三元组来直接修改像素值    img[100,100] = [255,255,255]    print(img[100,100])    #获取每个像素值,可以使用Numpy的array.item()和array.itemset(),返回值是标量(只有大小),矢量(大小与方向),想获得所有BGR,需要使用array.item()来分割    img.itemset( (10,10,2) , 100 )    red3 = img.item(10,10,2)    print(red3)    #img.shape返回行数,列数,色彩通道数(灰度图像不返回通道数)    print(img.shape)#提取出感兴趣的图像def imageROI():    img = cv2.imread("./roi.jpg" , 1)    #行对应了图像的高度,列数对应了图像的宽度,190,300    '''    我现在比较疑惑的地方就是shape返回的number of rows, columns and channels (if image is color):    shape返回的是(190, 302, 3)    实际上该图片是302*190的,也就是宽度是302对应列数    那么其实shape返回的值可以理解为:高度(y) , 宽度(x)    行数->对应图像多少行->图像高度->坐标y->对应于img[, y] ,总结: 行数->y    列数->对应图像多少列->图像宽度->坐标x->对应于img[x, ]    '''    print(img.shape)    #img.size返回图像的像素数目 = 高度 * 宽度 * 3(色彩通道)    print(img.size)    #img.dtype: 返回图像的数据类型    print("图像的数据类型:")    print(img.dtype)    '''    分析:如果我要移动足球到垂直上方处,那么首先x是固定不动的    由于shape返回190,302    因此宽度是302,高度是190,因此x的范围是[0,302],y的范围是[0,190]    球在右下角处,x大概是[150,225]    y大概是[160,190]    因为移动到正上方,所以x不变,y减小为[10,40]    现在关键就是对img[]    shape(y,x)    img(y,x)    因此真正的位置应该是    '''    ball = img[160:190 , 150:225 ]    img[10:40,150:225] = ball    '''    ball = img[150:225 , 160:190]    img[ 150:225 , 10:40 ] = ball    '''    cv2.imwrite("roi_modify.jpg" , img , [int(cv2.IMWRITE_JPEG_QUALITY) , 100 ])    outimg = cv2.imread("roi_modify.jpg" , 1)    cv2.imshow("roi_out" , outimg)    cv2.imshow("roi" , img)    cv2.waitKey(0)    cv2.destroyAllWindows()#拆分及合并图像通道,适用:对BGR三个通道分别进行操作,或者把独立通道的图片合并成BGR图像def mergeAndSplitImage():    img = cv2.imread("./roi.jpg" )    b,g,r = cv2.split(img)    #img = cv2.merge(b, g ,r)    print("分离的通道的bgr分别是")    print(cv2.split(img))    #合并时候最多接受两个参数    img2 = cv2.merge(b, g )    b = img[: , : , 0]    print("b色彩通道是")    print(b)    #使得所有像素红色通道值为0,split耗时,能用Numpy索引就尽量使用    img[: , : , 2] = 0    cv2.imshow("image" , img)    cv2.waitKey(0)    cv2.destroyAllWindows()#图像加法def imageAdd():    #cv2.add(src1 , src2 [ ,dst [, mask [,dtype]]]) ,返回dst,作用:对两幅图像进行加法运算    #opencv中的加法是饱和操作,超过最大值按最大值算,小于最小值按最小值算(例如大于1变成1)    #numpy中的加法是模操作,超过后,取模    #这里[250]表示是一个数组,该数组只有一个元素250    x = np.uint8([250])    print("x = np.uint8([250])的结果是")    print(x)    y = np.uint8([10])    print("cv2饱和加法结果是")    print(cv2.add(x,y)) # 250 + 10 = 260 => 255    print("numpy取模加法结果是")    print(x+y)    img1 = cv2.imread("./0_snap.png")    img2 = cv2.imread("./9_snap.png")    resImg = cv2.add(img1 , img2)    cv2.imshow("image add",resImg)    cv2.waitKey(0)    cv2.destroyAllWindows()'''图像混合,也是加法,只不过给与两幅图像的权重不同,给人混合或者透明的感觉图像混合的计算公式g(x) = (1-a)f(x) + ah(x)通过修改a的值,实现混合'''def imageBlending():    img1 = cv2.imread("./blend1.jpg")    img2 = cv2.imread("./blend2.jpg")    '''    cv2.addWeighted(src1 , alpha , src2 , beta , gamma[ , dst [,dtype]] ),返回dst,作用    dst( = saturate( src1 * alpha + src2 * beta + gamma )    saturate:饱和    '''    dst = cv2.addWeighted(img1 , 0.7 , img2 , 0.3 , 0)    cv2.imshow("dst" , dst)    cv2.waitKey(0)    cv2.destroyAllWindows()#按位运算,操作有:AND , OR , NOT , XOR,作用:选择非矩形ROI操作会很有用def bitOperation():    img1 = cv2.imread("roi.jpg")    img2 = cv2.imread("opencv_logo.jpg")    #希望把logo放在左上角    rows , cols , channels = img2.shape    roi = img1[0 : rows , 0 : cols]    #现在创建对于logo的掩码:将源码与掩码(需要的字段位为1)经过或运算得到符合需求的结果    '''    cv2.threshold(src, thresh , maxval , type[,dst] )返回retval,dst    src输入数组或者图像,dst输出图像,maxval用于二元阈值的最大值,type:阈值类型    作用:将阈值应用到单通道数组,需要用到灰度图像,主要是过滤掉太大或太小的图像    THRESH_BINARY    >threshold,为maxval,否则为0    \texttt{dst} (x,y) =  \fork{\texttt{maxval}}{if $\texttt{src}(x,y) > \texttt{thresh}$}{0}{otherwise}    THRESH_BINARY_INV    \texttt{dst} (x,y) =  \fork{0}{if $\texttt{src}(x,y) > \texttt{thresh}$}{\texttt{maxval}}{otherwise}    THRESH_TRUNC    \texttt{dst} (x,y) =  \fork{\texttt{threshold}}{if $\texttt{src}(x,y) > \texttt{thresh}$}{\texttt{src}(x,y)}{otherwise}    THRESH_TOZERO    \texttt{dst} (x,y) =  \fork{\texttt{src}(x,y)}{if $\texttt{src}(x,y) > \texttt{thresh}$}{0}{otherwise}    THRESH_TOZERO_INV    \texttt{dst} (x,y) =  \fork{0}{if $\texttt{src}(x,y) > \texttt{thresh}$}{\texttt{src}(x,y)}{otherwise}    '''    img2gray = cv2.cvtColor(img2 , cv2.COLOR_BGR2GRAY)    ret , mask = cv2.threshold( img2gray , 175 , 255 , cv2.THRESH_BINARY )    '''    cv2.bitwise_not(src[,dst[,mask]]) ,    src:输入数组,dst:输出数组(与src有同样的大小和类型),mask:可选择的操作掩码    作用:按位取反    dst(I) = 取反src(I)    bitwise表示按位    '''    mask_inv = cv2.bitwise_not(mask)    #下面就是讲ROI区域进行处理,取roi中与mask中不为零的值对应的像素的值,其他值为0    #注意这里必须有mask=mask 或者mask=mask_inv,其中的mask= 不能忽略    '''    cv2.bitwise_and(src1 ,src2[,dst[,mask]])->dst    src1:第一个输入数组或者标量    src2:第二个数组    src:单通道的输入数组    value:标量值    dst:输出数组    mask:掩码    计算按位与    dst(I) = src1(I) & src2(I) , if mask(I) != 0    '''    #这里的roi是足球照片,用于背景,mask是logo的灰度图像,0是黑,255是白,也就是把白色部分的像素拿出来求与,其实就是把足球偏白色的部分拿出来    img1_bg = cv2.bitwise_and(roi, roi , mask = mask)    #取roi中与mask_inv中不为0的值对应的像素的值,其他值为0,把logo中黑色部分提取出来    img2_fg = cv2.bitwise_and(img2 , img2 , mask = mask_inv)    #将ROI中的logo和修改主要的图像    dst = cv2.add(img1_bg , img2_fg)    #替换原来的图像    img1[0:rows , 0:cols] = dst    cv2.imshow("res" , img1)    cv2.waitKey(0)    cv2.destroyAllWindows()'''Canny边缘检测:原理:1986年由John F.Canny提出的算法步骤:1噪声去除由于边缘检测容易受到噪声影响,因此需去除噪声,第一步是使用5*5的高斯滤波器(先看5*5高斯滤波器)2计算图像梯度对平滑后的图像使用Sobel算子计算水平方向和竖直方向的一阶导数(图像梯度)(Gx和Gy)。根据得到的这两幅梯度图(Gx和Gy)找到边界的梯度和方向,公式如下:Edge_Gradient(G)=sqrt( Gx*Gx + Gy*Gy )Angle( C塔 ) = tan-1(上标)(Gx/Gy)梯度的方向一般总是与边界垂直。梯度方向有四类:垂直,水平,和两个对角线(算子和梯度也需要看)3非极大值抑制获得梯度的方向和大小后,对整幅图像做扫描,去除非边界上的点。对每个像素检查,看这个点的梯度是不是周围具有相同梯度方向中的点中最大的4滞后阈值需要设置两个阈值:minVal和maxVal。当图像的灰度梯度高于maxVal时被认为是真的边界,低于minVal的边界会被抛弃。介于两者之间的话,需要看该点是否与某个被确定为真正的边界点相连,如果是就认为它是边界点,否则就抛弃。边界是长的线段。'''if __name__ == "__main__":    #readImage_my()    #imwrite_test()    #modifyPixel()    #imageROI()    #mergeAndSplitImage()    #imageAdd()    #imageBlending()    bitOperation()'''可能有用的一些内容(简要了解,后面需要时再仔细学习):物体跟踪:应用提取某特定颜色的物体(从BGR转换到HSV后,HSV更容易表示特定颜色)步骤:1从视频中获取每一帧图像2将图像红钻换到HSV空间3设置HSV阈值到蓝色范围学习轮廓后,可以找到物体的重心,根据重心来跟踪物体几何变换:1扩展缩放,cv2.resize(),缩放使用cv2.INTER_AREA,扩展时使用v2.INTER_CUBIC(慢)和v2.INTER_LINEAR(快)默认改变图像尺寸大小插值方法是cv2.INTER_LINEAR2平移:将对戏那个换一个位置,cv2.warpAffine(宽度,高度,输出图像的大小)宽度对应列数,高度对应行数3旋转:cv2.getRotationMatrix24仿射变换:原图中所有的平行线在结果图像中同样平行,为了创建这个矩阵需要从原图像中找到三个点以及他们在输出图像中的位置cv2.getAffineTransform , cv2.warpAffine5透视变换视角变换,需要3*3变换矩阵,在变换前后直线还是直线,要构建这个矩阵,需要在输入图像中找4个点,以及他们在输出图像上对应的位置,4个点中任意三个不能共线变换矩阵可通过cv2.getPerspectiveTransform()构建然后矩阵传递给cv2.warpPerspective''''''''图像阈值:当像素高于阈值时,给这个像素赋予新值cv2.threshhold(),第一个参数是原图像,原图像应该是灰度图,第二个参数就是用来对像素值进行分类的阈值。第三个参数是像素高于(或小于)阈值时应被赋予的新像素值自适应阈值:根据图像上的每一个小区域计算与其对应的阈值Adaptive MethodOtsu's二值化对一个双峰图像自动根据其直方图计算出其阈值cv2.threshold(),多传入一个参数cv2.THRESH_OTSU,把阈值设为0''''''图像平滑(模糊)使用低通滤波器对图像进行模糊,使用自定义的滤波器对图像进行卷积(2D卷积)2D卷积:低通滤波去除噪音,模糊图像,高通滤波找到图像的边缘cv.filter2D()图像模糊(图像平滑)噪音是指高频成分,边界也会被模糊一点平均:归一化卷积狂完成,用卷积框覆盖区域所有像素平均值来代替中心元素可以使用函数cv2.blur()和cv2.boxFilter()来完成高斯模糊:把卷积核换成高斯核,中心值最大,其余会随距离中心元素的距离递减中值模糊:用卷积框对应像素的中值来代替中心像素的值双边滤波''''''图像梯度:梯度简单说就是求导梯度滤波器也叫高通滤波器:Sobel,Scharr(求一阶导数),Laplacian算子(二阶导数)'''



1 0
原创粉丝点击