opencv第七章

本章开始才是真正的难点

开篇边缘检测:canny,sobel,laplacian,scharr

更正一下,上面的GX,GY是算子乘上原图区域之得后得到的梯度结果,就是说右边差了个再乘上原图

这个算法搜索所有连通的弱边缘,如果一条连通的弱边缘的任何一个点和强边缘点连通,则保留这条弱边缘,否则抑制这条弱边缘。搜索时可以用广度优先或者深度优先算法。其中最容易的深度优先算法,一次连通一条边缘算法如下:

  1. 准备一个栈s,一个队列q,设联通指示变量connected为假。从图像的第一个点开始,进入2。
  2. 如果这个点是弱边界点并且没有被标记,把它标记,并把它作为第一个元素放入栈s中,同时把它放入记录连通曲线的队列q,进入3。如果这个点不是弱边界或者已经被标记过,到图像的下一个点,重复2。
  3. 从栈s中取出一个元素,查找它的8像素领域。如果一个领域像素是弱边界并且没有被标记过,把这个领域像素标记,并加入栈s中,同时加入队列q。同时查找领域对应的强边界图,如果有一个像素是强边界,表示这条弱边界曲线和强边界联通,设置connected为真。重复3直到栈中没有元素了。如果connected为假,则依次从队列q中取出每个元素,清空标记。如果connected为真,保留标记。
  4. 清空队列q,设置connected为假,移动到图像的下一个点,到2。

sobel
#include <opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;
int main( ){
	Mat grad_x, grad_y;//【0】创建 grad_x 和 grad_y 矩阵
	Mat abs_grad_x, abs_grad_y,dst;
	Mat src = imread("1.jpg");//【1】载入原始图//工程目录下应该有一张名为1.jpg的素材图
	imshow("【原始图】sobel边缘检测", src); //【2】显示原始图

	Sobel( src, grad_x, CV_16S, 1, 0, 3, 1, 0, BORDER_DEFAULT );//【3】求 X方向梯度
    //入图,出图,深度,X方向差分阶数,Y方向差分阶数,SOBEL核孔径,导数值缩放因子默认1,输出图偏移因子默认0,边界
	convertScaleAbs( grad_x, abs_grad_x );
	imshow("【效果图】 X方向Sobel", abs_grad_x);

	Sobel( src, grad_y, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT );//【4】求Y方向梯度
	convertScaleAbs( grad_y, abs_grad_y );
	imshow("【效果图】Y方向Sobel2", grad_y);
	imshow("【效果图】Y方向Sobel", abs_grad_y);

	addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dst );//【5】合并梯度(近似)
	imshow("【效果图】整体方向Sobel", dst);
	waitKey(0);
	return 0;
}

拉普拉斯算法

拉普拉斯算法:降噪转灰后,用SOBEL算子求X,Y二阶后合并得到梯度
#include <opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;
int main( ){
	Mat src,src_gray,dst, abs_dst;//【0】变量的定义
	src = imread("1.jpg");  【1】载入原始图,工程目录下应该有一张名为1.jpg的素材图
	imshow("【原始图】图像Laplace变换", src);//【2】显示原始图
	GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT );//【3】使用高斯滤波消除噪声
	cvtColor( src, src_gray, COLOR_RGB2GRAY );//【4】转换为灰度图
	Laplacian( src_gray, dst, CV_16S, 3, 1, 0, BORDER_DEFAULT );//【5】使用Laplace函数
    //入图,出图,深度,拉普拉斯比例因子,二阶导数滤波器孔径,结果存入目标前的delta,边界
	convertScaleAbs( dst, abs_dst );//【6】计算绝对值,并将结果转换成8位
	imshow( "【效果图】图像Laplace变换", abs_dst );//【7】显示效果图
	waitKey(0);
	return 0;
}

关于convertScaleAbs函数,其实就是把每一项都变成正数,算法只是考虑梯度的大小,大于一定值就视为边缘而已

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
using namespace std;
int main( ){
	Mat a=Mat(Size(3,3),CV_8SC3);
	a.at<Vec3b>(0,0)[0]=1;
	a.at<Vec3b>(0,1)[0]=2;
	a.at<Vec3b>(0,2)[0]=3;
	a.at<Vec3b>(1,0)[0]=-1;
	a.at<Vec3b>(1,1)[0]=-2;
	a.at<Vec3b>(1,2)[0]=-3;
	a.at<Vec3b>(2,0)[0]=4;
	a.at<Vec3b>(2,1)[0]=4;
	a.at<Vec3b>(2,2)[0]=4;
	cout<<a<<endl;
	Mat b;
    convertScaleAbs( a, b );
    cout<<b<<endl;
	waitKey();
	return 0;
}
[  1,   0,   0,   2,   0,   0,   3,   0,   0;
  -1,   0,   0,  -2,   0,   0,  -3,   0,   0;
   4,   0,   0,   4,   0,   0,   4,   0,   0]
[  1,   0,   0,   2,   0,   0,   3,   0,   0;
   1,   0,   0,   2,   0,   0,   3,   0,   0;
   4,   0,   0,   4,   0,   0,   4,   0,   0]
SCHARR
#include <opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;
int main( ){
	Mat grad_x, grad_y;//【0】创建 grad_x 和 grad_y 矩阵
	Mat abs_grad_x, abs_grad_y,dst;
	Mat src = imread("1.jpg");//【1】载入原始图,工程目录下应该有一张名为1.jpg的素材图
	imshow("【原始图】Scharr滤波器", src);//【2】显示原始图
	Scharr( src, grad_x, CV_16S, 1, 0, 1, 0, BORDER_DEFAULT );//【3】求 X方向梯度
	//入图,出图,深充,X差分阶数,Y差分阶数,缩放因子,delta值,边界(其实SOBEL中可调用)
	convertScaleAbs( grad_x, abs_grad_x );
	imshow("【效果图】 X方向Scharr", abs_grad_x);
	Scharr( src, grad_y, CV_16S, 0, 1, 1, 0, BORDER_DEFAULT );//【4】求Y方向梯度
	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 );//【5】合并梯度(近似)
	imshow("【效果图】合并梯度后Scharr", dst);//【6】显示效果图
	waitKey(0);
	return 0;
}
SCHARR特点是那个求梯度的滤波器
[   [3,10,3],
    [0,0,0],
    [-3,-10,-3]]

下面是本章最后一个难点:HOUGH!!!

霍夫线变换分为:标准,多尺度,累计概率

hough线检测
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;
int main( ){
	Mat srcImage = imread("1.jpg");  //工程目录下应该有一张名为1.jpg的素材图
	Mat midImage,dstImage;//临时变量和目标图的定义
	Canny(srcImage, midImage, 50, 200, 3);//进行一此canny边缘检测,低阀值,高阀值,边界
	cvtColor(midImage,dstImage, COLOR_GRAY2BGR);//转化边缘检测后的图为灰度图
	vector<Vec2f> lines;//定义一个矢量结构lines用于存放得到的线段矢量集合
	HoughLines(midImage, lines, 1, CV_PI/180, 150, 0, 0 );//进行霍夫线变换
    //入图,储存检测到的线,距离精度(直线搜索线步长),角度精度(直线搜索角步长),阀值函数(即多少个交点视为直线)
    //第六个参数:对于多尺度变换是第三个参数进步尺寸rho的除数距离
    //第七个参数:对于多尺度变换是第四个参数进步尺寸单位角度theta的除数距离
	for( size_t i = 0; i < lines.size(); i++ ){//【4】依次在图中绘制出每条线段
		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));//以X0,Y0为中心向一边走
		pt1.y = cvRound(y0 + 1000*(a));
		pt2.x = cvRound(x0 - 1000*(-b));//以X0,Y0为中心向另一边走
		pt2.y = cvRound(y0 - 1000*(a));
		line( dstImage, pt1, pt2, Scalar(55,100,195), 1, LINE_AA);//画线段
	}
	imshow("【原始图】", srcImage);//【5】显示原始图
	imshow("【边缘检测后的图】", midImage);//【6】边缘检测后的图
	imshow("【效果图】", dstImage);//【7】显示效果图
	waitKey(0);
	return 0;
}
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;
int main( ){
	//【1】载入原始图和Mat变量定义
	Mat srcImage = imread("1.jpg");  //工程目录下应该有一张名为1.jpg的素材图
	Mat midImage,dstImage;//临时变量和目标图的定义
	//【2】进行边缘检测和转化为灰度图
	Canny(srcImage, midImage, 50, 200, 3);//进行一此canny边缘检测
	cvtColor(midImage,dstImage, COLOR_GRAY2BGR);//转化边缘检测后的图为灰度图
	//【3】进行霍夫线变换
	vector<Vec4i> lines;//定义一个矢量结构lines用于存放得到的线段矢量集合
	HoughLinesP(midImage, lines, 1, CV_PI/180, 80, 50, 10 );//变换同时在中图画
	//第六个参数50表示最低线段长度,低于这个线段不被显现
	//第七个参数10表示允许同一行点与点间连接起来的最大距离
	//【4】依次在图中绘制出每条线段
	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);
	}
	//【5】显示原始图
	imshow("【原始图】", srcImage);
	//【6】边缘检测后的图
	imshow("【边缘检测后的图】", midImage);
	//【7】显示效果图
	imshow("【效果图】", dstImage);
	waitKey(0);
	return 0;
}

霍夫圆
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;
int main( ){
	//【1】载入原始图、Mat变量定义
	Mat srcImage = imread("1.jpg");  //工程目录下应该有一张名为1.jpg的素材图
	Mat midImage,dstImage;//临时变量和目标图的定义
	//【2】显示原始图
	imshow("【原始图】", srcImage);
	//【3】转为灰度图并进行图像平滑
	cvtColor(srcImage,midImage, COLOR_BGR2GRAY);//转化边缘检测后的图为灰度图
	GaussianBlur( midImage, midImage, Size(9, 9), 2, 2 );
	//【4】进行霍夫圆变换
	vector<Vec3f> circles;
	HoughCircles( midImage, circles, HOUGH_GRADIENT,1.5, 10, 200, 100, 0, 0 );
	//入图,输出矢量,检测方法,入图分辩率比类加器,圆心间最小距离
	//200是CANNY算子高阀值(低阀值为一半),100是累加器阀值(多少票视为圆),圆半径最小值,圆半径最大值
	//【5】依次在图中绘制出圆
	for( size_t i = 0; i < circles.size(); i++ ){
		//参数定义
		Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
		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 );
	}
	//【6】显示效果图
	imshow("【效果图】", srcImage);
	waitKey(0);
	return 0;
}

重映射

重映射
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace cv;
int main(){
	//【0】变量定义
	Mat srcImage, dstImage;
	Mat map_x, map_y;
	//【1】载入原始图
	srcImage = imread( "1.jpg", 1 );
	if(!srcImage.data ) { printf("读取图片错误,请确定目录下是否有imread函数指定的图片存在~! \n"); return false; }
	imshow("原始图",srcImage);
	//【2】创建和原始图一样的效果图,x重映射图,y重映射图
	dstImage.create( srcImage.size(), srcImage.type() );
	map_x.create( srcImage.size(), CV_32FC1 );
	map_y.create( srcImage.size(), CV_32FC1 );
	//【3】双层循环,遍历每一个像素点,改变map_x & map_y的值
	for( int j = 0; j < srcImage.rows;j++){
		for( int i = 0; i < srcImage.cols;i++){
			map_x.at<float>(j,i) = static_cast<float>(i);//改变map_x的值.
			map_y.at<float>(j,i) = static_cast<float>(srcImage.rows - j);//改变map_y的值.
		}
	}
	//【4】进行重映射操作:入图,出图,X映射,Y映射,双线性插值,边界模式,常数边界值
	remap( srcImage, dstImage, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(0,0, 0) );
	//【5】显示效果图
	imshow( "【程序窗口】", dstImage );
	waitKey();
	return 0;
}

变换有两个函数,第一个用于平移&拉伸,第二个用于旋转&缩放,考的是矩阵变换,原理要看线性代数!!!

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
#define WINDOW_NAME1 "【原始图窗口】"				//为窗口标题定义的宏
#define WINDOW_NAME2 "【经过Warp后的图像】"         //为窗口标题定义的宏
#define WINDOW_NAME3 "【经过Warp和Rotate后的图像】" //为窗口标题定义的宏
int main(){
    //【1】参数准备
	//定义两组点,代表两个三角形
	Point2f srcTriangle[3];
	Point2f dstTriangle[3];
	//定义一些Mat变量
	Mat rotMat( 2, 3, CV_32FC1 );
	Mat warpMat( 2, 3, CV_32FC1 );
	Mat srcImage, dstImage_warp, dstImage_warp_rotate;

	//【2】加载源图像并作一些初始化
	srcImage = imread( "1.jpg", 1 );
	if(!srcImage.data ) { printf("读取图片错误,请确定目录下是否有imread函数指定的图片存在~! \n"); return false; }
	// 设置目标图像的大小和类型与源图像一致
	dstImage_warp = Mat::zeros( srcImage.rows, srcImage.cols, srcImage.type() );

	//【3】设置源图像和目标图像上的三组点以计算仿射变换
	srcTriangle[0] = Point2f( 0,0 );
	srcTriangle[1] = Point2f( static_cast<float>(srcImage.cols - 1), 0 );
	srcTriangle[2] = Point2f( 0, static_cast<float>(srcImage.rows - 1 ));

	dstTriangle[0] = Point2f( static_cast<float>(srcImage.cols*0.0), static_cast<float>(srcImage.rows*0.33));
	dstTriangle[1] = Point2f( static_cast<float>(srcImage.cols*0.65), static_cast<float>(srcImage.rows*0.35));
	dstTriangle[2] = Point2f( static_cast<float>(srcImage.cols*0.15), static_cast<float>(srcImage.rows*0.6));

	//【4】求得仿射变换
	warpMat = getAffineTransform( srcTriangle, dstTriangle );//这一步得到的是仿射变换矩阵!!!平移&拉伸,全文第一处关键,请用线代知识证明

	//【5】对源图像应用刚刚求得的仿射变换
	warpAffine( srcImage, dstImage_warp, warpMat, dstImage_warp.size() );

	//【6】对图像进行缩放后再旋转
	// 计算绕图像中点顺时针旋转50度缩放因子为0.6的旋转矩阵
	Point center = Point( dstImage_warp.cols/2, dstImage_warp.rows/2 );
	double angle = -50.0;
	double scale = 0.6;
	// 通过上面的旋转细节信息求得旋转矩阵
	rotMat = getRotationMatrix2D( center, angle, scale );//这一步得到的是旋转矩阵!!!旋转&缩放,全文第二处关键,请用线代知识证明
	// 旋转已缩放后的图像
	warpAffine( dstImage_warp, dstImage_warp_rotate, rotMat, dstImage_warp.size() );

	//【7】显示结果
	imshow( WINDOW_NAME1, srcImage );
	imshow( WINDOW_NAME2, dstImage_warp );
	imshow( WINDOW_NAME3, dstImage_warp_rotate );

	// 等待用户按任意按键退出程序
	waitKey(0);

	return 0;
}

直方图均衡化,一点都不难!!!

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
using namespace cv;
int main( ){
	Mat srcImage, dstImage;
	srcImage = imread( "1.jpg", 1 );// 【1】加载源图像
	if(!srcImage.data ) { printf("读取图片错误,请确定目录下是否有imread函数指定图片存在~! \n"); return false; }
	cvtColor( srcImage, srcImage, COLOR_BGR2GRAY );// 【2】转为灰度图并显示出来
	imshow( "原始图", srcImage );
	equalizeHist( srcImage, dstImage );// 【3】进行直方图均衡化
	imshow( "经过直方图均衡化后的图", dstImage );// 【4】显示结果
	waitKey(0);// 等待用户按键退出程序
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值