1、模糊处理
对目标图像的噪声进行抑制。模糊处理需要滤波器
滤波器种类
线性滤波:每一个像素的输出值是一些输入像素的加权和。
三种线性滤波:方框滤波、均值滤波、高斯滤波
两种非线性滤波:中值滤波、双边滤波、
img = cv2.imread('lena.jpg')
blur = cv2.blur(img, (3, 3)) # 均值模糊
# 前面的均值滤波也可以用方框滤波实现:normalize=True
blur = cv2.boxFilter(img, -1, (3, 3), normalize=True)
gaussian = cv2.GaussianBlur(img, (5, 5), 1) # 高斯滤波
median = cv2.medianBlur(img, 5) # 中值滤波
blur = cv2.bilateralFilter(img, 9, 75, 75) # 双边滤波
方框滤波
1. 原理
先给出内核,用内核各点的值与其对应的图像像素值相乘
均值滤波
均值滤波,是最简单的一种滤波操作,输出图像的每一个像素是核窗口内输入图像对应像素的像素的平均值( 所有像素加权系数相等),其实说白了它就是归一化后的方框滤波,blur 函数内部中其实就是调用了一下 boxFilter。
我们来一个最简单的——3x3均值滤波的掩膜:
可以看到,均值掩膜内所有系数均相等——为1/9,且他们的和为1。
缺陷
均值滤波本身存在着固有的缺陷,即它不能很好地保护图像细节,在图像去噪的同时也破坏了图像的细节部分,从而使图像变得模糊,不能很好地去除噪声点。其实说白了它就是归一化后的方框滤波,blur 函数内部中其实就是调用了一下 boxFilter。
高斯滤波
https://www.zhihu.com/question/54918332/answer/141738672
高斯滤波和高斯分布是什么关系,使用高斯分布来求得高斯掩摸(卷积,kernel)
高斯分布公式:
中值滤波
中值滤波是一种典型的非线性滤波技术,基本思想是用像素点邻域灰度值的中值来代替该像素的灰度值,该方法在去除脉冲噪声椒盐噪声的同时又能保留图像的边缘信息。
缺点
对一些细节(特别是细、尖顶等)多的图像不太合适。
双边滤波
形态学操作
7种图像处理形态学:腐蚀、膨胀、开运算、闭运算、形态学梯度、顶帽、黑帽。
import cv2
import numpy as np
img = cv2.imread('j.bmp', 0)
kernel = np.ones((5, 5), np.uint8)
erosion = cv2.erode(img, kernel) # 腐蚀
dilation = cv2.dilate(img, kernel) # 膨胀
opening = cv2.morphologyEx(img1, cv2.MORPH_OPEN, kernel) #开运算
closing = cv2.morphologyEx(img2, cv2.MORPH_CLOSE, kernel) #闭运算
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel) #顶帽
blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel) #黑帽
https://blog.csdn.net/zhmxy555/article/details/23710721
腐蚀、膨胀
膨胀与腐蚀的功能:
消除噪声;
分割出独立的图像元素,在图像中连接相邻的元素;
寻找图像中的明细的极大值区域或极小值区域;
求出图像的梯度。
首先需要注意,腐蚀和膨胀是对白色部分(高亮部分)而言的,不是黑色部分。膨胀就是图像中的高亮部分进行膨胀,“领域扩张”,效果图拥有比原图更大的高亮区域。腐蚀就是原图中的高亮部分被腐蚀,“领域被蚕食”,效果图拥有比原图更小的高亮区域。
腐蚀
而膨胀就是求局部最大值的操作,核B与图形卷积,即计算核B覆盖的区域的像素点的最大值,并把这个最大值赋值给参考点指定的像素。这样就会使图像中的高亮区域逐渐增长。
膨胀
是相反的一对操作,所以腐蚀就是求局部最小值的操作。
开运算
开运算,其实就是先腐蚀在膨胀的过程。
开运算可以用来消除小物体、在纤细点处分离物体、平滑较大物体的边界的同时并不明显改变其面积。
闭运算
先膨胀后腐蚀的过程称为闭运算(Closing Operation)
闭运算能够排除小型黑洞(黑色区域)。
形态学梯度
形态学梯度(Morphological Gradient)为膨胀图与腐蚀图之差
对二值图像进行这一操作可以将团块(blob)的边缘突出出来。我们可以用形态学梯度来保留物体的边缘轮廓,如下所示:
顶帽
顶帽运算(Top Hat)又常常被译为”礼帽“运算。为原图像与上文刚刚介绍的“开运算“的结果图之差
因为开运算带来的结果是放大了裂缝或者局部低亮度的区域,因此,从原图中减去开运算后的图,得到的效果图突出了比原图轮廓周围的区域更明亮的区域,且这一操作和选择的核的大小相关。
顶帽运算往往用来分离比邻近点亮一些的斑块。当一幅图像具有大幅的背景的时候,而微小物品比较有规律的情况下,可以使用顶帽运算进行背景提取。
黑帽
黑帽(Black Hat)运算为”闭运算“的结果图与原图像之差。
黑帽运算后的效果图突出了比原图轮廓周围的区域更暗的区域,且这一操作和选择的核的大小相关。
所以,黑帽运算用来分离比邻近点暗一些的斑块。非常完美的轮廓效果图:
常用的特征提取方法
Harris、Gabor、LBP、SIFT、HOG
1、边缘检测算子有哪些
2、霍夫变换
霍夫变换直线原理
举个例子
https://zhuanlan.zhihu.com/p/34196381
如上图,假定在一个8*8的平面像素中有一条直线,并且从左上角(1,8)像素点开始分别计算θ为0°、45°、90°、135°、180°时的ρ,图中可以看出ρ分别为1、(9√2)/2、8、(7√2)/2、-1,并给这5个值分别记一票,同理计算像素点(3,6)点θ为0°、45°、90°、135°、180°时的r,再给计算出来的5个r值分别记一票,此时就会发现r = (9√2)/2的这个值已经记了两票了,以此类推,遍历完整个8*8的像素空间的时候r = (9√2)/2就记了5票, 别的ρ值的票数均小于5票,所以得到该直线在这个8*8的像素坐标中的极坐标方程为 (9√2)/2=x*Cos45°+y*Sin45°,到此该直线方程就求出来了。(PS:但实际中θ的取值不会跨度这么大,一般是PI/180)。
也可以看视频,这是视频还是不错的
https://www.bilibili.com/video/av44997359?from=search&seid=10778458614331441732
视频里面的代码
https://github.com/o0o0o0o0o0o0o/image-processing-from-scratch/tree/master/hough%20transform
#coding:utf-8
import numpy as np
import matplotlib.pyplot as plt
import os
import cv2
def lines_detector_hough(edge,ThetaDim = None,DistStep = None,threshold = None,halfThetaWindowSize = 2,halfDistWindowSize = None):
'''
:param edge: 经过边缘检测得到的二值图
:param ThetaDim: hough空间中theta轴的刻度数量(将[0,pi)均分为多少份),反应theta轴的粒度,越大粒度越细
:param DistStep: hough空间中dist轴的划分粒度,即dist轴的最小单位长度
:param threshold: 投票表决认定存在直线的起始阈值
:return: 返回检测出的所有直线的参数(theta,dist)
@author: bilibili-会飞的吴克
'''
imgsize = edge.shape
if ThetaDim == None:
ThetaDim = 90
if DistStep == None:
DistStep = 1
MaxDist = np.sqrt(imgsize[0]**2 + imgsize[1]**2)
DistDim = int(np.ceil(MaxDist/DistStep))
if halfDistWindowSize == None:
halfDistWindowSize = int(DistDim/50)
accumulator = np.zeros((ThetaDim,DistDim)) # theta的范围是[0,pi). 在这里将[0,pi)进行了线性映射.类似的,也对Dist轴进行了线性映射
sinTheta = [np.sin(t*np.pi/ThetaDim) for t in range(ThetaDim)]
cosTheta = [np.cos(t*np.pi/ThetaDim) for t in range(ThetaDim)]
for i in range(imgsize[0]):
for j in range(imgsize[1]):
if not edge[i,j] == 0:
for k in range(ThetaDim):
accumulator[k][int(round((i*cosTheta[k]+j*sinTheta[k])*DistDim/MaxDist))] += 1
M = accumulator.max()
if threshold == None:
threshold = int(M*2.3875/10)
result = np.array(np.where(accumulator > threshold)) # 阈值化
temp = [[],[]]
for i in range(result.shape[1]):
eight_neiborhood = accumulator[max(0, result[0,i] - halfThetaWindowSize + 1):min(result[0,i] + halfThetaWindowSize, accumulator.shape[0]), max(0, result[1,i] - halfDistWindowSize + 1):min(result[1,i] + halfDistWindowSize, accumulator.shape[1])]
if (accumulator[result[0,i],result[1,i]] >= eight_neiborhood).all():
temp[0].append(result[0,i])
temp[1].append(result[1,i])
result = np.array(temp) # 非极大值抑制
result = result.astype(np.float64)
result[0] = result[0]*np.pi/ThetaDim
result[1] = result[1]*MaxDist/DistDim
return result
def drawLines(lines,edge,color = (255,0,0),err = 3):
if len(edge.shape) == 2:
result = np.dstack((edge,edge,edge))
else:
result = edge
Cos = np.cos(lines[0])
Sin = np.sin(lines[0])
for i in range(edge.shape[0]):
for j in range(edge.shape[1]):
e = np.abs(lines[1] - i*Cos - j*Sin)
if (e < err).any():
result[i,j] = color
return result
if __name__=='__main__':
pic_path = './HoughImg/'
pics = os.listdir(pic_path)
for i in pics:
if i[-5:] == '.jpeg' or i[-4:] == '.jpg':
img = plt.imread(pic_path+i)
blurred = cv2.GaussianBlur(img, (3, 3), 0)
plt.imshow(blurred,cmap='gray')
plt.axis('off')
plt.show()
if not len(blurred.shape) == 2:
gray = cv2.cvtColor(blurred, cv2.COLOR_RGB2GRAY)
else:
gray = blurred
edge = cv2.Canny(gray, 50, 150) # 二值图 (0 或 255) 得到 canny边缘检测的结果
lines = lines_detector_hough(edge)
final_img = drawLines(lines,blurred)
plt.imshow(final_img,cmap='gray')
plt.axis('off')
plt.show()
霍夫圆变换
3、角点检测
推荐b站的视频
https://www.bilibili.com/video/av45011346
https://zhuanlan.zhihu.com/p/67770305
具体我们直接使用下面的方法评价角点的强度,大于某个阈值就证明它是角点
下面是上面使用的泰勒展开
4、直方图
手写直方图
3、图像特征提取方法
4、图像旋转、旋转矩阵、像素点怎么填充
5、opencv用过哪些
数据不均衡怎么处理
C++一些语法特性平时项目中会用到吗,比如多态、继承等
C++中内存管理
STL中vector的resize函数、reserve函数
C++中多态了解
C++