机器学习方向第二次培训——numpy与OpenCV基础操作


今天我们讲解的是numpy的基础操作和一些常用的api接口,大家目前的python学习大多数是学到numpy的使用或者刚刚学完,大多数时候在写一些底层或者基础的代码时候遇到矩阵的操作还需要上网去查询对应的使用文档,所以这次的numpy教程会比较偏常用的一些接口,给大家做一个汇总,然后还没有学完numpy的同学就要抓紧时间了。
然后就是初步认识一下OpenCV这个东西,相信对大部分的人这个是一个新的东西,他其实是一个功能十分强大的专业处理图像的Python库,然后具体的细节我们过一会再讲。

numpy基础操作

首先是numpy部分,大家应该都知道numpy是什么东西吧,NumPy 最重要的一个特点是其 N 维数组对象 ndarray,python里有很多与c语言或者c++不太一样的地方,比如说list,元祖,字典等,这里numpy的数据类型narray就有点类似于数组,他们存放的都是同类型元素,而且每个元素在内存中都有相同存储大小的区域,但在机器学习中,numpy所构建的矩阵大多数还是用来存放数字类型的,因为深度学习中的每一层网络,每一个神经元,都是用一个矩阵来存放在对应的权重的,所以今天的重点还是放在numpy中关于矩阵,尤其是对矩阵内部元素的操作上面

  1. 构建矩阵

首先是利用numpy来构建一个矩阵,这个操作应该每个同学在刚开始学习numpy库的时候都有进行过,大家请看我的PPT上的截图,第一张是最简单的基于numpy.array来构建矩阵的,大家自己动手把这几行代码给敲一下,看看跑出来的结果.我不知道你们在学习numpy的时候有没有看.array这一个函数内部具体参数的介绍,其中这个参数ndmin有人知道是用来干什么的吗,大家可以更改这个参数,看看输出结果有什么不同

Ndmin参数是用来设置矩阵最小的维度数的,我们要获取一个矩阵是几维用的是a.ndim,判断他是几行几列用的是a.shape

a = np.array([[1,2,3,4,5],[6,7,8,9,10]], ndmin =2)
print (a)
print(type(a))
print(a[0])
print(type(a[0]))
for dim in a:
    print(dim)
    for num in dim:
        print(num)

然后大家关注一下我们输出的a和a[0]的数据类型,可以发现都是类型都是numpy.ndarray,即使他长得看起来很像是一个list,所以使用对应的函数接口是一定要注意

然后介绍一种不太常见且比较麻烦的情况,不知道在处理数据的时候出现过没有
这种情况,这时候输出的矩阵的形状为(2,),而且print num输出的不再是我们矩阵每一维度的值了,这说明我们并未能按照我们的预期完成对这个矩阵的构建,可以把它看做原本的每一维度都变成了list形式挤在了第一行,变成一个一行n列的矩阵,如果我们把ndmin给去掉,即变成默认的矩阵维度1的时候,可以看见我们的维度变成了(3,),这样的type形式在平常的训练中是比较常见的,出现这种情况大多数是因为我们以为自己输入的数据,大多是以矩阵的形式输入,其实是参差不齐的,出现这种情况你就要考虑该怎么进一步处理,可以选择自动补零或者选择降维数据。

a = np.array([[1,2,3,4,5],[6,7,8,9]], ndmin =2)
print(a.shape)
print (a)
print(type(a))
print(a[0])
print(type(a[0]))
print(type(a[0][0]))
for dim in a:
    print(dim)
    for num in dim:
        print(num)
  1. 特殊矩阵构建

下面是一些常用的特殊矩阵的构建,这里主要介绍了四种,第一种是arrange一般要跟着reshape出现,否则会就输出的是一个一维度的向量,然后是empty,输出的是输出的是三行两列的随机矩阵,数据类型是int,然后我们需要对他进行初始化
然后是构建的比较常见的全1全0矩阵,用的是y = np.zeros((5,), dtype = np.int)
x = np.ones([2,2], dtype = int)
注意如果我们不加dtype是int的话,我们默认的属性是float类型
这个默认的数据类型非常非常关键,在马上的opencv中我们就会发现。

a=np.arange(1,24,2)
print(a)
x = np.empty([3,2])
print(x)
m= np.zeros((5,3), dtype = int)
n= np.ones([2,2], dtype = int)
print(m)
print(n)

还有是对矩阵的resize和reshape的操作哦,这两个都可以改变矩阵的维度和形状,你去查阅网络的一些教程会发现reshape不会改变原始数据,但resize会改变原始数据,其实这种说法是不准确的,我们调用resize函数的时候可以设置参数使其变成无需改变原函数的形式,关键在于resize是会对原始数据进行改变的,而reshape只会改变矩阵的维度和形状。resize:给定一个数组,和特定维度,将会返回一个给定维度形式的新数组。
如果新数组比原数组大,则将会copy原数组中的值对新数组进行填充
reshape:在不改变原数组数据的情况下,将它reshape成一个新的维度。
如果给定的数组数据和需要reshape的形状不符合时,将会报错。

X = np.array([[1, 2, 3, 4],
              [5, 6, 7, 8],
              [9, 10, 11, 12]])
X_new = np.resize(X, (3, 3))
print(X_new)
X = np.array([1, 2, 3, 4, 5, 6, 7, 8])
X_2 = X.reshape((2, 4))
X_3 = X.reshape((2, 2, 2))
print("X:\n", X)
print("X_2:\n", X_2)
print("X_3:\n", X_3)

下面给大家介绍一些压缩降维的算法,调用降维函数使矩阵变成向量,会方便我们之后对向量进行切割等操作,可以用在划分训练集与测试集当中,我们也可以使用自带的api对矩阵降维的操作,我们这里介绍ravel()、flatten()、squeeze()三个函数,

ndarray.flatten(order=‘C’),有点类似于把矩阵按照某个特定的顺序读取一遍显示出来
order:‘C’ – 按行,‘F’ – 按列,‘A’ – 原顺序,‘K’ – 元素在内存中的出现顺序。

squeeze 函数与上面两个函数不太一样,从数组的形状中删除单维度条目,即把shape中为1的维度去掉,比如你是(1,2)或者(2,2,1)这样的
用法:numpy.squeeze(a,axis = None)
1)a表示输入的数组;
2)axis用于指定需要删除的维度,但是指定的维度必须为单维度,否则将会报错;
3)axis的取值可为None 或 int 或 tuple of ints, 可选。若axis为空,则删除所有单维度的条目;
4)返回值:数组
5) 不会修改原数组

a = np.arange(12).reshape(3,4)
print ('对换数组:')
print (np.transpose(a))
print ('转置数组:')
print (a.T)
x=np.array([[1,2],[3,4]])
print(x.flatten())
print(x.ravel())
print('------')
print(x.flatten('F'))
x.flatten()[1] = 100
print(x)
x.ravel()[3]=100
print(x)
m=np.array([[1],[2],[3]])
print(m.shape)
print(m.squeeze())

• 然后是对numpy类型的数据的合并,首先是numpy数据的水平与竖直合并,我们用np.hstack((a,b))与np.vstack((a,b)),用==比较两个矩阵内部元素是否一致,这个函数放在二维的空间是比较理解的,但如果上升到多维度的矩阵,他其实是对矩阵的第一个维度和第二个维度的相加,所以我们可以用同一个函数完成构造,numpy.concatenate((a1, a2, …), axis=0)传入的数组必须具有相同的形状,这里的相同的形状可以满足在拼接方向axis轴上数组间的形状一致即可,这里的默认的axis的值是0,表示的是二维矩阵的横轴,如果axis=1的话就是对竖轴进行拼接。
如果我们输入的矩阵维度大于常见的二维,比如一个(1,2,2)的三维矩阵,把它合并起来就需要费点脑子,如果你对合并过程比较难以想想的话,可以将矩阵的维度标出来,然后对应维度对应相加即可,注意对应维度上的数量要相等

a = np.array([[1,2],[3,4]])
b = np.array([[1,5],[7,8]])
print(a.shape)
print(np.hstack((a,b)))
print(np.vstack((a,b)))
print (np.concatenate((a,b)))
print (np.concatenate((a,b)).shape)
print (np.concatenate((a,b),axis = 1))
print (np.concatenate((a,b),axis = 1).shape)
print(a==b)

OpenCV基础学习

• 首先我们介绍它读取图片的长宽高和通道数,一般我们的照片都是三通道,即GBR,每一个通道代表一种三原色,如果你只设一个通道得到的就是一张灰度图片
我们首先尝试一下从电脑中读取一张图片,并获取他的长宽高和通道数,读取图片在python中有很多函数库都可以实现,比如PIL的Image,还有matplotlib.pyplot 就是我们常见的plt,绘制图片也有很多库可以实现,其中就包含最基础的海龟turtle
这里图片是最常见的RGB色彩空间,一般为计算机、电视机色彩显示的方法,该颜色空间最为直观,任何颜色(共有256256256种)都能通过R、G、B三色不同分量的相加混合而成。
一般我们还有HSV色彩空间,更类似于人类感觉颜色的方式,因为Hue(色相),Saturation(饱和度),Value(亮度)一张图片转换到HSV色彩空间,我们经常可以用一个螺旋、漏斗一样的形状来描述HSV色彩空间

• 我们可以从电脑中读取图片,我们也可以自己创立一张色彩图片,因为读取的图片数据类型是numpy类型的,所以我们用numpy来构建一个图片

• 这个uint8是无符号八位整型,表示范围是[0, 255]的整数,如果不加我们的np.zeros默认的是一个浮点数类型的数据,范围是【0,1】,所以你输入大于一的数他都给你默认为最大值,所以输出的就是一张黑色图片,如果我们使用int32的话,他是三十二位整型,占四个字节,所以我们要把【0,255】投影到他的取值范围内

image=cv.imread("D:\\JAVA\\opencv\\sources\\samples\\data\\lena.jpg")
h,w,c=image.shape
#image[:, :, 0] =156
#image[:, :, 1] =156
#image[:, :, :] =200
cv.imshow("img",image)
img=cv.cvtColor(image,cv.COLOR_RGB2HSV)
cv.imshow('img2',img)
cv.waitKey(0)

• 下面我们展示一下如何实现图片的二值化,这个东西可以很复杂也可以很简单,二值化图片使用的范围非常广阔,比如说小车比赛,摄像头组,涉及到了图片的二值化和边缘提取,如何提高二值化的精度就十分重要,opencv已经为我们封装好了对应的接口,我们只需要调用函数,选取对应的算法即可

image=cv.imread("D:\\JAVA\\opencv\\sources\\samples\\data\\lena.jpg")
height,weight,channels=image.shape
cv.imshow("img1",image)
img_gray=cv.cvtColor(image,cv.COLOR_RGB2GRAY)
cv.imshow('img2',img_gray)
img_hsv=cv.cvtColor(image,cv.COLOR_RGB2HSV)
cv.imshow('img3',img_hsv)
for h in range(height):
    for w in range(weight):
        grag_pix=img_gray[h][w]
        img_gray[h][w]=255-grag_pix
img_gray[:,:]=255-img_gray[:,:]
ret, binary = cv.threshold(img_gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
cv.imshow('bin',binary)
cv.waitKey(0)

• cv.THRESH_BINARY | cv.THRESH_OTSU)#大律法,全局自适应阈值 参数0可改为任意数字但不起作用Otsu算法的基本思想是用某一假定的灰度值t将图像的灰度分为两组,当两组的类间方差最大时,此灰度值t就是图像二值化的最佳阈值。
• cv.THRESH_BINARY | cv.THRESH_TRIANGLE)#TRIANGLE法,,全局自适应阈值, 参数0可改为任意数字但不起作用,适用于单个波峰
• cv.THRESH_BINARY)# 自定义阈值为150,大于150的是白色 小于的是黑色
• cv.THRESH_BINARY_INV)# 自定义阈值为150,大于150的是黑色 小于的是白色
• cv.THRESH_TRUNC)# 截断 大于150的是改为150 小于150的保留

• 我们还可以使用自适应阈值的方式来二值化,可以使用cv2.ADAPTIVE_THRESH_MEAN_C 领域内均值
• 第五个Block size:规定领域大小(一个正方形的领域)
• 第六个常数C,阈值等于均值或者加权值减去这个常数(为0相当于阈值 就是求得领域内均值或者加权值)
现在大家实现以下一个求图片的平均灰度阈值然后实现二值化的函数,就是先求取图片的平均阈值,然后用求得的平均值实现二值化

def custom_threshold(image):
    gray = cv.cvtColor(image, cv.COLOR_RGB2GRAY) 
    h, w =gray.shape[:2]
    m = np.reshape(gray, [1,w*h])
    mean = m.sum()/(w*h)
    print("mean:",mean)
    ret, binary =  cv.threshold(gray, mean, 255, cv.THRESH_BINARY)
    cv.imshow("binary2", binary)

然后我们做一个小训练,尝试用numpy函数实现OpenCV里膨胀腐蚀的操作,下面是最粗略的代码展示,大家有兴趣的话可以搜索相关算法进行优化。

def detect_one(mat,cen_row,cen_col):
    flag=0
    for i in range(-1,2):
        for j in range(-1,2):
            if mat[cen_row+i,cen_col+j]==255:
                flag=1
                break
        if flag==1:
            break
    return flag


def dilate(rows,cols,mat):
    new_mat=np.zeros((rows,cols),np.uint8)
    for i in range(1,rows-1):
        for j in range(1,cols-1):
            flag=detect_one(mat,i,j)
            if (flag==1):
                new_mat[i,j]=255
                flag=0
            else:
                new_mat[i,j]=0
    return new_mat

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值