接上一篇文章,邊緣檢測的源代碼

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()

                                                                                              ‘’‘————霧雨流雲’‘’

 

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