对于这样的图片:
抠出其中的黑色区域,效果如下:
import cv2
import numpy as np
import matplotlib.pyplot as plt
import time
def findUnicomArea(img):
#先二值化
ret,threshold = cv2.threshold(img,128,255,cv2.THRESH_BINARY)
img_flag = np.zeros(threshold.shape,np.int8)
count = 0
findpoint = []
#首先遍历图像找到所有的联通区
for x in range(threshold.shape[0]):
for y in range(threshold.shape[1]):
if(threshold[x][y] == 0 and img_flag[x][y] == 0):
#这里表示已经找到了一个没有标志过的黑点,是一个新的联通区
count += 1
img_flag[x][y] = count
findpoint.append((x,y))
while len(findpoint) > 0:
xx,yy = findpoint.pop()
if xx > 0 :#上面
if threshold[xx-1][yy] == 0 and img_flag[xx-1][yy] == 0:
findpoint.append((xx-1,yy))
img_flag[xx-1][yy] = count
if xx < img.shape[0]:#下面
if threshold[xx + 1][yy] == 0 and img_flag[xx + 1][yy] == 0:
findpoint.append((xx + 1, yy))
img_flag[xx+1][yy] = count
if yy > 0:#左面
if threshold[xx][yy-1] == 0 and img_flag[xx][yy-1] == 0:
findpoint.append((xx, yy-1))
img_flag[xx][yy-1] = count
if yy < img.shape[1]:#右面
if threshold[xx][yy+1] == 0 and img_flag[xx][yy+1] == 0:
findpoint.append((xx, yy+1))
img_flag[xx][yy+1] = count
#联通区任然存在一张表中,需要将其分离
coutours = []
for num in range(1,count+1):
coutours.append([])
for x in range(img_flag.shape[0]):
for y in range(img_flag.shape[1]):
if img_flag[x][y] == num:
coutours[num-1].append([x,y,img_flag[x][y]])
desCoutous = np.empty(len(coutours),np.object)
for num in range(len(coutours)):
#将分离后的图像提取出来。计算出联通区所在的范围
tmp = np.mat(coutours[num])
minX = np.min(tmp[:,0])
maxX = np.max(tmp[:,0])
minY = np.min(tmp[:,1])
maxY = np.max(tmp[:,1])
desCoutous[num] = img[minX:maxX,minY:maxY]
return desCoutous
#测试程序如下
img = cv2.imread("testpic/connected_test.png",0);
cost = time.time()
unicoms = findUnicomArea(img)
print("cost",time.time()-cost)
for i in range(len(unicoms)):
cv2.imshow("test"+str(i),unicoms[i])
cv2.waitKey(0)
目前只是实现了功能,效率还不高,还有很大的优化空间。
这个程序显然有重复计算,第二次循环完全可以略去,可以合并到第一个循环中。另外,只需要遍历1~shape[0]-1的空间就能找到所有的点,所以边界的比较也可以省去,如此,程序如下:
def findUnicomArea(img):
#先二值化
ret,threshold = cv2.threshold(img,128,255,cv2.THRESH_BINARY)
img_flag = np.zeros(threshold.shape,np.int8)
count = 0
findpoint = []
coutours = []
#首先遍历图像找到所有的联通区
for x in range(1,threshold.shape[0]-1):
for y in range(1,threshold.shape[1]-1):
if(threshold[x][y] == 0 and img_flag[x][y] == 0):
#这里表示已经找到了一个没有标志过的黑点,是一个新的联通区
count += 1
#新增一个联通区存储点
coutours.append([])
img_flag[x][y] = count
findpoint.append((x,y))
while len(findpoint) > 0:
xx,yy = findpoint.pop()
#上面
if threshold[xx-1][yy] == 0 and img_flag[xx-1][yy] == 0:
findpoint.append((xx-1,yy))
img_flag[xx-1][yy] = count
coutours[count - 1].append([xx, yy, img_flag[x][y]])
#下面
if threshold[xx + 1][yy] == 0 and img_flag[xx + 1][yy] == 0:
findpoint.append((xx + 1, yy))
img_flag[xx+1][yy] = count
coutours[count - 1].append([xx, yy, img_flag[x][y]])
#左面
if threshold[xx][yy-1] == 0 and img_flag[xx][yy-1] == 0:
findpoint.append((xx, yy-1))
img_flag[xx][yy-1] = count
coutours[count - 1].append([xx, yy, img_flag[x][y]])
#右面
if threshold[xx][yy+1] == 0 and img_flag[xx][yy+1] == 0:
findpoint.append((xx, yy+1))
img_flag[xx][yy+1] = count
coutours[count - 1].append([xx, yy, img_flag[x][y]])
desCoutous = np.empty(len(coutours),np.object)
for num in range(len(coutours)):
#将分离后的图像提取出来。计算出联通区所在的范围
tmp = np.mat(coutours[num])
minX = np.min(tmp[:,0])
maxX = np.max(tmp[:,0])
minY = np.min(tmp[:,1])
maxY = np.max(tmp[:,1])
desCoutous[num] = img[minX:maxX,minY:maxY]
return desCoutous
这样程序性能从1.3秒提升至0.8秒,程序有了显著的提升。
如果我们只是抠出图中的联通区的话,只需要检测边界联通区的外边界就可以了,这样效率能进一步提升。
def findUnicomBoundry(img):
#先二值化
ret,threshold = cv2.threshold(img,128,255,cv2.THRESH_BINARY)
img_flag = np.zeros(threshold.shape,np.int8)
count = 0
findpoint = []
coutours = []
desCoutous = []
existCoutous = []
#首先遍历图像找到所有的联通区
for x in range(1,threshold.shape[0]-1):
for y in range(1,threshold.shape[1]-1):
if(threshold[x][y] == 0 and (threshold[x-1][y]==255 or threshold[x+1][y]==255 or threshold[x][y-1]==255 or threshold[x][y+1]==255) and img_flag[x][y] == 0):#是边界的条件是中心点为0,四周至少要有一个白点
#这里表示已经找到了一个边界点,并且是一个新的联通区的边界点
# 将分离后的图像提取出来。计算出联通区所在的范围
if count > len(desCoutous):
desCoutous.append([])
tmp = np.mat(coutours[count - 1])
minX = np.min(tmp[:, 0])
maxX = np.max(tmp[:, 0])
minY = np.min(tmp[:, 1])
maxY = np.max(tmp[:, 1])
existCoutous.append([minX, maxX, minY, maxY])
desCoutous[count - 1] = img[minX:maxX, minY:maxY]
desCoutous[count-1] = np.mat(desCoutous[count-1])
isChildArea = False
for num in range(len(existCoutous)):
if x>existCoutous[num][0] and x < existCoutous[num][1] and y > existCoutous[num][2] and y < existCoutous[num][3] :
isChildArea = True
if not isChildArea:
count += 1
#新增一个联通区的边界存储点
coutours.append([])
img_flag[x][y] = count
findpoint.append((x,y))
while len(findpoint) > 0:
#xx,yy肯定是一个边界点了,现在寻找下一个边界点
xx,yy = findpoint.pop()
#上面
if threshold[xx-1][yy] == 0 and (threshold[xx-2][yy]==255 or threshold[xx-1][yy-1]==255 or threshold[xx-1][yy+1]==255) and img_flag[xx-1][yy] == 0:
findpoint.append((xx-1,yy))
img_flag[xx-1][yy] = count
coutours[count - 1].append([xx-1, yy, img_flag[xx-1][yy]])
#下面
if threshold[xx + 1][yy] == 0 and (threshold[xx+1][yy]==255 or threshold[xx+1][yy-1]==255 or threshold[xx+1][yy+1]==255) and img_flag[xx + 1][yy] == 0:
findpoint.append((xx + 1, yy))
img_flag[xx+1][yy] = count
coutours[count - 1].append([xx+1, yy, img_flag[xx][yy]])
#左面
if threshold[xx][yy-1] == 0 and (threshold[xx][yy-2]==255 or threshold[xx-1][yy-1]==255 or threshold[xx+1][yy-1]==255) and img_flag[xx][yy-1] == 0:
findpoint.append((xx, yy-1))
img_flag[xx][yy-1] = count
coutours[count - 1].append([xx, yy-1, img_flag[xx][yy-1]])
#右面
if threshold[xx][yy+1] == 0 and (threshold[xx][yy+2]==255 or threshold[xx-1][yy+1]==255 or threshold[xx+1][yy+1]==255) and img_flag[xx][yy+1] == 0:
findpoint.append((xx, yy+1))
img_flag[xx][yy+1] = count
coutours[count - 1].append([xx, yy+1, img_flag[xx][yy+1]])
#左上
if threshold[xx-1][yy-1] == 0 and (threshold[xx-2][yy-1]==255 or threshold[xx][yy]==255 or threshold[xx-1][yy-2]==255 or threshold[xx-1][yy]==255) and img_flag[xx-1][yy-1] == 0:
findpoint.append((xx-1, yy-1))
img_flag[xx-1][yy-1] = count
coutours[count - 1].append([xx-1, yy-1, img_flag[xx-1][yy-1]])
#右上
if threshold[xx-1][yy+1] == 0 and (threshold[xx-2][yy+1]==255 or threshold[xx][yy+1]==255 or threshold[xx-1][yy]==255 or threshold[xx-1][yy+1]==255) and img_flag[xx-1][yy+1] == 0:
findpoint.append((xx-1, yy+1))
img_flag[xx-1][yy+1] = count
coutours[count - 1].append([xx-1, yy+1, img_flag[xx-1][yy+1]])
#左下
if threshold[xx+1][yy-1] == 0 and (threshold[xx][yy-1]==255 or threshold[xx+2][yy-1]==255 or threshold[xx+1][yy-2]==255 or threshold[xx+1][yy]==255) and img_flag[xx+1][yy-1] == 0:
findpoint.append((xx+1, yy-1))
img_flag[xx+1][yy-1] = count
coutours[count - 1].append([xx+1, yy-1, img_flag[xx+1][yy-1]])
#右下
if threshold[xx+1][yy+1] == 0 and (threshold[xx][yy+1]==255 or threshold[xx+2][yy+1]==255 or threshold[xx+1][yy]==255 or threshold[xx+1][yy+2]==255) and img_flag[xx+1][yy+1] == 0:
findpoint.append((xx+1, yy+1))
img_flag[xx+1][yy+1] = count
coutours[count - 1].append([xx+1, yy+1, img_flag[xx+1][yy+1]])
return desCoutous
程序的运行时间缩小到0.6秒