Python圖片存儲(chǔ)和訪(fǎng)問(wèn)的三種方式詳解
前言
ImageNet 是一個(gè)著名的公共圖像數(shù)據(jù)庫(kù),用于訓(xùn)練對(duì)象分類(lèi)、檢測(cè)和分割等任務(wù)的模型,它包含超過(guò) 1400 萬(wàn)張圖像。
在 Python 中處理圖像數(shù)據(jù)的時(shí)候,例如應(yīng)用卷積神經(jīng)網(wǎng)絡(luò)(也稱(chēng)CNN)等算法可以處理大量圖像數(shù)據(jù)集,這里就需要學(xué)習(xí)如何用最簡(jiǎn)單的方式存儲(chǔ)、讀取數(shù)據(jù)。
對(duì)于圖像數(shù)據(jù)處理應(yīng)該有有個(gè)定量的比較方式,讀取和寫(xiě)入文件需要多長(zhǎng)時(shí)間,以及將使用多少磁盤(pán)內(nèi)存。
分別用不同的方式去處理、解決圖像的存儲(chǔ)、性能優(yōu)化的問(wèn)題。
數(shù)據(jù)準(zhǔn)備
一個(gè)可以玩的數(shù)據(jù)集
我們熟知的圖像數(shù)據(jù)集 CIFAR-10,由 60000 個(gè) 32x32 像素的彩色圖像組成,這些圖像屬于不同的對(duì)象類(lèi)別,例如狗、貓和飛機(jī)。相對(duì)而言 CIFAR 不是一個(gè)非常大的數(shù)據(jù)集,但如使用完整的 TinyImages 數(shù)據(jù)集,那么將需要大約 400GB 的可用磁盤(pán)空間。
文中的代碼應(yīng)用的數(shù)據(jù)集下載地址 CIFAR-10 數(shù)據(jù)集 。

這份數(shù)據(jù)是使用cPickle進(jìn)行了序列化和批量保存。pickle模塊可以序列化任何 Python 對(duì)象,而無(wú)需進(jìn)行任何額外的代碼或轉(zhuǎn)換。但是有一個(gè)潛在的嚴(yán)重缺點(diǎn),即在處理大量數(shù)據(jù)時(shí)會(huì)帶來(lái)安全風(fēng)險(xiǎn)無(wú)法評(píng)估。
圖像加載到 NumPy 數(shù)組中
import numpy as np
import pickle
from pathlib import Path
# 文件路徑
data_dir = Path("data/cifar-10-batches-py/")
# 解碼功能
def unpickle(file):
with open(file, "rb") as fo:
dict = pickle.load(fo, encoding="bytes")
return dict
images, labels = [], []
for batch in data_dir.glob("data_batch_*"):
batch_data = unpickle(batch)
for i, flat_im in enumerate(batch_data[b"data"]):
im_channels = []
# 每個(gè)圖像都是扁平化的,通道按 R, G, B 的順序排列
for j in range(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)}")
圖像存儲(chǔ)的設(shè)置
安裝三方庫(kù) Pillow 用于圖像處理 。
pip install Pillow
LMDB
LMDB 也稱(chēng)為“閃電數(shù)據(jù)庫(kù)”,代表閃電內(nèi)存映射數(shù)據(jù)庫(kù),因?yàn)樗俣瓤觳⑶沂褂脙?nèi)存映射文件。它是鍵值存儲(chǔ),而不是關(guān)系數(shù)據(jù)庫(kù)。
安裝三方庫(kù) lmdb 用于圖像處理 。
pip install lmdb
HDF5
HDF5 代表 Hierarchical Data Format,一種稱(chēng)為 HDF4 或 HDF5 的文件格式。起源于美國(guó)國(guó)家超級(jí)計(jì)算應(yīng)用中心,是一種可移植、緊湊的科學(xué)數(shù)據(jù)格式。
安裝三方庫(kù) h5py 用于圖像處理 。
pip install h5py
單一圖像的存儲(chǔ)
3種不同的方式進(jìn)行數(shù)據(jù)讀取操作
from pathlib import Path
disk_dir = Path("data/disk/")
lmdb_dir = Path("data/lmdb/")
hdf5_dir = Path("data/hdf5/")同時(shí)加載的數(shù)據(jù)可以創(chuàng)建文件夾分開(kāi)保存
disk_dir.mkdir(parents=True, exist_ok=True) lmdb_dir.mkdir(parents=True, exist_ok=True) hdf5_dir.mkdir(parents=True, exist_ok=True)
存儲(chǔ)到 磁盤(pán)
使用 Pillow 完成輸入是一個(gè)單一的圖像 image,在內(nèi)存中作為一個(gè) NumPy 數(shù)組,并且使用唯一的圖像 ID 對(duì)其進(jìn)行命名image_id。
單個(gè)圖像保存到磁盤(pán)
from PIL import Image
import csv
def store_single_disk(image, image_id, label):
""" 將單個(gè)圖像作為 .png 文件存儲(chǔ)在磁盤(pán)上。
參數(shù):
---------------
image 圖像數(shù)組, (32, 32, 3) 格式
image_id 圖像的整數(shù)唯一 ID
label 圖像標(biāo)簽
"""
Image.fromarray(image).save(disk_dir / f"{image_id}.png")
with open(disk_dir / f"{image_id}.csv", "wt") as csvfile:
writer = csv.writer(
csvfile, delimiter=" ", quotechar="|", quoting=csv.QUOTE_MINIMAL
)
writer.writerow([label])
存儲(chǔ)到 LMDB
LMDB 是一個(gè)鍵值對(duì)存儲(chǔ)系統(tǒng),其中每個(gè)條目都保存為一個(gè)字節(jié)數(shù)組,鍵將是每個(gè)圖像的唯一標(biāo)識(shí)符,值將是圖像本身。
鍵和值都應(yīng)該是字符串。 常見(jiàn)的用法是將值序列化為字符串,然后在讀回時(shí)將其反序列化。
用于重建的圖像尺寸,某些數(shù)據(jù)集可能包含不同大小的圖像會(huì)使用到這個(gè)方法。
class CIFAR_Image:
def __init__(self, image, label):
self.channels = image.shape[2]
self.size = image.shape[:2]
self.image = image.tobytes()
self.label = label
def get_image(self):
""" 將圖像作為 numpy 數(shù)組返回 """
image = np.frombuffer(self.image, dtype=np.uint8)
return image.reshape(*self.size, self.channels)
單個(gè)圖像保存到 LMDB
import lmdb
import pickle
def store_single_lmdb(image, image_id, label):
""" 將單個(gè)圖像存儲(chǔ)到 LMDB
參數(shù):
---------------
image 圖像數(shù)組, (32, 32, 3) 格式
image_id 圖像的整數(shù)唯一 ID
label 圖像標(biāo)簽
"""
map_size = image.nbytes * 10
# Create a new LMDB environment
env = lmdb.open(str(lmdb_dir / f"single_lmdb"), map_size=map_size)
# Start a new write transaction
with env.begin(write=True) as txn:
# All key-value pairs need to be strings
value = CIFAR_Image(image, label)
key = f"{image_id:08}"
txn.put(key.encode("ascii"), pickle.dumps(value))
env.close()
存儲(chǔ) HDF5
一個(gè) HDF5 文件可以包含多個(gè)數(shù)據(jù)集??梢詣?chuàng)建兩個(gè)數(shù)據(jù)集,一個(gè)用于圖像,一個(gè)用于元數(shù)據(jù)。
import h5py
def store_single_hdf5(image, image_id, label):
""" 將單個(gè)圖像存儲(chǔ)到 HDF5 文件
參數(shù):
---------------
image 圖像數(shù)組, (32, 32, 3) 格式
image_id 圖像的整數(shù)唯一 ID
label 圖像標(biāo)簽
"""
# 創(chuàng)建一個(gè)新的 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()
存儲(chǔ)方式對(duì)比
將保存單個(gè)圖像的所有三個(gè)函數(shù)放入字典中。
_store_single_funcs = dict(
disk=store_single_disk,
lmdb=store_single_lmdb,
hdf5=store_single_hdf5
)
以三種不同的方式存儲(chǔ)保存 CIFAR 中的第一張圖像及其對(duì)應(yīng)的標(biāo)簽。
from timeit import timeit
store_single_timings = dict()
for method in ("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"存儲(chǔ)方法: {method}, 使用耗時(shí): {t}")
來(lái)一個(gè)表格看看對(duì)比。
| 存儲(chǔ)方法 | 存儲(chǔ)耗時(shí) | 使用內(nèi)存 |
|---|---|---|
| Disk | 2.1 ms | 8 K |
| LMDB | 1.7 ms | 32 K |
| HDF5 | 8.1 ms | 8 K |
多個(gè)圖像的存儲(chǔ)
同單個(gè)圖像存儲(chǔ)方法類(lèi)似,修改代碼進(jìn)行多個(gè)圖像數(shù)據(jù)的存儲(chǔ)。
多圖像調(diào)整代碼
將多個(gè)圖像保存為.png文件就可以理解為多次調(diào)用 store_single_method() 這樣。但這不適用于 LMDB 或 HDF5,因?yàn)槊總€(gè)圖像都有不同的數(shù)據(jù)庫(kù)文件。
將一組圖像存儲(chǔ)到磁盤(pán)
store_many_disk(images, labels):
""" 參數(shù):
---------------
images 圖像數(shù)組 (N, 32, 32, 3) 格式
labels 標(biāo)簽數(shù)組 (N,1) 格式
"""
num_images = len(images)
# 一張一張保存所有圖片
for i, image in enumerate(images):
Image.fromarray(image).save(disk_dir / f"{i}.png")
# 將所有標(biāo)簽保存到 csv 文件
with open(disk_dir / f"{num_images}.csv", "w") as csvfile:
writer = csv.writer(
csvfile, delimiter=" ", quotechar="|", quoting=csv.QUOTE_MINIMAL
)
for label in labels:
writer.writerow([label])
將一組圖像存儲(chǔ)到 LMDB
def store_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)建一個(gè)新的 LMDB 數(shù)據(jù)庫(kù)
env = lmdb.open(str(lmdb_dir / f"{num_images}_lmdb"), map_size=map_size)
# 在一個(gè)事務(wù)中寫(xiě)入所有圖像
with env.begin(write=True) as txn:
for i in range(num_images):
# 所有鍵值對(duì)都必須是字符串
value = CIFAR_Image(images[i], labels[i])
key = f"{i:08}"
txn.put(key.encode("ascii"), pickle.dumps(value))
env.close()
將一組圖像存儲(chǔ)到 HDF5
def store_many_hdf5(images, labels):
""" 參數(shù):
---------------
images 圖像數(shù)組 (N, 32, 32, 3) 格式
labels 標(biāo)簽數(shù)組 (N,1) 格式
"""
num_images = len(images)
# 創(chuàng)建一個(gè)新的 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ù)集對(duì)比
使用 100000 個(gè)圖像進(jìn)行測(cè)試
cutoffs = [10, 100, 1000, 10000, 100000] images = np.concatenate((images, images), axis=0) labels = np.concatenate((labels, labels), axis=0) # 確保有 100,000 個(gè)圖像和標(biāo)簽 print(np.shape(images)) print(np.shape(labels))
創(chuàng)建一個(gè)計(jì)算方式進(jìn)行對(duì)比
_store_many_funcs = dict(
disk=store_many_disk, lmdb=store_many_lmdb, hdf5=store_many_hdf5
)
from timeit import timeit
store_many_timings = {"disk": [], "lmdb": [], "hdf5": []}
for cutoff in cutoffs:
for method in ("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)
# 打印出方法、截止時(shí)間和使用時(shí)間
print(f"Method: {method}, Time usage: {t}")
PLOT 顯示具有多個(gè)數(shù)據(jù)集和匹配圖例的單個(gè)圖
import matplotlib.pyplot as plt
def plot_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_label x 軸標(biāo)簽
y_label y 軸標(biāo)簽
"""
plt.style.use("seaborn-whitegrid")
plt.figure(figsize=(10, 7))
if len(y_data) != len(legend_labels):
raise TypeError(
"數(shù)據(jù)集的數(shù)量與標(biāo)簽的數(shù)量不匹配"
)
all_plots = []
for data, label in zip(y_data, legend_labels):
if log:
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()
# Getting the store timings data to display
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],
["PNG files", "LMDB", "HDF5"],
"Number of images",
"Seconds to store",
"Storage time",
log=False,
)
plot_with_legend(
cutoffs,
[disk_x, lmdb_x, hdf5_x],
["PNG files", "LMDB", "HDF5"],
"Number of images",
"Seconds to store",
"Log storage time",
log=True,
)


單一圖像的讀取
從 磁盤(pán) 讀取
def read_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"))
with open(disk_dir / f"{image_id}.csv", "r") as csvfile:
reader = csv.reader(
csvfile, delimiter=" ", quotechar="|", quoting=csv.QUOTE_MINIMAL
)
label = int(next(reader)[0])
return image, label
從 LMDB 讀取
def read_single_lmdb(image_id):
""" 參數(shù):
---------------
image_id 圖像的整數(shù)唯一 ID
返回結(jié)果:
---------------
images 圖像數(shù)組 (N, 32, 32, 3) 格式
labels 標(biāo)簽數(shù)組 (N,1) 格式
"""
# 打開(kāi) LMDB 環(huán)境
env = lmdb.open(str(lmdb_dir / f"single_lmdb"), readonly=True)
# 開(kāi)始一個(gè)新的事務(wù)
with env.begin() as txn:
# 進(jìn)行編碼
data = txn.get(f"{image_id:08}".encode("ascii"))
# 加載的 CIFAR_Image 對(duì)象
cifar_image = pickle.loads(data)
# 檢索相關(guān)位
image = cifar_image.get_image()
label = cifar_image.label
env.close()
return image, label
從 HDF5 讀取
def read_single_hdf5(image_id):
""" 參數(shù):
---------------
image_id 圖像的整數(shù)唯一 ID
返回結(jié)果:
---------------
images 圖像數(shù)組 (N, 32, 32, 3) 格式
labels 標(biāo)簽數(shù)組 (N,1) 格式
"""
# 打開(kāi) 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"))
return image, label
讀取方式對(duì)比
from timeit import timeit
read_single_timings = dict()
for method in ("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}, 使用耗時(shí): {t}")
| 存儲(chǔ)方法 | 存儲(chǔ)耗時(shí) |
|---|---|
| Disk | 1.7 ms |
| LMDB | 4.4 ms |
| HDF5 | 2.3 ms |
多個(gè)圖像的讀取
將多個(gè)圖像保存為.png文件就可以理解為多次調(diào)用 read_single_method() 這樣。但這不適用于 LMDB 或 HDF5,因?yàn)槊總€(gè)圖像都有不同的數(shù)據(jù)庫(kù)文件。
多圖像調(diào)整代碼
從磁盤(pán)中讀取多個(gè)都圖像
def read_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,一張一張地讀取每張圖片
for image_id in range(num_images):
images.append(np.array(Image.open(disk_dir / f"{image_id}.png")))
with open(disk_dir / f"{num_images}.csv", "r") as csvfile:
reader = csv.reader(
csvfile, delimiter=" ", quotechar="|", quoting=csv.QUOTE_MINIMAL
)
for row in reader:
labels.append(int(row[0]))
return images, labels
從LMDB中讀取多個(gè)都圖像
def read_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)
# 開(kāi)始一個(gè)新的事務(wù)
with env.begin() as txn:
# 在一個(gè)事務(wù)中讀取,也可以拆分成多個(gè)事務(wù)分別讀取
for image_id in range(num_images):
data = txn.get(f"{image_id:08}".encode("ascii"))
# CIFAR_Image 對(duì)象,作為值存儲(chǔ)
cifar_image = pickle.loads(data)
# 檢索相關(guān)位
images.append(cifar_image.get_image())
labels.append(cifar_image.label)
env.close()
return images, labels
從HDF5中讀取多個(gè)都圖像
def read_many_hdf5(num_images):
""" 參數(shù):
---------------
num_images 要讀取的圖像數(shù)量
返回結(jié)果:
---------------
images 圖像數(shù)組 (N, 32, 32, 3) 格式
labels 標(biāo)簽數(shù)組 (N,1) 格式
"""
images, labels = [], []
# 打開(kāi) HDF5 文件
file = h5py.File(hdf5_dir / f"{num_images}_many.h5", "r+")
images = np.array(file["/images"]).astype("uint8")
labels = np.array(file["/meta"]).astype("uint8")
return images, labels
_read_many_funcs = dict(
disk=read_many_disk, lmdb=read_many_lmdb, hdf5=read_many_hdf5
)
準(zhǔn)備數(shù)據(jù)集對(duì)比
創(chuàng)建一個(gè)計(jì)算方式進(jìn)行對(duì)比
from timeit import timeit
read_many_timings = {"disk": [], "lmdb": [], "hdf5": []}
for cutoff in cutoffs:
for method in ("disk", "lmdb", "hdf5"):
t = timeit(
"_read_many_funcs[method](num_images)",
setup="num_images=cutoff",
number=1,
globals=globals(),
)
read_many_timings[method].append(t)
# Print out the method, cutoff, and elapsed time
print(f"讀取方法: {method}, No. images: {cutoff}, 耗時(shí): {t}")


讀寫(xiě)操作綜合比較
數(shù)據(jù)對(duì)比
同一張圖表上查看讀取和寫(xiě)入時(shí)間
plot_with_legend(
cutoffs,
[disk_x_r, lmdb_x_r, hdf5_x_r, disk_x, lmdb_x, hdf5_x],
[
"Read PNG",
"Read LMDB",
"Read HDF5",
"Write PNG",
"Write LMDB",
"Write HDF5",
],
"Number of images",
"Seconds",
"Log Store and Read Times",
log=False,
)
各種存儲(chǔ)方式使用磁盤(pán)空間

雖然 HDF5 和 LMDB 都占用更多的磁盤(pán)空間。需要注意的是 LMDB 和 HDF5 磁盤(pán)的使用和性能在很大程度上取決于各種因素,包括操作系統(tǒng),更重要的是存儲(chǔ)的數(shù)據(jù)大小。
并行操作
通常對(duì)于大的數(shù)據(jù)集,可以通過(guò)并行化來(lái)加速操作。 也就是我們經(jīng)常說(shuō)的并發(fā)處理。
作為.png 文件存儲(chǔ)到磁盤(pán)實(shí)際上允許完全并發(fā)。只要圖像名稱(chēng)不同就可以從不同的線(xiàn)程讀取多個(gè)圖像,或一次寫(xiě)入多個(gè)文件。
如果將所有 CIFAR 分成十組,那么可以為一組中的每個(gè)讀取設(shè)置十個(gè)進(jìn)程,并且相應(yīng)的處理時(shí)間可以減少到原來(lái)的10%左右。
以上就是Python圖片存儲(chǔ)和訪(fǎng)問(wèn)的三種方式詳解的詳細(xì)內(nèi)容,更多關(guān)于Python圖片存儲(chǔ)訪(fǎng)問(wèn)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python實(shí)現(xiàn)Mysql數(shù)據(jù)庫(kù)連接池實(shí)例詳解
這篇文章主要介紹了Python實(shí)現(xiàn)Mysql數(shù)據(jù)庫(kù)連接池實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-04-04
Python機(jī)器學(xué)習(xí)應(yīng)用之基于LightGBM的分類(lèi)預(yù)測(cè)篇解讀
這篇文章我們繼續(xù)學(xué)習(xí)一下GBDT模型的另一個(gè)進(jìn)化版本:LightGBM,LigthGBM是boosting集合模型中的新進(jìn)成員,由微軟提供,它和XGBoost一樣是對(duì)GBDT的高效實(shí)現(xiàn),原理上它和GBDT及XGBoost類(lèi)似,都采用損失函數(shù)的負(fù)梯度作為當(dāng)前決策樹(shù)的殘差近似值,去擬合新的決策樹(shù)2022-01-01
教你如何用Pytorch搭建數(shù)英混合驗(yàn)證碼圖片識(shí)別模型
大家都知道checkpoints存放的是模型文件,data存放的是數(shù)據(jù)集,本文給大家分享如何利用Pytorch搭建數(shù)英混合驗(yàn)證碼圖片識(shí)別模型包括普通卷積模塊,深度可分離卷積模塊,空間通道注意力模塊,殘差模塊,感興趣的朋友跟隨小編一起看看吧2024-04-04
python實(shí)現(xiàn)一個(gè)搖骰子小游戲
大家好,本篇文章主要講的是python實(shí)現(xiàn)一個(gè)搖骰子小游戲,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話(huà)記得收藏一下2022-01-01
PyCharm2020.1.1與Python3.7.7的安裝教程圖文詳解
這篇文章主要介紹了PyCharm2020.1.1與Python3.7.7的安裝教程,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08
python庫(kù)skimage給灰度圖像染色的方法示例
這篇文章主要介紹了python庫(kù)skimage給灰度圖像染色的方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04
詳解Python中如何將數(shù)據(jù)存儲(chǔ)為json格式的文件
這篇文章主要介紹了詳解Python中如何將數(shù)據(jù)存儲(chǔ)為json格式的文件,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
python GUI庫(kù)圖形界面開(kāi)發(fā)之PyQt5下拉列表框控件QComboBox詳細(xì)使用方法與實(shí)例
這篇文章主要介紹了python GUI庫(kù)圖形界面開(kāi)發(fā)之PyQt5下拉列表框控件QComboBox詳細(xì)使用方法與實(shí)例,需要的朋友可以參考下2020-02-02
Matplotlib自定義坐標(biāo)軸刻度的實(shí)現(xiàn)示例
這篇文章主要介紹了Matplotlib自定義坐標(biāo)軸刻度的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06

