1. 程式人生 > >深度學習--------圖片的位深度含義

深度學習--------圖片的位深度含義

以前沒接觸深度學習的時候沒注意過圖片位深度的問題,最近研究深度學習圖片輸入弄的也是莫名奇妙,焦頭爛額。記錄一下自己搜的資料的總結。首先要明白計算機的儲存方式位二進位制,只有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)

這個程式碼本來應該生成一箇中間有一個白色板塊,其他都是黑色的圖片,但是結果呢

3通道
3通道生成圖片
4通道生成圖片

只有一個白色的框,很明顯四通道中數值為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
a通道為0原圖
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!