利用opencv以及easygui实现简易视觉系统(二)包含图像去噪、阈值分割、分段线性拉伸、直方图拉伸、区域生长分割

it2025-04-03  9

import numpy as np from PIL import Image import matplotlib.pyplot as plt import matplotlib.cm as cm import scipy.signal as signal import cv2 as cv import random import easygui as g import imutils import time class Point(object): def __init__(self,x,y): self.x = x self.y = y def getX(self): return self.x def getY(self): return self.y def criterion(p): #定义我们自己种子生长的准则,p=1为一种规则,p=0为一种生长规则 if p == 1: connect = [Point(-1,-1),Point(-1,0),Point(0,-1),Point(0,1),Point(1,1),Point(1,0),Point(-1,1),Point(1,-1)] else: connect = [Point(-1,0),Point(0,-1),Point(0,1),Point(1,0)] return connect def gray_distance(image,point1,point2): #返回灰度值之间的差异,太大的我们舍弃 return abs(int(image[point1.x,point1.y])-int(image[point2.x,point2.y])) def seed_growing(image): thresh = 3 #我们自己设置的门限 label1 = 1 #label = 1这样的话图像中为黑色,容易发现 seed = [Point(250,100),Point(82,75),Point(20,300)] #定义初始种子点 image = image[:, :, 0] * 0.11 + image[:, :, 1] * 0.59 + image[:, :, 2] * 0.3 image = image.astype(np.uint8) rows = image.shape[0] cols = image.shape[1] image_mark = np.full((rows,cols),255) seedlist = [] p=1 #定义我们自己的准则 connects = criterion(p) for i in seed: seedlist.append(i) while ( len(seedlist) > 0): seed_testing = seedlist.pop(0) image_mark[seed_testing.x,seed_testing.y] = label1 for i in range(8): #因为我定义的P为1 所以是8个点,p=0则有四个点 tempX = seed_testing.x + connects[i].x tempY = seed_testing.y + connects[i].y if tempX < 0 or tempY < 0 or tempX >=rows or tempY >= cols: continue gray_dis = gray_distance(image,seed_testing,Point(tempX,tempY)) if gray_dis < thresh and image_mark[tempX,tempY] == 255: seedlist.append(Point(tempX,tempY)) image_mark[tempX,tempY] = label1 cv.imshow('seed grow',image_mark.astype(np.uint8)) cv.waitKey(0) def nothing(x): pass def change_number(image): image = image[:, :, 0] * 0.11 + image[:, :, 1] * 0.59 + image[:, :, 2] * 0.3 image = image.astype(np.uint8) # GRAY=0.3*R+0.59*G+0.11*B: rows = image.shape[0] cols = image.shape[1] min_area = 0 max_area = 0 area = rows * cols cv.namedWindow('could change threshhold') cv.createTrackbar('intensity', 'could change threshhold', 0, 255, nothing) count = 0 # chance =0 data1 = 699 data = 0 while (1): cv.imshow('could change threshhold', image) # 返回滑块所在位置对应的值 medium_number = cv.getTrackbarPos('intensity', 'could change threshhold') # if chance == 0: image2 =image.copy() for i in range(rows): for j in range(cols): if int(image2[i, j]) < medium_number: image2[i, j] = 0 min_area += 1 else: image2[i, j] = 255 max_area += 1 image2 = image2.astype(np.uint8) # GRAY=0.3*R+0.59*G+0.11*B: cv.imshow('image2',image2) data +=1 if data ==8: #设置我们自己的时钟,按Q退出 string = 'gray area is {},white area is {}'.format(min_area * area / (min_area + max_area),max_area * area / (min_area + max_area)) print(string) data = 0 # data +=1 # if data == 2: # if data1 != medium_number: # data1 = medium_number # count = 0 # else: # count +=1 # if count == 2: # image3 = image.copy() # for i in range(rows): # for j in range(cols): # if int(image3[i, j]) < medium_number: # image3[i, j] = 0 # min_area += 1 # else: # image3[i, j] = 255 # max_area += 1 # image3 = image3.astype(np.uint8) # GRAY=0.3*R+0.59*G+0.11*B: # string = 'gray area is {},white area is {}'.format(min_area * area / (min_area + max_area),max_area * area / (min_area + max_area)) # print(string) # count =0 # data = 0 # chance +=1 if cv.waitKey(1) == ord('q'): break cv.destroyAllWindows() def static_number(image): #也进行灰度化 image = image[:, :, 0] * 0.11 + image[:, :, 1] * 0.59 + image[:, :, 2] * 0.3 image = image.astype(np.uint8) # GRAY=0.3*R+0.59*G+0.11*B: rows = image.shape[0] cols = image.shape[1] sum2 = [] for i in range(rows): for j in range(cols): sum2.append(int(image[i, j])) sum2.sort() medium_number = sum2[len(sum2)//2] #去中位数的灰度值 min_area = 0 max_area = 0 area = rows * cols for i in range(rows): for j in range(cols): if int(image[i,j]) < medium_number: image[i,j] = 0 min_area +=1 else: image[i,j] = 255 max_area +=1 image = image.astype(np.uint8) # GRAY=0.3*R+0.59*G+0.11*B: g.msgbox('灰色区域面积为{0},白色面积为{1}'.format(min_area * area /(min_area+max_area),max_area * area/(min_area+max_area) )) cv.imshow('static number image',image) cv.waitKey(0) def myvar(image): #将输入图片转换为灰度图 image = image[:, :, 0] * 0.11 + image[:, :, 1] * 0.59 + image[:, :, 2] * 0.3 image = image.astype(np.uint8) # GRAY=0.3*R+0.59*G+0.11*B: rows = image.shape[0] cols = image.shape[1] sum1=[] for i in range(rows): for j in range(cols): sum1.append(int(image[i,j])) sum_average = sum(sum1)/len(sum1) var_sum=[] for i in range(rows): for j in range(cols): var_sum.append(image[i,j]**2/len(sum1)) var = sum(var_sum) - sum_average**2 return var def hist_stretch(image): #没做灰度变换 r_min, r_max = 255, 0 a=[] for i in range(image.shape[0]): for j in range(image.shape[1]): for k in range(image.shape[2]): a.append(image[i,j,k]) if image[i, j, k] > r_max: r_max = image[i, j, k] if image[i, j, k] < r_min: r_min = image[i, j, k] a=np.array(a).reshape(-1) a_var=np.var(a) r1, s1 = r_min, 0 r2, s2 = r_max, 255 # 这四个值决定了分段函数的走向 # k1 = s1 / r1 # k3 = (255 - s2) / (255 - r2) k2 = (s2 - s1) / (r2 - r1) #255 * (最大灰度值-最小灰度值) b=[] precewise_img = np.zeros((image.shape[0], image.shape[1], 3), dtype=np.float32) for i in range(image.shape[0]): for j in range(image.shape[1]): for k in range(image.shape[2]): precewise_img[i, j, k] = k2 * (image[i, j, k] - r1) b.append(precewise_img[i,j,k]) b = np.array(b).reshape(-1,1) b_var = np.var(b) # g.msgbox('变换前的方差为{},变换后的方差为{}'.format(int(a),int(b))) print(a) print(b) # 原图中做分段线性变化后需要对图像进行归一化操作,并将数据类型转换到np.uint8 cv.normalize(precewise_img, precewise_img, 0, 255, cv.NORM_MINMAX) precewise_img = cv.convertScaleAbs(precewise_img) g.msgbox('处理前的图片方差为{one},处理后的方差为{two}'.format(one=myvar(image), two=myvar(precewise_img))) cv.imshow('origin image', imutils.resize(image, 480)) cv.imshow('hist_stretch image', imutils.resize(precewise_img, 480)) if cv.waitKey(0) == 27: cv.destroyAllWindows() def muti_liner_stretch(image): #s1,s2分别为灰度级上的两个边界,#该分段线性拉伸法,将灰度级分成三分,一份小于最小灰度级,一份大于最大灰度级,这两部分无定义,直接映射中间部分 # r_min, r_max = 255, 0 # for i in range(image.shape[0]): #没做灰度变换 # for j in range(image.shape[1]): # for k in range(image.shape[2]): # if image[i, j, k] > r_max: # r_max = image[i, j, k] # if image[i, j, k] < r_min: # r_min = image[i, j, k] r1, s1 = 50,100 r2, s2 = 170,200 #这四个值决定了分段函数的走向 k1 = s1 / r1 k3 = (255 - s2) / (255 - r2) k2 = (s2 - s1) / (r2 - r1) precewise_img = np.zeros((image.shape[0], image.shape[1], 3), dtype=np.float32) for i in range(image.shape[0]): for j in range(image.shape[1]): for k in range(image.shape[2]): if r1 <= image[i, j, k] <= r2: precewise_img[i, j, k] = k2 * (image[i, j, k] - r1) elif image[i, j, k] < r1: precewise_img[i, j, k] = k1 * image[i, j, k] elif image[i, j, k] > r2: precewise_img[i, j, k] = k3 * (image[i, j, k] - r2) # 原图中做分段线性变化后需要对图像进行归一化操作,并将数据类型转换到np.uint8 cv.normalize(precewise_img, precewise_img, 0, 255, cv.NORM_MINMAX) precewise_img = cv.convertScaleAbs(precewise_img) g.msgbox('处理前的图片方差为{one},处理后的方差为{two}'.format(one=myvar(image),two=myvar(precewise_img))) #函数本身没做灰度化,但是求方差时我做了灰度化 cv.imshow('origin image', imutils.resize(image, 480)) cv.imshow('muti_liner_stretch image', imutils.resize(precewise_img, 480)) if cv.waitKey(0) == 27: cv.destroyAllWindows() def medium_filter(image): #中值滤波模板为3*3 image = image[:, :, 0] * 0.11 + image[:, :, 1] * 0.59 + image[:, :, 2] * 0.3 image = image.astype(np.uint8) # GRAY=0.3*R+0.59*G+0.11*B: # kernal_size=np.ones((3,3)) rows=image.shape[0] cols = image.shape[1] gray_data = image.copy() img_new = [] for i in range(rows-3): #减去3的原因是自己定义的模板都是3*3 line = [] #line记录着每一行的信息 for j in range(cols-3): a = gray_data[i:i+3,j:j+3] #此时类型a为np.uint8,转化为array类型方便后续计算 a=np.array(a) a=np.sort(a.reshape(-1)) line.append(a[4]) #np.multiply表示两个矩阵点乘 img_new.append(line) #记录着每一行卷积后的结果 image2=np.array(img_new) image2 = (image2 / float(image2.max())) * 255 # 显示图像 plt.subplot(2,1,1) plt.title('original image') plt.imshow(image,cmap=cm.gray) plt.axis("off") plt.subplot(2,1,2) plt.title('after medium image') plt.imshow(image2,cmap=cm.gray) plt.axis("off") plt.show() def PepperandSalt(image,percentage): # percentage表示噪声点出现的概率 #进来的第一步是灰度化 # R = np.mat(image[:, :, 0]) # G = np.mat(image[:, :, 1]) # B = np.mat(image[:, :, 2]) # img_gray2 = R * 0.299 + G * 0.587 + B * 0.114 img_gray2 = image[:, :, 0] * 0.11 + image[:, :, 1] * 0.59 + image[:, :, 2] * 0.3 img_gray2 = img_gray2.astype(np.uint8) # GRAY=0.3*R+0.59*G+0.11*B: NoiseImg=img_gray2 rows,cols=NoiseImg.shape NoiseNum=int(percentage*rows*cols) for i in range(NoiseNum): randX=np.random.randint(0,rows) randY=np.random.randint(0,cols) if random.randint(0,1) == 0: NoiseImg[randX,randY]=0 else: NoiseImg[randX,randY]=255 cv.imshow('Peppernoise image', NoiseImg) cv.waitKey(1000) def GaussianNoise(image,mean,sigma): #mean表示均值,sigma表示方差 #第一步是灰度化 # R=np.mat(image[:,:,0]) # G=np.mat(image[:,:,1]) # B=np.mat(image[:,:,2]) # img_gray2 = R*0.299+G*0.587+B*0.114 img_gray2 = image[:, :, 0] * 0.11 + image[:, :, 1] * 0.59 + image[:, :, 2] * 0.3 img_gray2 = img_gray2.astype(np.uint8) # GRAY=0.3*R+0.59*G+0.11*B: NoiseImg=img_gray2 rows = NoiseImg.shape[0] cols = NoiseImg.shape[1] rows,cols=NoiseImg.shape for i in range(rows): for j in range(cols): NoiseImg[i,j]=NoiseImg[i,j]+random.gauss(mean,sigma) # NoiseImg = NoiseImg+np.random.normal(mean,sigma,NoiseImg.shape) # NoiseImg = NoiseImg - np.full( NoiseImg.shape, np.min( NoiseImg)) # 全填充限定像素值下限(减去最小值,下限重新定义为0) # NoiseImg = NoiseImg * 255 / np.max( NoiseImg) #限定像素值上限 if NoiseImg[i,j]<0: NoiseImg[i,j] = 0 elif NoiseImg[i,j]>255: NoiseImg[i,j] = 255 cv.imshow('guasenoise image', NoiseImg) cv.waitKey(1000) def salt(image1,number): #number表述噪声点数量 image = image1.copy() rows= image.shape[0] cols = image.shape[1] for i in range(number): x=np.random.randint(0,rows) #np.ranom.randint 取不到右边界,ranodm.randint取得到右边界 y=np.random.randint(0,cols) c=random.randint(0,1) if c == 1: image[x,y] = 255 else: image[x,y] = 0 return image def convolution(kernal_size, image): rows=image.shape[0] cols = image.shape[1] gray_data = image.copy() img_new = [] for i in range(rows-3): #减去3的原因是自己定义的模板都是3*3 line = [] #line记录着每一行的信息 for j in range(cols-3): a = gray_data[i:i+3,j:j+3] a=np.array(a) line.append(np.sum(np.multiply(kernal_size, a))) #np.multiply表示两个矩阵点乘 img_new.append(line) #记录着每一行卷积后的结果 return np.array(img_new) def mean_image(image): #均值滤波 #进来的第一不也是灰度化 suanzi = np.ones((3,3))/9 # 创建全1算子(1/9) # 打开图像并转化成灰度图像 image = image[:, :, 0] * 0.11 + image[:, :, 1] * 0.59 + image[:, :, 2] * 0.3 image = image.astype(np.uint8) # GRAY=0.3*R+0.59*G+0.11*B: image2 = convolution(image=image,kernal_size=suanzi) # 将结果灰度值转化到0-255 image2 = (image2/float(image2.max()))*255 image3=cv.blur(image,(5,5)) # 显示图像 plt.subplot(3,1,1) plt.title('original image') plt.imshow(image,cmap=cm.gray) plt.axis("off") plt.subplot(3,1,2) plt.title('after meaning image') plt.imshow(image2,cmap=cm.gray) plt.axis("off") plt.subplot(3, 1, 3) plt.title('function made') plt.imshow(image3, cmap=cm.gray) plt.axis("off") plt.show() def func(x,y,sigma=1): return 100*(1/(2*np.pi*sigma))*np.exp(-((x-1)**2+(y-1)**2)/(2.0*sigma**2)) #创建高斯函数,该函数中心为(1,1),所以创建3*3比较合适 def gause_image(image): #高斯滤波,第一步也实现了灰度化 suanzi = np.fromfunction(func,(3,3),sigma=2) # 创建高斯函数,(1,1)为函数的中心,这里是生成3*3的标准差为2的高斯算子 # 打开图像并转化成灰度图像 image = image[:, :, 0] * 0.11 + image[:, :, 1] * 0.59 + image[:, :, 2] * 0.3 image = image.astype(np.uint8) # GRAY=0.3*R+0.59*G+0.11*B: image2 = convolution(image=image, kernal_size=suanzi) # 将结果灰度值转化到0-255 image2 = (image2 / float(image2.max())) * 255 # 显示图像 plt.subplot(2, 1, 1) plt.title('original image') plt.imshow(image, cmap=cm.gray) plt.axis("off") plt.subplot(2, 1, 2) plt.title('after gause image') plt.imshow(image2, cmap=cm.gray) plt.axis("off") plt.show() if __name__ == '__main__': # image1 = cv.imread('D:\\test.jpg') #读取我们的照片 # # image_salt = salt(image,2000) #加入噪声 # # mean_image(image_salt) # # gause_image(image_salt) # GaussianNoise(image1, mean=2, sigma=14) # cv.imshow('salt image', PepperandSalt(image1, percentage=0.01)) msg = "请输入您想要完成的任务(建议您第一步先打开图片)" title = '第二次作业' choice = ('打开图片', '退出') a = g.buttonbox(msg=msg, title=title, choices=choice) if a == '打开图片': filename = g.fileopenbox(msg="请打开一个jpg文件") img = cv.imread(filename) msg1 = "选择您想要实现的功能" title1 = '第二次作业' choice1 = ('显示噪声图', '滤波', '阈值分割', '分段线性法拉伸', '直方图拉伸', '区域生长法分割','重新选择图片','退出') q = 1 while q: b = g.buttonbox(msg=msg1, title=title1, choices=choice1) # while b!='退出': if b == '显示噪声图': msg2 = "选择您想要实现的功能" title2 = '第二次作业' choice2 = ('灰色椒盐噪声图', '灰色高斯噪声图','退出') q1=1 while q1: noise_image_choice = g.buttonbox(msg=msg2, title=title2, choices=choice2) if noise_image_choice == '灰色椒盐噪声图': PepperandSalt(img, percentage=0.01) #这里设置椒盐噪声点出现的概率为0.01 elif noise_image_choice == '灰色高斯噪声图': GaussianNoise(img, mean=2, sigma=14) #这里设置均值为2,方差为4 else: q1 =0 elif b == '滤波': msg_b = "选择您想要实现的功能" title_b = '第二次作业' choice_b = ('均值滤波', '高斯滤波','中值滤波') q_b = 1 while q_b: b_remove_noise = g.buttonbox(msg=msg_b, title=title_b, choices=choice_b) if b_remove_noise == '均值滤波': mean_image(salt(img,number=5000)) #salt为自己定义的可以随意增加噪声点的函数,number为自己定义噪声点的数量 elif b_remove_noise =='高斯滤波': gause_image(salt(img,number=5000)) elif b_remove_noise == '中值滤波': medium_filter(salt(img,number=5000)) else: q_b = 0 elif b == '阈值分割': msg_b1 = "选择您想要实现的功能" title_b1 = '第二次作业' choice_b1 = ('固定阈值', '调节参数窗') q_b1 = 1 while q_b1: b_remove_noise1 = g.buttonbox(msg=msg_b1, title=title_b1, choices=choice_b1) if b_remove_noise1 == '固定阈值': static_number(img) elif b_remove_noise1 == '调节参数窗': change_number(img) else: q_b1 = 0 elif b == '分段线性法拉伸': muti_liner_stretch(img) elif b == '直方图拉伸': hist_stretch(img) elif b == '区域生长法分割': seed_growing(img) elif b == '重新选择图片': filename = g.fileopenbox(msg="请打开一个jpg文件") img = cv.imread(filename) else: q = 0 ```python 在这里插入代码片
最新回复(0)