【更新2023/12/7】博客涉及代码部分已开源在github,需要自取,您的star⭐就是对我最大的支持💖:https://github.com/Scienthusiasts/cv-exp/tree/main/exp1
1.什么是直方图
直方图是可以对整幅图的灰度分布进行整体了解的图示,通过直方图我们可以对图像的对比度、亮度和灰度分布等有一个直观了解。图像的直方图用来形象描绘该图像像素值的分布情况。我们用一定数目的小区间(bin)来指定表征像素值的范围,每个小区间会得到落入该小区间表示范围的像素数目。因此直方图不能显示图像中某像素所在的空间位置信息。同时也需要注意一点,不同的图像可能会有相同的直方图,所以不能用单独的直方图去恢复图像.
绘制灰度图像直方图
import matplotlib.pyplot as plt
from PIL import Image
import numpy as np
import cv2
import sys;sys.path.append('../')
import utils
img = cv2.imread('luda04.jpg')[:,:, [0]]
# 图像reshape
img, h, w = utils.auto_reshape(img, 480)
# 计算直方图
img_eqhist = utils.histogram(img)
# 绘制直方图
utils.plot_hist(img, img_eqhist)
绘制彩色图像直方图
img = cv2.imread('luda04.jpg')[:,:, [2,1,0]]
# 图像reshape
img, h, w = utils.auto_reshape(img, 480)
# 计算直方图
img_eqhist = utils.histogram(img)
# 绘制直方图
utils.plot_hist(img, img_eqhist)
直方图均衡化
直方图均衡化可以用来改善图像的全局亮度和对比度。
直方图均衡化是指将一幅图像的灰度直方图变平,使变换后的图像中每个灰度值的分布概率都相同。在对图像做进一步处理之前,直方图均衡化通常是对图像灰度值进行归一化的一个非常好的方法,并且可以增强图像的对比度。
均衡化前后效果对比
均衡化图像直方图:
2.高斯滤波
高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,广泛应用于图像处理的减噪过程。 可以简单的理解为,高斯滤波就是对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值经过加权平均后得到。
高斯滤波和高斯模糊:
高斯滤波也叫做高斯平滑和高斯滤波。为什么叫做高斯滤波呢?那是因为对图像进行滤波操作。那为什么要加上高斯呢,那是因为卷积核(掩膜)是由高斯分布计算出来的所以就需要加上高斯两字。其实滤波范围比模糊要大,滤波还有高通滤波、低通滤波等。为什么叫做高斯模糊呢,是因为通过这个操作可以让图片变得模糊。那为什么又叫高斯平滑呢,那是因为使图像更加平滑了(平滑是图片变得更加平缓,更加模糊,不那么尖锐)。
高斯滤波的基本原理参考我之前写的一篇博客:【OpenCV学习2】图像滤波
3.utils.py
自定义函数库:
import numpy as np
import random
import cv2
import copy
import matplotlib.pyplot as plt
# 图像reshape
def auto_reshape(img, lim):
h, w = img.shape[:-1]
if h > w:
w = int(lim * w / h)
h = lim
else:
h = int(lim * h / w)
w = lim
img = cv2.resize(img, dsize=(w, h))
return img, h, w
# 图像直方图
def histogram(img):
channels = img.size // (img.shape[0] * img.shape[1])
if(channels == 3):
hist = np.zeros((3, 256))
for i in range(3):
for pix in img[:,:,i].reshape(-1):
hist[i, pix] += 1
else:
hist = np.zeros(256)
for pix in img.reshape(-1):
hist[pix] += 1
hist /= img.shape[0] * img.shape[1]
return hist
# 可视化图像直方图
def plot_hist(img, hist):
channels = img.size // (img.shape[0] * img.shape[1])
plt.figure(figsize=(19, 4))
plt.subplot(1,2 + channels,1)
plt.imshow(img)
plt.title('image')
plt.axis('off')
if channels == 3:
c = ["red", "green", "blue"]
plt.subplot(1,5,2)
for i in range(3):
plt.plot(hist[i], color=c[i], linewidth=1)
plt.ylim(0)
plt.grid(linestyle='-.')
plt.legend(c)
for i in range(channels):
plt.subplot(1,5,i+3)
plt.bar(range(256), hist[i], color=c[i])
plt.subplots_adjust(left=0.05,bottom=0.1,right=0.98,top=0.95,wspace=0.4,hspace=0.07)
plt.legend(c[i])
plt.grid(linestyle='-.')
else:
plt.subplot(1,3,2)
print(hist.shape)
plt.plot(hist, color='black', linewidth=1)
plt.ylim(0)
plt.grid(linestyle='-.')
plt.legend(["gray"])
plt.subplot(1,3,3)
plt.bar(range(256), hist, color='black')
plt.subplots_adjust(left=0.05,bottom=0.1,right=0.98,top=0.95,wspace=0.4,hspace=0.07)
plt.savefig('./histogram.jpg',dpi=200)
plt.legend(["gray"])
plt.grid(linestyle='-.')
plt.savefig('./histogram.jpg',dpi=200)
plt.show()
# 直方图均衡化
def histEqualize(img):
channels = img.size // (img.shape[0] * img.shape[1])
if channels == 3:
b, g, r = [cv2.equalizeHist(img[:,:,i]) for i in range(3)]
return cv2.merge((b, g, r))
else:
return cv2.equalizeHist(img)
# 可视化对比结果
def view_contrast(imgseries):
length = len(imgseries)
imgs = list(imgseries.values())
labels = list(imgseries.keys())
for i in range(length):
plt.subplot(1, length, i+1)
plt.imshow(imgs[i])
plt.title(labels[i])
plt.axis('off')
plt.subplots_adjust(left=0.02,bottom=0.01,right=0.98,top=0.99,wspace=0.2,hspace=0.02)
plt.show()