ZhangSuen法:
论文连接:A fast parallel algorithm for thinning digital patterns
代码连接:https://github.com/bsdnoobz/zhang-suen-thinning
上代码:
代码1
from scipy import weave
import numpy as np
import cv2
import sys
def _thinningIteration(im, iter):
I, M = im, np.zeros(im.shape, np.uint8)
expr = """
for (int i = 1; i < NI[0]-1; i++) {
for (int j = 1; j < NI[1]-1; j++) {
int p2 = I2(i-1, j);
int p3 = I2(i-1, j+1);
int p4 = I2(i, j+1);
int p5 = I2(i+1, j+1);
int p6 = I2(i+1, j);
int p7 = I2(i+1, j-1);
int p8 = I2(i, j-1);
int p9 = I2(i-1, j-1);
int A = (p2 == 0 && p3 == 1) + (p3 == 0 && p4 == 1) +
(p4 == 0 && p5 == 1) + (p5 == 0 && p6 == 1) +
(p6 == 0 && p7 == 1) + (p7 == 0 && p8 == 1) +
(p8 == 0 && p9 == 1) + (p9 == 0 && p2 == 1);
int B = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;
int m1 = iter == 0 ? (p2 * p4 * p6) : (p2 * p4 * p8);
int m2 = iter == 0 ? (p4 * p6 * p8) : (p2 * p6 * p8);
if (A == 1 && B >= 2 && B <= 6 && m1 == 0 && m2 == 0) {
M2(i,j) = 1;
}
}
}
"""
weave.inline(expr, ["I", "iter", "M"])
return (I & ~M)
def thinning(src):
dst = src.copy() / 255
prev = np.zeros(src.shape[:2], np.uint8)
diff = None
while True:
dst = _thinningIteration(dst, 0)
dst = _thinningIteration(dst, 1)
diff = np.absolute(dst - prev)
prev = dst.copy()
if np.sum(diff) == 0:
break
return dst * 255
if __name__ == "__main__":
src = cv2.imread("kanji.png")
if src == None:
sys.exit()
bw = cv2.cvtColor(src, cv2.cv.CV_BGR2GRAY)
_, bw2 = cv2.threshold(bw, 10, 255, cv2.THRESH_BINARY)
bw2 = thinning(bw2)
cv2.imshow("src", bw)
cv2.imshow("thinning", bw2)
cv2.waitKey()
代码2
import cv2
import numpy as np
import time
import matplotlib.pyplot as plt
def ROI(img):
indexXY = np.argwhere(img > 0)
minxy = np.min(indexXY, axis=0)
maxxy = np.max(indexXY, axis=0)
return minxy,maxxy
def neighbours(x,y,img):
i = img
x1,y1,x_1, y_1 = x+1, y-1, x-1, y+1
return [i[y1][x], i[y1][x1], i[y][x1], i[y_1][x1], # P2,P3,P4,P5
i[y_1][x], i[y_1][x_1], i[y][x_1], i[y1][x_1]] # P6,P7,P8,P9
def transitions(neighbours):
n = neighbours + neighbours[0:1] # P2, ... P9, P2
return sum((n1, n2) == (0, 1) for n1, n2 in zip(n, n[1:]))
def ZhangSuenPlus(image):
"""
运行时间55s
:param image:
:return:
"""
changing1 = changing2 = [(-1, -1)]
while changing1 or changing2:
# Step 1
changing1 = []
for y in range(1, len(image) - 1):
for x in range(1, len(image[0]) - 1):
P2,P3,P4,P5,P6,P7,P8,P9 = n = neighbours(x, y, image)
if (image[y][x] == 1 and # (Condition 0)
P4 * P6 * P8 == 0 and # Condition 4
P2 * P4 * P6 == 0 and # Condition 3
transitions(n) == 1 and # Condition 2
2 <= sum(n) <= 6): # Condition 1
changing1.append((x,y))
for x, y in changing1: image[y][x] = 0
# Step 2
changing2 = []
for y in range(1, len(image) - 1):
for x in range(1, len(image[0]) - 1):
P2,P3,P4,P5,P6,P7,P8,P9 = n = neighbours(x, y, image)
if (image[y][x] == 1 and # (Condition 0)
P2 * P6 * P8 == 0 and # Condition 4
P2 * P4 * P8 == 0 and # Condition 3
transitions(n) == 1 and # Condition 2
2 <= sum(n) <= 6): # Condition 1
changing2.append((x,y))
for x, y in changing2: image[y][x] = 0
#print changing1
#print changing2
flags = image>0
image[flags] = 255
#cv2.imshow("res",image)
return image
def ZhangSuenPlus02(image):
"""
# 运行时间12.135秒
:param image:
:return:
"""
indexXY = np.argwhere(image>0)
minxy = np.min(indexXY,axis=0)
maxxy = np.max(indexXY,axis=0)
roi = image[minxy[0]-1:maxxy[0]+2,minxy[1]-1:maxxy[1]+2]
changing1 = changing2 = [(-1, -1)]
while changing1 or changing2:
# Step 1
changing1 = []
for y in range(1, len(roi) - 1):
for x in range(1, len(roi[0]) - 1):
if roi[y][x] == 1:
P2,P3,P4,P5,P6,P7,P8,P9 = n = neighbours(x, y, roi)
if ( # (Condition 0)
P4 * P6 * P8 == 0 and # Condition 4
P2 * P4 * P6 == 0 and # Condition 3
transitions(n) == 1 and # Condition 2
2 <= sum(n) <= 6): # Condition 1
changing1.append((x,y))
for x, y in changing1: roi[y][x] = 0
# Step 2
changing2 = []
for y in range(1, len(roi) - 1):
for x in range(1, len(roi[0]) - 1):
if roi[y][x] == 1:
P2,P3,P4,P5,P6,P7,P8,P9 = n = neighbours(x, y, roi)
if ( # (Condition 0)
P2 * P6 * P8 == 0 and # Condition 4
P2 * P4 * P8 == 0 and # Condition 3
transitions(n) == 1 and # Condition 2
2 <= sum(n) <= 6): # Condition 1
changing2.append((x,y))
for x, y in changing2: roi[y][x] = 0
#print changing1
#print changing2
flags = roi>0
roi[flags] = 255
#cv2.imshow("res",image)
return image
def ZhangSuenPlus03(image):
"""
# 运行时间9秒
:param image:
:return:
"""
indexXY = np.argwhere(image>0)
minxy = np.min(indexXY,axis=0)
maxxy = np.max(indexXY,axis=0)
roi = image[minxy[0]-1:maxxy[0]+2,minxy[1]-1:maxxy[1]+2]
changing1 = changing2 = [(-1, -1)]
while changing1 or changing2:
indexXY = np.argwhere(roi>0)
minxy = np.min(indexXY, axis=0)
maxxy = np.max(indexXY, axis=0)
roi = roi[minxy[0] - 1:maxxy[0] + 2, minxy[1] - 1:maxxy[1] + 2]
# Step 1
changing1 = []
for y in range(1, len(roi) - 1):
for x in range(1, len(roi[0]) - 1):
if roi[y][x] == 1:
P2,P3,P4,P5,P6,P7,P8,P9 = n = neighbours(x, y, roi)
if ( # (Condition 0)
P4 * P6 * P8 == 0 and # Condition 4
P2 * P4 * P6 == 0 and # Condition 3
transitions(n) == 1 and # Condition 2
2 <= sum(n) <= 6): # Condition 1
changing1.append((x,y))
for x, y in changing1: roi[y][x] = 0
# Step 2
changing2 = []
for y in range(1, len(roi) - 1):
for x in range(1, len(roi[0]) - 1):
if roi[y][x] == 1:
P2,P3,P4,P5,P6,P7,P8,P9 = n = neighbours(x, y, roi)
if ( # (Condition 0)
P2 * P6 * P8 == 0 and # Condition 4
P2 * P4 * P8 == 0 and # Condition 3
transitions(n) == 1 and # Condition 2
2 <= sum(n) <= 6): # Condition 1
changing2.append((x,y))
for x, y in changing2: roi[y][x] = 0
#print changing1
#print changing2
flags = roi>0
roi[flags] = 255
#cv2.imshow("res",image)
return image
def ZhangSuen_Bad(img):
"""
将灰度值转化为0和1,企图加速计算过程
运行时间21.28s
thresh计算失败
:param img:
:return:
"""
copyMat = img.copy()
k = 0
row,col= img.shape
row = row-1
col = col-1
while(True):
k= k+1
stop= False
# step1
for i in range(1,row):
for j in range(1,col):
if img[i,j]>0:
print(">0")
p1 = 1 if img[i,j]>0 else 0
p2 = 1 if img[i-1,j]>0 else 0
p3 = 1 if img[i-1,j+1]>0 else 0
p4 = 1 if img[i, j+1] > 0 else 0
p5 = 1 if img[i+1, j+1] > 0 else 0
p6 = 1 if img[i+1, j] > 0 else 0
p7 = 1 if img[i+1, j-1] > 0 else 0
p8 = 1 if img[i,j-1] > 0 else 0
p9 = 1 if img[i-1, j-1] > 0 else 0
np1 = p2+p3+p4+p5+p6+p7+p8+p9
sp2 = 1 if (p2 == 0 and p3 == 1) else 0
sp3 = 1 if (p3 == 0 and p4 == 1) else 0
sp4 = 1 if (p4 == 0 and p5 == 1) else 0
sp5 = 1 if (p5 == 0 and p6 == 1) else 0
sp6 = 1 if (p6 == 0 and p7 == 1) else 0
sp7 = 1 if (p7 == 0 and p8 == 1) else 0
sp8 = 1 if (p8 == 0 and p9 == 1) else 0
sp9 = 1 if (p9 == 0 and p2 == 1) else 0
sp1 = sp2 + sp3 + sp4 + sp5 + sp6 + sp7 + sp8 + sp9
if np1>=2 and np1<=6 and sp1==1 and(p2*p4*p6)==0 and (p4*p6*p8)==0:
stop = True
copyMat[i,j] = 0
print("success")
img = copyMat.copy()
# step2
for i in range(1,row):
for j in range(1,col):
if img[i,j]>0:
print(">>")
p2 = 1 if img[i - 1, j] > 0 else 0
p3 = 1 if img[i - 1, j + 1] > 0 else 0
p4 = 1 if img[i, j + 1] > 0 else 0
p5 = 1 if img[i + 1, j + 1] > 0 else 0
p6 = 1 if img[i + 1, j] > 0 else 0
p7 = 1 if img[i + 1, j - 1] > 0 else 0
p8 = 1 if img[i, j - 1] > 0 else 0
p9 = 1 if img[i - 1, j - 1] > 0 else 0
np1 = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9
sp2 = 1 if (p2 == 0 and p3 == 1) else 0
sp3 = 1 if (p3 == 0 and p4 == 1) else 0
sp4 = 1 if (p4 == 0 and p5 == 1) else 0
sp5 = 1 if (p5 == 0 and p6 == 1) else 0
sp6 = 1 if (p6 == 0 and p7 == 1) else 0
sp7 = 1 if (p7 == 0 and p8 == 1) else 0
sp8 = 1 if (p8 == 0 and p9 == 1) else 0
sp9 = 1 if (p9 == 0 and p2 == 1) else 0
sp1 = sp2 + sp3 + sp4 + sp5 + sp6 + sp7 + sp8 + sp9
if np1 >= 2 and np1 <= 6 and sp1 == 1 and (p2*p4*p8) == 0 and (p2*p6*p8) == 0:
stop = True
copyMat[i,j] = 0
print("success")
img = copyMat.copy()
if(not stop):
break
resImg = copyMat.copy()
flags = resImg>0
resImg[flags] = 255
#print(k)
# cv2.imshow("res",resImg)
return resImg
def ZhangSuen(img):
"""
运行时间20.7s
:param img:
:return:
"""
#indexXY = np.argwhere(img>0)
#minxy = np.min(indexXY,axis=0)
#maxxy = np.max(indexXY,axis=0)
#roi = img[minxy[0]-3:maxxy[0]+4,minxy[1]-3:maxxy[1]+4]
#flags = roi>0
#roi[flags] = 255
#cv2.imshow("roi",roi)
#print(roi.shape)
roi = img
k = 0
row,col= roi.shape
changing1 = changing2 = [(-1, -1)]
while changing1 or changing2:
changing1 = []
for i in range(1,row-1):
for j in range(1,col-1):
if roi[i,j]==1:
p2 = roi[i-1,j]
p3 = roi[i-1,j+1]
p4 = roi[i, j+1]
p5 = roi[i+1, j+1]
p6 = roi[i+1, j]
p7 = roi[i+1, j-1]
p8 = roi[i,j-1]
p9 = roi[i-1, j-1]
np1 = p2+p3+p4+p5+p6+p7+p8+p9
sp2 = 1 if (p2,p3)==(0,1) else 0
sp3 = 1 if (p3,p4)==(0,1) else 0
sp4 = 1 if (p4,p5)==(0,1) else 0
sp5 = 1 if (p5,p6)==(0,1) else 0
sp6 = 1 if (p6,p7)==(0,1) else 0
sp7 = 1 if (p7,p8)==(0,1) else 0
sp8 = 1 if (p8,p9)==(0,1) else 0
sp9 = 1 if (p9,p2)==(0,1) else 0
sp1 = sp2 + sp3 + sp4 + sp5 + sp6 + sp7 + sp8 + sp9
if 2<=np1<=6 and sp1==1 and(p2*p4*p6)==0 and (p4*p6*p8)==0:
changing1.append([i,j])
for x,y in changing1:roi[x,y] = 0
# step2
changing2 = []
for i in range(1,row-1):
for j in range(1,col-1):
if roi[i,j]==1:
p2 = roi[i - 1, j]
p3 = roi[i - 1, j + 1]
p4 = roi[i, j + 1]
p5 = roi[i + 1, j + 1]
p6 = roi[i + 1, j]
p7 = roi[i + 1, j - 1]
p8 = roi[i, j - 1]
p9 = roi[i - 1, j - 1]
np1 = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9
sp2 = 1 if (p2, p3) == (0, 1) else 0
sp3 = 1 if (p3, p4) == (0, 1) else 0
sp4 = 1 if (p4, p5) == (0, 1) else 0
sp5 = 1 if (p5, p6) == (0, 1) else 0
sp6 = 1 if (p6, p7) == (0, 1) else 0
sp7 = 1 if (p7, p8) == (0, 1) else 0
sp8 = 1 if (p8, p9) == (0, 1) else 0
sp9 = 1 if (p9, p2) == (0, 1) else 0
sp1 = sp2 + sp3 + sp4 + sp5 + sp6 + sp7 + sp8 + sp9
if 2<=np1<= 6 and sp1 == 1 and (p2*p4*p8) == 0 and (p2*p6*p8) == 0:
#roi[i,j] = 0
changing2.append([i,j])
#print("success")
for x,y in changing2:roi[x,y] = 0
flags = roi>0
roi[flags] = 255
return roi
def Draw():
plt.figure()
plt.subplot(131)
plt.imshow(cv2.cvtColor(img,cv2.COLOR_BGR2RGB))
plt.title("origin image")
plt.axis("off")
plt.subplot(132)
# plt.imshow(res,"gray")
plt.title("res image")
plt.axis("off")
plt.subplot(133)
# plt.imshow(resP,"gray")
plt.title("resP image")
plt.axis("off")
plt.show()
# Draw()
def XiHua(img):
kernel_d = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
image_d = cv2.dilate(image, kernel_d, iterations=8)
# cv2.namedWindow('dilate', cv2.WINDOW_NORMAL)
# cv2.imshow('dilate', image_d)
kernel_e = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
image_e = cv2.erode(image_d, kernel_e)
image_ske = morphology.skeletonize(image_e)
image_e = np.multiply(image_e, image_ske)
return image_e
if __name__ == "__main__":
import os
import time
from skimage import morphology
image_path = '../images/'
save_path = '../train/do/'
per_time = 0
sum_time = 0
if not os.path.isdir(save_path): os.makedirs(save_path)
for img in os.listdir(image_path):
image = cv2.imread(os.path.join(image_path, img))
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 125, 255, cv2.THRESH_BINARY)
time1 = time.time()
result = ZhangSuen_Bad(thresh)
time2 = time.time()
temp_time = time2 - time1
sum_time += temp_time
print("one image time: ", temp_time)
cv2.namedWindow('result', 0)
cv2.imshow('result', result)
cv2.waitKey(10)
cv2.imwrite(os.path.join(save_path, img), result)
per_time = sum_time / len(os.listdir(image_path))
print("average image time:", per_time)