今天老师临时交给我的任务,本来需要在下位机完成,但是由于希望加快速度,就把比较耗时的分割步骤放在上位机进行处理。
进行图像分割我采用的是twopass方法,具体算法的细节部分大家可以百度一下。
因为是图片处理,建议大家最好不要使用不同的图片处理模块在一个程序当中,那样很容易造成混乱。
首先肯定是需要读取图片,我整个程序采用PIL包。并且在这里分享一个具体介绍PIL的一个博客:https://www.cnblogs.com/meitian/p/3699223.html
在使用twopass算法之前,有两个很关键的函数需要去定义的,一个是寻找根节点的函数,一个是把我们的区域连通起来的函数:
#寻找根节点
def find_root(label):
label = int(label)
while Parent[label] != 0:
label = Parent[label]
return label
#将不同label合并到一个联通域
def union_label(label1,label2):
label1 = int(label1)
label2 = int(label2)
while Parent[label1] != 0:
label1 = Parent[label1]
while Parent[label2] != 0:
label2 = Parent[label2]
if label1 != label2:
Parent[label1] = label2
按照twopass算法,我们需要遍历图片的每一个像素,寻找符合我们要求的像素点,然后给他一个标签,遍历像素点我用了load方法,读取了rgb的数值,最后我转化为了hsv,hsv更方便我们处理。
im = Image.open(r"C:\Users\Administrator\Desktop\JPEG\001.jpg")
pix = im.load()
width = im.size[0]
height = im.size[1]
for y in range(height):
for x in range(width):
r,g,b = pix[x, y]
h,s,v = rgb2hsv(r,g,b)
然后我们设定一个hsv的范围,就是寻找符合我们要求的像素点进行处理,我的方法就是使用画图测出来的。
然后我们就开始我们的twopass啦,首先当然是firstpass:
if h >= condition[0] and h <= condition[1] and s >= condition[2] and s <= condition[3] and v >= condition[4] and v <= condition[5]:
if x == 0 and y == 0:
labelcount += 1
label[x][y] = labelcount
elif y == 0:
if label[x-1][y] > 0:
label[x][y] = label[x-1][y]
else:
labelcount += 1
label[x][y] = labelcount
elif x == 0:
if label[x][y-1] > 0:
label[x][y] = label[x][y-1]
else:
labelcount += 1
label[x][y] = labelcount
else:
if label[x-1][y] > 0 and label[x][y-1] > 0:
if label[x-1][y] != label[x][y-1]:
label[x][y] = min(label[x-1][y],label[x][y-1])
union_label(max(label[x-1][y],label[x][y-1]),label[x][y])
else:
label[x][y] = label[x-1][y]
elif label[x-1][y] > 0:
label[x][y] = label[x-1][y]
elif label[x][y-1] > 0:
label[x][y] = label[x][y-1]
else:
labelcount += 1
label[x][y] = labelcount
else :
label[x][y] = 0
中间的labelcount初始化是0,是我们的标签,不符合我们要求的像素点都还是0,这样我们的第一步就完成了啊。
接下来就是secondpass啦,进行根节点的一个统计,把我们最多的根节点统计下来,最终得到我们最多的根节点,根据最多的根节点来进行分割:
#Second pass
for y in range(height):
for x in range(width):
label[x][y] = find_root(label[x][y])
if label[x][y] > 0:#因为我们不要的标签都定义为0,把我们不需要的都排除掉
labelsize[int(label[x][y])] += 1
#寻找最大连通区域标号
max_sum = max(labelsize)
max_label = labelsize.index(max_sum)
之后就可以根据标签来寻找分割区域的坐标啦:
#标记区域范围
xmin = 240
ymin = 320
xmax = 0
ymax = 0
for y in range(height):
for x in range(width):
if label[x][y] == max_label:
if x < xmin:
xmin = x
if y < ymin:
ymin = y
if x > xmax:
xmax = x
if y > ymax:
ymax = y
然后我画分割线的时候并没有使用什么模块,我是直接改变了像素值达到了画线的目的:
for i in range(xmin,xmax):
im.putpixel((i,ymin),(0,255,0))
for i in range(xmin,xmax):
im.putpixel((i,ymax),(0,255,0))
for i in range(ymin,ymax):
im.putpixel((xmin,i),(0,255,0))
for i in range(ymin,ymax):
im.putpixel((xmax,i),(0,255,0))
最后我们再show一下就出来啦。
附上整个过程的代码:
import numpy as np
from PIL import Image
condition = [195,220,0.2,1.0,0.5,1.0]
labelcount = 0
label = np.zeros((320,240))
Parent = [0]*1000
labelsize = [0]*1000
def rgb2hsv(r, g, b):
r, g, b = r/255.0, g/255.0, b/255.0
mx = max(r, g, b)
mn = min(r, g, b)
m = mx-mn
if mx == mn:
h = 0
elif mx == r:
if g >= b:
h = ((g-b)/m)*60
else:
h = ((g-b)/m)*60 + 360
elif mx == g:
h = ((b-r)/m)*60 + 120
elif mx == b:
h = ((r-g)/m)*60 + 240
if mx == 0:
s = 0
else:
s = m/mx
v = mx
return h, s, v
#寻找根节点
def find_root(label):
label = int(label)
while Parent[label] != 0:
label = Parent[label]
return label
#将不同label合并到一个联通域
def union_label(label1,label2):
label1 = int(label1)
label2 = int(label2)
while Parent[label1] != 0:
label1 = Parent[label1]
while Parent[label2] != 0:
label2 = Parent[label2]
if label1 != label2:
Parent[label1] = label2
#main
im = Image.open(r"C:\Users\Administrator\Desktop\JPEG\001.jpg")
pix = im.load()
width = im.size[0]
height = im.size[1]
for y in range(height):
for x in range(width):
r,g,b = pix[x, y]
h,s,v = rgb2hsv(r,g,b)
#First pass
if h >= condition[0] and h <= condition[1] and s >= condition[2] and s <= condition[3] and v >= condition[4] and v <= condition[5]:
if x == 0 and y == 0:
labelcount += 1
label[x][y] = labelcount
elif y == 0:
if label[x-1][y] > 0:
label[x][y] = label[x-1][y]
else:
labelcount += 1
label[x][y] = labelcount
elif x == 0:
if label[x][y-1] > 0:
label[x][y] = label[x][y-1]
else:
labelcount += 1
label[x][y] = labelcount
else:
if label[x-1][y] > 0 and label[x][y-1] > 0:
if label[x-1][y] != label[x][y-1]:
label[x][y] = min(label[x-1][y],label[x][y-1])
union_label(max(label[x-1][y],label[x][y-1]),label[x][y])
else:
label[x][y] = label[x-1][y]
elif label[x-1][y] > 0:
label[x][y] = label[x-1][y]
elif label[x][y-1] > 0:
label[x][y] = label[x][y-1]
else:
labelcount += 1
label[x][y] = labelcount
else :
label[x][y] = 0
#Second pass
for y in range(height):
for x in range(width):
label[x][y] = find_root(label[x][y])
if label[x][y] > 0:
labelsize[int(label[x][y])] += 1
#寻找最大连通区域标号
#max_sum = max(labelsize)#去掉最多的白色和红色
#labelsize.remove(max_sum)
max_sum = max(labelsize)#拿出次多的蓝色
max_label = labelsize.index(max_sum) #前面删除一个所以要加一
#标记区域范围
xmin = 240
ymin = 320
xmax = 0
ymax = 0
for y in range(height):
for x in range(width):
if label[x][y] == max_label:
if x < xmin:
xmin = x
if y < ymin:
ymin = y
if x > xmax:
xmax = x
if y > ymax:
ymax = y
for i in range(xmin,xmax):
im.putpixel((i,ymin),(0,255,0))
for i in range(xmin,xmax):
im.putpixel((i,ymax),(0,255,0))
for i in range(ymin,ymax):
im.putpixel((xmin,i),(0,255,0))
for i in range(ymin,ymax):
im.putpixel((xmax,i),(0,255,0))
im.show()