今天在实现图像阈值分割的时候,需要找到能将背景与物体区分开的灰度阈值,因为处理到的图像比较简单,它的直方图具有一个十分明显的特点,也就是它的直方图以双峰一谷的形式呈现,将物体与背景区分开来的阈值也就是谷所对应的阈值,利用数学概念解释一下,双峰就对应着两个极大值,谷对应着极小值,也就是在两个极大值之间找到这个最小值,当然也可以通过统计一下图像灰度值的分布,将灰度值分布以可视化的方式呈现,然后找到合适的阈值,这比排序找极小值的效率快很多,在这里我将介绍三种将灰度分布可视化的方式。
方法一————利用matplotlib库中的hist()函数
matplotlib.pyplot.hist(x, bins=None, range=None, density=False, weights=None, cumulative=False, bottom=None, histtype='bar', align='mid', orientation='vertical', rwidth=None, log=False, color=None, label=None, stacked=False, *, data=None, **kwargs)
一般只定义前面三个参数:
x: 输入的数据
bins:如果bins输入的是一个整数,那么它代表着在输出的图像中,横坐标被均分为多少份
range:它定义了横坐标的范围,输入的是存储了两个数的列表,左边的数是横坐标起点,右边的数是横坐标截止点
这个函数输出的最终结果,是显示每一个灰度值,以及其对应的频率的连续图
方法二————利用opencv中的calcHist函数
cv.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]])
image:需要被统计灰度值分布的图像,有一个血的教训,image一定要用[]框住
channels:图像通道,对于一个BGR图像, [0], [1],[2]分别对于B,G,R三个通道
mask:一般默认其为None即可
histSize:定义了直方图横坐标范围
ranges:定义了横坐标被分为多少份
方法三————利用PLotly进行可视化绘图
Plotly生成的图表是交互式的,也就是说当你用鼠标指向对应的一个灰度值时,他会直接显示这个灰度值的频率,但是耗时比较长,应为他需要用程序计算出每个灰度值对应的频数是多少。
在这里主要用到了:
Bar函数,来存储输入数据的横纵坐标
Layout函数,用来定义函数的标题,横纵坐标
offline.plot, 最终的绘图
三种方法的实现过程总程序如下:
import cv2
import matplotlib.pyplot as plt
from plotly import offline
from plotly.graph_objs import Bar, Layout
img_source = cv2.imread('C:\\Users\\yu\\Desktop\\picture_csdn\\cells_segmentation.jpg', cv2.IMREAD_COLOR)
img_gray = cv2.cvtColor(img_source, cv2.COLOR_BGR2GRAY)
cv2.imshow('img_gray', img_gray)
# 方法二————利用opencv中的calcHist函数
img_hist = cv2.calcHist([img_gray], [0], None, [256], [0, 256])
plt.plot(img_hist, color='blue')
plt.show()
# 方法一————利用matplotlib库中的hist()函数
plt.hist(img_gray.ravel(), 256, [0, 256])#ravel函数功能是将多维数组降为一维数组
plt.show()
ret, img_segmentation = cv2.threshold(img_gray, 80, 255, cv2.THRESH_TRUNC)# 对图像进行阈值分割
cv2.imshow('img_segmentation', img_segmentation)# 图像分割结果
# 方法三————利用PLotly进行可视化绘图
a_input = list(img_gray.ravel())
frequencies = []
for value in list(range(0, 256)):
print(value)
frequency = a_input.count(value)
frequencies.append(frequency)
# 对结果可视化
x_values = list(range(0, 256))
data = [Bar(x=x_values, y=frequencies)]
x_axis_config = {'title': '灰度值'}
y_axis_config = {'title': '灰度值的频率'}
my_layout = Layout(title='一个图像的灰度直方图', xaxis=x_axis_config, yaxis=y_axis_config)
offline.plot({'data': data, 'layout': my_layout}, filename='gray_histogram.html')
cv2.waitKey(0)
cv2.destroyAllWindows()
在上面的程序中,附带了一个我对图像进行阈值分割的两条代码,读者在使用程序的时候可以将其注释掉。
在这里我统计的图像是一个将彩色图像转化为灰度图像的细胞图像:
三种灰度直方分布结果如下所示:
方法一 方法二 方法三