在噪声的概念中,通常采用**信噪比(Signal-Noise Rate, SNR)**衡量图像噪声。通俗地姜就是信号占多少,噪声占多少,SNR越小,噪声占比越大。
在信号系统中,计量单位为dB,为 10 l g ( P S / P N ) 10lg(PS/PN) 10lg(PS/PN), P S PS PS与 P N PN PN分别代表信号和噪声的有效功率。
在这里,采用信号像素点的占比充当SNR,以衡量所添加噪声的多少。
举个例子,假设一张图像的高维10,宽为10,共计100个像素点,想让其中20个像素点变为噪声,其余80个像素点保留原值,则这里定义的 S N R = 80 / 100 = 0.8 SNR=80/100=0.8 SNR=80/100=0.8。
# 随机生成符合正态(高斯)分布的随机数,means,sigma为两个参数
import numpy as np
import cv2
from numpy import shape
import random
import matplotlib.pyplot as plt
def GaussianNoise(src, means, sigma, percetage):
NoiseImg = src
NoiseNum = int(percetage * src.shape[0] * src.shape[1])
for i in range(NoiseNum):
# 每次取一个随机点
# 把一张图片的像素用行和列表示的话,randX 代表随机生成的行,randY代表随机生成的列
# random.randint生成随机整数
# 高斯噪声图片边缘不处理,故-1
randX = random.randint(0, src.shape[0] - 1)
randY = random.randint(0, src.shape[1] - 1)
# 此处在原有像素灰度值上加上随机数
NoiseImg[randX, randY] = NoiseImg[randX, randY] + random.gauss(means, sigma)
# 若灰度值小于0则强制为0,若灰度值大于255则强制为255
if NoiseImg[randX, randY] < 0:
NoiseImg[randX, randY] = 0
elif NoiseImg[randX, randY] > 255:
NoiseImg[randX, randY] = 255
return NoiseImg
img = cv2.imread('lenna.png', 0)
img1 = GaussianNoise(img, 2, 4, 0.5)
img = cv2.imread('lenna.png')
b, g, r = cv2.split(img)
img = cv2.merge([r, g, b])
img2 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# cv2.imwrite('lenna_GaussianNoise.png',img1) # 保存图片
plt.subplot(121), plt.imshow(img2, cmap='gray'), plt.title('lenna_source'), plt.axis('off')
plt.subplot(122), plt.imshow(img1, cmap='gray'), plt.title('lenna_GaussianNoise'), plt.axis('off')
plt.show()
import numpy as np
import cv2
from numpy import shape
import random
import matplotlib.pyplot as plt
def pepper_salt_noise(src, percetage):
NoiseImg = src
NoiseNum = int(percetage * src.shape[0] * src.shape[1])
for i in range(NoiseNum): # 返还一个迭代器
# 每次取一个随机点
# 把一张图片的像素用行和列表示的话,randX 代表随机生成的行,randY代表随机生成的列
# random.randint生成随机整数
# 椒盐噪声图片边缘不处理,故-1
randX = random.randint(0, src.shape[0] - 1)
randY = random.randint(0, src.shape[1] - 1)
# random.random生成随机浮点数,随意取到一个像素点有一半的可能是白点255,一半的可能是黑点0
if random.random() <= 0.5:
NoiseImg[randX, randY] = 0
else:
NoiseImg[randX, randY] = 255
return NoiseImg
img = cv2.imread('lenna.png', 0) # 导入图片
img1 = pepper_salt_noise(img, 0.2) # 调pepper_salt_noise函数,0.2为参数
# cv2.imwrite('lenna_PepperandSalt.png',img1) # 在文件夹中写入命名为lenna_PepperandSalt.png的加噪后的图片
img = cv2.imread('lenna.png')
b, g, r = cv2.split(img)
img = cv2.merge([r, g, b])
img2 = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
plt.subplot(121), plt.imshow(img2, cmap='gray'), plt.title('lenna_source'), plt.axis('off')
plt.subplot(122), plt.imshow(img1, cmap='gray'), plt.title('pepper_salt_noise'), plt.axis('off')
plt.show()
泊松噪声:复合泊松分布的噪声模型,泊松分布适合于描述单位时间内随机事件发生的次数的概率分布。如一服务设施在一定时间内受到的服务请求的次数,电话交换机接到呼叫的次数、汽车站台的候车人数、机器出现的故障数、自然灾害发生的次数、DNA序列的变异数、放射性原子核的衰变数等等。
乘性噪声:一般有信道不理想引起,他们与信号的关系是相乘,信号在它在,信号不在它也不在。
瑞利噪声:相比高斯噪声而言,其形状向右歪斜,这对于你和某些歪斜直方图噪声很有用。瑞利噪声的实现可以借由平均噪声来实现。
伽马噪声:其分布服从了伽马曲线的分布。伽马噪声的实现,需要使用b个服从指数分布的噪声叠加而来。指数分布的噪声,可以使用均匀分布来实现。(b=1时为指数噪声,b>1时通过若干个实数噪声叠加,得到伽马噪声)
用scikit-image(skimage)添加各种噪声代码如下:
import cv2 as cv
import numpy as np
from PIL import Image
from skimage import util
import matplotlib.pyplot as plt
'''
def random_noise(image, mode='gaussian', seed=None, clip=True, **kwargs):
功能:为浮点型图片添加各种随机噪声
参数:
image:输入图片(将会被转换成浮点型),ndarray型
mode: 可选择,str型,表示要添加的噪声类型
gaussian:高斯噪声
localvar:高斯分布的加性噪声,在“图像”的每个点处具有指定的局部方差。
poisson:泊松噪声
salt:盐噪声,随机将像素值变成1
pepper:椒噪声,随机将像素值变成0或-1,取决于矩阵的值是否带符号
s&p:椒盐噪声
speckle:均匀噪声(均值mean方差variance),out=image+n*image
seed: 可选的,int型,如果选择的话,在生成噪声前会先设置随机种子以避免伪随机
clip: 可选的,bool型,如果是True,在添加均值,泊松以及高斯噪声后,会将图片的数据裁剪到合适范围内。如果谁False,则输出矩阵的值可能会超出[-1,1]
mean: 可选的,float型,高斯噪声和均值噪声中的mean参数,默认值=0
var: 可选的,float型,高斯噪声和均值噪声中的方差,默认值=0.01(注:不是标准差)
local_vars:可选的,ndarry型,用于定义每个像素点的局部方差,在localvar中使用
amount: 可选的,float型,是椒盐噪声所占比例,默认值=0.05
salt_vs_pepper:可选的,float型,椒盐噪声中椒盐比例,值越大表示盐噪声越多,默认值=0.5,即椒盐等量
--------
返回值:ndarry型,且值在[0,1]或者[-1,1]之间,取决于是否是有符号数
'''
img = cv.imread("lenna.png")
b, g, r = cv.split(img)
img = cv.merge([r, g, b]) # 转为RGB
noise_gaussian_img = util.random_noise(img, mode='gaussian')
noise_poisson_img = util.random_noise(img, mode='poisson')
noise_salt_img = util.random_noise(img, mode='salt')
noise_pepper_img = util.random_noise(img, mode='pepper')
noise_sp_img = util.random_noise(img, mode='s&p')
noise_speckle_img = util.random_noise(img, mode='speckle', mean=0.5, var=0.1)
noise_localvar_img = util.random_noise(img, mode='localvar')
plt.subplot(241), plt.imshow(img), plt.title('lenna_source'), plt.axis('off')
plt.subplot(242), plt.imshow(noise_gaussian_img), plt.title('noise_gaussian_img'), plt.axis('off')
plt.subplot(243), plt.imshow(noise_poisson_img), plt.title('noise_poisson_img'), plt.axis('off')
plt.subplot(244), plt.imshow(noise_salt_img), plt.title('noise_salt_img'), plt.axis('off')
plt.subplot(245), plt.imshow(noise_pepper_img), plt.title('noise_pepper_img'), plt.axis('off')
plt.subplot(246), plt.imshow(noise_sp_img), plt.title('noise_sp_img'), plt.axis('off')
plt.subplot(247), plt.imshow(noise_speckle_img), plt.title('noise_speckle_img'), plt.axis('off')
plt.subplot(248), plt.imshow(noise_localvar_img), plt.title('noise_localvar_img'), plt.axis('off')
plt.show()
1、图像滤波,即在尽量保留细节特征的条件下对目标图像的噪声进行抑制,是图像预处理中不可缺少的操作,其处理效果的好坏直接影响到后续图像处理和分析的有效性和可靠性。
2、消除图像中的噪声成分叫做图像的平滑化和滤波操作。信号或图像的能量大部分集中在幅度谱的低频和中频断是很常见的,而在较高频段,感兴趣的信息经常被噪声研磨。因此一个能降低高频成分幅度的滤波器就能够减弱噪声的影响。
3、平滑滤波是低频增强的空间域滤波技术。它的目的有两类:一类是模糊;另一类是消除噪音。空间域的平滑滤波一般采用简单平均法进行,就是求临近像素点的平均亮度值。邻域的大小和平滑的效果直接相关,因此邻域越大平滑的效果越好,但邻域越大,平滑会使边缘信息损失的越大,从而使输出的图像变得模糊,因此需要合理的选择邻域的大小。
4、关于滤波器,一种形象的比喻是:我们可以把滤波器想象成一个包含加权系数的窗口,当使用这个滤波器平滑处理图像时,就把这个窗口放到图像智商,透过这个窗口来看我们得到的图像。
线性滤波可以说是图像处理最基本的方法,它可以允许我们对图像进行处理,产生很多不同的效果。
1、消除图形中混入的噪声;
2、为图像识别抽取出图像特征。
1、不能损坏图像轮廓即边缘
2、图像视觉效果应当更好
均值滤波,是图像处理中最常用的手段,从频率域观点来看均值滤波就是一种低通滤波器,高频信号将会去掉,因此可以版主消除图像尖锐噪声,实现图像平滑,模糊等功能。理想的均值滤波是每个像素和它周围像素计算出来的平均值替换图像中的每个像素。
g ( x , y ) = 1 M ∑ f ∈ s f ( x , y ) g(x,y)=\frac1M\sum_{f\in s}f(x,y) g(x,y)=M1f∈s∑f(x,y)
中值滤波也是消除图像噪声最常见的手段之一,特别是消除椒盐噪声,中值滤波的效果要比均值滤波更好。中值滤波根据智滤波唯一不同是,不是同均值滤波来替换中心每个像素,而是将周围像素中和中心像素排序后,取中值。
一个3x3带下的中值滤波如下:
优点:抑制效果很好,画面的清晰度基本保持;
缺点:对高斯噪声的抑制效果不是很好。
最大最小值滤波是一种比较保守的图像处理手段,与中值滤波类似,首先要排序周围像素和中心像素值,然后江中心像素值与最大和最小值比较,如果比最小值小,则替换中心像素为最小值,如果中心像素比最大值大,则替换中心像素为最大值。
一个kernel矩阵为3x3的最大最小值滤波如下:
一种同时考虑了像素空间差异与强度差异的滤波器,因此具有保持图像边缘的特性。
先看看高斯滤波器:
W i j = 1 K i e x p ( − ∣ x j − x i ∣ 2 σ 2 ) W_{ij}=\frac1{K_i}exp\left(-\frac{\left|x_j-x_i\right|^2}{\sigma^2}\right) Wij=Ki1exp(−σ2∣xj−xi∣2)
其中W是权重,i和j是像素索引。公式中可以看出,权重和像素之间的空间距离有关系,无论图像的内容是什么,都有相同的滤波效果。
再看看双边滤波器,它只是在原有高斯函数的基础上加了一项:
W i j = 1 K i e x p ( − ∣ x j − x i ∣ 2 σ 2 ) ( − ∣ I j − I i ∣ 2 σ 2 ) W_{ij}=\frac1{K_i}exp\left(-\frac{\left|x_j-x_i\right|^2}{\sigma^2}\right)\left(-\frac{\left|I_j-I_i\right|^2}{\sigma^2}\right) Wij=Ki1exp(−σ2∣xj−xi∣2)(−σ2∣Ij−Ii∣2)
其中I是像素的强度值,所以在强度差距较大的地方(边缘),权重会减小,滤波效应也就变小。总体而言,就像素强度变换不大的区域,双边滤波有类似于高斯滤波的效果,而在图像边缘等强度梯度较大的地方,可以保持梯度。
图像增强可以分为两种:
图像增强现性变换主要对图像的对比度和亮度进行调整 y = a x + b y=ax+b y=ax+b参数a影响图像的对比度,参数b影响图像的亮度,具体可分为以下几种情况:
a > 1 a>1 a>1:增强图像的对比度,图像看起来更加清晰
a < 1 a<1 a<1:减小了图像的对比度,图像看起来变模糊
a = 1 a n d b ≠ 0 a=1\;and \;b\neq0 a=1andb=0:图像整体的灰度值上移或者下移,也就是图像整体变亮或者变暗,不会改变图像的对比度, b > 0 b>0 b>0时图像变亮, b < 0 b<0 b<0时图像变暗
a = − 1 a n d b = 255 a=-1\;and \;b=255 a=−1andb=255:图像翻转
即对处于某个感兴趣的区域x,将其对比系数a增大或减小,从而增大或减小这个区域的对比度。
{ y = a 1 x + b x < x 1 y = a 2 x + b x 1 < x < x 2 y = a 3 x + b x 2 < x \left\{\begin{array}{l}y=a_1x+b\;\;x
对数变换讲=将图像的灰度值部分扩展,即将高灰度部分压缩,已达到增强图像低灰度部分的目的,同时可以很好地压缩像素值变化较大的图像的动态范围,目的就是突出我们需要的细节。
y = c log ( 1 + x ) y=c\log(1+x) y=clog(1+x)
幂律变换主要用于图像的矫正,对漂白的图片或者过黑的图片可以进行修正。 y = c x γ y=cx^\gamma y=cxγ根据 γ \gamma γ的大小,主要可分为以下两种情况:
γ > 1 \gamma>1 γ>1:处理漂白的图片,进行灰度级压缩
γ < 1 \gamma<1 γ<1:处理过黑的图片,对比度增强,是的细节看的更加清楚。
直方图均值化
图像滤波
opencv对于读进来的图片的通道排列是BGR,而不是主流的RGB!谨记!
# opencv读入的矩阵是BGR,可用如下代码转为RGB
img = cv2.imread("lena.png")
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
1、除了opencv读入的彩色图片以BGR顺序存储外,其他所有图像库读入彩色图片都已RGB存储。
2、除了PIL读入图片时img类之外,其他库读进来的图都是numpy矩阵形式。
3、各大图像库的性能,最好的OpenCV,无论是速度还是图片操作的全面性,都属于碾压的存在,毕竟它是一个巨大的cv专用库。
1、图像的基本曹组读取、显示、存储:通过调用opencv中的cv2.imread(),cv2.imshow(),cv2.write()分别实现;
2、在opencv中实现将彩色像素转化为灰度像素。
3、图像的几何变换:平移、缩放、旋转、插值(最邻近、双线性)
4、对比增强:线性变换、伽马变换、直方图均衡化
5、边缘检测:Sobel、Laplace、Canny
6、图像的二维滤波:cvFilter2D
什么是线性行回归?
举个例子,某商品的利润在售价为2元、5元、10元时分别为4元、10元、20元。我们很容易得出商品利润与售价的关系复合直线: y = 2 x y=2x y=2x.
在上面这个简单的一元线性回归方程中,我们称“2”为回归系数,即斜率为回归系数。回归系数表示商品的售价(x)每变动一个单位,期利润(y)与之对应的变动关系。
线性回归表示这些离散的点总体上最逼近哪条直线。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
sales = pd.read_csv('train_data.csv', sep=r'\s*,\s*', engine='python') # 读取CSV
X = sales['X'].values # 存csv的第一列
Y = sales['Y'].values # 存csv的第二列
def get_data(slope, intercept, x_lim):
x_vals = np.array(x_lim)
y_vals = intercept + slope * x_vals
return x_vals, y_vals
# 初始化赋值
s1 = 0
s2 = 0
s3 = 0
s4 = 0
n = 4 # 你需要根据的数据量进行修改
# 循环累加
for i in range(n):
s1 = s1 + X[i] * Y[i] # X*Y,求和
s2 = s2 + X[i] # X的和
s3 = s3 + Y[i] # Y的和
s4 = s4 + X[i] * X[i] # X**2,求和
# 计算斜率和截距
k = (s2 * s3 - n * s1) / (s2 * s2 - s4 * n)
b = (s3 - k * s2) / n
print("Slope: {} Intercept: {}".format(k, b))
xx, yy = get_data(k, b, [min(X)-1, max(X)+1])
plt.scatter(X, Y, marker='.', color='red', s=40, label='original point')
plt.plot(xx, yy, 'b', label='least_square'), plt.title('least_square'), plt.xlim(min(X)-1, max(X)+1)
plt.legend(loc='best')
plt.show()
运行结果如下:
Slope: 1.4 Intercept: 3.5
RANSAC算法的输入:
1、一组观测数据(往往含有较大的噪声或无效点),
2、一个用于解释观测数据的参数化模型
3、一些可信的参数
RANSAC算法的步骤:
1、在数据中随机选择几个点设定为内群
2、计算适合内群的模型
3、把其他刚才没选到的点带入刚才建立的模型汇总,计算是否为内群
4、记下内群数量
5、重复以上步骤
6、比较哪次计算中内群数量最多,内群数量最多的哪次所建的模型就是我们所要求的解
注意:不同问题对应的数学模型不同,英雌在计算模型参数是方法必定不同,RANSAC的作用不在于计算模型参数,而是提供更好的输入数据(样本)。(这是ransac的缺点在于要求数学模型已知)
其代码实现如下:
import numpy as np
import scipy as sp
import scipy.linalg as sl
def ransac(data, model, n, k, t, d, debug=False, return_all=False):
"""
输入:
data - 样本点
model - 假设模型:事先自己确定
n - 生成模型所需的最少样本点
k - 最大迭代次数
t - 阈值:作为判断点满足模型的条件
d - 拟合较好时,需要的样本点最少的个数,当做阈值看待
输出:
bestfit - 最优拟合解(返回nil,如果未找到)
iterations = 0
bestfit = nil #后面更新
besterr = something really large #后期更新besterr = thiserr
while iterations < k
{
maybeinliers = 从样本中随机选取n个,不一定全是局内点,甚至全部为局外点
maybemodel = n个maybeinliers 拟合出来的可能符合要求的模型
alsoinliers = emptyset #满足误差要求的样本点,开始置空
for (每一个不是maybeinliers的样本点)
{
if 满足maybemodel即error < t
将点加入alsoinliers
}
if (alsoinliers样本点数目 > d)
{
%有了较好的模型,测试模型符合度
bettermodel = 利用所有的maybeinliers 和 alsoinliers 重新生成更好的模型
thiserr = 所有的maybeinliers 和 alsoinliers 样本点的误差度量
if thiserr < besterr
{
bestfit = bettermodel
besterr = thiserr
}
}
iterations++
}
return bestfit
"""
iterations = 0
bestfit = None
besterr = np.inf # 设置默认值
best_inlier_idxs = None
while iterations < k:
maybe_idxs, test_idxs = random_partition(n, data.shape[0])
print('test_idxs = ', test_idxs)
maybe_inliers = data[maybe_idxs, :] # 获取size(maybe_idxs)行数据(Xi,Yi)
test_points = data[test_idxs] # 若干行(Xi,Yi)数据点
maybemodel = model.fit(maybe_inliers) # 拟合模型
test_err = model.get_error(test_points, maybemodel) # 计算误差:平方和最小
print('test_err = ', test_err < t)
also_idxs = test_idxs[test_err < t]
print('also_idxs = ', also_idxs)
also_inliers = data[also_idxs, :]
if debug:
print('test_err.min()', test_err.min())
print('test_err.max()', test_err.max())
print('numpy.mean(test_err)', numpy.mean(test_err))
print('iteration %d:len(alsoinliers) = %d' % (iterations, len(also_inliers)))
# if len(also_inliers > d):
print('d = ', d)
if (len(also_inliers) > d):
betterdata = np.concatenate((maybe_inliers, also_inliers)) # 样本连接
bettermodel = model.fit(betterdata)
better_errs = model.get_error(betterdata, bettermodel)
thiserr = np.mean(better_errs) # 平均误差作为新的误差
if thiserr < besterr:
bestfit = bettermodel
besterr = thiserr
best_inlier_idxs = np.concatenate((maybe_idxs, also_idxs)) # 更新局内点,将新点加入
iterations += 1
if bestfit is None:
raise ValueError("did't meet fit acceptance criteria")
if return_all:
return bestfit, {'inliers': best_inlier_idxs}
else:
return bestfit
def random_partition(n, n_data):
"""return n random rows of data and the other len(data) - n rows"""
all_idxs = np.arange(n_data) # 获取n_data下标索引
np.random.shuffle(all_idxs) # 打乱下标索引
idxs1 = all_idxs[:n]
idxs2 = all_idxs[n:]
return idxs1, idxs2
class LinearLeastSquareModel:
# 最小二乘求线性解,用于RANSAC的输入模型
def __init__(self, input_columns, output_columns, debug=False):
self.input_columns = input_columns
self.output_columns = output_columns
self.debug = debug
def fit(self, data):
# np.vstack按垂直方向(行顺序)堆叠数组构成一个新的数组
A = np.vstack([data[:, i] for i in self.input_columns]).T # 第一列Xi-->行Xi
B = np.vstack([data[:, i] for i in self.output_columns]).T # 第二列Yi-->行Yi
x, resids, rank, s = sl.lstsq(A, B) # residues:残差和
return x # 返回最小平方和向量
def get_error(self, data, model):
A = np.vstack([data[:, i] for i in self.input_columns]).T # 第一列Xi-->行Xi
B = np.vstack([data[:, i] for i in self.output_columns]).T # 第二列Yi-->行Yi
B_fit = sp.dot(A, model) # 计算的y值,B_fit = model.k*A + model.b
err_per_point = np.sum((B - B_fit) ** 2, axis=1) # sum squared error per row
return err_per_point
def test():
# 生成理想数据
n_samples = 500 # 样本个数
n_inputs = 1 # 输入变量个数
n_outputs = 1 # 输出变量个数
A_exact = 20 * np.random.random((n_samples, n_inputs)) # 随机生成0-20之间的500个数据:行向量
perfect_fit = 60 * np.random.normal(size=(n_inputs, n_outputs)) # 随机线性度,即随机生成一个斜率
B_exact = sp.dot(A_exact, perfect_fit) # y = x * k
# 加入高斯噪声,最小二乘能很好的处理
A_noisy = A_exact + np.random.normal(size=A_exact.shape) # 500 * 1行向量,代表Xi
B_noisy = B_exact + np.random.normal(size=B_exact.shape) # 500 * 1行向量,代表Yi
if 1:
# 添加"局外点"
n_outliers = 100
all_idxs = np.arange(A_noisy.shape[0]) # 获取索引0-499
np.random.shuffle(all_idxs) # 将all_idxs打乱
outlier_idxs = all_idxs[:n_outliers] # 100个0-500的随机局外点
A_noisy[outlier_idxs] = 20 * np.random.random((n_outliers, n_inputs)) # 加入噪声和局外点的Xi
B_noisy[outlier_idxs] = 50 * np.random.normal(size=(n_outliers, n_outputs)) # 加入噪声和局外点的Yi
# setup model
all_data = np.hstack((A_noisy, B_noisy)) # 形式([Xi,Yi]....) shape:(500,2)500行2列
input_columns = range(n_inputs) # 数组的第一列x:0
output_columns = [n_inputs + i for i in range(n_outputs)] # 数组最后一列y:1
debug = False
model = LinearLeastSquareModel(input_columns, output_columns, debug=debug) # 类的实例化:用最小二乘生成已知模型
linear_fit, resids, rank, s = sp.linalg.lstsq(all_data[:, input_columns], all_data[:, output_columns])
# run RANSAC 算法
ransac_fit, ransac_data = ransac(all_data, model, 50, 1000, 7e3, 300, debug=debug, return_all=True)
if 1:
import pylab
sort_idxs = np.argsort(A_exact[:, 0])
A_col0_sorted = A_exact[sort_idxs] # 秩为2的数组
if 1:
pylab.plot(A_noisy[:, 0], B_noisy[:, 0], 'k.', label='data') # 散点图
pylab.plot(A_noisy[ransac_data['inliers'], 0], B_noisy[ransac_data['inliers'], 0], 'bx',
label="RANSAC data")
else:
pylab.plot(A_noisy[non_outlier_idxs, 0], B_noisy[non_outlier_idxs, 0], 'k.', label='noisy data')
pylab.plot(A_noisy[outlier_idxs, 0], B_noisy[outlier_idxs, 0], 'r.', label='outlier data')
pylab.plot(A_col0_sorted[:, 0],
np.dot(A_col0_sorted, ransac_fit)[:, 0],
label='RANSAC fit')
pylab.plot(A_col0_sorted[:, 0],
np.dot(A_col0_sorted, perfect_fit)[:, 0],
label='exact system')
pylab.plot(A_col0_sorted[:, 0],
np.dot(A_col0_sorted, linear_fit)[:, 0],
label='linear fit')
pylab.legend()
pylab.show()
if __name__ == "__main__":
test()
1、针对某个场景拍摄多张/序列图像
2、通过匹配特征(sift匹配)计算下一张图像与上一张图像之间的变换结构。
3、图像映射,将下一张图像叠加到上一张图像的坐标系中
4、变换后的融合/合成
优点:
1、它能鲁棒的估计模型参数。例如,他能从包含大量局外点的数据集中估计出高精度的参数。
缺点:
1、它计算参数的迭代次数没有上限;如果设置迭代次数上限,得到的结果可能不是最优的结果,甚至可能得到错误的结果;
2、只有一定的概率得到可信的模型,概率与迭代次数成正比;
3、它要求实则根问题相关的阈值;
4、RACSAC智能从特定数据集中估计出一个模型,如果存在两个(或多个模型),RACSAC不能找到别的模型;
5、要求数学模型已知。
哈希算法作为一种加密函数,其拥有两个最重要的特点:
1、不可逆性。输入信息得出输出的那个看似乱码的字符串(哈希值)非常容易,但是从输出的字符反推处输入的记过却非常非常困难。
2、输出值唯一性和不可预测性。只要输入的信息有一点点区别,那么根据哈希算法得出来的输出值也相差甚远。
两个整数之间的汉明距离指的是这两个数字对应二进制不同的位置的数目。
例:输入:x=1,y=4 ;输出:2
1、缩放:图片所防伪8*8,保留结构,删除细节。
2、灰度化:转化为灰度图。
3、求平局值:计算灰度图所有像素的平均值。
4、比较:像素值大于平均值记作1,相反记作0,总共64位。
5、生成哈希:将上述步骤生成的1和0按顺序组合起来就是图片的指纹
6、对比指纹:将两幅图的指纹对比,计算汉明距离,即两个64位的hash值有多少位是不一样的,不相同位数越少,图片越相似。
差值哈希算法相较于均值哈希算法,前期和后期基本相同,只有中间比较hash有变化。
1、缩放:图片所防伪8*9,保留结构,删除细节。
2、灰度化:转化为灰度图。
3、求平局值:计算灰度图所有像素的平均值。
4、比较:像素值大于后一个像素值记作1,相反记作0。本行不予下一行做对比,每行9个像素,八个差值,有8行,总共64位。
5、生成哈希:将上述步骤生成的1和0按顺序组合起来就是图片的指纹
6、对比指纹:将两幅图的指纹对比,计算汉明距离,即两个64位的hash值有多少位是不一样的,不相同位数越少,图片越相似。
均值哈希算法过于严格,不够精确,更适合搜索缩略图,为了获得更精准的记过可以选择感知哈希算法,它采用的是DCT(离散余弦变换)来降低频率的方法。
1、缩小图片:3232是一个比较好的大小,这样方便DCT计算;
2、转化为灰度图:把缩放后的图片转换为灰度图;
3、计算DCT:DCT把图片分离成分率的几何;
4、缩小DCT:DCT计算后的矩阵是3232,保留左上角的8*8,这些图片代表图片的最低频率;
5、计算平均值:计算缩小DCT后所有像素点的平均值;
6、进一步减小DCT:大于平均值记录为1,反之记录为0;
7、得到信息指纹:组合64个信息为,顺序随意保持一致性;
8、最后比对两张图片的指纹,获得汉明距离即可。
import cv2
import numpy as np
# 均值哈希算法
def aHash(img):
# 缩放为8*8
img = cv2.resize(img, (8, 8), interpolation=cv2.INTER_CUBIC)
# 转换为灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# s为像素和初值为0,hash_str为hash值初值为''
s = 0
hash_str = ''
# 遍历累加求像素和
for i in range(8):
for j in range(8):
s = s + gray[i, j]
# 求平均灰度
avg = s / 64
# 灰度大于平均值为1相反为0生成图片的hash值
for i in range(8):
for j in range(8):
if gray[i, j] > avg:
hash_str = hash_str + '1'
else:
hash_str = hash_str + '0'
return hash_str
# 差值感知算法
def dHash(img):
# 缩放8*9
img = cv2.resize(img, (9, 8), interpolation=cv2.INTER_CUBIC)
# 转换灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
hash_str = ''
# 每行前一个像素大于后一个像素为1,相反为0,生成哈希
for i in range(8):
for j in range(8):
if gray[i, j] > gray[i, j + 1]:
hash_str = hash_str + '1'
else:
hash_str = hash_str + '0'
return hash_str
# Hash值对比
def cmpHash(hash1, hash2):
n = 0
# hash长度不同则返回-1代表传参出错
if len(hash1) != len(hash2):
return -1
# 遍历判断
for i in range(len(hash1)):
# 不相等则n计数+1,n最终为相似度
if hash1[i] != hash2[i]:
n = n + 1
return n
img1 = cv2.imread('lenna.png')
img2 = cv2.imread('lenna_noise.png')
hash1 = aHash(img1)
hash2 = aHash(img2)
print(hash1)
print(hash2)
n = cmpHash(hash1, hash2)
print('均值哈希算法相似度:', n)
hash1 = dHash(img1)
hash2 = dHash(img2)
print(hash1)
print(hash2)
n = cmpHash(hash1, hash2)
print('差值哈希算法相似度:', n)
运行结果如下:
1011111010011110100111011010100110101011101000110000111000101100
1011011010011110100111011010100110101011101000111010111000101100
均值哈希算法相似度: 3
1000100110001101101000101010010001000110111011001010010110000011
1001100110001101100000101110010011000110011011000010010111000011
差值哈希算法相似度: 7