论文连接: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)