计算机视觉:图像基本操作实验
文章目录
1.实验内容:
1.分别使用PIL库和OpenCV库读取图像并实现可视化,对比 OpenCV读取和PIL读取的差异;
实现方法:
def Showimg():
img1=cv2.imread(ImagePath)
img2=Image.open(ImagePath)
print('opencv_type',type(img1))#输出类型对比差别
print("pil_type",type(img2))
print('opencv_shape',img1.shape)#输出读入顺序
print('pil_size',img2.size)
# img1.show()
cv2.imshow('opencvimg',img1)
cv2.waitKey(0)
img2.show()
# cv2.imshow('pilimg',img2)
实验结果:
Opencv读取图像可视化
PIL读取图像可视化
读取差别验证:
结果分析:
二者的图像读取格式不同,当图像格式为jpg时,PIL读入图像,类型为PIL.JpegImagePlugin.JpegImageFile;OpenCV读入图像,直接就是numpy.ndarray。
二者的宽高的读取顺序不同,PIL读入图像,顺序为:(宽,高)OpenCV读入图像,顺序为:(高,宽,通道数)
除此外二者的区别还有读取的通道顺序不同,PIL读入为R、G、B;OpenCV读入为B、G、R
2.利用thumbnail()函数创建图像缩略图,利用resize()函数 处理图像,对比两者差别;
实现方法:
#利用thumbnail()函数创建图像缩略图,利用resize()函数处理图像,对比两者差别;
def ChangeSize():
img1=Image.open(ImagePath)
img2=Image.open(ImagePath)
print('原尺寸',img1.size)
img1.thumbnail((256,256))
print('缩略图尺寸',img1.size)
img1.show('thumbnail')
img2=img2.resize((256,256))
print('resize尺寸',img2.size)
img2.show('resize')
实验结果:
左边为thumbnail处理图像,右边为resize处理图像
处理前后图片大小对比:
结果分析:
thumbnail ()之后的图片大小与预设的不一样,而 resize() 就不会这样
resize()函数会返回一个Image对象, thumbnail()函数返回None。
resize()中的size参数直接设定了resize之后图片的规格, 而thumbnail()中的size参数则是设定了图片大小的最大值. 所以经过resize()处理的图片可能会被拉伸, 而经过thumbnail()处理的图片不会被拉伸。
3.绘制图像的轮廓与直方图;
实现方法:
#绘制图像的轮廓与直方图
def ContourAndHist():
img=array(Image.open(ImagePath).convert('L'))#读取转化灰度
# cv2.imshow('grayimg',img)
# cv2.waitKey(0)
figure()
gray()#不使用颜色信息
contour(img,origin="image")
axis=('equal')
axis=('off')
figure()
hist(img.flatten(),128)
show()
实验结果:
结果分析:
绘制轮廓需要对每个坐标的像素值施加一个阈值,所以首先需要将图像灰度化。
直方图:用来表征该图像像素值得分布情况。用一定的小区间来指定表征像素值的范围,每个小区间会得到落入该小区间表示范围的像素数目。hist()函数:参数二:指定小区间的数目。参数一:只接受一维数组作为输入,因此在绘制图像直方图前,必须对图像进行压平处理。flatten()将任意数组按照行优先准则转换成一维数组。
4.实现图像的灰度变换、直方图均衡化;
实现方法:
#实现图像的灰度变换、直方图均衡化
def GraytrAndHisteq():
img=array(Image.open(ImagePath).convert('L'))
img1=255-img#反相处理
img2=(100.0/255)*img+100#灰度值转化到100至200间
img3=255.0*(img/255.0)**2#灰度值平方
figure()
gray()
imshow(img)
figure()
gray()
imshow(img1)
figure()
gray()
imshow(img2)
figure()
gray()
imshow(img3)
# Image.fromarray(uint8(img)).show()
# Image.fromarray(uint8(img1)).show()
# Image.fromarray(uint8(img2)).show()
# Image.fromarray(uint8(img3)).show()
img0,cdf=histeq(img)
figure()
gray()
imshow(img0)
# Image.fromarray(uint8(img0)).show()
figure()
hist(img0.flatten(),128)
show()
#直方图均衡化具体方法
def histeq(img,nbr_bins=256):#bin指定直方图条数
imghist,bins = histogram(img.flatten(),nbr_bins,normed=True)#计算图像的直方图
cdf=imghist.cumsum()
cdf=255*cdf/cdf[-1]#归一化
img2=interp(img.flatten(),bins[:-1],cdf)#使用cdf的线性插值计算新的像素值
return img2.reshape(img.shape),cdf
实验结果:
从左到右依次为 :原图、反相处理、灰度值转化到100至200间、灰度值平方
直方图均衡化后的灰度图以及灰度直方图:
结果分析:
直方图均衡化后图像的对比度增强了,原先图像灰色区域的细节变得清晰
5.实现图像的不同高斯模糊、计算导数;
实现方法:
高斯模糊
#实现图像的不同高斯模糊
def GaussianBlur():
#模糊灰度图
grayimg=array(Image.open(ImagePath).convert('L'))
for i in range(3):
img0=filters.gaussian_filter(grayimg,5*i+5)
Image.fromarray(uint8(img0)).show()
#高斯模糊彩色图像
img=array(Image.open(ImagePath))
img1=zeros(img.shape)#创建一个列表用来存储彩色图像
for i in range(3):
for j in range(3):
img1[:,:,j]=filters.gaussian_filter(img[:,:,j],5*i+5)
img1=uint8(img1)
img1=array(img1,'uint8')
Image.fromarray(uint8(img1)).show()
计算导数:
#计算导数
def Derivative():
img=array(Image.open(ImagePath).convert('L'))
#Sobel滤波
imgy=zeros(img.shape)
filters.sobel(img,0,imgy)#导数方向选择,1为x方向,0为y方向
Image.fromarray(uint8(imgy)).show()
imgx=zeros(img.shape)
filters.sobel(img,1,imgx)#导数方向选择,1为x方向,0为y方向
Image.fromarray(uint8(imgx)).show()
#gaussian滤波
sigma=5
imgy2=zeros(img.shape)
filters.gaussian_filter(img,(sigma,sigma),(1,0),imgy2)#导数方向选择,1,0为y方向
Image.fromarray(uint8(imgy2)).show()
imgx2=zeros(img.shape)
filters.gaussian_filter(img,(sigma,sigma),(0,1),imgx2)#导数方向选择,0,1为x方向
Image.fromarray(uint8(imgx2)).show()
实验结果:
灰度图像的不同高斯模糊:σ=5,σ=10,σ=15
彩色图像的不同高斯模糊:σ=5,σ=10,σ=15
Sobel滤波求导数:Y方向、X方向
高斯滤波求导数:Y方向、X方向、sigma=5
高斯滤波求导数:Y方向、X方向、sigma=1
结果分析:
sobel()函数的第二个参数表示选择x或者y方向导数,第三个参数保存输出的变量,在使用sobel两个导数图像中,正导数显示为亮的像素,负导数显示为暗的像素。灰色区域表示导数的值接近于零
使用Gaussian滤波求导的效果可视化较差,原因是由于sigma过大,当将sigma调小后,可视化效果变得较好。
6.形态学计数(计算圆形个数等)、去噪;
实现方法:
形态学计数
def ObjNum():
#载入图像
img=array(Image.open('./cell.png').convert('L'))
#阙值化操作,保证图像是二值图像
img=1*(img<128)
labels,num= measurements.label(img)
print('数量:',num)
# print(type(labels))
# Image.fromarray(uint8(img)).show()
figure()
gray()
imshow(img)
plt.title(num)
# figure()
# gray()
# imshow(labels)
show()
去噪
#ROF模型实现图像去噪
def Denoise():
img=array(Image.open(ImagePath).convert('L'))
figure()
gray()
imshow(img)
U,T=denoise(img,img)
figure()
gray()
imshow(U)
figure()
gray()
imshow(T)
show()
#去噪声具体方法 返回的U
def denoise(im,U_init,tolerance=0.1,tau=0.125,tv_weight=100):
"""使用A. Chambolle(2005)在公式(11)中的计算步骤实现Rudin-Osher-Fatemi(ROF)去噪模型
输入:含有噪声的输入图像(灰度图像)、U的初始值、TV正则项权值、步长、停业条件
输出:去噪和去除纹理后的图像、纹理残留"""
m,n = im.shape #噪声图像的大小
#初始化
U = U_init
Px = im #对偶域的x分量
Py = im #对偶域为y分量
error = 1
while(error>tolerance):
Uold = U
#原始变量的梯度
GradUx = roll(U,-1,axis=1)-U #变量U梯度的x分量
GradUy = roll(U,-1,axis=0)-U #变量U梯度的y分量
#更新对偶变量
PxNew = Px + (tau/tv_weight)*GradUx
PyNew = Py + (tau/tv_weight)*GradUy
NormNew = maximum(1,sqrt(PxNew**2+PyNew**2))
Px = PxNew/NormNew #更新x分量(对偶)
Py = PyNew/NormNew #更新y分量(对偶)
#更新原始变量
RxPx = roll(Px,1,axis=1) #对x分量进行向右x轴平移
RyPy = roll(Py,1,axis=0) #对y分量进行向右y轴平移
DivP = (Px-RxPx) + (Py-RyPy) #对偶域的散度
U = im + tv_weight*DivP #更新原始变量
#更新误差
error = linalg.norm(U - Uold)/sqrt(n*m)
return U,im-U #去噪后的图像和纹理残余
实验结果:
终端或图片标题可以查看估计的图形数量:
从左到右分别为原图的灰度图、去噪后图像、去噪后的纹理残余图像
结果分析:
上述使用的计数方法的结果受图像的二值化效果影响较大,当二值化的阈值改变时,对计数结果影响很大。
2.实验实现总代码
import cv2
import numpy as np
from PIL import Image
import os
from pylab import *
from scipy.ndimage import filters
from scipy.ndimage import measurements,morphology
ImagePath='./testimg.jpg'
#分别使用PIL库和OpenCV库读取图像并实现可视化,对比OpenCV读取和PIL读取的差异;
def Showimg():
img1=cv2.imread(ImagePath)
img2=Image.open(ImagePath)
print('opencv_type',type(img1))#输出类型对比差别
print("pil_type",type(img2))
print('opencv_shape',img1.shape)#输出读入顺序
print('pil_size',img2.size)
# img1.show()
cv2.imshow('opencvimg',img1)
cv2.waitKey(0)
img2.show()
# cv2.imshow('pilimg',img2)
#利用thumbnail()函数创建图像缩略图,利用resize()函数处理图像,对比两者差别;
def ChangeSize():
img1=Image.open(ImagePath)
img2=Image.open(ImagePath)
print('原尺寸',img1.size)
img1.thumbnail((256,256))
print('缩略图尺寸',img1.size)
img1.show('thumbnail')
img2=img2.resize((256,256))
print('resize尺寸',img2.size)
img2.show('resize')
#绘制图像的轮廓与直方图
def ContourAndHist():
img=array(Image.open(ImagePath).convert('L'))#读取转化灰度
# cv2.imshow('grayimg',img)
# cv2.waitKey(0)
figure()
gray()#不使用颜色信息
contour(img,origin="image")
axis=('equal')
axis=('off')
figure()
hist(img.flatten(),128)
show()
#实现图像的灰度变换、直方图均衡化
def GraytrAndHisteq():
img=array(Image.open(ImagePath).convert('L'))
img1=255-img#反相处理
img2=(100.0/255)*img+100#灰度值转化到100至200间
img3=255.0*(img/255.0)**2#灰度值平方
figure()
gray()
imshow(img)
figure()
gray()
imshow(img1)
figure()
gray()
imshow(img2)
figure()
gray()
imshow(img3)
# Image.fromarray(uint8(img)).show()
# Image.fromarray(uint8(img1)).show()
# Image.fromarray(uint8(img2)).show()
# Image.fromarray(uint8(img3)).show()
img0,cdf=histeq(img)
figure()
gray()
imshow(img0)
# Image.fromarray(uint8(img0)).show()
figure()
hist(img0.flatten(),128)
show()
#直方图均衡化具体方法
def histeq(img,nbr_bins=256):#bin指定直方图条数
imghist,bins = histogram(img.flatten(),nbr_bins,normed=True)#计算图像的直方图
cdf=imghist.cumsum()
cdf=255*cdf/cdf[-1]#归一化
img2=interp(img.flatten(),bins[:-1],cdf)#使用cdf的线性插值计算新的像素值
return img2.reshape(img.shape),cdf
#实现图像的不同高斯模糊
def GaussianBlur():
#模糊灰度图
grayimg=array(Image.open(ImagePath).convert('L'))
for i in range(3):
img0=filters.gaussian_filter(grayimg,5*i+5)
Image.fromarray(uint8(img0)).show()
#高斯模糊彩色图像
img=array(Image.open(ImagePath))
img1=zeros(img.shape)#创建一个列表用来存储彩色图像
for i in range(3):
for j in range(3):
img1[:,:,j]=filters.gaussian_filter(img[:,:,j],5*i+5)
img1=uint8(img1)
img1=array(img1,'uint8')
Image.fromarray(uint8(img1)).show()
#计算导数
def Derivative():
img=array(Image.open(ImagePath).convert('L'))
#Sobel滤波
imgy=zeros(img.shape)
filters.sobel(img,0,imgy)#导数方向选择,1为x方向,0为y方向
Image.fromarray(uint8(imgy)).show()
imgx=zeros(img.shape)
filters.sobel(img,1,imgx)#导数方向选择,1为x方向,0为y方向
Image.fromarray(uint8(imgx)).show()
#gaussian滤波
sigma=5
imgy2=zeros(img.shape)
filters.gaussian_filter(img,(sigma,sigma),(1,0),imgy2)#导数方向选择,1,0为y方向
Image.fromarray(uint8(imgy2)).show()
imgx2=zeros(img.shape)
filters.gaussian_filter(img,(sigma,sigma),(0,1),imgx2)#导数方向选择,0,1为x方向
Image.fromarray(uint8(imgx2)).show()
def ObjNum():
#载入图像
img=array(Image.open('./cell.png').convert('L'))
#阙值化操作,保证图像是二值图像
img=1*(img<128)
labels,num= measurements.label(img)
print('数量:',num)
print(type(labels))
# Image.fromarray(uint8(img)).show()
figure()
gray()
imshow(img)
# figure()
# gray()
# imshow(labels)
show()
#ROF模型实现图像去噪
def Denoise():
img=array(Image.open(ImagePath).convert('L'))
figure()
gray()
imshow(img)
U,T=denoise(img,img)
figure()
gray()
imshow(U)
figure()
gray()
imshow(T)
show()
#去噪声具体方法 返回的U
def denoise(im,U_init,tolerance=0.1,tau=0.125,tv_weight=100):
"""使用A. Chambolle(2005)在公式(11)中的计算步骤实现Rudin-Osher-Fatemi(ROF)去噪模型
输入:含有噪声的输入图像(灰度图像)、U的初始值、TV正则项权值、步长、停业条件
输出:去噪和去除纹理后的图像、纹理残留"""
m,n = im.shape #噪声图像的大小
#初始化
U = U_init
Px = im #对偶域的x分量
Py = im #对偶域为y分量
error = 1
while(error>tolerance):
Uold = U
#原始变量的梯度
GradUx = roll(U,-1,axis=1)-U #变量U梯度的x分量
GradUy = roll(U,-1,axis=0)-U #变量U梯度的y分量
#更新对偶变量
PxNew = Px + (tau/tv_weight)*GradUx
PyNew = Py + (tau/tv_weight)*GradUy
NormNew = maximum(1,sqrt(PxNew**2+PyNew**2))
Px = PxNew/NormNew #更新x分量(对偶)
Py = PyNew/NormNew #更新y分量(对偶)
#更新原始变量
RxPx = roll(Px,1,axis=1) #对x分量进行向右x轴平移
RyPy = roll(Py,1,axis=0) #对y分量进行向右y轴平移
DivP = (Px-RxPx) + (Py-RyPy) #对偶域的散度
U = im + tv_weight*DivP #更新原始变量
#更新误差
error = linalg.norm(U - Uold)/sqrt(n*m)
return U,im-U #去噪后的图像和纹理残余
if __name__ == '__main__':
# Showimg()
# ChangeSize()
# ContourAndHist()
# GraytrAndHisteq()
# GaussianBlur()
# Derivative()
# ObjNum()
# Denoise()