OpenCv3编程学习十

图像变换

1.基于OpenCV的边缘检测
canny算子,soble算子,laplacian算子,Scharr滤波器。
边缘检测的步骤:
1.滤波:用滤波器来改善和噪音有关的性能
2.增强:这个的作用是确定图像个点领域强度的变化值。
3.检测:也就是将增强之后的点进行筛选。
2.canny算子
目标是找到一个最优的边缘检测算法,有以下三个评价标准
1.低错误率:标识出尽可能多的实际边缘
2.高定位性:标识出的边缘要和图像中实际边缘尽可能接近
3.最小响应:边缘只需要标识一次
主要步骤:消除噪声,计算梯度幅值和方向,非极大值抑制和滞后阈值。
3.canny()函数
其参数为:输入和输出图像,滞后性的阈值,孔径大小和计算图像地图幅值的标识。

#include<opencv2/opencv.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>


using namespace cv;

int main()
{
	//载入原始图
	Mat src = imread("1.jpg");
	Mat src1 = src.clone();
	//显示原始图
	imshow("[原始图]Canny边缘检测", src);
	//使用高阶的canny 用法:转换为灰度图,降噪,再用canny,最后将边缘作为
	//掩码,拷贝原图到效果图,得到彩色的边缘图
	Mat dst, edge, gray;
	//创建和src同类和大小的矩阵
	dst.create(src1.size(), src1.type());
	//将原图转换为灰度图像
	cvtColor(src1, gray, COLOR_BGR2GRAY);
	//再用3*3内核来降噪
	blur(gray, edge, Size(3, 3));
	//运行Canny算子
	Canny(edge, edge, 3, 9, 3);
	//将所有元素设置为0
	dst = Scalar::all(0);
	//使用Canny算子输出的边缘图来进行复制
	src1.copyTo(dst, edge);
	//再把效果图显示
	imshow("[效果图]Canny边缘检测2", dst);
	waitKey(0);
	return 0;
}

4.soble算子
它是结合了高斯平滑和微分求导,用来计算图像灰度函数的近似值梯度。
他的参数如下:输入和目标图像,输入图像的深度,x,y方向上的差分阶数,和Sobel核的大小,double类型的scale,是计算导数值时可选的缩放因子。

#include<opencv2/opencv.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>

using namespace cv;

int main()
{
	//创建grad_x和grad_y矩阵
	Mat grad_x, grad_y;
	Mat abs_grad_x, abs_grad_y, dst;
	//载入原图
	Mat src = imread("1.jpg");
	//再显示图片
	imshow("[原始图]sobel边缘检测", src);
	//再求x方法的梯度
	Sobel(src, grad_x, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT);
	convertScaleAbs(grad_x, abs_grad_x);
	imshow("[效果图]X方向Sobel", abs_grad_x);
	//再求y方法的梯度
	Sobel(src, grad_y, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT);
	convertScaleAbs(grad_y, abs_grad_y);
	imshow("[效果图]Y方向Sobel", abs_grad_y);

	//再把梯度合并
	addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dst);
	//再展示
	imshow("[效果图]整体方向Sobel", dst);
	waitKey(0);
	return 0;
}

5.Laplacian算子
这个算子就是定义为梯度grad的散度div,也就是Laplacian()函数,参数分别是输入和输出的图像,图像深度,孔径尺寸,可选的比例因子,和结果的存储图像以及边界模式。

#include<opencv2/opencv.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>

using namespace cv;

int main()
{
	//定义变量
	Mat src, src_gray, dst, abs_dst;
	//载入原始图
	src = imread("1.jpg");
	//显示原始图
	imshow("[原始图]图像Laplace变换", src);
	//使用高斯滤波消除噪音
	GaussianBlur(src, src, Size(3, 3), 0, 0, BORDER_DEFAULT);
	//再转化为灰度图
	cvtColor(src, src_gray, COLOR_RGB2GRAY);
	//使用Laplace函数
	Laplacian(src_gray, dst, CV_16S, 3, 1, 0, BORDER_DEFAULT);
	//计算绝对值,并将结果转化为8位
	convertScaleAbs(dst, abs_dst);
	//显示效果图
	imshow("[效果图]图像Laplace变换", abs_dst);
	waitKey(0);
	return 0;
}

6.scharr滤波器
算是调用了Scharr()函数,有以下参数:src,dst,图像深度,和x,y方向的差分阶数,缩放因子,delta值和边界模型

#include<opencv2/opencv.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>

using namespace cv;

int main()
{
	//定义变量
	Mat grad_x, grad_y;
	Mat abs_grad_x, abs_grad_y,dst;
	//载入原始图
	Mat src = imread("1.jpg");
	//显示原始图
	imshow("[原始图]Scharr滤波器", src);
	///再求x方向的梯度
	Scharr(src , grad_x, CV_16S, 1, 0, 1, 0, BORDER_DEFAULT);
	convertScaleAbs(grad_x, abs_grad_x);
	imshow("[效果图]X方向Scharr", abs_grad_x);
	//再求Y方向的梯度
	Scharr(src, grad_y, CV_16S, 0, 1, 1, 0, BORDER_DEFAULT);
	convertScaleAbs(grad_y, abs_grad_y);
	imshow("[效果图]Y方向Scharr", abs_grad_y);
	//合并梯度
	addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5,0, dst);
	//显示效果图
	imshow("[效果图]合并梯度后Scharr", dst);
	waitKey(0);
	return 0;
}

最后再写一个综合函数:
出现了一个

Error: Sizes of input arguments do not match (The operation is neither ‘array op array’ (where arrays have the same size and the same number of channels), nor ‘array op scalar’, nor ‘scalar op array’) in

这个问题,也就是输入的参数尺寸不匹配。

#include<opencv2/opencv.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>

using namespace cv;

//先设置全局变量
Mat g_srcImage, g_srcGrayImage, g_dstImage;
//Canny边缘检测相关变量
Mat g_cannyDetectedEdges;
int g_cannyLowThreshold = 1;//TrackBar的位置参数
//Sobel边缘检测相关变量
Mat g_sobelGradient_X, g_sobelGradient_Y;
Mat g_sobelAbsGraient_X, g_sobelAbsGradient_Y;
int g_sobelKernelSize = 1;
//滤波器的相关变量
Mat g_scharrGradient_X, g_scharrGradient_Y;
Mat g_scharrAbsGradient_X, g_scharrAbsGradient_Y;

//全局函数声明
static void on_Canny(int, void*);//Canny边缘检测
static void on_Sobel(int, void*);//Soble边缘检测窗口
void Scharr();//封装了Scharr边缘检测相关代码的函数


int main(int argc,char** argv)
{
	//先改变字体颜色
	system("color 2F");
	//载入原图
	g_srcImage = imread("1.jpg");
	if (!g_srcImage.data) {
		printf_s("读取srcImage错误!\n");
		return false;
	}
	//显示原始图;
	namedWindow("[原始图]");
	imshow("[原始图]", g_srcImage);
	//创建与src同类型和大小的矩阵
	g_dstImage.create(g_srcImage.size(), g_srcImage.type());
	//将原图像转化为灰度图像
	cvtColor(g_srcImage, g_srcGrayImage, COLOR_BGR2GRAY);
	//创建显示窗口
	namedWindow("[效果图]Canny边缘检测", WINDOW_AUTOSIZE);
	namedWindow("[效果图]soble边缘检测", WINDOW_AUTOSIZE);
	//创建trackbar
	createTrackbar("参数值:", "[效果图]Canny边缘检测",&g_cannyLowThreshold,120,on_Canny);
	createTrackbar("参数值:", "[效果图]Sobel边缘检测", &g_sobelKernelSize, 3, on_Sobel);
	//调用回填函数
	on_Canny(0, 0);
	on_Sobel(0, 0);
	//调用了封装了Scharr边缘检测代码的函数
	Scharr();
	//按下Q退出
	while ((char(waitKey(1)) != 'q')) {}
	return 0;
}
//on_Canny函数
void on_Canny(int, void*)
{
	//先降噪
	blur(g_srcGrayImage, g_cannyDetectedEdges, Size(3, 3));
	//再进行运算
	Canny(g_cannyDetectedEdges, g_cannyDetectedEdges, g_cannyLowThreshold, g_cannyLowThreshold * 3, 3);
	//先将g_dstImage内的所有元素设置为0
	g_dstImage = Scalar::all(0);
	//使用Canny算子输入的边缘图作为掩码,进行拷贝
	g_srcImage.copyTo(g_dstImage, g_cannyDetectedEdges);
	//显示效果图
	imshow("[效果图]Canny边缘检测", g_dstImage);

}

//用on_Sobel()函数
void on_Sobel(int, void*)
{
	//先求X方向的梯度
	Sobel(g_srcImage, g_sobelGradient_X, CV_16S, 1, 0, (2 * g_sobelKernelSize + 1), 1, 1, BORDER_DEFAULT);
	convertScaleAbs(g_sobelGradient_X, g_sobelAbsGraient_X);

	//先求Y方向的梯度
	Sobel(g_srcImage, g_sobelGradient_Y, CV_16S, 0, 1, (2 * g_sobelKernelSize + 1), 1, 1, BORDER_DEFAULT);
	convertScaleAbs(g_sobelGradient_Y, g_sobelAbsGradient_Y);

	//合并梯度
	addWeighted(g_sobelAbsGraient_X, 0.5, g_sobelAbsGradient_Y,0.5,0,g_dstImage);

	//显示效果图
	imshow("[效果图]Sobel边缘检测", g_dstImage);
}
//最后一组Scharr()函数
void Scharr()
{
	//先求X方向的梯度
	Scharr(g_srcImage,g_scharrGradient_X, CV_16S, 1, 0,  1, 0, BORDER_DEFAULT);
	convertScaleAbs(g_scharrGradient_X, g_sobelAbsGraient_X);
	//再求Y方向的
	Sobel(g_srcImage, g_scharrGradient_Y, CV_16S, 1, 0, 1, 0, BORDER_DEFAULT);
	convertScaleAbs(g_scharrGradient_Y, g_scharrAbsGradient_Y);

	addWeighted(g_scharrAbsGradient_X, 0.5, g_scharrAbsGradient_Y, 0.5, 0, g_dstImage);

	imshow("[效果图]Scharr滤波器", g_dstImage);
}

7.霍夫变换
作用主要是从当前的图像中提取所需要的特征信息,所以需要在很多场合中快读准确地检测出直线或圆,霍夫变换就是可以识别几何形状的基本方法。
有三种霍夫线变换:1.标准霍夫变换 2.多尺度霍夫变换 3.累计概率霍夫变换。前两个是用HoughLines函数调用的,而后一个是用HoughLinesp函数调用。
第一个函数是HoughLines()函数:
第一个参数是输入图像,第二个是拥有两个元素的输出矢量,然后是以像素为单位的距离精度和以弧度为单位的角度精度,子暗示识别某个部分为图中一条直线时它在累计平面中必须达到的值最后是拥有两个默认值的参数。

#include<opencv2/opencv.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>

using namespace cv;
using namespace std;

int main()
{
	//先载入原始图和对应的变量
	Mat srcImage = imread("1.jpg");
	Mat midImage, dstImage;//一个是临时变量,一个是目标图的定义
	//进行边缘检测和转换为灰度值
	Canny(srcImage, midImage, 50, 200, 3);
	cvtColor(midImage, dstImage, CV_GRAY2BGR);//转化为灰度值
	//再进行霍夫线变换
	//先定义一个矢量结构用来存放线段矢量几何
	vector<Vec2f> lines;
	HoughLines(midImage, lines, 1, CV_PI / 180, 150, 0, 0);
	//再开始在图中绘制每条线段
	for (size_t i = 0; i < lines.size(); i++)
	{
		float rho = lines[i][0], theta = lines[i][1];
		Point pt1, pt2;
		double a = cos(theta), b = sin(theta);
		double x0 = a * rho, y0 = b * rho;
		pt1.x = cvRound(x0 + 1000 * (-b));
		pt1.y = cvRound(y0 + 1000 * (a));
		pt2.x = cvRound(x0 -1000 * (-b));
		pt2.y = cvRound(y0 - 1000 * (a));

		line(dstImage, pt1, pt2, Scalar(55, 100, 195), 1, LINE_AA);
	}
	//先显示原始图
	imshow("[原始图]", srcImage);
	//再显示边缘检测后的图
	imshow("[边缘检测后的图]", midImage);
	//最后显示效果图
	imshow("[效果图]", dstImage);
	waitKey(0);
	return 0;

}

HoughLinesP()函数的话,就是在HoughLines的基础之上,在末尾加了一个能代表概率的P

#include<opencv2/opencv.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>

using namespace cv;
using namespace std;

int main()
{
	//先载入原始图和对应的变量
	Mat srcImage = imread("1.jpg");
	Mat midImage, dstImage;//一个是临时变量,一个是目标图的定义
	//进行边缘检测和转换为灰度值
	Canny(srcImage, midImage, 50, 200, 3);
	cvtColor(midImage, dstImage, CV_GRAY2BGR);//转化为灰度值
	//再进行霍夫线变换
	//先定义一个矢量结构用来存放线段矢量几何
	vector<Vec4i> lines;
	HoughLinesP(midImage, lines, 1, CV_PI / 180,80,50,10);
	//再开始在图中绘制每条线段
	for (size_t i = 0; i < lines.size(); i++)
	{
		Vec4i l = lines[i];
		line(dstImage, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(186, 88, 255), 1, LINE_AA);
	}
	//先显示原始图
	imshow("[原始图]", srcImage);
	//再显示边缘检测后的图
	imshow("[边缘检测后的图]", midImage);
	//最后显示效果图
	imshow("[效果图]", dstImage);
	waitKey(0);
	return 0;

}

霍夫圆变换的话,区别于直线。基本原理是一样的,只不过从表示直线的二维,变成了表示圆的三维。分别是圆心的x,y和一个半径。

它的原理:
1.图像应用边缘检测
2.对每一个非零点用Sobel函数得到梯度
3.用得到的梯度和斜率指定的指向上的点都累加
4.标记图像中每一个非0像素的位置
5.筛选图像的中心
6.对每一个中心,考虑所有的非0像素
7.对像素进行排序
8.保留那些能满足条件的中心

HoughCircles()函数,主要参数是:灰度的输入图像,包括三个元素的输出矢量,检测方法,和一个检测圆心的累加器图像的分别率于输入图像之比的倒数,也就是累加器和输入图像之间分辨率的区别。再是检测到的圆心之间的距离。和检测方法的对应参数。最后以此是圆的最小和最大半径。

#include<opencv2/opencv.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>

using namespace cv;
using namespace std;

int main()
{
	//先载入原始图和对应的变量
	Mat srcImage = imread("1.jpg");
	Mat midImage, dstImage;//一个是临时变量,一个是目标图的定义
	//显示原始图
	imshow("[原始图]", srcImage);
	//再转换为灰度图
	cvtColor(srcImage, midImage, COLOR_BGR2GRAY);//变成灰度图
	GaussianBlur(midImage, midImage, Size(9, 9), 2, 2);
	//再进行霍夫圆变换
	vector<Vec3f> circles;
	HoughCircles(midImage, circles, HOUGH_GRADIENT, 1.5, 10, 200, 100, 0, 0);
	//再一次在图中绘制圆
	for (size_t i = 0; i < circles.size(); i++)
	{
		//定义参数
		Point center(cvRound(circles[i][0]));
			int radius = cvRound(circles[i][2]);
		//绘制圆心
		circle(srcImage, center, 3, Scalar(0, 255, 0), -1, 8, 0);
		//绘制圆轮廓
		circle(srcImage, center, radius, Scalar(155, 50, 255), 3, 8, 0);
	}
	imshow("[效果图]", srcImage);
	waitKey(0);
	return 0;

}

8.重映射
也就是把一幅图像中某位置的像素放置到另一个图片指定位置的过程。也就是需要一个映射函数,将两个位置进行相对的比较和对应。
remap()函数,参数依次是输入和输出图像,再是输入类型的map1和map2再是插值方式:如最近邻插值,双线性插值,双三次样条插值等,最后两个是有默认值的边界参数。

#include<opencv2/opencv.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<iostream>

using namespace cv;
using namespace std;

int main()
{
	//定义变量
	Mat srcImage, dstImage;
	Mat map_x, map_y;

	//载入原始图
	srcImage = imread("1.jpg");
	if (!srcImage.data) {
		printf_s("读取图片错误\n");
		return false;
	}
	imshow("原始图", srcImage);

	//创建和原始图一样的效果图,x重映射图,y重映射图
	dstImage.create(srcImage.size(), srcImage.type());
	map_x.create(srcImage.size(), CV_32FC1);
	map_y.create(srcImage.size(), CV_32FC1);
	//开始双层循环,遍历每一个像素点
	for (int j = 0; j < srcImage.rows; j++) {
		for (int i = 0; i < srcImage.cols; i++)
		{
			//改变map_x和map_y的值
			map_x.at<float>(j, i) = static_cast<float>(i);
			map_y.at<float>(j, i) = static_cast<float>(srcImage.rows - j);

		}
	}
	//再进行重映射操作
	remap(srcImage, dstImage, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));
	//显示效果图
	imshow("[程序窗口]", dstImage);
	waitKey(0);
	return 0;

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值