Python 您所在的位置:网站首页 python中递归算法 Python

Python

2023-11-28 03:35| 来源: 网络整理| 查看: 265

Python——基于局部自适应二值化(递归法)的裂缝图像分割 Python------基于局部自适应二值化(递归法)的裂缝图像分割一、局部自适应二值化二、递归法局部自适应二值化介绍三、Python实现1、将图像划分为若干个窗口2、预先确定阈值T3、确定各个窗口的最佳阈值4、利用OpenCV中的threshold函数实现二值化5、图像重构输出 四、测试五、完整代码六、不足

Python------基于局部自适应二值化(递归法)的裂缝图像分割 一、局部自适应二值化

在这里插入图片描述在这里插入图片描述

可以参考这几篇文章:

图像的自适应二值化OpenCV全局/局部阀值二值化OpenCV_基于局部自适应阈值的图像二值化 二、递归法局部自适应二值化介绍

在这里插入图片描述 在这里插入图片描述

三、Python实现 1、将图像划分为若干个窗口

Step 1:确定窗口大小

在这里插入图片描述 注:因为文章中只说了按照条件,并没有给出具体的条件,于是,我便自定义了窗口的大小,window_w和window_h,然后计算出每幅图像的窗口数量,窗口越大,窗口数量越少。

#--------划分窗口--------- #窗口大小 window_w = 11 #11是经过多次试验后,比较令人满意的经验值 window_h = 11 window_size = window_w * window_h window_w_num = math.floor(mw/window_w) #取整,图像的宽共有多少个 window_h_num = math.floor(mh/window_h) print(window_w_num,window_h_num) #窗口总数 window_num = window_w_num * window_h_num print(window_num)

Step 2:将图像中每个窗口的值单独取出,放入windows二维矩阵

注:此是输入的图像的灰度图像,每一幅图像都是由不同的灰度值像素点构成,划分窗口是概念上的理解,真正计算的还是数值。

示例图片:(宿舍采的裂缝) 在这里插入图片描述 图像大小

在做数值处理的时候,划分窗口就好比怎么把两个相同面积但长宽不同的长方体相互转换。好比: 在这里插入图片描述 我想破脑阔,就算用四个循环也没办法实现。后来我舍友一句话点醒了我,她说转换不了就打破呗。哦!我又悟了! 于是。。。 在这里插入图片描述 那我就先把原来的图像转化为一维数组(蓝色),再把它调整为我想要的窗口大小,这样就避免了直接转换的困难。完美!

windows = [] #二维数组,存放窗口值(对应红色矩形框)windows.shape = (window_num, window_size) for m in range(window_h_num): #四个循环,完成转换 for k in range(window_w_num): for i in range(window_h): for j in range(window_w): windows.append(median[i+window_h*m][j+window_w*k]) arr_windows = np.array(windows) #列表转数组 print(arr_windows.shape) reshape_arr = arr_windows.reshape(window_num,window_size) print(reshape_arr.shape) 2、预先确定阈值T

在这里插入图片描述

F_max = np.amax(reshape_arr, axis=1) #按行找出最大值 print(reshape_arr[0,:]) #print(F_max[0],F_max.shape) #713 F_min = np.min(reshape_arr, axis=1) print(F_min[0]) 3、确定各个窗口的最佳阈值

在这里插入图片描述

#-----------确定各个窗口的最佳阈值----------- Ts = np.zeros(window_num) for i in range(window_num): Ts[i] = round((int(F_max[i]) + int(F_min[i])) / 2) T_uint = np.array(Ts,dtype='uint8') print(T_uint.shape,T_uint.dtype,F_max.dtype) # temp = np.zeros(window_size,dtype='uint8') #print(reshape_arr.shape,temp.shape) # ground = np.empty(window_size,dtype='uint8') # crack = np.empty(window_size,dtype='uint8') ground = [] crack = [] for i in range(window_num): T = 0 temp = reshape_arr[i,:] temp = np.array(temp,dtype='uint8') T1 = T_uint[i] #一般T都不会是零 #print(T1) while T1 != T : #循环实现阈值更新 T = T1 for j in range(window_size): if temp[j]>= T1: ground.append(temp[j]) else: crack.append(temp[j]) R1 = int(np.mean(crack)) R2 = int(np.mean(ground)) T1 = int((R1 + R2) / 2) #print(T,T1) T_uint[i] = T1 print(T_uint.shape,T_uint.dtype) #713个窗口 4、利用OpenCV中的threshold函数实现二值化 #---------局部自适应二值化----------- binary_gray = np.zeros((window_num,window_size),dtype='uint8') for i in range(window_num): temp = reshape_arr[i, :] temp = np.array(temp, dtype='uint8') #temp_reshape = np.reshape(temp,(window_h,window_w)) ret, th = cv.threshold(temp, T_uint[i], 255, cv.THRESH_BINARY) thresh = np.array(th, dtype='uint8') thresh = np.squeeze(thresh) binary_gray[i, :] = thresh print(binary_gray.shape,thresh.shape) 5、图像重构输出

在这里插入图片描述

#---------图像重构输出显示------------- binary_gray = np.reshape(binary_gray,window_num*window_size) print(binary_gray.shape) c = 0 #测试用的,可以去掉 gray_binary = np.zeros((window_h_num*window_h,window_w_num*window_w),dtype='uint8') for m in range(window_h_num): for k in range(window_w_num): for i in range(window_h): for j in range(window_w): gray_binary[i+window_h*m][j+window_w*k] = binary_gray[c] c = c + 1 print(c) cv.imshow('binary_gray',gray_binary)

到此,递归法局部自适应二值化就完成啦!看一下效果。

四、测试

我们用上述裂缝图像,先用OpenCV自带的函数看一下效果。

代码:

#coding = utf-8 import cv2 as cv import numpy as np import math from skimage import morphology from skimage import img_as_float from skimage import img_as_ubyte import matplotlib.pyplot as plt image = cv.imread("C:\\Users\\LENOVO\\Desktop\\004.png") #你的图片路径 # 图像灰度化 gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY) #加权平均法 Gray(i,j) = 0.299R(i,j) + 0.578G(i,j) + 0.114B(i,j) 可尝试其他方法,但目前此方法最优 cv.imshow('show', gray) ret,th1 = cv.threshold(gray,70,255,cv.THRESH_BINARY) #全局二值化 # 3为Block size, 5为param1值 th2 = cv.adaptiveThreshold(gray,255,cv.ADAPTIVE_THRESH_MEAN_C,cv.THRESH_BINARY,11,5) #adaptive_thresh_mean局部二值化 th3 = cv.adaptiveThreshold(gray,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,cv.THRESH_BINARY,11,5) #adaptive_thresh_gaussian局部二值化 titles = ['Gray Image', 'Global Thresholding (v = 70)', 'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding'] images = [gray, th1, th2, th3] print(ret) for i in range(4): plt.subplot(2,2,i+1),plt.imshow(images[i],'gray') plt.title(titles[i]) plt.xticks([]),plt.yticks([]) plt.show() while True: key = cv.waitKey(10) if key == 27: cv.destroyAllWindows() #按Esc键退出

效果: 在这里插入图片描述 在这里插入图片描述 emmmm,全局的裂缝几乎快没了,局部的一片混乱55555

看一下本文中的方法的结果: 在这里插入图片描述 貌似还行,,,但这背景也是太杂了。。。 于是,看着OpenCV自带的函数,我又悟了!-v-

在阈值那里,把最终得到的最佳阈值都减去5(5应该是经验值),效果8错。 在这里插入图片描述

五、完整代码

代码的前面部分是图像预处理。

#coding=utf-8 import cv2 as cv import numpy as np import math from skimage import morphology from skimage import img_as_float from skimage import img_as_ubyte import matplotlib.pyplot as plt #1、加载图片 image = cv.imread("C:\\Users\\LENOVO\\Desktop\\004.png") #你的图片路径 (h, w, d) = image.shape print("width={}, height={}, depth={}".format(w, h, d)) # 2、图像灰度化 gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY) #加权平均法 Gray(i,j) = 0.299R(i,j) + 0.578G(i,j) + 0.114B(i,j) 可尝试其他方法,但目前此方法最优 cv.imshow('show', gray) #3、中值滤波 (论文中用的是中值滤波,但我采的图片没有很多椒盐噪声,所以换为高斯滤波器,名字懒得改了-v-) median = cv.GaussianBlur(gray, (3, 3), 0) #sigmaX = 0时,标准差大小由高斯核大小自动确定 cv.imshow('Gaus', median) (mh, mw) = median.shape # median = cv.medianBlur(gray,5) #sigmaX = 0时,标准差大小由高斯核大小自动确定 # cv.imshow('Median', median) # (mh, mw) = median.shape print("medianwidth={}, medianheight={}".format(mw, mh)) #4、局部自适应二值化(递归法) (gh, gw) = gray.shape print("graywidth={}, grayheight={}".format(gw, gh)) # for i in range(gh): # for j in range(gw): # print(gray[i][j]) #--------划分窗口--------- #窗口大小 window_w = 11 window_h = 11 window_size = window_w * window_h window_w_num = math.floor(mw/window_w) window_h_num = math.floor(mh/window_h) print(window_w_num,window_h_num) #窗口总数 window_num = window_w_num * window_h_num print(window_num) windows = [] #print(windows,windows.shape) for m in range(window_h_num): for k in range(window_w_num): for i in range(window_h): for j in range(window_w): windows.append(median[i+window_h*m][j+window_w*k]) arr_windows = np.array(windows) print(arr_windows.shape) reshape_arr = arr_windows.reshape(window_num,window_size) print(reshape_arr.shape) F_max = np.amax(reshape_arr, axis=1) print(reshape_arr[0,:]) #print(F_max[0],F_max.shape) #713 F_min = np.min(reshape_arr, axis=1) print(F_min[0]) #-----------确定各个窗口的最佳阈值----------- Ts = np.zeros(window_num) for i in range(window_num): Ts[i] = round((int(F_max[i]) + int(F_min[i])) / 2) T_uint = np.array(Ts,dtype='uint8') print(T_uint.shape,T_uint.dtype,F_max.dtype) # temp = np.zeros(window_size,dtype='uint8') #print(reshape_arr.shape,temp.shape) # ground = np.empty(window_size,dtype='uint8') # crack = np.empty(window_size,dtype='uint8') ground = [] crack = [] for i in range(window_num): T = 0 temp = reshape_arr[i,:] temp = np.array(temp,dtype='uint8') T1 = T_uint[i] #一般T都不会是零 #print(T1) while T1 != T : T = T1 for j in range(window_size): if temp[j]>= T1: ground.append(temp[j]) else: crack.append(temp[j]) R1 = int(np.mean(crack)) R2 = int(np.mean(ground)) T1 = int((R1 + R2) / 2) #print(T,T1) T_uint[i] = T1 - 5 print(T_uint.shape,T_uint.dtype) #713个窗口 #---------局部自适应二值化----------- binary_gray = np.zeros((window_num,window_size),dtype='uint8') for i in range(window_num): temp = reshape_arr[i, :] temp = np.array(temp, dtype='uint8') #temp_reshape = np.reshape(temp,(window_h,window_w)) ret, th = cv.threshold(temp, T_uint[i], 255, cv.THRESH_BINARY) thresh = np.array(th, dtype='uint8') thresh = np.squeeze(thresh) binary_gray[i, :] = thresh print(binary_gray.shape,thresh.shape) #---------图像重构输出显示------------- binary_gray = np.reshape(binary_gray,window_num*window_size) print(binary_gray.shape) c = 0 gray_binary = np.zeros((window_h_num*window_h,window_w_num*window_w),dtype='uint8') for m in range(window_h_num): for k in range(window_w_num): for i in range(window_h): for j in range(window_w): gray_binary[i+window_h*m][j+window_w*k] = binary_gray[c] c = c + 1 print(c) cv.imshow('binary_gray',gray_binary) plt.imsave('C:\\Users\\LENOVO\\Desktop\\binary_gray.png',gray_binary) while True: key = cv.waitKey(10) if key == 27: cv.destroyAllWindows() #按Esc键退出 六、不足

1、算法时间较长,比如上面那张图987x742,需要跑大概十几分钟,OpenCV自带的函数就几秒钟 2、特定场景表现得较好,有些场景表现不好

例如下面这张图: 在这里插入图片描述 OpenCV自带函数的二值化效果: 在这里插入图片描述 在这里插入图片描述 本文中的递归法(不减去5): 在这里插入图片描述 本文中的递归法(减去5): 在这里插入图片描述 结论:减去5应用比较广,且细节清楚,但整体效果还是不如OpenCV自带的。

*** 第一次写博客,记录更容易成长。知道自己很菜,但慢慢来。若有错误之处,欢迎指正交流。***



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有