共计 2600 个字符,预计需要花费 7 分钟才能阅读完成。
单阈值大津法
大津法属于全局阈值办法中的一种,即是最大类间方差法
大津法次要原理在于会主动找出一个阈值 使得宰割后的两部分类间方差最大 实用于有双波峰的图像,大津法作为图像宰割中阈值选取的罕用算法,计算简略,不受图像亮度和对比度的影响,次要原理如下:
影像的大小为 M×N,将前景区域和背景区域的宰割阈值记作 T,影像中像素值小于阈值 T 的像素个数记为 N0,像素值大于阈值 T 的像素个数记为 N1,则有:
w0=N0/(M×N)
w1=N1/(M×N)
μ=w0×μ0+w1×μ1
g=w0×(μ0-μ)^2+w1×(μ1-μ)^2
其中 w0 为前景区域像素个数占整幅影像的比例,其像素均值为 μ0;w1 是背景区域像素个数占整幅影像的比例,其像素均值为 μ1;μ 为影像的总像素均值,g 为类间方差,当计算出的类间方差 g 最大时,对应的阈值 T 即为最佳宰割成果的阈值。
其实比照 方差的求解公式
很容易了解 最大类间方差
类间方差就是把图像分成两团 两个整体 别离计算 每个整体的方差
方差 1 xi 就是 前景的均值 u0 x 均匀 就是整幅影像均值 u n=1
方差 2 同样
而后再乘以这两局部的权重 相加即可
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2\imgproc\types_c.h>
#include <opencv2/highgui/highgui_c.h>
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
double Otsu(Mat& image)
{
int threshold = 0;
double maxVariance = 0;
double w0 = 0, w1 = 0;// 前景与背景像素点所占比例
double u0 = 0, u1 = 0;// 前景与背景像素值均匀灰度
int histogram[256] = {0}; // 定义一个数组 长度为 256 0-255
int Num = image.cols * image.rows; // 总像素个数
// 统计 256 个 bin,每个 bin 像素的个数
for (int i = 0; i < image.rows; i++)
{const uchar* p = image.ptr<uchar>(i);
for (int j = 0; j < image.cols; j++)
{histogram[int(*p++)]++; //cout<<"Histogram[data[i*image.step+j]]++:;"<<histogram[int(*p++)]++<<endl;
}
//*p++, * 和 ++ 优先级是雷同的 先解援用取出指针指向的值,// 而后再将指针地址加 1,指向下一个地位。也就是取值为 *p 然而这时候指针曾经指向下一个地位
}
// 前景像素统计
for (int i = 1; i < 256; i++)
{
w0 = 0; // 前景像素所占比例
w1 = 0; // 背景像素所占比例
u0 = 0; // 前景像素灰度均值
u1 = 0; // 背景像素灰度均值
for (int j = 1; j <= i; j++)
{w0 = w0 + histogram[j];// 以 i 为阈值,统计前景像素比例
u0 = u0 + j * histogram[j];// 以 i 为阈值,统计前景像素灰度总和
}
u0 = u0 / w0; w0 = w0 / Num; //Num 是总像素个数
// 背景像素统计
for (int j = i + 1; j <= 255; j++)
{w1 = w1 + histogram[j];// 以 i 为阈值,统计前景像素个数
u1 = u1 + j * histogram[j];// 以 i 为阈值,统计前景像素灰度总和 histogram[j]是像素值为 j 的像素个数
}
u1 = u1 / w1; w1 = w1 / Num;
// 后面的 u1 是总灰度和 除以 w1 总个数是前景的灰度均值
// 后面的 w1 是总个数 除以 Num 当前才是比例
double variance = w0 * w1 * (u1 - u0) * (u1 - u0); // 以后类间方差计算
if (variance > maxVariance)
{
maxVariance = variance;
threshold = i;
}
}
cout << "threshold:" << threshold << endl;
return threshold;
}
int main()
{Mat img = imread("C://Users// 马亚飞 //Pictures//Saved Pictures// 湖人.jpg");
imshow("原图", img);
Mat img1;
img.copyTo(img1);
cvtColor(img, img, CV_BGR2GRAY); // 把 img 转为灰度图
cvtColor(img1, img1, CV_BGR2GRAY); // 把 img1 转为灰度图
double th = Otsu(img); // 调用 Otsu 函数 失去阈值 th
cout << "The return value of getOstu is:" << th << endl; // 输入阈值 th
cout << "The return value of opencv threshold is:" << threshold(img1, img1, th, 255, CV_THRESH_OTSU);//opencv 已实现的大津法
for (int i = 0; i < img.rows; i++) // 行循环
{uchar* data = img.ptr<uchar>(i); // 获取第 i 行的首地址
for (int j = 0; j < img.cols; j++) // 列循环
{if (data[j] <= th)
data[j] = 0;
else
data[j] = 255;
} // 行解决完结
}
imshow("Ostu_img", img);
//cv::namedWindow("Opencv_img", CV_WINDOW_NORMAL);
cv::imshow("Opencv_img", img1);
// 对一次大津法 的彩色或者红色局部进行掩膜
//bitwise_not(img1, img1); // 这里先变反转色彩
/*Mat src = imread("D://opencvdata//0//0.png");
src.setTo(0,img1);
imshow("掩膜", src);*/
waitKey(0);
return 0;
}
(威少的黑白图还有点像利拉德)
都差不多
正文完