注解

此笔记本可在此处下载: Image_Processing_Tutorial_4.ipynb

图像处理

Python提供了几个很棒的库,允许对图像进行广泛的操作。有关更多信息,请阅读以下教程:* OpenCV * Scikit Image

在本笔记本中,我们只介绍一些玩骰子时的经典图像处理操作。这个例子的目的是计算一个骰子的总分,答案是 \(113\) .

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from scipy import ndimage
import pandas as pd
import os
%matplotlib nbagg

您可以在此处下载本示例中使用的图像: dices.jpg .如果图像与笔记本本身位于同一目录中,则以下代码将起作用。

首先,让我们检查一下 dices.tif 在当前目录中。

path = "dices.tif"
files = os.listdir("./")
if path in files:
    print("Ok, the file is in {0}".format(files))
else:
    print("The file is not in {0} , retry !".format(files))
Ok, the file is in ['_data', '02_Image_Processing.ipynb', '06_Practical_Work', '.ipynb_checkpoints', '00_Basics.ipynb', 'dices.tif', '04_Tutorials', '02_Advanced_Examples']

现在让我们用 python图像库(又称pil)

im = Image.open(path)
Nc, Nl = im.size
im = im.resize((Nc // 2 ,Nl // 2),Image.ANTIALIAS)
fig, ax = plt.subplots()
ax.axis("off")
plt.imshow(im)
plt.show()
<IPython.core.display.Javascript object>

转换为灰度

R, G, B = im.split()
R = np.array(R)
G = np.array(G)
B = np.array(B)
R
array([[223, 221, 224, ..., 195, 195, 193],
       [225, 225, 221, ..., 194, 195, 194],
       [223, 223, 223, ..., 195, 195, 195],
       ...,
       [229, 228, 231, ..., 192, 195, 196],
       [230, 229, 229, ..., 192, 194, 195],
       [230, 229, 228, ..., 193, 195, 196]], dtype=uint8)
fig = plt.figure()
ax1 = fig.add_subplot(3, 1, 1)
plt.title("R")
plt.imshow(R, cmap = cm.gray)
ax1.axis("off")
ax1 = fig.add_subplot(3, 1, 2)
plt.title("G")
plt.imshow(G, cmap = cm.gray)
ax1.axis("off")
ax1 = fig.add_subplot(3, 1, 3)
plt.title("B")
plt.imshow(B, cmap = cm.gray)
ax1.axis("off")
plt.show()
<IPython.core.display.Javascript object>

绿色通道有一个很大的障碍,所以我们现在只选择在这个通道上工作。

直方图

柱状图显示了色阶上像素的重新划分。

plt.figure()
plt.hist(G.flatten(), bins = np.arange(256), histtype = "stepfilled")
plt.grid()
plt.xlabel("Pixel value")
plt.ylabel("Pixel count")
plt.show()
<IPython.core.display.Javascript object>

阈值化

使用柱状图,可以看到有3个峰值。左峰是最暗的,对应于骰子体的颜色。我们可以绕过去 \(120\) 将骰子体与骰子上的点分离。

进一步阅读: Thresholding (Scikit)

Gt = G < 120 # Thresholding
plt.figure()
plt.imshow(Gt, cmap = cm.gray, interpolation = "nearest")
plt.grid()
#plt.colorbar()
plt.show()
<IPython.core.display.Javascript object>

侵蚀/膨胀

struc = np.ones((8,8))
Gtd = ndimage.binary_dilation(Gt, structure = struc)
Gtde = ndimage.binary_erosion(Gtd, structure = struc)
plt.figure()
plt.imshow(Gtde, cmap = cm.gray, interpolation = "nearest")
plt.grid()
plt.show()
<IPython.core.display.Javascript object>

标记

Gtdel, number = ndimage.measurements.label(Gtde == False)
number
114
plt.figure()
plt.imshow(Gtde,cmap = cm.gray, interpolation = "nearest")
plt.imshow(np.where(Gtdel > 1, Gtdel, np.nan),
           cmap = cm.jet, interpolation = "nearest")
plt.grid()
plt.show()
<IPython.core.display.Javascript object>
data = Gtdel.flatten()
count = np.bincount(data)
(count < 1000).sum()
113

所以总分是 \(113\) ,方法有效!