OpenCV--041:Triangle二值寻找算法

三角形的二值化法:

不用自己指定thresh值,系统会进行计算并且作为返回值返回。

THRESH_OTSU最适用于双波峰。
THRESH_TRIANGLE最适用于单个波峰,最开始用于医学分割细胞等


  • 原理:
    1.图像转灰度
    2.计算图像灰度直方图
    3.寻找直方图中两侧边界
    4.寻找直方图最大值
    5.检测是否最大波峰在亮的一侧,否则翻转
    6.计算阈值得到阈值T,如果翻转则255-T
void Threshold(Mat& src, Mat& dst, double thresh) {
	int bt;
	//遍历灰度图像,统计灰度级的个数
	for (int i = 0; i < src.rows; i++)
	{
		uchar* p = src.ptr<uchar>(i);
		uchar* p1 = dst.ptr<uchar>(i);
		for (int j = 0; j < src.cols; j++)
		{
		    bt = p[j];
			cout << "bt=" << bt << " ";
			if (bt > thresh) {
				bt = 255;
			}
			else {
				bt = 0;
			}
			p1[j] = bt;

		
		}
	}
	imshow("src", src);
	imshow("dst", dst);
}


void Triangle(Mat& src, Mat& dst) {

	int i = 0, j = 0;
	int gray;
	int temp = 0;
	bool isflipped = false;

	//求直方图
	//void calcHist( const Mat* images, int nimages,
	//                const int* channels, InputArray mask,
	//	            OutputArray hist, int dims, const int* histSize,
	//	            const float** ranges, bool uniform = true, bool accumulate = false );
	//
	/*int nimages = 1;
	int channels[1] = { 0 };
	Mat calchist;
	int dims = 1;

	int histSize[1] = { 256 };
	//每一维数值的取值范围ranges
	float hranges[2] = { 0,255 };
	//每一维数值的取值范围
	const float* ranges[1] = { hranges };
	//灰度级别

	calcHist(&src, nimages, channels, Mat(), calchist, dims, histSize, ranges);
	*/

	int calchist[256] = { 0 };
	//遍历灰度图像,统计灰度级的个数
	for (i = 0; i < src.rows; i++)
	{
		uchar* p = src.ptr<uchar>(i);
		for (j = 0; j < src.cols; j++)
		{
			int value = p[j];
			calchist[value]++;
		}
	}
	
	
	//寻找直方图中两侧边界
	int left_bound = 0;
	int right_bound = 0;
	int max = 0;
	int max_index = 0;

	//左侧为零的位置
	for (i = 0; i < 256; i++) {
		if (calchist[i] > 0) {
			left_bound = i;
			break;
		}
	}
	//直方图为零的位置
	if (left_bound > 0) {
		left_bound--;
	}

	//直方图右侧为零的位置
	for (i = 255; i > 0; i--) {
		if (calchist[i] > 0) {
			right_bound = i;
			break;
		}
	}

	//直方图为零的地方
	if (right_bound > 0) {
		right_bound++;
	}

	//寻找直方图最大值
	for (i = 0; i < 256; i++) {
		if (calchist[i] > max) {
			max = calchist[i];
			max_index = i;
		}
	}

	//判断最大值是否在最左侧,如果是则不用翻转
	//因为三角形二值化只能适用于最大值在最右侧
	if (max_index - left_bound < right_bound - max_index) {
		isflipped = true;
		i = 0;
		j = 255;
		while (i < j) {
			//左右交换
			temp = calchist[i];
			calchist[i] = calchist[j];
			calchist[j] = temp;
			i++;
			j--;
		}
		left_bound = 255 - right_bound;
		max_index = 255 - max_index;

	}

	//求阈值
	double thresh = left_bound;
	double a, b, dist = 0, tempdist;
	a = max;
	b = left_bound - max_index;
	for (int i = left_bound+1; i <= max_index; i++)
	{
		//计算距离--不需要真正计算
		tempdist = a * i + b * calchist[i];
		if (tempdist > dist) {
			dist = tempdist;
			thresh = i;
		}
	}
	thresh--;

	// 对已经得到的阈值T,如果前面已经翻转了,则阈值要用255-T
	if (isflipped)
	{
		thresh = 255 - thresh;
	}

	//二值化
	Threshold(image, dst, thresh);
	
    

}

int main() {
	Mat src = imread("D:/test/src.jpg", 0);
	Mat dst;
	//threshold(src, dst, 0, 255, THRESH_BINARY | THRESH_OTSU);

	Triangle(src, dst);

	
	waitKey(0);
	return 0;




}

OpenCV中的实现


在这里插入图片描述
在这里插入图片描述

学习:

OpenCV—图像二值化

图像处理之三角法图像二值化

c++ 图像处理(十六) 三角法的二值化法

图像的二值化(需要是灰度图像) import cv2 as cv import numpy as np def threshold_demo(image): gray = cv.cvtColor(image,cv.COLOR_BGR2GRAY) #cv.THRESH_TRIANGLE与cv.THRESH_OTSU是自动寻找阈值,这个时候threshold值必须是0 #如果threshold不为0,即是自己指定的(如127),那么type就直接THRESH_BINARY就够了 ret,binary = cv.threshold(gray,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU) print(ret) cv.imshow("binary",binary) def local_threshold(image): gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY) binary =cv.adaptiveThreshold(gray,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,cv.THRESH_BINARY,25,10) cv.imshow("binary1", binary) src =cv.imread("E:/opencv/picture/dog.jpg") cv.imshow("initial_window",src) threshold_demo(src) local_threshold(src) cv.waitKey(0) cv.destroyAllWindows() 分析: 1. 全局阈值 def threshold_demo(image): gray = cv.cvtColor(image,cv.COLOR_BGR2GRAY) #cv.THRESH_TRIANGLE与cv.THRESH_OTSU是自动寻找阈值,这个时候threshold值必须是0 #如果threshold不为0,即是自己指定的(如127),那么type就直接THRESH_BINARY就够了 ret,binary = cv.threshold(gray,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU) print(ret) cv.imshow("binary",binary) threshold其函数原型为:threshold(src, thresh, maxval, type[, dst]) -> retval, dst src参数表示输入图像(多通道,8位或32位浮点)。 thresh参数表示阈值。(如果type是自动二值化就设置为0) maxval参数表示与THRESH_BINARY和THRESH_BINARY_INV阈值类型一起使用设置的最大值。 type参数表示阈值类型。 retval参数表示返回的阈值。若是全局固定阈值算法,则返回thresh参数值。若是全局自适应阈值算法,则返回自适应计算得出的合适阈值。 dst参数表示输出与src相同大小和类型以及相同通道数的图像。 type阈值类型说明 cv.THRESH_BINARY | cv.THRESH_OTSU)#大律法,全局自适应阈值 参数0可改为任意数字但不起作用 cv.THRESH_BINARY | cv.THRESH_TRIANGLE)#TRIANGLE法,,全局自适应阈值, 参数0可改为任意数字但不起作用,适用于单个波峰 cv.THRESH_BINARY)# 自定义阈值为127,大于127的是白色 小于的是黑色 cv.THRESH_BINARY_INV)# 自定义阈值为127,大于127的是黑色 小于的是白色 cv.THRESH_TRUNC)# 截断 大于127的是改为127 小于127的保留 cv.THRESH_TOZERO)# 截断 小于127的是改为127 大于127的保留 2. 局部阈值法 3. def local_threshold(image): gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY) binary =cv.adaptiveThreshold(gray,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,cv.THRESH_BINARY,25,10) cv.imshow("binary1", binary) adaptiveThreshold函数进行局部阈值 函数原型为:adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C[, dst]) -> dst src参数表示输入图像(8位单通道图像)。 maxValue参数表示使用 THRESH_BINARY 和 THRESH_BINARY_INV 的最大值. adaptiveMethod参数表示自适应阈值算法, 平均— cv2.ADAPTIVE_THRESH_MEAN_C :领域内均值 高斯—cv2.ADAPTIVE_THRESH_GAUSSIAN_C :领域内像素点加权和,权 重为一个高斯窗口 thresholdType参数表示阈值类型,必须为THRESH_BINARY或THRESH_BINARY_INV的阈值类型。 blockSize参数表示块大小,规定领域大小(奇数且大于1,比如3,5,7........ )。 C参数是常数,表示从平均值或加权平均值中减去的数。 通常情况下,这是正值,但也可能为零或负值。 二.对超大图像进行二值化 如果这个时候只是单纯的用二值化api,图像上会出现很多噪声,所以我们特地介绍了一种对大图像进行二值化的方法import cv2 as cv import numpy as np from matplotlib import pyplot as plt #对超大图像进行二值化 def big_image_threshold(image): cw = 256 ch = 256 h,w = image.shape[:2] gray = cv.cvtColor(image,cv.COLOR_BGR2GRAY) for row in range(0, h, ch): for col in range(0, w, cw): #gray[0:3] 从索引0开始取,直到索引3为止,但不包括索引3。即索引0,1,2,正好是3个元素。 roi = gray[row:row+ch,col:col+ch]#表示从[row,col]到[row+ch,col+ch]的所有元素所组成的矩阵 #推荐使用局部阈值二值化 dst = cv.adaptiveThreshold(roi,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,cv.THRESH_BINARY,127,20) gray[row:row+ch,col:col+ch] =dst cv.imwrite("E:/opencv/picture/bigpicture1.jpg",gray) src = cv.imread("E:/opencv/picture/bigpicture.jpg") t1 = cv.getTickCount() big_image_threshold(src) t2 = cv.getTickCount() time= (t2-t1)/cv.getTickFrequency() #print("time =%sms\n"%(time)*1000) cv.waitKey(0) cv.destroyAllWindows()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值