OpenCV3学习笔记(七)-----------图像变换

1、基于OpenCV的边缘检测

步骤:①滤波:边缘检测的算法只要是基于图像增强的一阶和二阶导数,但导数通常对噪声很明感,因此必须采用滤波器来改善与噪音有关的边缘检测器的性能。(高斯滤波采用高斯离散化的高斯函数产生一组归一化的高斯核,然后基于高斯核函数对图像灰度矩阵的每一点进行加权求和)

          ②增强:增强边缘的基础是确定图像各点邻域强度的变化值。增强算法可以将灰度点邻域强度值有显著变化的点凸显出来。在具体编程现实时,可通过计算梯度幅值来确定。

          ③检测:采用阈值化方法来检测,从而去一些点进行取舍。

Canny边缘检测:

步骤:①消除噪声-----高斯平滑滤波器卷积降噪(5*5的核)

          ②计算梯度幅值和方向(sobel滤波器)

          ③非极大值抑制------排除非边缘像素,保留一些细微线条

         ④滞后阈值(高阈值、低阈值)-----较小的值用于边缘连接,较大的值用于控制强边缘的初始段(高低比2:1到3:1之间)

canny()函数:

void Canny(
InputArray image,                //输入的原图像
OutputArray edges,               //输出的边缘图
double threshold1,double threshold2,  //两个滞后性阈值
int apertureSize=3,                   //表示应用Sobel算子的孔径大小(默认值3)
bool L2gradient=false                 //一个计算图像梯度幅值的标识(默认false)
);

sobel算子: 

sobel算子主要用于边缘检测的离散微分算子。结合了高斯平滑和微分求导,用来计算图像灰度函数的近似梯度。在图像的任何一点使用此算子,都将产生对应的梯度矢量或是其矢量法。

sobel()函数:

void Sobel(
InputArray src,OutputArray dst,//输入图像、目标图像
int ddepth,                    //输出图像的深度
int dx,int dy,                 //x、y方向上的差分阶数
int ksize=1,                    //表示sobel核的大小(默认3   取1,3,5或7)
double delta=0,                //计算导数值时可选的缩放因子(默认1即无缩放)
int borderType=BORDER_DEFAULT  //边界模式
);

Laplacian算子(二阶微分算子): 

让一幅图像减去他的laplacian算子可以增强对比度

Laplacian()函数:

void Laplacian(
InputArray src,OutputArray dst,  //输入输出图像
int ddepth,                     // 目标图像的深度
int ksize=1,                   //用于计算二阶导数的滤波器的孔径大小(奇数)
double scale=1,                //计算阿普拉斯值的时候可选的比例因子
double delta=0,                //表示存入目标图像之前可选的delta值
int borderType=BORDER_DEFAULT  //边界模式
); 

scharr滤波器: 

为配合Sobel算子的运算而存在。

Scharr()函数:

void Scharr(
InputArray src,OutputArray dst,//输入图像、目标图像
int ddepth,                    //输出图像的深度
int dx,int dy,                 //x、y方向上的差分阶数
double scale=1,                计算导数值时可选的缩放因子(默认1即无缩放)
double delta=0,                //表示存入目标图之前可选的delta值(默认0)
int borderType=BORDER_DEFAULT  //边界模式
);

边缘检测的综合示例:

 

//--------------------【边缘检测综合示例】------------------
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>

using namespace cv;
using namespace std;

//-----------------【全局变量声明部分】---------------------------
//      描述:全局变量声明
//----------------------------------------------------------
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_sobelAbsGradient_x, g_sobelAbsGradeng_y;
int g_sobelKernelSize = 1;//TrackBar位置参数

//Scharr滤波器相关变量
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*);//Sobel边缘检测窗口滚动条的回调函数
void Scharr();//封装了Scharr边缘检测相关代码的函数

//-----------------【main()函数】---------------------------
//      描述:控制台应用程序的入口函数,我们的程序从这里开始
//----------------------------------------------------------
int main(int argc,char** argv) {
	//改变console字体颜色
	system("color 2F");

	//载入原图
	g_srcImage = imread("juan.jpg");
	if (!g_srcImage.data) { printf("读取图片错误 \n"); return false; }

	//显示原始图像
	namedWindow("【原始图】");
	imshow("【原始图】",g_srcImage);

	//创建于src同类型和大小的矩阵(dst)
	g_dstImage.create(g_srcImage.size(), g_srcImage.type());
	
	//将原图像转换为灰度图像
	cvtColor(g_srcImage,g_srcGrayImage,COLOR_BGR2GRAY);

	//创建显示图像
	namedWindow("【效果图】Canny边缘检测",WINDOW_AUTOSIZE);
	namedWindow("【效果图】Sobel边缘检测", 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')) {}
	
	system("pause");
	return 0;
}
//-----------------【on_Canny()函数】---------------------------
//      描述:Canny边缘检测窗口滚动条的回调函数
//----------------------------------------------------------
void on_Canny(int,void*) {
	//先使用3x3内核来降噪
	blur(g_srcGrayImage,g_cannyDetectedEdges,Size(3,3));

	//运行我的Canny算子
	Canny(g_cannyDetectedEdges,g_cannyDetectedEdges,g_cannyLowThreshold,g_cannyLowThreshold*3,3);

	//先将g_dstImage内的所有元素设置为0
	g_dstImage = Scalar::all(0);

	//使用Canny算子输出的边缘图g_cannyDetectedEdges作为掩码,来将原图g_srcIMage拷到目标图g_dstImage中
	g_srcImage.copyTo(g_dstImage,g_cannyDetectedEdges);

	//显示效果图
	imshow("【效果图】Canny边缘检测",g_dstImage);
}


//-----------------【on_Sobel()函数】---------------------------
//      描述: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_sobelAbsGradient_x);//计算绝对值,并将结果装换成8位

	//求y方向的梯度
	Sobel(g_srcImage, g_sobelGradient_y, CV_16S, 0, 1, (2 * g_sobelKernelSize + 1), 1, 1, BORDER_DEFAULT);
	convertScaleAbs(g_sobelGradient_y, g_sobelAbsGradeng_y);//计算绝对值,并将结果装换成8位

	//合并梯度
	addWeighted(g_sobelAbsGradient_x,0.5,g_sobelAbsGradeng_y,0.5,0,g_dstImage);
	//显示效果图
	imshow("【效果图】Sobel边缘检测", g_dstImage);
}

//-----------------【Scharr()函数】---------------------------
//      描述:Sobel边缘检测窗口滚动条的回调函数
//----------------------------------------------------------
void Scharr() {
	//求x方向梯度
	Scharr(g_srcImage, g_scharrGradient_x, CV_16S, 1, 0, 1, 0, BORDER_DEFAULT);
	convertScaleAbs(g_scharrGradient_x, g_scharrAbsGradient_x);//计算绝对值,并将结果装换成8位

	//求y方向的梯度
	Scharr(g_srcImage, g_scharrGradient_y, CV_16S, 0,1, 1, 0, BORDER_DEFAULT);
	convertScaleAbs(g_scharrGradient_y, g_scharrAbsGradient_y);//计算绝对值,并将结果装换成8位

	//合并梯度
	addWeighted(g_scharrAbsGradient_x, 0.5, g_scharrAbsGradient_y, 0.5, 0, g_dstImage);
	//显示效果图
	imshow("【效果图】Scharr滤波器", g_dstImage);
}

2、霍夫变换

图像处理中从图像中识别几何形状的基本方法之一。最基本的霍夫变换是从黑白图像中检测直线。

霍夫变换是图像处理中的一种特征提取技术,该过程在一个参数空间中通过计算累计结果的局部最大值得到一个符合该特定形状的集合作为霍夫变换的结果。

使用霍夫变换前首先要对图像进行边缘检测处理,即霍夫变换的直接输入只能是边缘二值图像

标准霍夫变换------HoughLines()函数:

void HoughLines(
InputArray image,   //输入图像
OutputArray lines,  //经过调用HoughLines函数后存储了霍夫变换检测到线条的输出矢量
double rho,         //以像素为单位的距离精度(直线搜索时的进步尺寸的单位半径)
double theta,       //以弧度为单位的角度精度(直线搜索时的进步尺寸的单位角度)
int threshold, 
//累加平面的阈值参数(识别某部分为图中的一条直线时它在累加平面中必须达到的值(返回大于阈值的))
double srn=0,       //(默认0)参数进步尺寸rho的除数距离
double stn=0        //进步尺寸的单位角度theta的除数距离
);

累计概率霍夫变换------HoughLinesP()函数:

void HoughLinesP(
InputArray image,   //输入图像
OutputArray lines,  //经过调用HoughLines函数后存储了霍夫变换检测到线条的输出矢量
double rho,         //以像素为单位的距离精度(直线搜索时的进步尺寸的单位半径)
double theta,       //以弧度为单位的角度精度(直线搜索时的进步尺寸的单位角度)
int threshold, 
//累加平面的阈值参数(识别某部分为图中的一条直线时它在累加平面中必须达到的值(返回大于阈值的))
double minLineLength=0,       //(默认0)表示最低线段的长度(短与它不显示)
double maxLineGap=0        //(默认0)允许将同一行点与点之间连接起来的最大距离
);

霍夫圆变换------HoughCircles()函数:

void HoughCircles(
InputArray image,   //输入图像
OutputArray circles,  //经过调用HoughCircles函数后存储了检测到的圆的输出矢量
int method,           //使用的检测方法
double dp,            //用来检测圆心的累加器图像的分辨率与输入图像之比的倒数
double minDist,      //检测到的圆心之间的距离
double paraml=100,   //参数三设置的检测方法对应的参数(默认100)
double param2=100,   //参数三设置的检测方法对应的参数(默认100)
int minRadius=0,     //(默认0)表示圆半径的最小值
int maxRadius=0      //(默认0)表示圆半径的最大值
);

霍夫变换综合示例代码:

//-------------------------【霍夫变换(特征提取技术)】-------------------------------------------------
//   描述:图像处理中从图像中识别几何形状的基本方法之一;可以快速准确的检测出直线或者圆。
//        最基本的霍夫变换是从黑白图像中检测直线(线段)
//---------------------------------------------------------------------------------------

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

using namespace cv;
using namespace std;

//--------------------------【全局变量声明部分】-------------------------
//     描述:全局变量声明
//-----------------------------------------------------------------------
Mat g_srcImage, g_dstImage, g_midImage;//原始图、效果图、中间图
vector<Vec4i> g_lines;//定义一个矢量结构,用于存放得到的线段矢量集合

int g_nThreshold = 100;//变量接收的TrackBar位置参数


//--------------------------【全局函数声明部分】-------------------------
//     描述:全局函数声明
//-----------------------------------------------------------------------
static void on_HoughLines(int,void*);//回调函数


//--------------------------【main()函数】-------------------------------
//     描述:控制台应用程序的入口函数,我们的程序从这里开始
//-----------------------------------------------------------------------
int main() {
	//改变console字体颜色
	system("color 3F");

	//载入原始图像和Mat变量定义
	g_srcImage = imread("juan.jpg");

	imshow("【原始图】",g_srcImage);

	//创建滚动条
	namedWindow("【效果图】",1);
	createTrackbar("值","【效果图】",&g_nThreshold,200,on_HoughLines);

	//进行边缘检测和转化为灰度图
	Canny(g_srcImage,g_midImage,50,200,3);//进行一次canny边缘检测
	//namedWindow("【原始图边缘检测】");
	//imshow("【原始图边缘检测】", g_midImage);
	cvtColor(g_midImage,g_dstImage,COLOR_GRAY2BGR);//转化边缘检测后的图像为灰度图

	//调用一次回调函数,调用一次HoughLinesP函数
	on_HoughLines(g_nThreshold,0);
	HoughLinesP(g_midImage,g_lines,1,CV_PI/180,80,50,10);
	
	imshow("【效果图】",g_dstImage);
	waitKey(0);
	return 0;
}


//--------------------------【on_HoughLines()函数】----------------------
//     描述:on_HoughLines()函数
//-----------------------------------------------------------------------
static void on_HoughLines(int,void*) {
	
	//定义局部变量储存全局变量
	Mat dstImage = g_dstImage.clone();
	Mat midImage = g_midImage.clone();

	//调用HoughLinesP函数
	vector<Vec4i> mylines;
	HoughLinesP(midImage,mylines,1,CV_PI/180,g_nThreshold+1,50,10);

	//循环遍历绘制每一条线段
	for (size_t i = 0; i < mylines.size();i++) {
		Vec4i l = mylines[i];
		line(dstImage,Point(l[0],l[1]),Point(l[2],l[3]),Scalar(23,180,55),1,LINE_AA);

	}
	imshow("【效果图】", g_dstImage);
}

 

3、重映射

重映射就是把一幅图像中某位置的像素放置到另一个图片指定位置的过程。为了完成映射过程,需要获取一些插值为非整数像素的坐标,因为原图像与目标图像的像素坐标不是一一对应的。

重映射函数---remap()函数

void remap(
InputArray src,OutprtArray dst,    //输入输出图像
InputArray map1,
//有两种可能表示的对象:点的第一个映射(x,y);CV_32FC2或CV_32FC1或CV_16SC2类型的X值 
InputArray map2,  
//有两种可能表示的对象:若map1表示点(x,y)时,此参数不代表任何值;CV_16UC1或CV_32FC1类型的Y值 
int interpolation,                 //插值方式     
int borderMode=BORDER_CONSTANT,    //边界模式
const Scalar& borderValue=Scalar() //当有常数边界时使用的值(默认Scalar()即0)
); 

实现多种重映射综合示例代码:

//-------------------------【重映射】-------------------------------------------------
//   描述:把一幅图像中某位置的像素放置到另一个图片指定位置的过程
//---------------------------------------------------------------------------------------

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

using namespace cv;
using namespace std;

#define WINDOW_NAME "【程序窗口】"  //为窗口标题定义的宏

//--------------------------【全局变量声明部分】-------------------------
//     描述:全局变量声明
//-----------------------------------------------------------------------
Mat g_srcImage, g_dstImage;//原始图、效果图
Mat g_map_x, g_map_y;

//--------------------------【全局函数声明部分】-------------------------
//     描述:全局函数声明
//-----------------------------------------------------------------------

int update_map(int key);//回调函数
static void ShowHelpText();//输出帮助文字


//--------------------------【main()函数】-------------------------------
//     描述:控制台应用程序的入口函数,我们的程序从这里开始
//-----------------------------------------------------------------------
int main(int argc,char** argv) {
	
	//改变console字体颜色
	system("color 2F");
	//显示帮助文档
	ShowHelpText();

	//【1】载入原始图像
	g_srcImage = imread("juan.jpg",1);
	if (!g_srcImage.data) { printf("读取图片错误~ \n"); return false; }
	imshow("【原始图】", g_srcImage);

	//【2】创建和原图一样的效果图,x重映射图,y重映射图

	g_dstImage.create(g_srcImage.size(),g_srcImage.type());
	g_map_x.create(g_srcImage.size(),CV_32FC1);
	g_map_y.create(g_srcImage.size(),CV_32FC1);

	//【3】创建窗口并显示
	namedWindow(WINDOW_NAME,WINDOW_AUTOSIZE);
	imshow(WINDOW_NAME, g_srcImage);

	//【4】轮询按键,更新map_x和map_y的值,进行重映射操作并显示效果图
	while (1)
	{
		//获取键盘按键
		int key = waitKey(0);

		//判断ESC是否按下,若按下便退出
		if ((key&255)==27) {
			cout << "程序退出。。。。。。 \n";
			break;
		}
		//根据按下的键盘按键来更新map_x&map_y的值,然后调用remap()进行重映射
		update_map(key);
		remap(g_srcImage,g_dstImage,g_map_x,g_map_y,INTER_LINEAR,BORDER_CONSTANT,Scalar(0,0,0));

		//显示效果图
		imshow(WINDOW_NAME, g_dstImage);
	}
	return 0;
}


//--------------------------【update_map()函数】----------------------
//     描述:根据按键来更新map_x与map_y的值
//-----------------------------------------------------------------------
int update_map(int key) {

	//双层循环,遍历每一个像素点
	for (int j = 0; j < g_srcImage.rows;j++) {
		for (int i = 0; i < g_srcImage.cols; i++) {
			switch (key)
			{
			case '1':  //键盘【1】键按下,进行第一种重映射操作
				if (i>g_srcImage.cols*0.25 && i<g_srcImage.cols*0.75 && j>g_srcImage.rows*0.25 && j<g_srcImage.rows*0.75) {
					g_map_x.at<float>(j, i) = static_cast<float>(2 * (i - g_srcImage.cols*0.25) + 0.5);
					g_map_y.at<float>(j, i) = static_cast<float>(2 * (j - g_srcImage.rows*0.25) + 0.5);
				}
				else
				{
					g_map_x.at<float>(j, i) = 0;
					g_map_y.at<float>(j, i) = 0;
				}
				break;
			case '2'://键盘【2】键按下,进行第二种重映射操作
				g_map_x.at<float>(j, i) = static_cast<float>(i);
				g_map_y.at<float>(j, i) = static_cast<float>(g_srcImage.rows-j);
				break;
			case '3'://键盘【3】键按下,进行第三种重映射操作
				g_map_x.at<float>(j, i) = static_cast<float>(g_srcImage.cols-i);
				g_map_y.at<float>(j, i) = static_cast<float>(j);
				break;
			case '4'://键盘【4】键按下,进行第四种重映射操作
				g_map_x.at<float>(j, i) = static_cast<float>(g_srcImage.cols-i);
				g_map_y.at<float>(j, i) = static_cast<float>(g_srcImage.rows - j);
				break;
			}

		}

	}
	return 1;
}

//--------------------------【ShowHelpText()函数】----------------------
//     描述:输出一些帮助信息
//-----------------------------------------------------------------------
static void ShowHelpText() {
	//输出一些帮助信息
	printf("\n\n\n\t欢迎来到重映射示例程序~\n\n");
	printf("\t当前使用的opencv版本为opencv3.4.1");
	printf("\n\n\t按键操作说明:\n\n"
		"\t\t键盘按键【ESC】~退出程序\n"
		"\t\t键盘按键【1】~第一种映射方式\n"
		"\t\t键盘按键【2】~第二种映射方式\n"
		"\t\t键盘按键【3】~第三种映射方式\n"
		"\t\t键盘按键【4】~第四种映射方式\n"
	);
}

 

4、仿射变换

仿射变换是指在几何中,一个向量空间进行一次线性变换并接上一个平移,变换为另一个向量空间的过程。

 一个任意的仿射变换都能表示为乘以一个矩阵(线性变换)接着再加上一个向量(平移)的形式
仿射变换形式:旋转rotation、平移translation、缩放scale

进行仿射变换----warpAffine()函数:

void warpAffine(
InputArray src,OutprtArray dst,    //输入输出图像
InputArray M,                      //2*3的变换矩阵
Size dsize,                        //表示输出图像的尺寸
int flags=INTER_LINEAR,            //插值方法的标识符
int borderMode=BORDER_CONSTANT,    //边界像素模式(默认BORDER_CONSTANT)
const Scalar& borderValue=Scalar() //当有常数边界时使用的值(默认Scalar()即0)
 );

计算二维旋转变换矩阵:getRotationMatrix2D()函数

Mat getRotationMatrix2D(
Point2f center,   //表示原图像的旋转中心
double angle,     //旋转角度
double scale      //缩放系数
);

 仿射变换示例程序代码:

//--------------------------【仿射变换】--------------------------
//  描述:是指在几何中,一个向量空间进行一次线性变换并接上一个平移,变换为另一个向量空间的过程。
//        一个任意的仿射变换都能表示为乘以一个矩阵(线性变换)接着再加上一个向量(平移)的形式
//         变换形式:旋转rotation、平移translation、缩放scale


#include <opencv2/opencv.hpp>
#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后的图像】"  //为窗口标题定义的宏

//--------------------------【全局函数声明部分】-------------------------
//     描述:全局函数声明
//-----------------------------------------------------------------------

static void ShowHelpText();//输出帮助文字


//--------------------------【main()函数】-------------------------------
//     描述:控制台应用程序的入口函数,我们的程序从这里开始
//-----------------------------------------------------------------------
int main(int argc,char** argv) {

	//【0】改变console字体颜色
	system("color 1A");
	//【0】显示帮助文档
	ShowHelpText();

	//【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("juan.jpg",1);
	if (!srcImage.data) { printf("读取图片错误~ \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 = -30.0;//旋转角度
	double scale = 0.8;//旋转系数(比例)

	//通过上面的旋转细节信息求得旋转矩阵
	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;
}

//--------------------------【ShowHelpText()函数】----------------------
//     描述:输出一些帮助信息
//-----------------------------------------------------------------------
static void ShowHelpText() {
	//输出一些帮助信息
	printf("\n\n\n\t欢迎来到【仿射变换】示例程序~\n\n");
	printf("\t当前使用的opencv版本为opencv3.4.1");
	
}

5、直方图均衡化

用来扩大图像的动态范围。用一定的算法使直方图大致平和的方法。是通过拉伸像素强度分布范围来增强图像对比度的一种方法。

实现直方图均衡化:equalizeHist()函数

void equalizeHist(InputArray src,OutputArray dst);

直方图均衡化示例代码:

//------------------------【直方图均衡化(灰度变换的应用)】------------------------
//    描述:用来扩大图像的动态范围。用一定的算法使直方图大致平和的方法。
//         是通过拉伸像素强度分布范围来增强图像对比度的一种方法。
//-----------------------------------------------------------------------------------

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

using namespace cv;

//--------------------------【main()函数】-------------------------------
//     描述:控制台应用程序的入口函数,我们的程序从这里开始
//-----------------------------------------------------------------------
int main() {
	
	//【1】加载原图
	Mat srcImage, dstImage;
	srcImage = imread("juan.jpg",1);
	if (!srcImage.data) { printf("读取图片错误~ \n"); return false; }

	//【2】转换为灰度图像并显示
	cvtColor(srcImage,srcImage,COLOR_BGR2GRAY);
	imshow("原始图",srcImage);

	//【3】进行直方图均衡化
	equalizeHist(srcImage,dstImage);

	//【4】显示结果
	imshow("经过直方图均衡化后的图",dstImage);
	waitKey(0);
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值