灰度图像是只含亮度信息,不含色彩信息的图像。灰度化处理是把彩色图像转换为灰度图像的过程,是图像处理中的基本操作。OpenCV 中彩色图像使用 BGR 格式。灰度图像中用 8bit 数字 0~255 表示灰度,如:0 表示纯黑,255 表示纯白。
import cv2
img = cv2.imread('image.jpg')
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imshow('Gray Image', gray_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
import cv2
img = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)
cv2.imshow('Gray Image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
图像的二值化,就是将图像上的像素点的灰度值设置为0或255,也就是将整个图像呈现出明显的只有黑和白的视觉效果。
常用的方法就是设定一个阈值T,用T将图像的数据分成两部分:大于T的像素群和小于T的像素群。其实图像二值化的方法有不下二十种。一般分为Global和Local两类,区别就是寻找那个阈值的时候使用到了哪里的信息。
但是单一的图像二值化方法(指基于直方图的二值化)往往比不过其他的方法,因为,毕竟你信息丢了太多。但是二值化快啊……你可以进行一百次不同的二值化,然后再得到一个更好的结果……
简单阈值是选取一个全局阈值,然后把整幅图像分成非黑即白的二值图像,灰度值大于阈值就赋为255反之为0。
特点:对整幅图像都是用一个统一的阈值来进行二值化,方法简单易于实现。但是对光照不均匀的图像容易出现错误的二值分割。
cv::threshold(graySrc,dst, threshold_value, threshold_max,THRESH_BINARY);
自适应阈值法的原理就是将像素点与该点所在区域的像素的平均值(最大值、中位数等)做比较,大于则赋予255;反之,为0。
特点:在同一幅图像上的不同区域采用的是不同的阈值,从而使我们能在亮度不同的情况下得到更好的结果。
cv.adaptiveThreshold(src,dst,maxValue,adaptiveMethod,blockvalue,C)
原文链接:https://blog.csdn.net/weixin_51775350/article/details/128175134
Otsu算法(大津法或最大类间方差法)使用的是聚类的思想,把图像的灰度数按灰度级分成2个部分,使得两个部分之间的灰度值差异最大,每个部分之间的灰度差异最小,(相当于类间保持差异性,类内保持一致性)通过方差的计算来寻找一个合适的灰度级别来划分。 所以可以在二值化的时候采用otsu算法来自动选取阈值进行二值化。otsu算法被认为是图像分割中阈值选取的最佳算法,计算简单,不受图像亮度和对比度的影响。因此,使类间方差最大的分割意味着错分概率最小。
大津算法的核心思想是通过寻找一个阈值,将图像的像素分为两个类别:前景和背景。具体步骤如下:
特点:类间方差法对噪音和目标大小十分敏感,它仅对类间方差为单峰的图像产生较好的分割效果。当目标与背景的大小比例悬殊时,类间方差准则函数可能呈现双峰或多峰,此时效果不好,但是类间方差法是用时最少的。
cv::threshold(gray, img_Thr_O, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
// *第一个参数:待二值化的图像,图像只能是CV_8U和CV_32F两种类型。对于
// 图像通道数目的要求与选择二值化的方法有关。
// *第二个参数:二值化后的图像
// *第三个参数:二值化阈值
// *第四个参数:二值化过程的最大值,它只在THRESH_BINARY和THRESH_BINARY_INV
// 两种方法中才使用。
方差(Variance)是用来衡量一组数据离其平均值的分散程度的统计量。这组数据的每个数值与其平均值之间的差的平方的平均值就是这组数据的方差。数学上的定义如下:
设有一组数据X={x1, x2, …, xn},其中n是数据量,其平均值为μ,那么方差σ2的计算公式为:σ2 = (1/n) * Σ(xi - μ)^2 , Σ代表所有数据的累加。
方差的计算描述了数据数值与其平均值之间的差异性,方差越大,数据的分散程度越大,反之则数据更集中。
边缘检测是图像处理中非常重要的一项任务,它的目标是找到图像中亮度变化明显的区域,这些区域通常对应物理世界中的物体边缘。边缘检测常用于图像分割和特征提取。
图像的边缘检测大幅度减少数据量,并剔除了可以认为不相关的信息,保留了图像重要的结构属性。有许多方法用于边缘检测,它们的绝大部分可以划分为两类:基于搜索和基于零穿越。
备注:sobel算子时基于图像的空间强度变化,对应在水平和垂直方向的差异性,即像素的强度在边缘地方有显著变化。
Sobel算子的一种形式在水平方向(dx)的核是这样的:
-1 0 1
-2 0 2
-1 0 1
这个核的设计是为了计算图像在水平方向上的梯度,并提取出边缘。核中的每一个元素对应一个权重,用于对其覆盖的像素区域加权求和。
中间的列(0, 0, 0)给予了原始位置的像素0的权重,这意味着原始位置的像素对结果没有影响。
左边和右边的列(-1, -2, -1)和(1, 2, 1)则对原始像素的左右两旁的像素赋予了权重,左边是负数,右边是正数。这代表我们希望检测从暗到亮(左到右)的边缘。
轮廓可以简单认为成将连续的点(连着边界)连在一起的曲线,具有相同的颜色或灰度,提取轮廓就是提取这些具有相同颜色或者灰度的曲线,或者说是连通域,轮廓在形状分析和物体检测和识别中非常有用。
cv2.findContours() 是一个在OpenCV库中的函数,它用于从二值图像中检测轮廓。
函数的定义如下:
参数说明:
cv2.findContours(image, mode, method[, contours[, hierarchy[, offset]]])
函数返回值:
以下python代码会找到并画出图像中的所有外部轮廓:
import cv2
import numpy as np
# 加载图像
image = cv2.imread('image.png', cv2.IMREAD_GRAYSCALE)
# 二值化图像
_, thresholded = cv2.threshold(image, 127, 255, cv2.THRESH_BINARY)
# 寻找轮廓
contours, _ = cv2.findContours(thresholded, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 在原图上画出轮廓
cv2.drawContours(image, contours, -1, (0,255,0), 3)
cv2.imshow("Contours", image)
cv2.waitKey(0)
cv2.destroyAllWindows()