Radon变换就是将数字图像矩阵在某一角度射线方向上做投影变换,按照投影方向累加像素。
根据同一物体区域内像素相似性质来聚集像素点。选定图像中的一个点(或一组点),从初始起点开始,将相邻的具有同样性质的像素或归并到目前的区域中从而逐步增长区域,直到没有可以归并的点为止。
将图像看作拓扑地貌,图像中的每一点像素的灰度值表示该点的海拔高度,每一局部极小值及其影响区域就是集水盆地,集水盆地的边界则形成分水岭。在每一个局部最小值表面刺穿一个孔,然后向模型里注水,随着水量增多,局部最小值的影响逐渐向外扩展,而集水盆间交界处筑成大坝即形成分水岭。
方法一:Sobel算子利用像素邻近区域的梯度值来计算一个像素的梯度,再根据一定的绝对值来判断其是不是噪声点。
方法二:计算图像一块区域的像素平均值,再算出该区域内每个点像素值与均值的差绝对值,设定阈值,大于某个阈值则该点算为噪声点。
方法一:Kolmogorov-Smirnov检验:统计两个区域0-255每个像素值出现的次数,比较像数值的频率分布,两个区域间每个元素对应一个频率差值,如果最大的频率差值小于规定的值,则两区域相似,反之不相似。
方法二:通过直方图余弦值计算相似性。将两区域像素点的灰度值统计成直方图,压缩灰度级别,每间隔四个数合为一个分向量,共分为64个分向量,记作一个向量;计算2个区域向量夹角的余弦值,作为相似度。
def create_hist(a,b,n):
"""
:param a: 形状为H*W的预测值(H为高,W为宽)
:param b: 形状为H*W的真实值(H为高,W为宽)
:param n: 类别数
:return: 混淆矩阵
"""
#确保a和b在0~n-1的范围内
k = (a>=0)&(a
#生成初始种子
def originaSeed(gray):
"""
:param gray: 传入灰度图
:return: 连通域中心
"""
ret,img1 = cv2.threshold(gray,245,255,cv2.THRESH_BINARY)#二值化
num_labels,labels,stats,centroids = cv2.connectedComponentsWithStats(img1)#进行连通域连通
centroids = centroids.astype(int)
return centroids
#求两个点像素值差值
def Graydiff(gray,currentpoint,tmppoint):
return abs(int(gray[currentpoint[0],currentpoint[1]])-int(gray[tmppoint[0],tmppoint[1]]))
#区域生长
def regional_growth(gray,seeds):
"""
:param gray:灰度图片
:param seeds:初始种子,连通域中心
:return:图片矩阵
"""
#像素种子的8个邻接点
approximal_point = [(-1,-1),(0, -1), (1, -1), (1, 0),
(1, 1), (0, 1), (-1, 1), (-1, 0)]
threshold = 5 #生长相似性的阈值,Graydiff不超过5就符合
height,weight = gray.shape
img = np.zeros(gray.shape)#创建等灰度图尺寸的矩阵,满足生长规则的点改为1
seedlist = []
for seed in seeds:
#种子位置大于0且不超过图片尺寸
if (seed[0] < gray.shape[0] and seed[1] < gray.shape[1] and seed[0] > 0 and seed[1] > 0):
seedlist.append(seed)
while len(seedlist)>0:#循环到列表中没有种子点
currentPoint = seedlist.pop(0)#最新的种子点等于列表里的第一个种子点,同时取出第一个点后删除该点做到列表更新
img[currentPoint[0],currentPoint[1]] = 1#找到对应位置把0改为1
#对该位置8领域进行象素差判断
for i in range(8):
tmpX = currentPoint[0] + approximal_point[i][0]
tmpY = currentPoint[1] + approximal_point[i][1]
if tmpX < 0 or tmpY <0 or tmpX >= height or tmpY >= weight:#如果位置值超过图片大小或者非正数
continue#跳过并继续
grayDiff = Graydiff(gray,currentPoint,(tmpX,tmpY))#计算像素差
if grayDiff < threshold and img[tmpX,tmpY]==0:#如果小于阈值并且矩阵该点为0
img[tmpX,tmpY] = 1
seedlist.append((tmpX,tmpY))
return img
def original_growth():
img = cv2.imread('E:\\Machine vision\\images\\images\\shapes.png')
img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
o_img = copy.deepcopy(img)
seed = originaSeed(img)
img = regional_growth(img,seed)
#显示区域生长效果
plt.rcParams['font.sans-serif'] = ['SimHei']#正常显示中文标签
plt.figure(figsize=(10, 5))
plt.subplot(121), plt.imshow(o_img, cmap='gray'), plt.title('区域生长前'),plt.axis("off")
plt.subplot(122),plt.imshow(img,cmap='gray'),plt.title('区域生长以后'),plt.axis("off")
plt.show()
test_original_growth()
def kmeans_segmentation():
image = cv2.imread('E:\\Machine vision\\images\\images\\shapes.png')
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
#展成一维
img1 = image.reshape((image.shape[0] * image.shape[1], 1))
img1 = np.float32(img1)
#迭代终止条件:精度满足0.2/迭代次数超过阈值100
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.2)
k = 3
# cv2.kmeans返回紧密度、标签、聚类中心
compactness, labels, (centers) = cv2.kmeans(img1, k, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)#每次随机选择中心
# 标签尺寸改变为原图尺寸
img2 = labels.reshape((image.shape[0], image.shape[1]))
plt.figure()
plt.imshow(img2),plt.title('segmented image'),plt.axis('off')
plt.show()
return img2
def iou_test():
true_img = np.int64(original_growth())
predict_img = np.int64(kmeans_segmentation())
hist = create_hist(predict_img,true_img,3)#获取混淆矩阵
iou = per_iou(hist)#获取每一类的iou
m_iou = np.sum(iou)
result = m_iou/3#求预测的平均值
return result
print("准确率为{}".format(iou_test()))
#判断区域是否需要再拆分为四个
def judge(img,x0,y0,w,h):
arr = img[y0:y0+h,x0:x0+w]
ave = np.mean(arr)#求平均
std = np.std(arr)#计算标准差
count = len(np.where(img - ave < std)[1])#判断区域相似度
acc = w * h
if count/acc<0.95:#判断该区域是否还需要再分
return False
else:
return True
def recursion(img,x0,y0,w,h):#递归
if judge(img,x0,y0,w,h) and (min(w,h)>5):#不用细分到每个像素点为一个区域
recursion(img,x0,y0,int(w/2),int(h/2))
recursion(img,x0+int(w/2),y0,int(w/2),int(h/2))
recursion(img,x0,y0+int(h/2),int(w/2),int(h/2))
recursion(img,x0+int(w/2),y0+int(h/2),int(w/2),int(h/2))
else:
ret,img = cv2.threshold(img,125,255,cv2.THRESH_BINARY)
return img
def rec_test():
img = cv2.imread('E:\\Machine vision\\images\\images\\shapes.png')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#灰度转换
cv2.imshow('input',gray)
cv2.waitKey(0)
height, width = gray.shape
out_img = recursion(gray,0,0,width,height)
cv2.imshow('output',out_img)
cv2.waitKey(0)
def oranges():
img = cv2.imread('E:\\Machine vision\\images\\images\\oranges.png') # 读取图片
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 灰度图转化
ret, thresh = cv2.threshold(gray, 0, 255,
cv2.THRESH_BINARY + cv2.THRESH_OTSU) # 图像二值化,cv2.THRESH_BINARY+cv2.THRESH_OTSU作用是自适应阈值
kernel = np.ones((5, 5), np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2) # 开操作:去除噪声
sure_bg = cv2.dilate(opening, kernel, iterations=3) # 腐蚀操作,减小前景物体
dist_transform = cv2.distanceTransform(sure_bg, cv2.DIST_L2, 5) # 距离变换:得到每个非零像素点与其最近的零像素点之间的距离,输出为距离
ret, sure_fg = cv2.threshold(dist_transform, 0.53 * dist_transform.max(), 255,0) # 二值化操作,阈值为距离变换得到的距离,分离前景中的粘连物体
sure_fg = np.uint8(sure_fg) # 转化数据类型,连通域函数接收8位单通道二值图像
# 连通域函数:label与原图大小一致,对应为当前像素为第几个轮廓;stats对应轮廓信息,每行有五个值,分别为x,y,width,height,area;centroids对应每个连通区域的质心点
retval, labels, stats, centroids = cv2.connectedComponentsWithStats(sure_fg)
for i in range(1, len(centroids)):
cv2.circle(img, (int(centroids[i, 0]), int(centroids[i, 1])), 6, [255, 0, 0], -1) # 勾画质心点,实心圆
cv2.putText(img, str(i), (int(centroids[i, 0]), int(centroids[i, 1])), cv2.FONT_HERSHEY_SIMPLEX, 0.5,(0, 255, 0)) # 标记对应质心点的编号,最大值为个数-1
print('计数个数:', len(centroids) - 1)
cv2.imshow('img',img)
cv2.waitKey(0)
oranges()