图像金字塔与尺寸缩放:
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
#define WINDOW_NAME "【程序窗口】" //为窗口标题定义的宏
Mat g_srcImage, g_dstImage, g_tmpImage;
static void ShowHelpText();
int main( )
{
//改变console字体颜色
system("color 2F");
//显示帮助文字
ShowHelpText();
//载入原图
g_srcImage = imread("1.jpg");//工程目录下需要有一张名为1.jpg的测试图像,且其尺寸需被2的N次方整除,N为可以缩放的次数
if( !g_srcImage.data ) { printf("Oh,no,读取srcImage错误~! \n"); return false; }
// 创建显示窗口
namedWindow( WINDOW_NAME, CV_WINDOW_AUTOSIZE );
imshow(WINDOW_NAME, g_srcImage);
//参数赋值
g_tmpImage = g_srcImage;
g_dstImage = g_tmpImage;
int key =0;
//轮询获取按键信息
while(1)
{
key=waitKey(9) ;//读取键值到key变量中
//根据key变量的值,进行不同的操作
switch(key)
{
//======================【程序退出相关键值处理】=======================
case 27://按键ESC
return 0;
break;
case 'q'://按键Q
return 0;
break;
//======================【图片放大相关键值处理】=======================
case 'a'://按键A按下,调用pyrUp函数
pyrUp( g_tmpImage, g_dstImage, Size( g_tmpImage.cols*2, g_tmpImage.rows*2 ) );
/*向上采样并模糊一张图片,即放大一张图片,朝向金字塔下方
第一个参数:输入图像;
第二个参数:输出图像;
第三个const Size&类型的dstsize,输出图像的大小;有默认值Size(),即在默认情况下,由Size(src.cols*2,src.rows*2)来计算,
且一直需要满足:|dstsize.width-src.cols*2|<=(dstsize.width mode 2)所以各边放大到原来的2倍;
第四个参数:边界模式
实现过程:将原来维数扩大一倍,对于增加值用0填充再与高斯矩阵卷积;
拉普拉斯金字塔:图像首先在每个维度上扩大为原来的两倍,新增的行以0填充,然后给指定的滤波器进行卷积(实际上是一个在每一维上都扩大为2倍的过滤器)
去估计“丢失”像素的近似值。得到后的图像与原来的图像相比较会发觉比较模糊,丢失了一些信息。为了恢复出原来的图像,我们需要获得这些丢失的信息,
这些信息就构成了拉普拉斯金字塔。*/
printf( ">检测到按键【A】被按下,开始进行基于【pyrUp】函数的图片放大:图片尺寸×2 \n" );
break;
case 'w'://按键W按下,调用resize函数
resize(g_tmpImage,g_dstImage,Size( g_tmpImage.cols*2, g_tmpImage.rows*2 ));
/*第一个参数:输入图像;第二个参数:输出图像,当其为非零时,有着第三参数的尺寸,或者由src.size()计算出来;
第三个参数:Size类型的dsize,输出图像的大小。如果它等于零,则由dsize=Size(round(fx*src.cols),round(fy*src.rows))计算得到round为四舍五入;
第四个参数:double类型的fx,沿水平轴的缩放系数,有默认值0,且当其为0时,由(double)dsize.width/src.cols计算得到;
第五个参数:double类型的fy,沿垂直轴的缩放系数,同上;
第六个参数:int类型的interpolation,用于指定插值方式,默认为INTER_LINEAR(线性插值)具体方式如下:
INTER_NEAREST - 最近邻插值法
INTER_LINEAR - 双线性插值法(默认)
INTER_AREA - 基于局部像素的重采样(resampling using pixel area relation)。对于图像抽取(image decimation)来说,这可能是一个更好的方法。但如果是放大图像时,它和最近邻法的效果类似。
INTER_CUBIC - 基于4x4像素邻域的3次插值法
INTER_LANCZOS4 - 基于8x8像素邻域的Lanczos插值
若要缩小图像,一般情况下最好用CV_INTER_AREA来插值;若要放大图像,一般情况下最好用CV_INTER_CUBIC(效率不高,慢)或CV_INTER_LINEAR(效率较高,速度较快,推荐使用)
*/
printf( ">检测到按键【W】被按下,开始进行基于【resize】函数的图片放大:图片尺寸×2 \n" );
break;
case '1'://按键1按下,调用resize函数
resize(g_tmpImage,g_dstImage,Size( g_tmpImage.cols*2, g_tmpImage.rows*2 ));
printf( ">检测到按键【1】被按下,开始进行基于【resize】函数的图片放大:图片尺寸×2 \n" );
break;
case '3': //按键3按下,调用pyrUp函数
pyrUp( g_tmpImage, g_dstImage, Size( g_tmpImage.cols*2, g_tmpImage.rows*2 ));
printf( ">检测到按键【3】被按下,开始进行基于【pyrUp】函数的图片放大:图片尺寸×2 \n" );
break;
//======================【图片缩小相关键值处理】=======================
case 'd': //按键D按下,调用pyrDown函数
pyrDown( g_tmpImage, g_dstImage, Size( g_tmpImage.cols/2, g_tmpImage.rows/2 ));
/*向下采样并模糊一张图片,即缩小一张图片,朝向金字塔上方
第一个参数:输入图像;
第二个参数:输出图像;
第三个const Size&类型的dstsize,输出图像的大小;有默认值Size(),即在默认情况下,由Size((src.cols+1)/2,(src.rows+1)/2)来计算,
且一直需要满足:|dstsize.width*2-src.cols|<=2,|dstsize.height*2-src.rows|<=2所以各边缩小到原来的0.5倍;
第四个参数:边界模式
实现过程:高斯金字塔:金字塔从i层生成第i+1层,我们要先用高斯核对Gi进行卷积,然后,删除所有偶数行和偶数列。这样,新得到的图像面积会变为源图像的四分之一*/
printf( ">检测到按键【D】被按下,开始进行基于【pyrDown】函数的图片缩小:图片尺寸/2\n" );
break;
case 's' : //按键S按下,调用resize函数
resize(g_tmpImage,g_dstImage,Size( g_tmpImage.cols/2, g_tmpImage.rows/2 ));
printf( ">检测到按键【S】被按下,开始进行基于【resize】函数的图片缩小:图片尺寸/2\n" );
break;
case '2'://按键2按下,调用resize函数
resize(g_tmpImage,g_dstImage,Size( g_tmpImage.cols/2, g_tmpImage.rows/2 ));
printf( ">检测到按键【2】被按下,开始进行基于【resize】函数的图片缩小:图片尺寸/2\n" );
break;
case '4': //按键4按下,调用pyrDown函数
pyrDown( g_tmpImage, g_dstImage, Size( g_tmpImage.cols/2, g_tmpImage.rows/2 ) );
printf( ">检测到按键【4】被按下,开始进行基于【pyrDown】函数的图片缩小:图片尺寸/2\n" );
break;
}
//经过操作后,显示变化后的图
imshow( WINDOW_NAME, g_dstImage );
//将g_dstImage赋给g_tmpImage,方便下一次循环
g_tmpImage = g_dstImage;
}
return 0;
}
//-----------------------------------【ShowHelpText( )函数】----------------------------------
// 描述:输出一些帮助信息
//----------------------------------------------------------------------------------------------
static void ShowHelpText()
{
//输出一些帮助信息
printf("\n\t欢迎来到OpenCV图像金字塔和resize示例程序~\n\n");
printf( "\n\n\t按键操作说明: \n\n"
"\t\t键盘按键【ESC】或者【Q】- 退出程序\n"
"\t\t键盘按键【1】或者【W】- 进行基于【resize】函数的图片放大\n"
"\t\t键盘按键【2】或者【S】- 进行基于【resize】函数的图片缩小\n"
"\t\t键盘按键【3】或者【A】- 进行基于【pyrUp】函数的图片放大\n"
"\t\t键盘按键【4】或者【D】- 进行基于【pyrDown】函数的图片缩小\n"
);
}
阈值与自适应阈值操作
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;
#define WINDOW_NAME "【程序窗口】" //为窗口标题定义的宏
int g_nThresholdValue = 100;
int g_nThresholdType = 3;
Mat g_srcImage, g_grayImage, g_dstImage;
static void ShowHelpText( );//输出帮助文字
void on_Threshold( int, void* );//回调函数
int main( )
{
//【0】改变console字体颜色
system("color 1F");
//【0】显示欢迎和帮助文字
ShowHelpText( );
//【1】读入源图片
g_srcImage = imread("1.jpg");
if(!g_srcImage.data ) { printf("读取图片错误,请确定目录下是否有imread函数指定的图片存在~! \n"); return false; }
imshow("原始图",g_srcImage);
//【2】存留一份原图的灰度图
cvtColor( g_srcImage, g_grayImage, CV_RGB2GRAY );
//【3】创建窗口并显示原始图
namedWindow( WINDOW_NAME, CV_WINDOW_AUTOSIZE );
//【4】创建滑动条来控制阈值
createTrackbar( "模式",
WINDOW_NAME, &g_nThresholdType,
5, on_Threshold );
createTrackbar( "参数值",
WINDOW_NAME, &g_nThresholdValue,
255, on_Threshold );
//【5】初始化自定义的阈值回调函数
on_Threshold( 0, 0 );
// 【6】轮询等待用户按键,如果ESC键按下则退出程序
while(1)
{
int key;
key = waitKey( 20 );
if( (char)key == 27 ){ break; }
}
}
//-----------------------------------【on_Threshold( )函数】------------------------------------
// 描述:自定义的阈值回调函数
//-----------------------------------------------------------------------------------------------
void on_Threshold( int, void* )
{
//调用阈值函数
if(g_nThresholdType<5){threshold(g_grayImage,g_dstImage,g_nThresholdValue,255,g_nThresholdType);}
/*阈值可以被视作最简单的图像分割方法,基本思想是:给定一个数组(图像)和一个阈值,然后根据数组中的每个元素是高于还是低于阈值而进行一些处理
该函数针对单通道数组应用固定阈值操作,该函数的典型应用是对灰度图像进行阈值操作得到二值图像,(compare()函数也可达到此目的)或者是去掉噪声,
例如过滤掉很大或很小像素值的图像点。
第一个参数:输入图像,为单通道8位或32位浮点类型的Mat;
第二个参数:输出图像;
第三个参数:double类型的thresh,阈值的具体值;
第四个参数:double类型的maxval,当第五个参数阈值类型type取CV_THRESH_BINARY或CV_THRESH_BINARY_INV时阈值类型时的最大值;
第五个参数:int类型的type,阈值类型,具体如下:
0: THRESH_BINARY 二进制阈值 ,当前点值大于阈值时,取Maxval,也就是第四个参数,否则设置为0
1: THRESH_BINARY_INV (INV为逆)反二进制阈值, 当前点值大于阈值时,设置为0,否则设置为Maxval
2: THRESH_TRUNC 截断阈值 ,当前点值大于阈值时,设置为阈值,否则不改变
3: THRESH_TOZERO 阈值化为0 ,当前点值大于阈值时,不改变,否则设置为0
4: THRESH_TOZERO_INV 反阈值化为0 , 当前点值大于阈值时,设置为0,否则不改变
*/
//更新效果图
else adaptiveThreshold(g_grayImage,g_dstImage,255,ADAPTIVE_THRESH_MEAN_C,THRESH_BINARY,5,g_nThresholdValue);
/*自适应阈值操作:能够根据不同区域亮度不均,自动改变相应阈值,支持两种自适应方法,即cv::ADAPTIVE_THRESH_MEAN_C(平均)和cv::ADAPTIVE_THRESH_GAUSSIAN_C(高斯)。
在两种情况下,自适应阈值T(x, y)。通过计算每个像素周围bxb大小像素块的加权均值并减去常量C得到。其中,b由blockSize给出,大小必须为奇数;
如果使用平均的方法,则所有像素周围的权值相同;如果使用高斯的方法,则(x,y)周围的像素的权值则根据其到中心点的距离通过高斯方程得到。
第一个参数:输入图像单通道;
第二个参数:输出图像;
第三个参数:double类型的maxValue;
第四个参数:int类型的指定要使用的自适应阈值算法,ADAPTIVE_THRESH_MEAN_C(平均)和ADAPTIVE_THRESH_GAUSSIAN_C(高斯);
第五个参数:int类型的阈值类型:THRESH_BINARY、THRESH_BINARY_INV其中之一;
第六个参数:int类型的blockSize用于计算阈值大小的一个像素的邻域尺寸,为奇数;
第七个参数:double类型的C,减去的常数值,通常为正数,但少数情况下也可以为0或负数
最后的阈值为每个像素周围bxb大小像素块的加权均值并减去常量C得到*/
imshow( WINDOW_NAME, g_dstImage );
}
//-----------------------------------【ShowHelpText( )函数】----------------------------------
// 描述:输出一些帮助信息
//----------------------------------------------------------------------------------------------
static void ShowHelpText()
{ printf( "\n\t欢迎来到【基本阈值操作】示例程序~\n\n");
printf( "\n\t按键操作说明: \n\n"
"\t\t键盘按键【ESC】- 退出程序\n"
"\t\t滚动条模式0- 二进制阈值\n"
"\t\t滚动条模式1- 反二进制阈值\n"
"\t\t滚动条模式2- 截断阈值\n"
"\t\t滚动条模式3- 反阈值化为0\n"
"\t\t滚动条模式4- 阈值化为0\n"
"\t\t滚动条模式5- 自适应阈值操作\n" );
}