问题描述
编一个程序实现如下功能:
1、读入一幅指纹图像(自己找);
2、对图像进行二值化(方法自定,可以是阈值法);
3、采用形态学骨架提取和距离变换骨架提取两种算法分别提取图像骨架;
4、采用裁剪算法,并分析其效果。
问题求解
指纹图像
问题二 用阈值法对图像进行二值化,阈值采用的是全局阈值算法得到,然后令前景像素为 1,背景像素为 0。阈值算法代码如下所示:
def threshold(img):
med = np.mean(img)
med1 = 0
while np.mean(med1-med)>=0.0001:
miu1 = np.mean(img<=med)
miu2 = np.mean(img>med)
med1 = med
med = 0.5*(miu1+miu2)
return med
运行结果如下图所示:
问题三
腐蚀运算的实现代码为:
x = cv2.erode(src, kernel, iterations=1)
骨架提取的实现代码为,其中的开运算拆开成了腐蚀和膨胀:
def morphology(src):
# 生成卷积核
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))
# 进行腐蚀处理
x = cv2.erode(src, kernel, iterations=1)
img = src - cv2.dilate(x, kernel, iterations=1)
while np.any(src == 1):
src = cv2.erode(src, kernel, iterations=1)
x = cv2.erode(src, kernel, iterations=1)
src1 = src - cv2.dilate(x, kernel, iterations=1)
img = UU(src1, img)
return img
运行结果如下所示:
(2) 距离变换骨架提取
基本思想是把离散分布在空间中的目标根据一定的距离定义方式生成距离图, 其中每一点的距离值是到所有空间目标距离中最小的一个。本文采用的是欧式距 离,采用的串行距离变换算法,算法示意图如下所示,a=1,b=2。
算法步骤:
step1:求取二值图像的边界
img_o = img.copy()
# 边界图
img[img == 0.0] = 0.5
img[img == 1.0] = 0.0
img[img == 0.5] = 1.0
step2: 对边界二值图像求取距离变换
def distance(img):
# 初始化 将1变为0 将0变为一个特别大的值(就可以赋值最小距离)
img[img == 0.0] = 100
img[img == 1.0] = 0.0
# 图像左变换
for i in range(img.shape[0]):
for j in range(img.shape[1]):
# 上
if InArea(i - 1, j, img.shape[0], img.shape[1]):
img[i, j] = min(img[i,j], 1 + img[i - 1,j]);
# 左上
if InArea(i - 1, j - 1, img.shape[0], img.shape[1]):
img[i, j] = min(img[i, j], 2 + img[i - 1, j - 1]);
# 左
if InArea(i, j - 1, img.shape[0], img.shape[1]):
img[i, j] = min(img[i, j], 1 + img[i, j - 1]);
# 左下
if InArea(i + 1, j - 1, img.shape[0], img.shape[1]):
img[i, j] = min(img[i, j], 2 + img[i + 1, j - 1]);
# 图像右变换
for i in range(img.shape[0]-1, -1, -1):
for j in range(img.shape[1]-1, -1, -1):
# 下
if InArea(i + 1, j, img.shape[0], img.shape[1]):
img[i, j] = min(img[i, j], 1 + img[i + 1, j]);
# 右下
if InArea(i + 1, j + 1, img.shape[0], img.shape[1]):
img[i, j] = min(img[i, j], 2 + img[i + 1, j + 1]);
# 右
if InArea(i, j + 1, img.shape[0], img.shape[1]):
img[i, j] = min(img[i, j], 1 + img[i, j + 1]);
# 右上
if InArea(i - 1, j + 1, img.shape[0], img.shape[1]):
img[i, j] = min(img[i, j], 2 + img[i - 1, j + 1]);
return img
step3:求距离变换图中的局部极大值
step4:落入原二值图像中的局部极大值就是图像的骨架
运行结果如下图所示
细化实现
def thin(A, B1, B2):
return A - hit_miss(A,B1,B2)
击中击不中实现
def hit_miss(A, B1, B2):
A1 = cv2.erode(A,B1,iterations=1)
A2 = cv2.erode(1-A,B2,iterations=1)
return NN(A1,A2)
裁剪算法实现
def Tailoring(img):
A = img.copy()
B11 = np.array([[0,0,0],[1,1,0],[0,0,0]], dtype='uint8')
B12 = np.array([[0,1,1],[0,0,1],[0,1,1]], dtype='uint8')
B21 = np.array([[1,0,0],[0,1,0],[0,0,0]], dtype='uint8')
B22 = 1-B21
for j in range(3):
for i in range(4):
img = thin(img, B11, B12)
B11 = np.rot90(B11)
B12 = np.rot90(B12)
for i in range(4):
img = thin(img, B21, B22)
B21 = np.rot90(B21)
B22 = np.rot90(B22)
X1 = img
X2 = hit_miss(X1, B11, B12)
for i in range(3):
B11 = np.rot90(B11)
B12 = np.rot90(B12)
X2 = UU(hit_miss(X1,B11, B12),X2)
for i in range(4):
X2 = UU(hit_miss(X1, B21, B22), X2)
B21 = np.rot90(B21)
B22 = np.rot90(B22)
H = np.array([[1,1,1],[1,1,1],[1,1,1]], dtype='uint8')
for i in range(3):
X3 = NN(cv2.dilate(X2,H,iterations=1),A)
X4 = UU(X1,X3)
return X4
全部代码
import numpy as np
from scipy.ndimage import maximum_filter
import cv2
def normalization(img):
img = (img - np.min(img))/(np.max(img)-np.min(img))
return img
def threshold(img):
med = np.mean(img)
med1 = 0
while np.mean(med1-med)>=0.0001:
miu1 = np.mean(img<=med)
miu2 = np.mean(img>med)
med1 = med
med = 0.5*(miu1+miu2)
return med
def InArea(i, j, row, col):
if i < 0 or i >= row or j < 0 or j >= col:
return False
return True
def min(a,b):
if a>=b:
return b
else:
return a
def distance(img):
# 初始化 将1变为0 将0变为一个特别大的值(就可以赋值最小距离)
img[img == 0.0] = 100
img[img == 1.0] = 0.0
# 图像左变换
for i in range(img.shape[0]):
for j in range(img.shape[1]):
# 上
if InArea(i - 1, j, img.shape[0], img.shape[1]):
img[i, j] = min(img[i,j], 1 + img[i - 1,j]);
# 左上
if InArea(i - 1, j - 1, img.shape[0], img.shape[1]):
img[i, j] = min(img[i, j], 2 + img[i - 1, j - 1]);
# 左
if InArea(i, j - 1, img.shape[0], img.shape[1]):
img[i, j] = min(img[i, j], 1 + img[i, j - 1]);
# 左下
if InArea(i + 1, j - 1, img.shape[0], img.shape[1]):
img[i, j] = min(img[i, j], 2 + img[i + 1, j - 1]);
# 图像右变换
for i in range(img.shape[0]-1, -1, -1):
for j in range(img.shape[1]-1, -1, -1):
# 下
if InArea(i + 1, j, img.shape[0], img.shape[1]):
img[i, j] = min(img[i, j], 1 + img[i + 1, j]);
# 右下
if InArea(i + 1, j + 1, img.shape[0], img.shape[1]):
img[i, j] = min(img[i, j], 2 + img[i + 1, j + 1]);
# 右
if InArea(i, j + 1, img.shape[0], img.shape[1]):
img[i, j] = min(img[i, j], 1 + img[i, j + 1]);
# 右上
if InArea(i - 1, j + 1, img.shape[0], img.shape[1]):
img[i, j] = min(img[i, j], 2 + img[i - 1, j + 1]);
return img
def UU(a, b):
arr = np.zeros(a.shape)
for i in range(a.shape[0]):
for j in range(a.shape[1]):
arr[i,j] = a[i,j] or b[i,j]
return arr
def NN(a, b):
arr = np.zeros(a.shape)
for i in range(a.shape[0]):
for j in range(a.shape[1]):
arr[i, j] = a[i, j] and b[i, j]
return arr
def morphology(src):
# 生成卷积核
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))
# 进行腐蚀处理
x = cv2.erode(src, kernel, iterations=1)
img = src - cv2.dilate(x, kernel, iterations=1)
while np.any(src == 1):
src = cv2.erode(src, kernel, iterations=1)
x = cv2.erode(src, kernel, iterations=1)
src1 = src - cv2.dilate(x, kernel, iterations=1)
img = UU(src1, img)
return img
def distance_sk(img):
img_o = img.copy()
# 边界图
img[img == 0.0] = 0.5
img[img == 1.0] = 0.0
img[img == 0.5] = 1.0
img = distance(img)
imgx = maximum_filter(img, size=3)
imgy = np.where(img == imgx, 1.0, 0.0)
return NN(img_o,imgy)
def hit_miss(A, B1, B2):
A1 = cv2.erode(A,B1,iterations=1)
A2 = cv2.erode(1-A,B2,iterations=1)
return NN(A1,A2)
def thin(A, B1, B2):
return A - hit_miss(A,B1,B2)
def Tailoring(img):
A = img.copy()
B11 = np.array([[0,0,0],[1,1,0],[0,0,0]], dtype='uint8')
B12 = np.array([[0,1,1],[0,0,1],[0,1,1]], dtype='uint8')
B21 = np.array([[1,0,0],[0,1,0],[0,0,0]], dtype='uint8')
B22 = 1-B21
for j in range(3):
for i in range(4):
img = thin(img, B11, B12)
B11 = np.rot90(B11)
B12 = np.rot90(B12)
for i in range(4):
img = thin(img, B21, B22)
B21 = np.rot90(B21)
B22 = np.rot90(B22)
X1 = img
X2 = hit_miss(X1, B11, B12)
for i in range(3):
B11 = np.rot90(B11)
B12 = np.rot90(B12)
X2 = UU(hit_miss(X1,B11, B12),X2)
for i in range(4):
X2 = UU(hit_miss(X1, B21, B22), X2)
B21 = np.rot90(B21)
B22 = np.rot90(B22)
H = np.array([[1,1,1],[1,1,1],[1,1,1]], dtype='uint8')
for i in range(3):
X3 = NN(cv2.dilate(X2,H,iterations=1),A)
X4 = UU(X1,X3)
return X4
if __name__ == '__main__':
img = cv2.imread('zw.jpg',cv2.IMREAD_GRAYSCALE)
img = normalization(img)
img_o = img.copy()
cv2.imshow('original', img_o)
med = threshold(img)
img[img >= med] = 0.0
img[img != 0.0] = 1.0
cv2.imshow('binary', img)
img1 = morphology(img)
img2 = distance_sk(img)
img3 = Tailoring(img1)
img4 = Tailoring(img2)
cv2.imshow('morphology', img1)
cv2.imshow('distance', img2)
cv2.imshow('tailoring_m', img3)
cv2.imshow('tailoring_d', img4)
cv2.waitKey(0)
cv2.destroyAllWindows()