基于otsu和hough海天线检测算法

对理论感兴趣的同学可以参考 基于局部otsu分割与hough变换的海天线检测 这边文献,我的代码是依据该文献实现的。

IDE:vs2015

依赖项:opencv 3.x

一.对图像做中值滤波

opencv现成的函数

    cv::Mat src1 = imread("test1.png");
	cv::Mat srcGray;
    //转换为二值图像
	cvtColor(src1, srcGray, CV_BGR2GRAY);

	//中值滤波,过滤噪声
	medianBlur(srcGray, srcGray, 3);

二、otsu图像分割

//otsu 最大类间距算法,通过灰度直方图,找出阈值。
//类似k-means 聚类算法
int otsu(cv::Mat image)
{
	assert(!image.empty());

	int width = image.cols;
	int height = image.rows;
	int x = 0, y = 0;
	int pixelCount[256];
	float pixelPro[256];
	int i, j, pixelSum = width * height, threshold = 0;

	uchar* data = (uchar*)image.data;

	//初始化
	for (i = 0; i < 256; i++)
	{
		pixelCount[i] = 0;
		pixelPro[i] = 0;
	}

	//统计灰度级中每个像素在整幅图像中的个数
	for (i = y; i < height; i++)
	{
		for (j = x; j < width; j++)
		{
			pixelCount[data[i * image.step + j]]++;
		}
	}

	//计算每个像素在整幅图像中的比例
	for (i = 0; i < 256; i++)
	{
		pixelPro[i] = (float)(pixelCount[i]) / (float)(pixelSum);
	}

	//经典ostu算法,得到前景和背景的分割
	//遍历灰度级[0,255],计算出方差最大的灰度值,为最佳阈值
	float w0, w1, u0tmp, u1tmp, u0, u1, u, deltaTmp, deltaMax = 0;
	for (i = 0; i < 256; i++)
	{
		w0 = w1 = u0tmp = u1tmp = u0 = u1 = u = deltaTmp = 0;

		for (j = 0; j < 256; j++)
		{
			if (j <= i) //背景部分
			{
				//以i为阈值分类,第一类总的概率
				w0 += pixelPro[j];
				u0tmp += j * pixelPro[j];
			}
			else       //前景部分
			{
				//以i为阈值分类,第二类总的概率
				w1 += pixelPro[j];
				u1tmp += j * pixelPro[j];
			}
		}

		u0 = u0tmp / w0;        //第一类的平均灰度
		u1 = u1tmp / w1;        //第二类的平均灰度
		u = u0tmp + u1tmp;        //整幅图像的平均灰度
								  //计算类间方差
		deltaTmp = w0 * (u0 - u)*(u0 - u) + w1 * (u1 - u)*(u1 - u);
		//找出最大类间方差以及对应的阈值
		if (deltaTmp > deltaMax)
		{
			deltaMax = deltaTmp;
			threshold = i;
		}
	}
	//返回最佳阈值;
	return threshold;
}

三、边缘提取

//对二值图像做边缘提取,没有采用canny
//对二值图像的纵向相邻像素做异或处理,提取像素值跳跃边界线
cv::Mat edge(cv::Mat image)
{
	cv::Mat dst = cv::Mat::zeros(image.rows, image.cols, CV_8UC1);

	uchar* data = (uchar*)image.data;
	uchar* data1 = (uchar*)dst.data;
	for (int i = 0; i

四、hough变换提取直线

//霍夫变换
/*功能:将输入图像按照给出参数要求提取线段,放在lines中。

	lines : 是一个vector, Vec4i是一个包含4个int数据类型的结构体,[x1, y1, x2, y2], 可以表示一个线段。

	rho : 就是一个半径的分辨率。 以像素为单位的距离精度。 另一种形容方式是直线搜索时的进步尺寸的单位半径。

	theta : 角度分辨率。以弧度为单位的角度精度。另一种形容方式是直线搜索时的进步尺寸的单位角度

	threshold : 判断直线点数的阈值。累加平面的阈值参数,即识别某部分为图中的一条直线时它在累加平面中必须达到的值。 大于阈值 threshold 的线段才可以被检测通过并返回到结果中。

	minLineLength:线段长度阈值。有默认值0,表示最低线段的长度,比这个设定参数短的线段就不能被显现出来。

	minLineGap : 线段上最近两点之间的阈值 有默认值0,允许将同一行点与点之间连接起来的最大的距离
*/
static void on_HoughLines(cv::Mat src, cv::Mat dst)
{
	Mat midImage = src.clone();

	imshow("2", midImage);
	waitKey(15);
	//调用HoughLinesP函数  
	vector mylines;
	HoughLinesP(midImage, mylines, 1, CV_PI / 180, 50 + 1, 30, 10);//局部otsu和全局otsu分别设置不同的参数
	//循环遍历绘制每一条线段  
	for (size_t i = 0; i < mylines.size(); i++)
	{
		Vec4i l = mylines[i];
		line(dst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 255, 0), 1, 8);
	}
}

完整代码在github上 https://github.com/Tudou880306/sea-sky-line-detection

你可能感兴趣的:(人工智能,海天线检测,otsu图像分割,hough霍夫变换)