来自这篇博客的定义:
高斯模糊: 基于权重,权重只考虑像素空间的分布,中间的权重大,边缘的权重小。没有考虑像素值之间的差异问题,没有考虑边缘。
边缘保留滤波: 像素之间的差异很大,说明是显著特征,如果直接平滑(滤波),显著特征会消失。像素之间差异大的地方通常是边缘,所以边缘保留滤波处理后的图片,在平滑(滤波)的情况下,依旧能够保留图像的边缘。
边缘保留滤波EFP:其实就是磨皮效果!!!保留边缘,像素差异小的地方进行模糊处理
import cv2 as cv
import numpy as np
def bi_demo(image):
dst=cv.bilateralFilter(image,0,100,15) #磨皮 高斯双边滤波
cv.imshow('bi_demo',dst)
def shift_demo(image): #磨皮
dst=cv.pyrMeanShiftFiltering(image,0,100,100) #均值迁移,类似油画
cv.imshow('shift_demo',dst)
src=cv.imread('C:\\Users\\22852\\Desktop\\opencv\\data\\girl.jpg')
# cv.namedWindow("input image",cv.WINDOW_AUTOSIZE)
cv.imshow("input image:",src)
bi_demo(src)
shift_demo(src)
cv.waitKey(0)
cv.destroyAllWindows()
- 直方图的 x 轴是灰度值( 0 到 255), y 轴是图片中具有同一个灰度值的点的数目
- 通过直方图可以对图像的对比度,亮度,灰度分布进行了解
对应直方图如下:
通过直方图可以看出图片整体过亮,对比度大,有四个波峰。
代码:
def plot_demo(image):
plt.hist(image.ravel(),256,[0,256])
plt.show()
def image_hist(image):
color=('blue','green','red')
for i ,color in enumerate(color):
hist=cv.calcHist([image],[i],None,[256],[0,256])
plt.plot(hist,color)
plt.xlim([0,256])
plt.show()
代码:
def equalHist_demo(image):#直方图均衡化
gray=cv.cvtColor(image,cv.COLOR_BGR2GRAY)
dst=cv.equalizeHist(gray)
cv.imshow('equalHist_demo',dst)
参考
equalizeHist这种全局的均衡化也会存在一些问题,由于整体亮度的提升,也会使得局部图像的细节变得模糊,因为我们需要进行分块的局部均衡化操作
def claHe_demo(image):#局部自适应直方图均衡化
gray=cv.cvtColor(image,cv.COLOR_BGR2GRAY)
clache=cv.createCLAHE(clipLimit=3.0,tileGridSize=(8,8))
dst=clache.apply(gray)
cv.imshow('clahe_demo',dst)
cv.compareHist:
相关系数:值越大,相关度越高[0~1]
卡方系数:值越小,相关度越高[0~]
相交系数: 值越大,相关度越高[0~9.455319]
巴氏距离:值越小,相关度越高[0~1]
def create_rgb_hist(image):
h,w,c = image.shape
rgbHist=np.zeros([16*16*16,1],np.float32)
bsize=256/16
for row in range(h):
for col in range(w):
b=image[row,col,0]
g=image[row,col,1]
r=image[row,col,2]
index=int(b/bsize+16+16+g/bsize+16+r/bsize)
rgbHist[index,0]=rgbHist[index,0]+1
return rgbHist
def hist_compare(image1,image2): #比较
hist1=create_rgb_hist(image1)
hist2=create_rgb_hist(image2)
match1=cv.compareHist(hist1,hist2,cv.HISTCMP_BHATTACHARYYA)
match2=cv.compareHist(hist1,hist2,cv.HISTCMP_CORREL)
match3 = cv.compareHist(hist1, hist2, cv.HISTCMP_CHISQR)
print("巴氏距离: %s,相关性: %s,卡方: %s"%(match1,match2,match3))
巴氏距离: 0.9134011518713788,相关性: 0.06669171290986387,卡方: 468.4549783549784
以上为自己写的直方图,也可以直接用API计算的直方图进行比较和计算
实际上是原图像的256个灰度值(0~255)划分为对应几个区间,反向投影矩阵中某点的值就是它对应的原图像中的点所在区间的灰度直方图值。
所以,一个区间点越多,在反向投影矩阵中就越亮。
如果两幅图的反向投影矩阵相似或相同,那么我们就可以判定这两幅图这个特征是相同的。
参考
def hist2d_demo(image):
hsv=cv.cvtColor(image,cv.COLOR_BGR2HSV)
hist=cv.calcHist([hsv],[0,1],None,[180,256],[0,180,0,256])
cv.imshow("hist2d",hist)
plt.imshow(hist,interpolation='nearest')
plt.title('2D Histogram')
plt.show()
cv.calcBackProject:
反向投影可以用来做图像分割, 或者在图像中找寻我们感兴趣的部分。 它会输出与输入图像(待搜索)同样大小的图像,
其中的每一个像素值代表了输入图像上对应点属于目标对象的概率。
输出图像中像素值越高(越白)的点就越可能代表我们要搜索的目标(在输入图像所在的位置)。 直方图投影经常与camshift 算法等一起使用。
步骤:
- 为一张包含我们要查找目标的图像创建直方图, 我们要查找的对象要尽量占满这张图像。 最好使用颜色直方图,因为一个物体的颜色要比它的灰度能更好的被用来进行图像分割与对象识别。
- 再把这个颜色直方图投影到输入图像中寻找我们的目标, 也就是找到输入图像中的每一个像素点的像素值在直方图中对应的概率,这样我们就得到一个概率图像。
- 设置适当的阈值对概率图像进行二值化
参考
def back_project_demo(sample,target):
roi_hsv = cv.cvtColor(sample, cv.COLOR_BGR2HSV)
target_hsv = cv.cvtColor(target, cv.COLOR_BGR2HSV)
roiHist = cv.calcHist([roi_hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
# 归一化: 原始图像,结果图像,映射到结果图像中的最小值,最大值,归一化类型
# cv.NORM_MINMAX对数组的所有值进行转化,使它们线性映射到最小值和最大值之间
# 归一化后的图像便于显示, 归一化后到0~255之间
cv.normalize(roiHist, roiHist, 0, 255, cv.NORM_MINMAX)
# images, channels, hist, ranges, scale,
dst = cv.calcBackProject([target_hsv], [0, 1], roiHist, [0, 180, 0, 256], 1)
cv.imshow("backProjectionDemo", dst)
代码
def countours_demo(image):
dst=cv.GaussianBlur(image,(3,3),0)#高斯滤波
# img=cv.cvtColor(image,cv.COLOR_BGR2GRAY)
img=cv.cvtColor(dst,cv.COLOR_BGR2GRAY)
ret,binary=cv.threshold(img,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU)
cv.imshow("binary:",binary)
# binary=edge_demo(binary)
img, contours, hierarchy=cv.findContours(binary,cv.RETR_LIST,cv.CHAIN_APPROX_SIMPLE)#cv.RETR_LIST发现所有形状
# contours, hierarchy=cv.findContours(binary,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)#cv.RETR_EXTERNAL只发现边缘
for i,contour in enumerate(contours):
# cv.drawContours(image,contours,i,[0,0,255])
# cv.drawContours(image,contours,i,[0,0,255],-1)#填充
cv.drawContours(image,contours,i,[0,0,255],2)#填充
print(i)
cv.imshow("circles:",image)
cv.RETR_EXTERNAL只发现边缘,线宽2
cv.RETR_LIST发现所有形状,线宽2,cv.drawContours:-1填充
def edge_demo(image):
blurred=cv.GaussianBlur(image,(3,3),0)#高斯滤波
#sigmaX Gaussian kernel standard deviation in X direction.
gray=cv.cvtColor(blurred,cv.COLOR_BGR2GRAY)
xgrad=cv.Sobel(gray,cv.CV_16SC1,1,0)
ygrad=cv.Sobel(gray,cv.CV_16SC1,0,1)
dst1=cv.Canny(xgrad,ygrad,50,150)
dst2=cv.Canny(image,50,150)
dst3=cv.Canny(gray,50,150)
cv.imshow("Candy Edge_xygrad:",dst1)
cv.imshow("Candy Edge_image:",dst2)
cv.imshow("Candy Edge_gray:",dst3)
return dst1
def countours_demo(image):
dst=cv.GaussianBlur(image,(3,3),0)#高斯滤波
# # img=cv.cvtColor(image,cv.COLOR_BGR2GRAY)
# img=cv.cvtColor(dst,cv.COLOR_BGR2GRAY)
# ret,binary=cv.threshold(img,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU)
# cv.imshow("binary:",binary)
binary=edge_demo(dst)
img, contours, hierarchy=cv.findContours(binary,cv.RETR_LIST,cv.CHAIN_APPROX_SIMPLE)#cv.RETR_LIST发现所有形状
# img,contours, hierarchy=cv.findContours(binary,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)#cv.RETR_EXTERNAL只发现边缘
for i,contour in enumerate(contours):
# cv.drawContours(image,contours,i,[0,0,255])
# cv.drawContours(image,contours,i,[0,0,255],2)#2为线的宽度
cv.drawContours(image,contours,i,[0,0,255],-1)#填充
print(i)
cv.imshow("circles:",image)
只发现边缘
发现所有形状
填充