接上一篇文章,边缘检测的源代码

2017-11-18 00:59

 '''原来写的代码太过凌乱,又花了5个小时重写了代码,把大部分功能定义成了函数,代码总行数比原来少了10%。

幸好是python语言,如果用c语言,估计得写三四百行,python的优点就是语法简单,比其他语言更贴近人类的
法,这些代码中也使用了pythonic,使代码可读性提高了一点'''

import numpy as np#导入numpy库,并命名为np,之后会用到

def run():#定义函数run()
    #这里狗图的储存位置为'e:\\images\\12.bmp',狗图为12.bmp,可自行更改
    fp=open('e:\\img\\12.bmp','rb')
    fheader=fp.read(54)#读取12.bmp的前54字节,赋值给fheader。
    fp.seek(18,0)#使读指针定位到文件起始处向后偏移18字节
    '''在24位bmp位图中,第19~22这四个字节储存了图片的宽度,第23~26这四字节储存了图片的高度'''
    #读取图片大小,oct1()可以将4字节的16进制数组转化为10进制
    width=oct1(fp.read(4))
    height=oct1(fp.read(4))
    #定义一个元素全为0的矩阵,用来储存生成的图像矩阵,元素类型为16位整型
    image=np.zeros((height,width),dtype=np.uint16)
    fp.seek(54,0)
    '''使读指针定位到文件起始处向后偏移54字节,从这里向后就是24位bmp图像的数据区,
每3字节代表一个像素,这三个字节依次储存蓝、绿、红三种颜色的亮度。'''
    num=er(width)#确定每行像素后应该添加的字节数
    '''根据bmp文件的格式,每一行像素对应的字节数应是4的倍数,不足要补0.例如一张24位的bmp位图大小为13*11,那么这张图片
的宽度就是13px(px表示像素),上面已经说过24位位图每三字节表示一个像素,因此13*3=39,39字节表示了一行像素,但39不是4的
倍数,还差一个字节,于是就会在每行后面添加一个空字节(0x00)。'''
    for i in range(height):
        for j in range(width):
            chs=fp.read(3)#chs是一个数组,可以储存三个字节,python的一个好处就是你可以不用自己定义变量
            f1=np.uint16(chs[0])
            f2=np.uint16(chs[1])
            f3=np.uint16(chs[2])
            image[height-1-i][j]=f1+f2+f3
        fp.seek(num,1)
    '''把三个字节转换为整数后相加,确定像素的值,然后赋给数组image,位图的储存方式有点特别,例如,第55~57字节
所代表的那个像素,其实在图片的左下角,整个文件最后的一个像素在图片的右上角'''
    fp.close()#关闭12.bmp文件
    image_expand=expand(image)#将扩充后的矩阵赋给image_expand
    image_gaus=gaus(image_expand,3,1)#使用定义的gaus()函数,把生成高斯滤波后的矩阵赋给image_gaus,image为原图像
    fw(image_gaus,'e:\\13g.bmp',fheader)#生成滤波处理后的图片,文件路径为'e:\\13g.bmp',fheader是54字节的文件头
    image_gaus_expand=expand(image_gaus)#扩充经过高斯滤波后的矩阵
    image_gaus_sobel=sobel(image_gaus_expand)
    fw(image_gaus_sobel,'e:\\13s.bmp',fheader)
#将16进制转化为10进制
def oct1(a):
    num=a[0]+a[1]*16*16+a[2]*16*16*16+a[3]*16*16*16*16
    return num
#计算在字节数不是4的倍数时应该补加的字节数
def er(width):
    if (width*3)%4==3:
        error=1
    elif (width*3)%4==2:
        error=2
    elif (width*3)%4==1:
        if (width*3+1)%4==2:
            error=3
        else:
            error=1
    else:
        error=0
    return error
#定义扩充函数,这个函数可以在矩阵四周添加0,image为原数组,函数回返回生成的数组
def expand(image):
    height=image.shape[0]
    width=image.shape[1]
    image_expand=np.zeros((height+2,width+2),dtype=np.uint16)
    for i in range(height+2):
        if i==0:
            image_expand[0]=0
        elif i>0 and i<(height+1):
            image_expand[i][0],image_expand[i][width+1]=0,0
            for b in range(width):
                image_expand[i][b+1]=image[i-1][b]
        else:
            image_expand[i]=0
    return image_expand
#参数依次为原图像,高斯滤波卷积核大小,sigma值
def gaus(image,size,sigma):
    height=image.shape[0]-2
    width=image.shape[1]-2
    center=size/2
    gaus_kernels=np.zeros((size,size))
    sum=0
    for i in range(size):
        for j in range(size):
            gaus_kernels[i][j]=(1/(2*np.pi*sigma*sigma))*np.exp(-((i-center)*(i-center)+(j-center)*(j-center))/(2*sigma*sigma))
            sum=sum+gaus_kernels[i][j]
    for m in range(size):
        for n in range(size):
            gaus_kernels[m][n]=gaus_kernels[m][n]/sum#高斯滤波卷积核
    i,j=0,0 #令i,j的值等于零,方便下一次循环
    gaus_cen=np.zeros((size,size))#作为中间值,储存截取出的3*3矩阵
    gaus_image=np.zeros((height,width))#储存转换完成后的矩阵
    for i in range(height):
        for j in range(width):
            gaus_cen[0][0]=image[i][j]
            gaus_cen[0][1]=image[i][j+1]
            gaus_cen[0][2]=image[i][j+2]
            gaus_cen[1][0]=image[i+1][j]
            gaus_cen[1][1]=image[i+1][j+1]
            gaus_cen[1][2]=image[i+1][j+2]
            gaus_cen[2][0]=image[i+2][j]
            gaus_cen[2][1]=image[i+2][j+1]
            gaus_cen[2][2]=image[i+2][j+2]
            gaus_image[i][j]=np.sum(gaus_cen*gaus_kernels)
            #两个矩阵对应元素相乘,np.sum可以求矩阵中的所有元素相加的和
    return gaus_image
def sobel(image):
    width,height=image.shape[1]-2,image.shape[0]-2
    sobel_cen=np.zeros((3,3))#定义中间值
    sobel_image=np.zeros((height,width))#用来存放生成的矩阵
    sobel_x=np.array([[-1,0,1],[-2,0,2],[-1,0,1]])#sobel算子x轴方向
    sobel_y=np.array([[1,2,1],[0,0,0],[-1,-2,-1]])#sobel算子y轴方向
    for x in range(height):
        for y in range(width):
            sobel_cen[0][0]=image[x][y]
            sobel_cen[0][1]=image[x][y+1]
            sobel_cen[0][2]=image[x][y+2]
            sobel_cen[1][0]=image[x+1][y]
            sobel_cen[1][1]=image[x+1][y+1]
            sobel_cen[1][2]=image[x+1][y+2]
            sobel_cen[2][0]=image[x+2][y]
            sobel_cen[2][1]=image[x+2][y+1]
            sobel_cen[2][2]=image[x+2][y+2]
            Gx=np.sum(sobel_cen*sobel_x)#sobel的Gx分向量
            Gy=np.sum(sobel_cen*sobel_y)#sobel的Gy分向量
            sobel_image[x][y]=np.sqrt(Gx*Gx+Gy*Gy)
    return sobel_image
#定义这个函数用来把图像矩阵写入文件,生成图像,参数依次为图像矩阵,输出的文件路径.
def fw(image,src,head):
    fg=open(src,'wb')#以二进制写入方式打开文件
    width,height=image.shape[1],image.shape[0]
    fg.write(head)
    num=er(width)
    for i in range(height):
        for j in range(width):
            fg.write(np.uint8(image[height-1-i][j]/3))
            fg.write(np.uint8(image[height-1-i][j]/3))
            fg.write(np.uint8(image[height-1-i][j]/3))
            j+=2
        for n in range(num):
            fg.write(np.int8(0))
    fg.close()
if __name__ == '__main__':
    run()

                                                                                              ‘’‘————雾雨流云’‘’

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章