图像二值化
全局法Threshold
大津法
大津法OSTU阈值类型——适用于双峰直方图
OTSU算法也称最大类间差法,由大津于1979年提出,被认为是图像分割中阈值选取的最佳算法,计算简单,不受图像亮度和对比度的影响,它是按图像的灰度特性,将图像分成背景和前景两部分。因方差是灰度分布均匀性的一种度量,背景和前景之间的类间方差越大,说明构成图像的两部分的差别越大,利于后续的图像分割,当部分前景错分为背景或部分背景错分为前景都会导致两部分差别变小。因此,使类间方差最大的分割意味着错分概率最小。
三角法
该方法是使用直方图数据,最适用于单个波峰,基于纯几何方法来寻找最佳阈值,它的成立条件是假设直方图最大波峰在靠近最亮的一侧,然后通过三角形求得最大直线距离,根据最大直线距离对应的直方图灰度等级即为分割阈值
图像处理之三角法图像二值化_三角阈值法-CSDN博客
局部法adaptiveThreshold
适用于光照不均衡以及更加复杂的情况下。二值化标志只能是THRESH_BINARY,THRESH_BINARY_INV
均值算法ADAPTIVE_THRESH_MEAN_C
平均值法就是对目标像素点的周围取一定size(为奇数)的块区域,将该区域的像素点灰度值的平均值再减去参数C的值得到的值作为阈值
高斯法(ADAPTIVE_THRESH_GAUSSIAN_C)
使用高斯的方法,则每个像素周围像素的权值则根据其到中心点的距离通过高斯方程得到,然后阈值就会等于各像素点权值乘以灰度值的积的累加再减去C,权值的和为1
关于Block Size和C的取值,一般Block Size取3~17比较合适,C也不宜太大,可取3~9,具体的值需要自己测试调节。
【C++ OpenCV】阈值二值化、阈值反二值化、截断、阈值取零、阈值反取零、自适应阈值使用方法以及时机_固定阈值二值化-CSDN博客
图像处理——图像的二值化操作及阈值化操作(固定阈值法(全局阈值法——大津法OTSU和三角法TRIANGLE)和自适应阈值法(局部阈值法——均值和高斯法)) | 码农家园 (codenong.com)https://www.codenong.com/cs107102117/
两者比较:
固定阈值的二值化效果一般比较差,尤其是在处理亮度差别很大的图像,它是对整个图像进行阈值操作,图像比较平滑,细节较少。自适应阈值法则是围绕目标像素点的一小块区域进行阈值化操作,效果会更好,图像的细纹都保留了下来,即图像细节得到了保存。
#include <opencv2\opencv.hpp>
#include <iostream>
#include <vector>
using namespace std;
using namespace cv;
int main()
{
Mat img = imread("lena.png");
if (img.empty())
{
cout << "请确认图像文件名称是否正确" << endl;
return -1;
}
Mat gray;
cvtColor(img, gray, COLOR_BGR2GRAY);
Mat img_B, img_B_V, gray_B, gray_B_V, gray_T, gray_T_V, gray_TRUNC;
//彩色图像二值化
threshold(img, img_B, 125, 255, THRESH_BINARY);
threshold(img, img_B_V, 125, 255, THRESH_BINARY_INV);
imshow("img_B", img_B);
imshow("img_B_V", img_B_V);
//灰度图BINARY二值化
threshold(gray, gray_B, 125, 255, THRESH_BINARY);
threshold(gray, gray_B_V, 125, 255, THRESH_BINARY_INV);
imshow("gray_B", gray_B);
imshow("gray_B_V", gray_B_V);
//灰度图像TOZERO变换
threshold(gray, gray_T, 125, 255, THRESH_TOZERO);
threshold(gray, gray_T_V, 125, 255, THRESH_TOZERO_INV);
imshow("gray_T", gray_T);
imshow("gray_T_V", gray_T_V);
//灰度图像TRUNC变换
threshold(gray, gray_TRUNC, 125, 255, THRESH_TRUNC);
imshow("gray_TRUNC", gray_TRUNC);
//灰度图像大津法和三角形法二值化
Mat img_Thr = imread("threshold.png", IMREAD_GRAYSCALE);
Mat img_Thr_O, img_Thr_T;
threshold(img_Thr, img_Thr_O, 100, 255, THRESH_BINARY | THRESH_OTSU);
threshold(img_Thr, img_Thr_T, 125, 255, THRESH_BINARY | THRESH_TRIANGLE);
imshow("img_Thr", img_Thr);
imshow("img_Thr_O", img_Thr_O);
imshow("img_Thr_T", img_Thr_T);
//灰度图像自适应二值化
Mat adaptive_mean, adaptive_gauss;
adaptiveThreshold(img_Thr, adaptive_mean, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 55, 0);
adaptiveThreshold(img_Thr, adaptive_gauss, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 55, 0);
imshow("adaptive_mean", adaptive_mean);
imshow("adaptive_gauss", adaptive_gauss);
waitKey(0);
return 0;
}
LUT查表,多阈值
在OpenCV中,LUT代表查找表(Lookup Table),它是一种用于像素值映射的技术。查找表是一个数组,其中每个元素对应于输入像素值的一个映射值。使用LUT可以有效地对图像进行像素值的转换,常用于颜色空间转换或者对特定像素值进行操作。
LUT通常在需要将图像像素值映射到其他值域时使用,例如将灰度图像转换为伪彩色图像。通过定义一个映射表,可以将原始图像中的每个像素值映射到新的颜色或灰度值,从而实现不同的效果。
因此,LUT主要用于对图像像素值进行映射,从而实现颜色空间转换等操作,而二值化阈值化则用于将灰度图像转换为二值图像。两者的主要区别在于处理的目标和操作方式。
和阈值threshold有什么区别?
阈值threshold只能将图片全局按照一个阈值进行映射,LUT可以按照自己设置的阈值范围进行映射,兼容了threshold的二值化,但是可以多阈值划分。不仅仅可以应用于0-255像素值。
【C++ OpenCV】LUT查找表原理、实操、使用时机_dagengen12138的博客-CSDN博客
#include <opencv2\opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
//LUT查找表第一层
uchar lutFirst[256];
for (int i = 0; i<256; i++)
{
if (i <= 100)
lutFirst[i] = 0;
if (i > 100 && i <= 200)
lutFirst[i] = 100;
if (i > 200)
lutFirst[i] = 255;
}
Mat lutOne(1, 256, CV_8UC1, lutFirst);
//LUT查找表第二层
uchar lutSecond[256];
for (int i = 0; i<256; i++)
{
if (i <= 100)
lutSecond[i] = 0;
if (i > 100 && i <= 150)
lutSecond[i] = 100;
if (i > 150 && i <= 200)
lutSecond[i] = 150;
if (i > 200)
lutSecond[i] = 255;
}
Mat lutTwo(1, 256, CV_8UC1, lutSecond);
//LUT查找表第三层
uchar lutThird[256];
for (int i = 0; i<256; i++)
{
if (i <= 100)
lutThird[i] = 100;
if (i > 100 && i <= 200)
lutThird[i] = 200;
if (i > 200)
lutThird[i] = 255;
}
Mat lutThree(1, 256, CV_8UC1, lutThird);
//拥有三通道的LUT查找表矩阵
vector<Mat> mergeMats;
mergeMats.push_back(lutOne);
mergeMats.push_back(lutTwo);
mergeMats.push_back(lutThree);
Mat LutTree;
merge(mergeMats, LutTree);
//计算图像的查找表
Mat img = imread("lena.png");
if (img.empty())
{
cout << "请确认图像文件名称是否正确" << endl;
return -1;
}
Mat gray, out0, out1, out2;
cvtColor(img, gray, COLOR_BGR2GRAY);
LUT(gray, lutOne, out0);
LUT(img, lutOne, out1);
LUT(img, LutTree, out2);
imshow("out0", out0);
imshow("out1", out1);
imshow("out2", out2);
waitKey(0);
return 0;
}