Python圖片存儲和訪問的三種方式詳解_第1頁
Python圖片存儲和訪問的三種方式詳解_第2頁
Python圖片存儲和訪問的三種方式詳解_第3頁
Python圖片存儲和訪問的三種方式詳解_第4頁
Python圖片存儲和訪問的三種方式詳解_第5頁
已閱讀5頁,還剩16頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

第Python圖片存儲和訪問的三種方式詳解目錄前言數(shù)據(jù)準(zhǔn)備一個可以玩的數(shù)據(jù)集圖像存儲的設(shè)置LMDBHDF5單一圖像的存儲存儲到磁盤存儲到LMDB存儲HDF5存儲方式對比多個圖像的存儲多圖像調(diào)整代碼準(zhǔn)備數(shù)據(jù)集對比單一圖像的讀取從磁盤讀取從LMDB讀取從HDF5讀取讀取方式對比多個圖像的讀取多圖像調(diào)整代碼準(zhǔn)備數(shù)據(jù)集對比讀寫操作綜合比較數(shù)據(jù)對比并行操作

前言

ImageNet是一個著名的公共圖像數(shù)據(jù)庫,用于訓(xùn)練對象分類、檢測和分割等任務(wù)的模型,它包含超過1400萬張圖像。

在Python中處理圖像數(shù)據(jù)的時候,例如應(yīng)用卷積神經(jīng)網(wǎng)絡(luò)(也稱CNN)等算法可以處理大量圖像數(shù)據(jù)集,這里就需要學(xué)習(xí)如何用最簡單的方式存儲、讀取數(shù)據(jù)。

對于圖像數(shù)據(jù)處理應(yīng)該有有個定量的比較方式,讀取和寫入文件需要多長時間,以及將使用多少磁盤內(nèi)存。

分別用不同的方式去處理、解決圖像的存儲、性能優(yōu)化的問題。

數(shù)據(jù)準(zhǔn)備

一個可以玩的數(shù)據(jù)集

我們熟知的圖像數(shù)據(jù)集CIFAR-10,由60000個32x32像素的彩色圖像組成,這些圖像屬于不同的對象類別,例如狗、貓和飛機。相對而言CIFAR不是一個非常大的數(shù)據(jù)集,但如使用完整的TinyImages數(shù)據(jù)集,那么將需要大約400GB的可用磁盤空間。

文中的代碼應(yīng)用的數(shù)據(jù)集下載地址CIFAR-10數(shù)據(jù)集。

這份數(shù)據(jù)是使用cPickle進(jìn)行了序列化和批量保存。pickle模塊可以序列化任何Python對象,而無需進(jìn)行任何額外的代碼或轉(zhuǎn)換。但是有一個潛在的嚴(yán)重缺點,即在處理大量數(shù)據(jù)時會帶來安全風(fēng)險無法評估。

圖像加載到NumPy數(shù)組中

importnumpyasnp

importpickle

frompathlibimportPath

#文件路徑

data_dir=Path("data/cifar-10-batches-py/")

#解碼功能

defunpickle(file):

withopen(file,"rb")asfo:

dict=pickle.load(fo,encoding="bytes")

returndict

images,labels=[],[]

forbatchindata_dir.glob("data_batch_*"):

batch_data=unpickle(batch)

fori,flat_iminenumerate(batch_data[b"data"]):

im_channels=[]

#每個圖像都是扁平化的,通道按R,G,B的順序排列

forjinrange(3):

im_channels.append(

flat_im[j*1024:(j+1)*1024].reshape((32,32))

#重建原始圖像

images.append(np.dstack((im_channels)))

#保存標(biāo)簽

labels.append(batch_data[b"labels"][i])

print("加載CIFAR-10訓(xùn)練集:")

print(f"-np.shape(images){np.shape(images)}")

print(f"-np.shape(labels){np.shape(labels)}")

圖像存儲的設(shè)置

安裝三方庫Pillow用于圖像處理。

pipinstallPillow

LMDB

LMDB也稱為閃電數(shù)據(jù)庫,代表閃電內(nèi)存映射數(shù)據(jù)庫,因為速度快并且使用內(nèi)存映射文件。它是鍵值存儲,而不是關(guān)系數(shù)據(jù)庫。

安裝三方庫lmdb用于圖像處理。

pipinstalllmdb

HDF5

HDF5代表HierarchicalDataFormat,一種稱為HDF4或HDF5的文件格式。起源于美國國家超級計算應(yīng)用中心,是一種可移植、緊湊的科學(xué)數(shù)據(jù)格式。

安裝三方庫h5py用于圖像處理。

pipinstallh5py

單一圖像的存儲

3種不同的方式進(jìn)行數(shù)據(jù)讀取操作

frompathlibimportPath

disk_dir=Path("data/disk/")

lmdb_dir=Path("data/lmdb/")

hdf5_dir=Path("data/hdf5/")

同時加載的數(shù)據(jù)可以創(chuàng)建文件夾分開保存

disk_dir.mkdir(parents=True,exist_ok=True)

lmdb_dir.mkdir(parents=True,exist_ok=True)

hdf5_dir.mkdir(parents=True,exist_ok=True)

存儲到磁盤

使用Pillow完成輸入是一個單一的圖像image,在內(nèi)存中作為一個NumPy數(shù)組,并且使用唯一的圖像ID對其進(jìn)行命名image_id。

單個圖像保存到磁盤

fromPILimportImage

importcsv

defstore_single_disk(image,image_id,label):

"""將單個圖像作為.png文件存儲在磁盤上。

---------------

image圖像數(shù)組,(32,32,3)格式

image_id圖像的整數(shù)唯一ID

label圖像標(biāo)簽

Image.fromarray(image).save(disk_dir/f"{image_id}.png")

withopen(disk_dir/f"{image_id}.csv","wt")ascsvfile:

writer=csv.writer(

csvfile,delimiter="",quotechar="|",quoting=csv.QUOTE_MINIMAL

writer.writerow([label])

存儲到LMDB

LMDB是一個鍵值對存儲系統(tǒng),其中每個條目都保存為一個字節(jié)數(shù)組,鍵將是每個圖像的唯一標(biāo)識符,值將是圖像本身。

鍵和值都應(yīng)該是字符串。常見的用法是將值序列化為字符串,然后在讀回時將其反序列化。

用于重建的圖像尺寸,某些數(shù)據(jù)集可能包含不同大小的圖像會使用到這個方法。

classCIFAR_Image:

def__init__(self,image,label):

self.channels=image.shape[2]

self.size=image.shape[:2]

self.image=image.tobytes()

self.label=label

defget_image(self):

"""將圖像作為numpy數(shù)組返回"""

image=np.frombuffer(self.image,dtype=np.uint8)

returnimage.reshape(*self.size,self.channels)

單個圖像保存到LMDB

importlmdb

importpickle

defstore_single_lmdb(image,image_id,label):

"""將單個圖像存儲到LMDB

---------------

image圖像數(shù)組,(32,32,3)格式

image_id圖像的整數(shù)唯一ID

label圖像標(biāo)簽

map_size=image.nbytes*10

#CreateanewLMDBenvironment

env=lmdb.open(str(lmdb_dir/f"single_lmdb"),map_size=map_size)

#Startanewwritetransaction

withenv.begin(write=True)astxn:

#Allkey-valuepairsneedtobestrings

value=CIFAR_Image(image,label)

key=f"{image_id:08}"

txn.put(key.encode("ascii"),pickle.dumps(value))

env.close()

存儲HDF5

一個HDF5文件可以包含多個數(shù)據(jù)集??梢詣?chuàng)建兩個數(shù)據(jù)集,一個用于圖像,一個用于元數(shù)據(jù)。

importh5py

defstore_single_hdf5(image,image_id,label):

"""將單個圖像存儲到HDF5文件

---------------

image圖像數(shù)組,(32,32,3)格式

image_id圖像的整數(shù)唯一ID

label圖像標(biāo)簽

#創(chuàng)建一個新的HDF5文件

file=h5py.File(hdf5_dir/f"{image_id}.h5","w")

#在文件中創(chuàng)建數(shù)據(jù)集

dataset=file.create_dataset(

"image",np.shape(image),h5py.h5t.STD_U8BE,data=image

meta_set=file.create_dataset(

"meta",np.shape(label),h5py.h5t.STD_U8BE,data=label

file.close()

存儲方式對比

將保存單個圖像的所有三個函數(shù)放入字典中。

_store_single_funcs=dict(

disk=store_single_disk,

lmdb=store_single_lmdb,

hdf5=store_single_hdf5

以三種不同的方式存儲保存CIFAR中的第一張圖像及其對應(yīng)的標(biāo)簽。

fromtimeitimporttimeit

store_single_timings=dict()

formethodin("disk","lmdb","hdf5"):

t=timeit(

"_store_single_funcs[method](image,0,label)",

setup="image=images[0];label=labels[0]",

number=1,

globals=globals(),

store_single_timings[method]=t

print(f"存儲方法:{method},使用耗時:{t}")

來一個表格看看對比。

存儲方法存儲耗時使用內(nèi)存Disk2.1ms8KLMDB1.7ms32KHDF58.1ms8K

多個圖像的存儲

同單個圖像存儲方法類似,修改代碼進(jìn)行多個圖像數(shù)據(jù)的存儲。

多圖像調(diào)整代碼

將多個圖像保存為.png文件就可以理解為多次調(diào)用store_single_method()這樣。但這不適用于LMDB或HDF5,因為每個圖像都有不同的數(shù)據(jù)庫文件。

將一組圖像存儲到磁盤

store_many_disk(images,labels):

"""參數(shù):

---------------

images圖像數(shù)組(N,32,32,3)格式

labels標(biāo)簽數(shù)組(N,1)格式

num_images=len(images)

#一張一張保存所有圖片

fori,imageinenumerate(images):

Image.fromarray(image).save(disk_dir/f"{i}.png")

#將所有標(biāo)簽保存到csv文件

withopen(disk_dir/f"{num_images}.csv","w")ascsvfile:

writer=csv.writer(

csvfile,delimiter="",quotechar="|",quoting=csv.QUOTE_MINIMAL

forlabelinlabels:

writer.writerow([label])

將一組圖像存儲到LMDB

defstore_many_lmdb(images,labels):

"""參數(shù):

---------------

images圖像數(shù)組(N,32,32,3)格式

labels標(biāo)簽數(shù)組(N,1)格式

num_images=len(images)

map_size=num_images*images[0].nbytes*10

#為所有圖像創(chuàng)建一個新的LMDB數(shù)據(jù)庫

env=lmdb.open(str(lmdb_dir/f"{num_images}_lmdb"),map_size=map_size)

#在一個事務(wù)中寫入所有圖像

withenv.begin(write=True)astxn:

foriinrange(num_images):

#所有鍵值對都必須是字符串

value=CIFAR_Image(images[i],labels[i])

key=f"{i:08}"

txn.put(key.encode("ascii"),pickle.dumps(value))

env.close()

將一組圖像存儲到HDF5

defstore_many_hdf5(images,labels):

"""參數(shù):

---------------

images圖像數(shù)組(N,32,32,3)格式

labels標(biāo)簽數(shù)組(N,1)格式

num_images=len(images)

#創(chuàng)建一個新的HDF5文件

file=h5py.File(hdf5_dir/f"{num_images}_many.h5","w")

#在文件中創(chuàng)建數(shù)據(jù)集

dataset=file.create_dataset(

"images",np.shape(images),h5py.h5t.STD_U8BE,data=images

meta_set=file.create_dataset(

"meta",np.shape(labels),h5py.h5t.STD_U8BE,data=labels

file.close()

準(zhǔn)備數(shù)據(jù)集對比

使用100000個圖像進(jìn)行測試

cutoffs=[10,100,1000,10000,100000]

images=np.concatenate((images,images),axis=0)

labels=np.concatenate((labels,labels),axis=0)

#確保有100,000個圖像和標(biāo)簽

print(np.shape(images))

print(np.shape(labels))

創(chuàng)建一個計算方式進(jìn)行對比

_store_many_funcs=dict(

disk=store_many_disk,lmdb=store_many_lmdb,hdf5=store_many_hdf5

fromtimeitimporttimeit

store_many_timings={"disk":[],"lmdb":[],"hdf5":[]}

forcutoffincutoffs:

formethodin("disk","lmdb","hdf5"):

t=timeit(

"_store_many_funcs[method](images_,labels_)",

setup="images_=images[:cutoff];labels_=labels[:cutoff]",

number=1,

globals=globals(),

store_many_timings[method].append(t)

#打印出方法、截止時間和使用時間

print(f"Method:{method},Timeusage:{t}")

PLOT顯示具有多個數(shù)據(jù)集和匹配圖例的單個圖

importmatplotlib.pyplotasplt

defplot_with_legend(

x_range,y_data,legend_labels,x_label,y_label,title,log=False

"""參數(shù):

--------------

x_range包含x數(shù)據(jù)的列表

y_data包含y值的列表

legend_labels字符串圖例標(biāo)簽列表

x_labelx軸標(biāo)簽

y_labely軸標(biāo)簽

plt.style.use("seaborn-whitegrid")

plt.figure(figsize=(10,7))

iflen(y_data)!=len(legend_labels):

raiseTypeError(

"數(shù)據(jù)集的數(shù)量與標(biāo)簽的數(shù)量不匹配"

all_plots=[]

fordata,labelinzip(y_data,legend_labels):

iflog:

temp,=plt.loglog(x_range,data,label=label)

else:

temp,=plt.plot(x_range,data,label=label)

all_plots.append(temp)

plt.title(title)

plt.xlabel(x_label)

plt.ylabel(y_label)

plt.legend(handles=all_plots)

plt.show()

#Gettingthestoretimingsdatatodisplay

disk_x=store_many_timings["disk"]

lmdb_x=store_many_timings["lmdb"]

hdf5_x=store_many_timings["hdf5"]

plot_with_legend(

cutoffs,

[disk_x,lmdb_x,hdf5_x],

["PNGfiles","LMDB","HDF5"],

"Numberofimages",

"Secondstostore",

"Storagetime",

log=False,

plot_with_legend(

cutoffs,

[disk_x,lmdb_x,hdf5_x],

["PNGfiles","LMDB","HDF5"],

"Numberofimages",

"Secondstostore",

"Logstoragetime",

log=True,

單一圖像的讀取

從磁盤讀取

defread_single_disk(image_id):

"""參數(shù):

---------------

image_id圖像的整數(shù)唯一ID

返回結(jié)果:

---------------

images圖像數(shù)組(N,32,32,3)格式

labels標(biāo)簽數(shù)組(N,1)格式

image=np.array(Image.open(disk_dir/f"{image_id}.png"))

withopen(disk_dir/f"{image_id}.csv","r")ascsvfile:

reader=csv.reader(

csvfile,delimiter="",quotechar="|",quoting=csv.QUOTE_MINIMAL

label=int(next(reader)[0])

returnimage,label

從LMDB讀取

defread_single_lmdb(image_id):

"""參數(shù):

---------------

image_id圖像的整數(shù)唯一ID

返回結(jié)果:

---------------

images圖像數(shù)組(N,32,32,3)格式

labels標(biāo)簽數(shù)組(N,1)格式

#打開LMDB環(huán)境

env=lmdb.open(str(lmdb_dir/f"single_lmdb"),readonly=True)

#開始一個新的事務(wù)

withenv.begin()astxn:

#進(jìn)行編碼

data=txn.get(f"{image_id:08}".encode("ascii"))

#加載的CIFAR_Image對象

cifar_image=pickle.loads(data)

#檢索相關(guān)位

image=cifar_image.get_image()

label=cifar_image.label

env.close()

returnimage,label

從HDF5讀取

defread_single_hdf5(image_id):

"""參數(shù):

---------------

image_id圖像的整數(shù)唯一ID

返回結(jié)果:

---------------

images圖像數(shù)組(N,32,32,3)格式

labels標(biāo)簽數(shù)組(N,1)格式

#打開HDF5文件

file=h5py.File(hdf5_dir/f"{image_id}.h5","r+")

image=np.array(file["/image"]).astype("uint8")

label=int(np.array(file["/meta"]).astype("uint8"))

returnimage,label

讀取方式對比

fromtimeitimporttimeit

read_single_timings=dict()

formethodin("disk","lmdb","hdf5"):

t=timeit(

"_read_single_funcs[method](0)",

setup="image=images[0];label=labels[0]",

number=1,

globals=globals(),

read_single_timings[method]=t

print(f"讀取方法:{method},使用耗時:{t}")

存儲方法存儲耗時Disk1.7msLMDB4.4msHDF52.3ms

多個圖像的讀取

將多個圖像保存為.png文件就可以理解為多次調(diào)用read_single_method()這樣。但這不適用于LMDB或HDF5,因為每個圖像都有不同的數(shù)據(jù)庫文件。

多圖像調(diào)整代碼

從磁盤中讀取多個都圖像

defread_many_disk(num_images):

"""參數(shù):

---------------

num_images要讀取的圖像數(shù)量

返回結(jié)果:

---------------

images圖像數(shù)組(N,32,32,3)格式

labels標(biāo)簽數(shù)組(N,1)格式

images,labels=[],[]

#循環(huán)遍歷所有ID,一張一張地讀取每張圖片

forimage_idinrange(num_images):

images.append(np.array(Image.open(disk_dir/f"{image_id}.png")))

withopen(disk_dir/f"{num_images}.csv","r")ascsvfile:

reader=csv.reader(

csvfile,delimiter="",quotechar="|",quoting=csv.QUOTE_MINIMAL

forrowinreader:

labels.append(int(row[0]))

returnimages,labels

從LMDB中讀取多個都圖像

defread_many_lmdb(num_images):

"""參數(shù):

---------------

num_images要讀取的圖像數(shù)量

返回結(jié)果:

---------------

images圖像數(shù)組(N,32,32,3)格式

labels標(biāo)簽數(shù)組(N,1)格式

images,labels=[],[]

env=lmdb.open(str(lmdb_dir/f"{num_images}_lmdb"),readonly=True)

#開始一個新的事務(wù)

withenv.begin()astxn:

#在一個事務(wù)中讀取,也可以拆分成多個事務(wù)分別讀取

forimage_idinrange(num_images):

data=txn.get(f"{image_id:08}".encode("ascii"))

#CIFAR_Image對象,作為值存儲

cifar_image=pickle.loads(data)

#檢索相關(guān)位

images.append(cifar_image.get_image())

labels.append(cifar_image.label)

env.close()

returnimages,labels

從HDF5中讀取多個都圖像

defread_many_hdf5(num_images):

"""參數(shù):

---------------

num_images要讀取的圖像數(shù)量

返回結(jié)果:

---------------

images圖像數(shù)組(N,32,32,3)格式

labels標(biāo)簽數(shù)組(N,1)格式

images,labels=[],[]

#打開HDF5文件

file=h5py.File(hdf5_dir/f"{num_images}_many.h5","r+")

images=np.array(fi

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論