计算机视觉(第一季)学习笔记

计算机视觉的体系结构

在这里插入图片描述

图像与照明

  • 颜色的空间表达:
    RBG:
    CMYK:
    在这里插入图片描述
    HSI:
    色调H是描述纯色的属性
    饱和度S表示的是一种纯色被白光稀释的程度的度值
    亮度体现了无色的光强度概念,是一种主观的描述
    在这里插入图片描述

  • 颜色空间分解:
    在opencv中,颜色空间需要注意以下几点:
    (1)opencv中,彩色图像缺省为BGR格式,颜色三通道的顺序为B、G、R,分别对应索引0,1,2
    (2)opencv中,HSI/HSV颜色空间中的H的范围是0-180,是为了取得颜色的一个整数表示,其他两个是0-255
    (3)两个相似概念:HSI和HSV空间。HSV里面的v指的是RGB里面的最大值,v = max(r,g,b);而HSI的I是平均值,I = (r+g+b)/3 ,另外两个分量是一样的。

对应程序实现:

import cv2 as cv
f = '/Users/loongc/Documents/love_dwr/computer_vision/lena.jpeg'
img = cv.imread(f)
cv.imshow('hello lena',img)

gray = cv.cvtColor(img,cv.COLOR_RGB2GRAY)
cv.imshow('gray',gray)
#cv.waitKey(0)
#cv.destroyAllWindows()

hsv = cv.cvtColor(img,cv.COLOR_RGB2HSV)
cv.imshow('hsv',hsv)
#cv.waitKey(0)

cv.imshow('Hue',hsv[:,:,0])
cv.imshow('Saturation',hsv[:,:,1])
cv.imshow('Value',hsv[:,:,2])
#cv.waitKey(0)

cv.imshow('Blue',img[:,:,0])
cv.imshow('Green',img[:,:,1])
cv.imshow('Red',img[:,:,2])
cv.waitKey(0)

图像平滑滤波

  • 平均滤波(损失边缘细节)
  • 加权平均滤波
  • 高斯滤波(较常用)
  • 双边滤波
  • 中值滤波(对椒盐噪声有效,即独立点的噪声效果好)
  • 形态学滤波
    图像形态学基本操作-----膨胀
    在这里插入图片描述
    图像形态学基本操作-----腐蚀
    在这里插入图片描述
    图像形态学操作------开闭运算
    膨胀和腐蚀并不是互为逆运算,二者级联使用可以生成新的形态学运算:
    开运算:先腐蚀后膨胀
    闭运算:先膨胀后腐蚀
    先开后闭可以有效的去除噪声

对应程序实现:

import cv2 as cv
import numpy as np
f = '/Users/loongc/Documents/love_dwr/computer_vision/lena.jpeg'
img = cv.imread(f)

def gauss_noise(image,mean=0,var=0.001):
    image = np.array(image/255,dtype = float)
    noise = np.random.normal(mean,var**0.5,image.shape)
    out = image+noise
    if out.min()<0:
        low_clip = -1
    else:
        low_clip = 0
    out = np.clip(out,low_clip,1.0)
    out = np.uint8(out*255)
    return out

img = gauss_noise(img) 

#平均滤波
blur = cv.blur(img,(5,5))
#高斯平滑滤波
gauss = cv.GaussianBlur(img,(5,5),0)
#中值滤波
median = cv.medianBlur(img,5)
#双边滤波器
bilateral = cv.bilateralFilter(img,5,150,150)

cv.imshow('hello lena',img)
cv.imshow('blur',blur)
cv.imshow('gauss',gauss)
cv.imshow('median',median)
cv.imshow('bilateral',bilateral)

cv.waitKey()

形态学滤波实战演练:
在这里插入图片描述

#形态学滤波
import cv2 as cv
import numpy as np
f = '/Users/loongc/Documents/love_dwr/computer_vision/lena.jpeg'
img = cv.imread(f)

def gauss_noise(image,mean=0,var=0.001):
    image = np.array(image/255,dtype = float)
    noise = np.random.normal(mean,var**0.5,image.shape)
    out = image+noise
    if out.min()<0:
        low_clip = -1
    else:
        low_clip = 0
    out = np.clip(out,low_clip,1.0)
    out = np.uint8(out*255)
    return out

nimg = gauss_noise(img)

kernel = cv.getStructuringElement(cv.MORPH_CROSS,(3,3))
eroded = cv.erode(nimg,kernel)
dilated = cv.dilate(nimg,kernel)

opened = cv.morphologyEx(nimg,cv.MORPH_OPEN,kernel)
closed = cv.morphologyEx(opened,cv.MORPH_CLOSE,kernel)

cv.imshow('noised image',nimg)
cv.imshow('eroded image',eroded)
cv.imshow('dilated image',dilated)
cv.imshow('opened image',opened)
cv.imshow('closed omage',closed)
cv.waitKey()

边缘检测

  • 边缘检测基本思想
    相邻两个值做差分
  • 边缘检测算子
    Robert算子:
    在这里插入图片描述
    Sobel算子:
    在这里插入图片描述
    Laplace算子:
    在这里插入图片描述
    LoG算子:
    在这里插入图片描述Canny算子:
    已有方法问题:噪声;断裂:虚检(渐变灰度)
    canny算子的核心优点:边缘可以自动连通
    算法步骤:
    平滑图像–>计算梯度(幅值和方向)–>梯度幅值进行非极大值抑制–>自动边缘连接

程序实现:
基础边缘检测算子代码实现:

import cv2 as cv
import numpy as np
f = '/Users/loongc/Documents/love_dwr/computer_vision/lena.jpeg'
img = cv.imread(f)

#Sobel算子边缘检测
sobel = cv.Sobel(img,cv.CV_16S,1,0,ksize = 3)#CV_16S表示目标图像所需深度16位有符号的整数
#Laplacian边缘检测
laplacian = cv.Laplacian(img,cv.CV_16S)
#Canny边缘检测,最小阈值50,最大阈值120
canny = cv.Canny(img,50,120)

sobel_show = cv.convertScaleAbs(sobel)#将16位有符号的图像转换成可显示的8位无符号的整数
lap_show = cv.convertScaleAbs(laplacian)
cv.imshow('sobel',sobel_show)
cv.imshow('laplacian',lap_show)
cv.imshow('canny',canny)
cv.waitKey()

图像形态学操作

在这里插入图片描述
类似于边缘检测结果。
在这里插入图片描述
顶帽操作:适用于原始图像背景是暗的,而前景是亮的。可以把明亮的前景突出出来
底帽操作:可以把明亮北京中的暗色的前景突出出来

顶帽和底帽操作结合使用:常用的做法是源图像加上顶帽变换再减去底帽变换,可以增强对比度
在这里插入图片描述
扩展的形态学变换的结果实现:

#以下分别计算并显示梯度、顶帽和黑帽变换结果
kernel = cv.getStructuringElement(cv.MORPH_CROSS,(3,3))
gradient = cv.morphologyEx(img,cv.MORPH_GRADIENT,kernel)
cv.imshow('image gradient',gradient)

tophat = cv.morphologyEx(img,cv.MORPH_TOPHAT,kernel)
bottomhat = cv.morphologyEx(img,cv.MORPH_BLACKHAT,kernel)
cv.imshow('tophat',tophat)
cv.imshow('blackhat',bottomhat)

#利用顶帽和黑帽变换进行图像增强,并显示结果
enhanced = img + tophat - bottomhat
cv.imshow('enhanced image',enhanced)

#计算击中或击不中(HMT)变换结果并显示
kernel_hmt = np.array(([0,1,0],[1,-1,1],[0,1,0]),dtype = 'int')
hmt = cv.morphologyEx(img,cv.MORPH_HITMISS,kernel_hmt)
cv.imshow('hit or miss transform',hmt)
cv.waitKey()

图像变换

图像变换的意义:
使图像的特征更为突出;使原来无法直接观测的特征直接显现出来;需要提取图像中的特征,便于后续处理和图西那个理解。
图像几何变换:
图像放缩、图像平移、图像旋转、图像镜像、图像翻转
图像距离变换:
在这里插入图片描述
具有细化的效果
对数极坐标变换:
在这里插入图片描述
应用:全景展开

灰度直方图
直方图均衡化的作用就是图像增强,需要满足的条件是亮的依然亮,暗的依然暗。但会增强噪声
为了实现直方图均衡化,我们需要采用直方图重新映射的方法:在这里插入图片描述
局部直方图均衡化:
在这里插入图片描述
改进局部直方图均衡化:
在这里插入图片描述
改进的局部直方图均衡结果:
在这里插入图片描述
霍夫变换:

在这里插入图片描述
总结:霍夫变换基于直线法线表示及对应的参数空间(@,p);最终直线参数确定采用投票机制,统计参数空间小格中的曲线数目。

程序实现:

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
f = '/Users/loongc/Documents/love_dwr/computer_vision/lena.jpeg'
img = cv.imread(f)

#实现图像改变大小和翻转
w,h = img.shape[0:2]
resized = cv.resize(img,(int(w/4),int(h/2)))
fliped = cv.flip(img,-1)#此处-1、0、1实现上下左右翻转
#cv.imshow('resized',resized)
#cv.imshow('fliped',fliped)
#cv.waitKey()

#实现图像的距离变换
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
ret,thr = cv.threshold(gray,100,255,cv.THRESH_OTSU)
#距离计算方式:DIST_L1、DIST_L2或DIST_C,实际中常用L2
#masksize:可取DIST_MASKPRECISE或DIST_MASK_3、5
dist = cv.distanceTransform(thr,cv.DIST_L2,cv.DIST_MASK_3)
dist_norm = cv.convertScaleAbs(dist)
#cv.imshow('dist_norm',dist_norm)
#cv.waitKey()

#实现Log_polar变换
center =(w/2,h/2)#变换中心
maxRadius = 0.7*min(center)
M = w/cv.log(maxRadius)#幅值尺度参数
print(maxRadius,M[0])
#系数越大,对应黑色区域越小
#把图像映射到极指数空间
log_polar = cv.logPolar(img,center,M[0]*0.8,cv.INTER_LINEAR+cv.WARP_FILL_OUTLIERS)
#CV_WARP_FILL_OUTLIERS 填充输出图像所有像素,如果这些点有和外点对应的,则置零
#cv_WARP_INVERSE_MAP 表示矩阵是从目标图像到源图像的反变换
#cv.imshow('log_polar',log_polar)
#cv.waitKey()

#实现灰度直方图和直方图均衡化
plt.hist(gray.ravel(),256,[0,256])
plt.show()
equa = cv.equalizeHist(gray)
#cv.imshow('equalized image',equa)
#cv.waitKey()

#实现Hough变换
edges = cv.Canny(thr,50,150)
disp_edge = cv.cvtColor(edges,cv.COLOR_GRAY2BGR)
lines = cv.HoughLinesP(edges,1,1*np.pi/180,10)
#10表示累加平面的阈值参数,超过设定阈值才被检测出线段,值越大,检测出的线段越长,检出的线段个数越少
for line in lines:
    for x1,y1,x2,y2 in line:
        cv.line(disp_edge,(x1,y1),(x2,y2),(0,255,0),1)
    pass
print('line count',len(lines))
cv.imshow('disp_edge',disp_edge)
cv.waitKey()

图像分割I

基于灰度直方图的阈值分割
自动阈值分割方法-----大津(Otsu)算法
根据统计分析理论,最佳阈值确定的最佳二分类应使类内方差最小,等同于类间方差最大。于是,大津算法的基本思想:确定使灰度直方图类间方差最大的最佳阈。
大津算法原理:略
大津算法的求解采用遍历方式,思想直接,实现速度快。
基于边缘轮廓的分割
程序实例:

import numpy as np
import matplotlib.pyplot as plt
import copy
f = '/Users/loongc/Documents/love_dwr/computer_vision/rice.jpg'
img = cv.imread(f)
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY) 
#大津算法灰度阈值化
thr,bw = cv.threshold(gray,0,0xff,cv.THRESH_OTSU)
#bw阈值后的二值图像,thr使用大津算法计算得出的阈值
print('Threshold is:',thr)

#画出灰度直方图
plt.hist(gray.ravel(),256,[0,256])
plt.show()

element = cv.getStructuringElement(cv.MORPH_CROSS,(3,3))
bw = cv.morphologyEx(bw,cv.MORPH_OPEN,element)

seg = copy.deepcopy(bw)
#计算轮廓
cnts,hier = cv.findContours(seg,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)
#hier分割以后的结果,cnts分割完的所有轮廓存在其中
#cv.RETR_EXTERNAL只检测最外围的轮廓,cv.RETR_LIST检测所有轮廓,还有其他
#cv.CHAIN_APPROX_SIMPLE只保存轮廓的拐点信息
count = 0
for i in range(len(cnts),0,-1):
    c = cnts[i-1]
    area = cv.contourArea(c)
    if area < 10:
        continue
    count = count + 1
    print('blob',i,':',area)
    #区域画框并标记
    x,y,w,h = cv.boundingRect(c)
    cv.rectangle(img,(x,y),(x+w,y+h),(0,0,0xff),1)
    cv.putText(img,str(count),(x,y),cv.FONT_HERSHEY_PLAIN,0.5,(0,0xff,0))
    
print('米粒数量:',count)
cv.imshow('原图',img)
cv.imshow('阈值化图',bw)
cv.waitKey()

阈值化分割扩展分割方法----局部阈值法

图1
图2
图2

阈值化分割扩展方法----多阈值分割法

图1
图2
图3

图像分割II

基于区域的分割
基于区域的分割-----区域生长法:
区域生长:从种子点开始,按照一定规则(如相邻像素灰度相似性)向周围扩散,将领域相似像素加入区域中,
搜索扩散有两种方式:深度优先、广度优先
在这里插入图片描述
基于区域的分割-----区域分裂合并法:
对区域分裂合并法
区域分裂合并实现步骤:对区域分裂合并法无需预先指定种子点,它按某种一致性准则分裂或者合并区域;可以先进性分裂运算,然后再进行合并运算,也可以分裂和合并运算同时进行,经过连续的分裂和合并,最后得到图像的精确分割效果;分裂合并法对分割复杂的场景图像比较有效。

总结: 区域生长法基于相邻像素间的相似性,由种子像素逐步生长得到;分裂合并基于图像块内在的相似性,通过不断分裂得到区域外边界,通过合并将不同块连接.

分水岭算法分割
由于噪声点或者其他干扰因素的存在,使用分水岭算法常常存在过度分割的现象,这是因为有很多局部极小值点的存在。
在这里插入图片描述
在这里插入图片描述

分水岭算法步骤

为了解决过度分割的问题,可以使用基于标记mark图像的分水岭算法,就是指定mark图像,在这个区域洪水淹没过程中,水平面都是从定义的marker开始的,这样可以避免一些很小的噪声极值区域的分割。

图像分割算法程序实现
在这里插入图片描述

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
import copy
f = '/Users/loongc/Documents/love_dwr/computer_vision/coins.jpg'
img = cv.imread(f)
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY) 
#大津算法做自适应阈值化,作为预处理的第一步
ret,thresh = cv.threshold(gray,0,255,cv.THRESH_BINARY_INV+cv.THRESH_OTSU)
print('threshold is:',ret)

#对阈值图像做开运算,去除一些白色小的噪声点
kernel = np.ones((3,3),np.uint8)
opening = cv.morphologyEx(thresh,cv.MORPH_OPEN,kernel,iterations = 2)

#再做膨胀运算,使用膨胀运算确保背景与原图一致
sure_bg = cv.dilate(opening,kernel,iterations = 3)

#cv.imshow('gray',gray)
cv.imshow('thresh',thresh)
cv.imshow('opening',opening)
cv.imshow('sure_bg',sure_bg)
#cv.waitKey()

#做距离变换计算每个硬币中心,鲁棒性更好
dist_transform = cv.distanceTransform(opening,cv.DIST_L2,5)
ret,sure_fg = cv.threshold(dist_transform,0.7*dist_transform.max(),255,0)

sure_fg = np.uint8(sure_fg)
unknown = cv.subtract(sure_bg,sure_fg)

cv.imshow('dist_transform',dist_transform)
cv.imshow('sure_fg',sure_fg)
cv.imshow('unknown',unknown)
#cv.waitKey()

ret,markers = cv.connectedComponents(sure_fg)#为了确定有多少个目标
markers = markers+1#标记+1,让标记从1开始
markers[unknown==255]=0#不确定区域设置为0,便于下一步分割
markers = cv.watershed(img,markers)#使用watershed做分水岭分割
img[markers == -1] = [255,0,0]#分割线用蓝色标记

cv.imshow('markers',markers)
cv.imshow('img',img)
cv.waitKey()

图像描述

简单描述----边界描述

  • 边界的长度:由轮廓决定。如果图像内部区域是由4-连通确定,则得到的边界是8-连通的;如果图像内部区域是由8-连通确定,则得到的边界是4-连通的。
  • 计算方式:把所有的边缘点做连线,连线长度即边界长度(内边界)
  • 边界的直径:边界上相隔最远的2点的距离,有时也称为图像的主轴长度。
  • 轮廓的表示方法----链码:用于表示顺序连接的具有指定长度和方向的直线段组成的边界线。4连接用0-3编码,8连接用0-7编码
    在这里插入图片描述
    起点不同,造成编码不同;角度不同,造成的编码不同。为了解决该问题,我们使用链码的差分替代码字本身。
基于边界轮廓的简单描述

简单描述-----区域描述

  • 区域面积
  • 区域重心
  • 区域内部的灰度特性
    平均灰度、最大灰度、最小灰度、灰度中值、灰度方差
基于区域的简单描述

一般描述

  • 最小包围矩形(MSR)
    -离心率:最长弦A与垂直于A的最长弦B的长度比(主次轴比)
  • 椭圆拟合
  • 投影
  • 多边形拟合与D-P算法
  • 不变矩

程序实现

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
import copy
f = '/Users/loongc/Documents/love_dwr/computer_vision/circle.jpg'
img = cv.imread(f)
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)

#首先对图像进行阈值化
_,thr = cv.threshold(gray,200,255,cv.THRESH_BINARY)
cv.imshow('img',gray)
#cv.imshow('threshold image',thr)
#cv.waitKey()

#进一步得到图像的轮廓
cnts,hier = cv.findContours(thr,cv.RETR_LIST,cv.CHAIN_APPROX_NONE)
count = 0
#用于显示的图像
disp_poly = img.copy()
disp_elli = img.copy()
for i in range(len(cnts)):
    c = cnts[i]
    poly = cv.approxPolyDP(c,5,True)#5,参数越大拟合允许误差越大
    cv.polylines(disp_poly,[poly],True,(255,255,255),2)
    
    #拟合椭圆
    if (len(c)>5):
        ellipse = cv.fitEllipse(c)
        cv.ellipse(disp_elli,ellipse,(255,255,255),2)
    
    #计算hu不变矩
    area = cv.contourArea(c)
    length = cv.arcLength(c,True)
    moments = cv.moments(c)
    hu = cv.HuMoments(moments)
    print(i+1,':','length is %.1f'%length,'area =',area,
          'm00=%.3f,m01=%.3f,m10=%.3f,m11=%.3f,'%(hu[0],hu[1],hu[2],hu[3]))
    x,y,w,h = cv.boundingRect(c)
    cv.putText(disp_poly,str(i+1),(x,y),cv.FONT_HERSHEY_PLAIN,0.8,(0xff,0xff,0xff))

cv.imshow('disp_poly',disp_poly)
cv.imshow('disp_elli',disp_elli)
cv.waitKey()

课程总结

图像滤波:卷积和滤波的概念、图像平滑去燥,图像边缘检测,使用形态学滤波可以完成特征提取、边缘检测、图像增强
灰度直方图,hough变换与直线检测,道路检测,图像边缘检测,在自动驾驶时非常实用。使用距离变换可以分开互相粘连的图像。
图像分割与描述:基于灰度直方图的阈值分割(分离前后背景差异比较明显),基于区域生长法(渐变图像),分水岭算法
图像的描述:

机器视觉:生产线缺陷检测,零件识别、计数等
图像处理:图像美颜、图像风格定制化、图像增强等
医学图像处理:细胞分类、异常组织间的、分割等
卫星与航空遥感图像处理:特定目标检测、识别等

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值