[opencv][python] 学习手册2:练习代码2
26_灰度图的直方图.py
27_灰度直方图api.py
28_灰度图的直方图均衡化.py
29_灰度图直方图均衡化-api.py
30_彩色图像的直方图.py
31_彩色图像直方图均衡化.py
文章目录
26_灰度图的直方图.py
概念
在统计学中,直方图(英语:Histogram)是一种对数据分布情况的图形表示,是一种二维统计图表,它的两个坐标分别是统计样本(横坐标)和该样本对应的某个属性的度量(纵坐标),以长条图(bar)的形式具体表现。因为直方图的长度及宽度很适合用来表现数量上的变化,所以较容易解读差异小的数值。(wiki)
在灰度图直方图中,统计样本(横坐标)是灰度值的分布范围(对 np.uint8 类型,0-255),样本统计值(纵坐标)是每一个灰度值在图像中出现的总次数。
代码
"""
需求:
统计灰度图中每一个灰度值出现的次数
并绘制灰度值次数直方图
1.读取图像,获取信息
2.定义一个0-255的容器,x轴:灰度值,y轴:出现次数
3.统计
4.绘制直方图
"""
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
# 1.读取图像,获取信息
filename = r"../img/lena.jpg"
src = cv.imread(filename, cv.IMREAD_COLOR)
src_gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
height = src.shape[0]
width = src.shape[1]
# 2.定义一个0-255的容器,x轴:灰度值,y轴:出现次数
statistic_array = np.zeros(256, np.int)
# 3.统计
for row in range(height):
for col in range(width):
color = src_gray[row, col]
statistic_array[color] += 1
# 4.绘制直方图
x = np.linspace(0, 255, 256)
y = statistic_array
plt.bar(x, y, width=0.8, color="red")
cv.imshow("src", src)
plt.show()
cv.waitKey(0)
运行结果
27_灰度直方图api.py
代码
"""
需求:
统计灰度图中每一个灰度值出现的次数
并绘制灰度值次数直方图
1.读取图像,获取信息
2.使用 cv 的 api calcHist 绘制直方图
3.使用 plt 的 hist 绘制直方图
"""
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
# 1.读取图像,获取信息
filename = r"../img/lena.jpg"
src = cv.imread(filename, cv.IMREAD_COLOR)
src_gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
# 2.使用 cv 的 api calcHist 绘制直方图
# # 1. 计算直方图
hist = cv.calcHist([src_gray], [0], None, [256], [0, 256])
# # 2. 绘制直方图
plt.figure()
plt.plot(hist, color="red")
# 3.使用 plt 的 hist 绘制直方图
# print(src_gray.shape) # (400, 400)
# print(src_gray.ravel().shape) # (160000,), A 1-D array, containing the elements of the input, is returned. np.ravel
plt.figure()
plt.hist(src_gray.ravel(), bins=256, rwidth=0.8)
plt.show()
运行结果
补充
使用matplotlib绘制直方图有两种方式
方式一:
# 使用api将直方图数据计算好 图片 通道 掩膜 数量 值的范围
hist = cv.calcHist([grayImg],[0],None,[256],[0.0,255.0])
# 调用plot函数显示
plt.plot(hist,color="green")
plt.show()
方式二:
# 1.使用Img.ravel()将多行的矩阵转成单行的矩阵
# 2. 然后调用matplot的hist函数自动计算直方图,bins表示像素区间数量
plt.hist(grayImg.ravel(),color="red",bins=256)
plt.show()
28_灰度图的直方图均衡化.py
概念
- 直方图均衡化是将原图象的直方图通过变换函数修正为均匀的直方图,然后按均衡直方图修正原图象。图象均衡化处理后,图象的直方图是平直的,即各灰度级具有相同的出现频数,那么由于灰度级具有均匀的概率分布,图象看起来就更清晰了。
- 经过直方图均衡化处理之后,我们整个图像的颜色变化就是一种平滑变化的状态
代码
"""
需求:
对灰度图像进行手动直方图均衡化
不借助 api,全手工
算法:
1. 计算图像的直方图(颜色统计报告,x:颜色值,y:颜色出现次数)
2. 计算概率直方图(x:颜色值,y:次数概率 = 次数 / 像素总数),通过直方图
3. 计算累积概率直方图,通过概率直方图
4. 对图像进行均衡化,old_color -> sum_ration ->_new color
步骤:
1. 读取图像,获取信息,转化成灰度图
2. 直方图均衡化
3. 显示图像,等待按键
"""
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
# 1. 读取图像,获取信息,转化成灰度图
filename = r"../img/lena.jpg"
src = cv.imread(filename, cv.IMREAD_COLOR)
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
height = src.shape[0]
width = src.shape[1]
# 2. 直方图均衡化
# # 1. 计算图像的直方图(颜色统计报告,x:颜色值,y:颜色出现次数)
# color_count = np.zeros(256, np.int)
hist = np.zeros(256, np.int)
for row in range(height):
for col in range(width):
color = gray[row, col]
hist[color] += 1
fig1 = plt.figure()
fig1.canvas.set_window_title('histogram')
x = np.linspace(0, 255, 256)
y = hist
plt.bar(x, y, color="red")
# # 2. 计算概率直方图(x:颜色值,y:次数概率 = 次数 / 像素总数),通过直方图
total_pix = height * width
hist_ratio = hist / total_pix
fig2 = plt.figure()
fig2.canvas.set_window_title('histogram_ratio')
x = np.linspace(0, 255, 256)
y = hist_ratio
plt.bar(x, y, color="orange")
# # 3. 计算累积概率直方图,通过概率直方图
hist_ratio_accum = np.zeros(256, np.float)
for i in range(256):
if i == 0:
hist_ratio_accum[i] = hist_ratio[i]
else:
hist_ratio_accum[i] += (hist_ratio_accum[i - 1] + hist_ratio[i])
fig3 = plt.figure()
fig3.canvas.set_window_title('histogram_ratio_accum')
x = np.linspace(0, 255, 256)
y = hist_ratio_accum
plt.bar(x, y, color="blue")
# # 4. 对图像进行均衡化,old_color -> sum_ration ->_new color
dst = np.zeros((height, width), np.uint8)
for row in range(height):
for col in range(width):
old_color = gray[row, col]
old_color_ratio_accum = hist_ratio_accum[old_color]
new_color = np.uint(old_color_ratio_accum * 255)
dst[row, col] = new_color
# # 5. 计算 dst 的直方图
hist_dst = np.zeros(256, np.int)
for row in range(height):
for col in range(width):
color = dst[row, col]
hist_dst[color] += 1
fig4 = plt.figure()
fig4.canvas.set_window_title('histogram_dst')
x = np.linspace(0, 255, 256)
y = hist_dst
plt.bar(x, y, color="green")
# 3. 显示图像,等待按键
cv.imshow("src", src)
cv.imshow("gray", gray)
cv.imshow("dst", dst)
plt.show()
key = cv.waitKey(1)
print("key = ", key)
运行结果
优化代码
"""
需求:
对灰度图像进行手动直方图均衡化
不借助 api,全手工
算法:
1. 计算图像的直方图(颜色统计报告,x:颜色值,y:颜色出现次数)
2. 计算概率直方图(x:颜色值,y:次数概率 = 次数 / 像素总数),通过直方图
3. 计算累积概率直方图,通过概率直方图
4. 对图像进行均衡化,old_color -> sum_ration ->_new color
步骤:
1. 读取图像,获取信息,转化成灰度图
2. 直方图均衡化
3. 显示图像,等待按键
"""
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
"""------------------------- 函数代码区 -------------------------"""
def histogram_equalization(gray, name):
global row, col, color, x, y, dst
# # 1. 计算图像的直方图(颜色统计报告,x:颜色值,y:颜色出现次数)
hist = calc_histogram(gray, name)
# # 2. 计算概率直方图(x:颜色值,y:次数概率 = 次数 / 像素总数),通过直方图
hist_ratio = calc_histogram_ratio(hist, name)
# # 3. 计算累积概率直方图,通过概率直方图
hist_ratio_accum = calc_histogram_ratio_accu(hist_ratio, name)
# # 4. 对图像进行均衡化,old_color -> sum_ration ->_new color
# dst = np.zeros((height, width), np.uint8)
do_equalization(dst, gray, hist_ratio_accum)
def do_equalization(dst, gray, hist_ratio_accum):
global row, col
for row in range(height):
for col in range(width):
old_color = gray[row, col]
old_color_ratio_accum = hist_ratio_accum[old_color]
new_color = np.uint(old_color_ratio_accum * 255)
dst[row, col] = new_color
def calc_histogram_ratio_accu(hist_ratio, name):
global x, y
hist_ratio_accum = np.zeros(256, np.float)
for i in range(256):
if i == 0:
hist_ratio_accum[i] = hist_ratio[i]
else:
hist_ratio_accum[i] += (hist_ratio_accum[i - 1] + hist_ratio[i])
fig3 = plt.figure()
fig3.canvas.set_window_title('histogram_ratio_accum_{0}'.format(name))
x = np.linspace(0, 255, 256)
y = hist_ratio_accum
plt.bar(x, y, color="blue")
return hist_ratio_accum
def calc_histogram_ratio(hist, name):
global x, y
total_pix = height * width
hist_ratio = hist / total_pix
fig2 = plt.figure()
fig2.canvas.set_window_title('histogram_ratio_{0}'.format(name))
x = np.linspace(0, 255, 256)
y = hist_ratio
plt.bar(x, y, color="orange")
return hist_ratio
def calc_histogram(gray, name):
global row, col, color, x, y
# color_count = np.zeros(256, np.int)
hist = np.zeros(256, np.int)
for row in range(height):
for col in range(width):
color = gray[row, col]
hist[color] += 1
fig1 = plt.figure()
fig1.canvas.set_window_title('histogram_{0}'.format(name))
x = np.linspace(0, 255, 256)
y = hist
plt.bar(x, y, color="red")
return hist
"""------------------------- 测试代码区 -------------------------"""
# 1. 读取图像,获取信息,转化成灰度图
filename = r"../img/lena.jpg"
src = cv.imread(filename, cv.IMREAD_COLOR)
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
height = src.shape[0]
width = src.shape[1]
# 2. src-gray 直方图均衡化
dst = np.zeros((height, width), np.uint8)
histogram_equalization(gray, "src")
# # 5. 计算 dst 的直方图
hist_dst = calc_histogram(dst, "dst")
# # 6. 计算 dst 的累积直方图
hist_dst_ratio = calc_histogram_ratio(hist_dst, "dst")
hist_dst_ratio_accu = calc_histogram_ratio_accu(hist_dst_ratio, "dst")
# 3. 显示图像,等待按键
cv.imshow("src", src)
cv.imshow("gray", gray)
cv.imshow("dst", dst)
plt.show()
key = cv.waitKey(1)
print("key = ", key)
运行结果
- 可以看到,直方图均衡化之后的图像的累积直方图的分布是线性的。
- 线性关系:两个变量之间存在一次方函数关系,就称它们之间存在线性关系。
29_灰度图直方图均衡化-api.py
代码
"""
需求:
1. 读取灰度图
2. 绘制灰度图直方图
3. 直方图均衡化,equalizeHist api
4. 绘制直方图
5. 显示图像,等待按键
"""
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
# 1. 读取灰度图
filename = r"../img/lena.jpg"
gray = cv.imread(filename, cv.IMREAD_GRAYSCALE)
# 2. 绘制灰度图直方图
fig1 = plt.figure()
fig1.canvas.set_window_title("hist_gray")
plt.hist(gray.ravel(), bins=256)
# 3. 直方图均衡化,equalizeHist api
dst = cv.equalizeHist(gray)
# 4. 绘制直方图
fig2 = plt.figure()
fig2.canvas.set_window_title("hist_dst")
plt.hist(dst.ravel(), bins=256)
# 5. 显示图像,等待按键
cv.imshow("gray", gray)
cv.imshow("dst", dst)
plt.show()
key = cv.waitKey(0)
print("key = ", key)
运行结果
30_彩色图像的直方图.py
代码
"""
需求:
1. 读取彩色图像
2. 拆分图像 split
3. 分别统计 BGR 通道直方图,使用 api
"""
import cv2 as cv
import matplotlib.pyplot as plt
# 1. 读取彩色图像
filename = r"../img/lena.jpg"
src = cv.imread(filename, cv.IMREAD_COLOR)
# 2. 拆分图像 split
channels = cv.split(src)
colors = ["blue", "green", "red"]
# 3. 分别统计 BGR 通道直方图,使用 api
for i in range(3):
fig = plt.figure()
fig.canvas.set_window_title("hist_{0}".format(colors[i]))
plt.hist(channels[i].ravel(), bins=256, color=colors[i], rwidth=0.8)
plt.show()
运行结果
31_彩色图像直方图均衡化.py
代码
"""
需求:
1. 读取彩色图像
2. 拆分图像 split
3. 对每个通道进行均衡化 equalizeHist api
4. 再将均衡化的单通道进行融合 merge api
"""
import cv2 as cv
import matplotlib.pyplot as plt
# 1. 读取彩色图像
filename = r"../img/lena.jpg"
src = cv.imread(filename, cv.IMREAD_COLOR)
# 2. 拆分图像 split
channels = cv.split(src)
# # 3. 对每个通道进行均衡化 equalizeHist api
cb_eq = cv.equalizeHist(channels[0])
cg_eq = cv.equalizeHist(channels[1])
cr_eq = cv.equalizeHist(channels[2])
# 4. 再将均衡化的单通道进行融合 merge api
c3_eq = cv.merge([cb_eq, cg_eq, cr_eq])
# 5. 显示图像,等待按键
cv.imshow("src", src)
cv.imshow("c3_eq", c3_eq)
# fig = plt.figure()
# fig.canvas.set_window_title("c3_equalize")
# plt.hist(c3_eq.ravel(), bins=256, histtype="barstacked")
plt.figure()
plt.hist(cb_eq.ravel(), bins=256, color="blue", histtype="stepfilled")
plt.figure()
plt.hist(cg_eq.ravel(), bins=256, color="green", histtype="stepfilled")
plt.figure()
plt.hist(cr_eq.ravel(), bins=256, color="red", histtype="stepfilled")
plt.show()
key = cv.waitKey(0)
print("key = ", key)
运行结果