深度學習--------圖片的位深度含義
以前沒接觸深度學習的時候沒注意過圖片位深度的問題,最近研究深度學習圖片輸入弄的也是莫名奇妙,焦頭爛額。記錄一下自己搜的資料的總結。首先要明白計算機的儲存方式位二進位制,只有0和1,因此圖片的畫素矩陣也不例外
這裡可以看到圖片的位深度為16,因此可以表示的顏色為2**16=655536
但是為什麼是2的16呢,這裡就是因為計算機的儲存方式了。因為是從0開始所以,65535轉化為二進位制,1111 1111 1111 1111 每一位有兩種形式0和1,因此是2**16。同理其他的位深度也是這樣計算。
現在轉入正題,圖片轉化位陣列形式,目前我掌握的有兩 種方式:
import cv2 import numpy as np import skimage.io list = np.zeros((500,500)) list[:30,50:500] = 125 cv2.imwrite('1.png',list) # cv2.S # print(list) img = cv2.imread('1.png') img2 = skimage.io.imread('1.png') print(img.shape) print(img2.shape)
生成一個二維陣列,然後儲存成圖片,再用兩種方式去讀取看看會發生什麼。
(500, 500, 3)
(500, 500)
可以看出opencv預設的讀取方式就是按照三維陣列後面是通道數,而skimage是按照原始的形式去讀取。如果設定三維的圖片呢。修改程式碼:
list = np.zeros((500,500,3))
輸出結果:
(500, 500, 3)
(500, 500, 3)
全部都是三維了。
但是我轉念一想如果是4通道呢
list = np.zeros((500,500,4))
輸出結果:
(500, 500, 3)
(500, 500, 4)
opencv竟然依舊是三維的,怎麼回事呢,原來opencv讀取預設是rgb的方式,如果要加上通道則後面加上引數-1,0則為灰度圖,沒有通道數,1就是預設rgb 3通道。好了讀取的方式現在明白了,那麼不同位深度如何轉換呢。先上一段程式碼,這個程式碼來自別人,影象處理時,我偶然發現位深度竟然改變了。
def change(img): t = img.astype(np.float32) # 減小異常值的影響 maxv = np.percentile(t, 99) minv = np.percentile(t, 1) t = (t-minv)/(maxv-minv) meanv = t.mean() # 均值統一拉到0.5 t += (0.5-meanv) # 擴大範圍至0-65535 t *= 65535 t[t<0] = 0 t[t>65535] = 65535 img = t.astype(np.uint16) cv2.imwrite('5.png',img)
PS:在處理四通道的圖片的時候我竟然又有了新的發現(我的發現為什麼這麼多,無知啊,知識瞭解的太少,各位同學記得好好學習)修改程式碼,
list = np.zeros((500,500,4))
list[50:100,50:100] = 255
cv2.imwrite('1.png',list)
這個程式碼本來應該生成一箇中間有一個白色板塊,其他都是黑色的圖片,但是結果呢
只有一個白色的框,很明顯四通道中數值為0的是透明的,因為rgba的a通道是透明通道,原來如此,竟然是透明的。
繼續用change函式看下結果如何。這裡需要說明一下,2維陣列位深度位為8,三通道則是24,四通道則是32,為什麼一開始是8這裡其實我不是很明白,但是根據上面說明的,8通道總共的顏色是2**8=256 而我們熟知的rgb正好是0-255,所以應該是和計算機顯示有關係,但是並不影響了,同時還涉及到圖片格式,坑以後填上。在最後一個通道上的測試中我又發現了(好吧,發現了就記得,不然明天就忘記了)
我嘗試讀取一張彩色的圖片的時候輸出的畫素矩陣究竟最後一位是255,那麼如果把最後一位變成0對前面的有什麼影響嗎,(陣列全是0的,圖片顏色會隨著最後一位通道數0-255而逐漸變深,就是最後通道數值為255的時候圖片是全黑的上度娘)通過度孃的一番訴說,發現自己真的無知第四個是透明通道,數值變成255意思就是百分百不透明啊,不透明不是黑色難道不成是粉色?不過利用這一點可以用程式碼實現圖片透明度的改變。
ist[:,:,3]=100#陣列切片,索引最後一個可以理解為行數吧,但其實是維度,但是正好對應,這樣也好理解,
#或者就理解成對應的通道數,0是r,1是g,2是b,3是a,把第四個通道行列全部裁剪,值變成100
但是如何把一張黑圖變成粉色的呢,首先我搜到了粉色的rgb值(241,204,226)
改寫程式碼:
img = skimage.io.imread('1_255.png')
img[:,:,0]=249
img[:,:,1]=204
img[:,:,2]=226
print(img)
cv2.imwrite('fen.png',img)
出來的結果:
和想想中不太一樣啊,黑的就算是變成粉色很不自然
那麼到底深度是如何改變的呢:我突然想起了開頭的16位深度,和程式碼中的數值 t *= 65535 陣列中的每個數值都 * 65535,這樣如果有資料,資料不都變成比65535大的數值了嗎,用二進位制位數表達時,位數不就改變了嗎?但是要是數值是0,或者數值不為0,乘積肯定要大於 65535,這就不只是64位,但是 t[t<0] = 0 t[t>65535] = 65535這兩個條件限制了範圍,統統16位表示,當然了這裡不是排列組合所以是,4*16=64,神奇的二進位制!
由此提出兩個猜想:一、位深度是資料中最大的一個數的數值的二進位制長度*通道數。二、以上猜想正確。
為了驗證我的猜想,我做了如下實驗:全部是0,或全部和1
一維陣列,位深度8 三維陣列 位深度24 四維陣列 位深度32
可見並不是如猜想那樣,0也很神奇,二進位制0的長度可以變化?還是如果沒有最大值的時候,會根據維度預設補全生成?
或者是圖片一個通道按照標準必須是2**8 = 256 255轉化位二級制 1111 1111 如果這樣,我的猜想在標準成立的條件下是成立的,現在認為猜想在每個通道初始是8的基礎上成立,那麼用此猜想改變下位深度試試。如果三個維度分別是16,48,64,那麼此猜想可作為經驗來解決改變位深度的問題。上結果
完全ok!