700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 【Python CUDA版】河北工业大学计算机图像处理实验五:图像分割

【Python CUDA版】河北工业大学计算机图像处理实验五:图像分割

时间:2022-10-24 00:04:24

相关推荐

【Python CUDA版】河北工业大学计算机图像处理实验五:图像分割

一、实验目的与要求

1.了解图像分割的意义和常用方法

2.掌握常用的图像分割方法

二、实验相关知识

图像分割就是把图像分成互不重叠的区域并提取出感兴趣目标的技术,是由图像处理到图像分析的关键步骤。

和本实验有关的常用Matlab函数:

edge:检测灰度或二值图像的边缘,返回一个二值图像,1像素是检测到的边缘,0像素是非边缘

用法:BW=edge(I,'sobel',thresh,direction); %I为检测对象;

边缘检测算子可用sobel、roberts、prewitt、zerocross、log、canny;

thresh指定阈值,检测时忽略所有小于阈值的边缘,默认自动选择阈值;

direction指定方向,可选项有horizontal、vertical或both,在指定的方向上用算子进行边缘检测

三、实验内容

1、分别用Roberts、Prewitt、Sobel三种边缘检测算子,对图像wire.bmp进行水平、垂直及各个方向的边界检测,并将检测结果转化为白底黑线条的方式显示出来;

2、使用手动阈值分割法对bottle图像进行分割,显示分割结果,并分析其优缺点。

3、对下图A进行处理,得到类似图B的样子;

图A

图B

四、实验代码及结果

1、边界检测

import cv2 as cvimport matplotlib.pyplot as pltimport numpy as npimport argparseparser = argparse.ArgumentParser("")parser.add_argument("--method", type=int, default=1, choices=[1, 2, 3], help="1:Sobel\t2:Prewitt\t3:Roberts")parser.add_argument("--file", type=str, default="img.png")args = parser.parse_args()if __name__ == "__main__":plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']plt.subplot(221)origin = cv.imread(args.file, 0)plt.imshow(origin, cmap="gray")plt.title("原图像")plt.axis(False)if args.method == 1:# OpenCV文档中对Sobel算子的介绍:“in the case of 8-bit input images it will result in truncated derivatives”。# 即Sobel函数求完导数后会有负值,还有会大于255的值,所以使用16位有符号数表示梯度# 然后用 cv.convertScaleAbs转回uint8(8位无符号数)形式# 索贝尔算子# 边界类型选择REPLICATE,与MATLAB edge函数文档中默认方式一致x = cv.Sobel(origin, cv.CV_16S, 1, 0, borderType=cv.BORDER_REPLICATE)y = cv.Sobel(origin, cv.CV_16S, 0, 1, borderType=cv.BORDER_REPLICATE)absX = cv.convertScaleAbs(x)ret, Sobel_X = cv.threshold(absX, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)plt.subplot(222)plt.imshow(255 - Sobel_X, cmap="gray")plt.title("垂直方向检测边缘")plt.axis(False)absY = cv.convertScaleAbs(y)ret, Sobel_Y = cv.threshold(absY, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)plt.subplot(223)plt.imshow(255 - Sobel_Y, cmap="gray")plt.title("水平方向检测边缘")plt.axis(False)Sobel = cv.addWeighted(Sobel_X, 0.5, Sobel_Y, 0.5, 0)plt.subplot(224)plt.imshow(255 - Sobel, cmap="gray")plt.axis(False)plt.suptitle("Sobel算子", fontsize=20)plt.show()if args.method == 2:# prewitt算子# 自定义x, y方向卷积核,然后通过卷积实现prewitt_kernel_x = np.array([[-1, 0, 1], [-1, 0, 1], [-1, 0, 1]], dtype=int)prewitt_kernel_y = np.array([[-1, -1, -1], [0, 0, 0], [1, 1, 1]], dtype=int)x = cv.filter2D(origin, cv.CV_16S, prewitt_kernel_x, borderType=cv.BORDER_REPLICATE)y = cv.filter2D(origin, cv.CV_16S, prewitt_kernel_y, borderType=cv.BORDER_REPLICATE)absX = cv.convertScaleAbs(x)ret, Prewitt_X = cv.threshold(absX, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)plt.subplot(222)plt.imshow(255 - Prewitt_X, cmap="gray")plt.title("垂直方向检测边缘")plt.axis(False)absY = cv.convertScaleAbs(y)ret, Prewitt_Y = cv.threshold(absY, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)plt.subplot(223)plt.imshow(255 - Prewitt_Y, cmap="gray")plt.title("水平方向检测边缘")plt.axis(False)Prewitt = cv.addWeighted(absX, 0.5, absY, 0.5, 0)plt.subplot(224)plt.imshow(255 - Prewitt, cmap="gray")plt.axis(False)plt.suptitle("Prewitt算子", fontsize=20)plt.show()if args.method == 3:# matlab edge方法中的Roberts算子实际上有除以2,[[-1, 0], [0, 1]]/2,[[0, -1], [1, 0]]/2# 但是在这里加上/2效果依然比MATLAB函数要好roberts_kernel_x = np.array([[-1, 0], [0, 1]], dtype=int)roberts_kernel_y = np.array([[0, -1], [1, 0]], dtype=int)x = cv.filter2D(origin, cv.CV_16S, roberts_kernel_x)y = cv.filter2D(origin, cv.CV_16S, roberts_kernel_y)absX = cv.convertScaleAbs(x)ret, Roberts_X = cv.threshold(absX, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)plt.subplot(222)plt.imshow(255 - Roberts_X, cmap="gray")plt.title("垂直方向检测边缘")plt.axis(False)absY = cv.convertScaleAbs(y)ret, Roberts_Y = cv.threshold(absY, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)plt.subplot(223)plt.imshow(255 - Roberts_Y, cmap="gray")plt.title("水平方向检测边缘")plt.axis(False)Roberts = cv.addWeighted(absX, 0.5, absY, 0.5, 0)plt.subplot(224)plt.imshow(255 - Roberts, "gray")plt.title("Roberts算子")plt.axis(False)plt.show()

实验结果:

2、阈值分割

import mathimport cv2 as cvimport matplotlib.pyplot as pltimport numpy as npfrom scipy import signalfrom numba import cuda@cuda.jit()def segment(img, height, width, low_ind):i = cuda.blockIdx.x * cuda.blockDim.x + cuda.threadIdx.xj = cuda.blockIdx.y * cuda.blockDim.y + cuda.threadIdx.yif i < height and j < width:if img[i, j] > low_ind:img[i, j] = 255else:img[i, j] = 0if __name__ == "__main__":plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']img = cv.imread("bottle.png", 0)plt.subplot(131)plt.imshow(img, cmap="gray")plt.title("原图像")plt.axis(False)# 使用cv库函数统计灰度直方图greyScale_map = cv.calcHist([img], [0], None, [256], [0, 256])greyScale_map = np.array(greyScale_map).reshape(256)plt.subplot(132)plt.bar(range(256), greyScale_map, width=1)plt.title("直方图")# 将灰度直方图拟合为3次曲线z = np.polyfit(range(256), greyScale_map, 5)y = np.poly1d(z)(range(256))# print(y)plt.plot(range(256), y, color="red")# 找到极小值点,即波谷low_ind = signal.argrelextrema(y, np.less)[0]print(low_ind)# 进行阈值分割threadsperblock = (32, 32)blockspergrid_x = int(math.ceil(img.shape[0] / threadsperblock[0]))blockspergrid_y = int(math.ceil(img.shape[1] / threadsperblock[1]))blockspergrid = (blockspergrid_x, blockspergrid_y)cuda.synchronize()cuda_img = cuda.to_device(img)segment[blockspergrid, threadsperblock](cuda_img, img.shape[0], img.shape[1], low_ind[0])plt.subplot(133)plt.imshow(cuda_img.copy_to_host(), cmap="gray")plt.axis(False)plt.title("阈值分割后")plt.show()

灰度图像中画面比较简单且对象物的灰度分布比较有规律,背景和对象物 在图像的灰度直方图上各形成一个波峰,由于每两个波峰间形成一个低谷,因而选择双峰间低谷处所对应的灰度值为阈值,可将两个区域分离。 因为图像较为简单,这里选择用三次曲线拟合直方图,极小值点为阈值。 【优缺点分析】 优点: (1)操作简单方便。 (2)在物体与背景有较强的对比度的图像中,此种方法应用特别有效。比如说物体内部灰度分布均匀一致,背景在另一个灰度级上也分布均匀,这时利用阈值可以将目标与背景分割得很好。如果目标和背景的差别是某些其他特征而不是灰 度特征时,那么先将这些特征差别转化为灰度差别,然后再应用阈值分割方法进行处理,这样使用阈值分割技术也可能是有效的 。 缺点: (1)不适合处理峰值较多,灰度级分布较密的图像。 (2)无法获取最优阈值,因此无法获得最佳结果。

3、

import mathimport cv2 as cvimport matplotlib.pyplot as pltimport numpy as npfrom numba import cudafrom scipy import signal@cuda.jit()def segment(img, height, width, low_ind):i = cuda.blockIdx.x * cuda.blockDim.x + cuda.threadIdx.xj = cuda.blockIdx.y * cuda.blockDim.y + cuda.threadIdx.yif i < height and j < width:if img[i, j] > low_ind:img[i, j] = 255else:img[i, j] = 0if __name__ == "__main__":plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']img = cv.imread("particle.png", 0)plt.subplot(221)plt.imshow(img, cmap="gray")plt.axis(False)plt.title("原图像")greyScale_map = cv.calcHist([img], [0], None, [256], [0, 256])greyScale_map = np.array(greyScale_map).reshape(256)plt.subplot(222)plt.bar(range(256), greyScale_map, width=1)plt.title("直方图")# 阈值分割threadsperblock = (32, 32)blockspergrid_x = int(math.ceil(img.shape[0] / threadsperblock[0]))blockspergrid_y = int(math.ceil(img.shape[1] / threadsperblock[1]))blockspergrid = (blockspergrid_x, blockspergrid_y)cuda.synchronize()cuda_img = cuda.to_device(img)segment[blockspergrid, threadsperblock](cuda_img, img.shape[0], img.shape[1], 110)new_image = cuda_img.copy_to_host()del cuda_imgplt.subplot(223)plt.imshow(new_image, cmap="gray")plt.axis(False)plt.title("阈值分割后")# Sobel算子进行边缘检测x = cv.Sobel(new_image, cv.CV_16S, 1, 0, borderType=cv.BORDER_REPLICATE)y = cv.Sobel(new_image, cv.CV_16S, 0, 1, borderType=cv.BORDER_REPLICATE)absX = cv.convertScaleAbs(x)absY = cv.convertScaleAbs(y)# 二值化ret, Sobel_X = cv.threshold(absX, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)ret, Sobel_Y = cv.threshold(absY, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)Sobel = cv.addWeighted(Sobel_X, 0.5, Sobel_Y, 0.5, 0)plt.subplot(224)plt.imshow(255 - Sobel, cmap="gray")plt.axis(False)plt.title("Sobel算子边缘检测")plt.show()

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。