您的位置:首页 > 运维架构

【OpenCV学习笔记 004】 图像的缩放、Canny边缘检测和图像的二值化

2016-06-30 23:26 921 查看

一、图像的缩放

本篇将介绍使用OpenCV来缩放图片。首先介绍几个关键函数——cvResize和cvCreateImage

1.主要函数介绍

1.1 cvResize

函数功能:图像大小变换

函数原型:

voidcvResize(

  const CvArr* src,

  CvArr* dst,

  intinterpolation=CV_INTER_LINEAR

);

函数说明:

第一个参数表示输入图像。

第二个参数表示输出图像。

第三个参数表示插值方法,可以有以下四种:

CV_INTER_NN - 最近邻插值,

CV_INTER_LINEAR - 双线性插值 (缺省使用)

CV_INTER_AREA - 使用象素关系重采样。当图像缩小时候,该方法可以避免波纹出现。当图像放大时,类似于 CV_INTER_NN 方法..

CV_INTER_CUBIC - 立方插值.

这个函数在功能上与Win32 API中的StretchBlt()函数类似。

1.2 cvCreateImage

函数功能:创建图像

函数原型:

IplImage* cvCreateImage(CvSize size, intdepth,intchannels);

函数说明:

第一个参数表示图像的大小。

第二个参数表示图像的深度,可以为IPL_DEPTH_8U,IPL_DEPTH_16U等等。

第三个参数表示图像的通道数。

2. 示例程序代码

有了这二个函数后,不难写出代码:

//缩放图像文件
#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
//隐藏控制台窗口
#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")

int main(){

const char* psrcImageName = "monster.jpg";
const char* pdstImageName = "smallMonster.jpg";
const char* psrcImageTitle = "大怪兽";
const char* pdstImageTitle = "小怪兽";

double fScale = 0.18;	//缩放倍数
CvSize czSize;	//目标图像尺寸

//从文件中读取图像
IplImage *psrcImage = cvLoadImage(psrcImageName, CV_LOAD_IMAGE_UNCHANGED);
IplImage *pdstImage = NULL;

//计算目标图像大小
czSize.width = psrcImage->width * fScale;
czSize.height = psrcImage->height * fScale;

//创建图像并缩放
pdstImage = cvCreateImage(czSize, psrcImage->depth, psrcImage->nChannels);
cvResize(psrcImage, pdstImage, CV_INTER_AREA);

//创建窗口
cvNamedWindow(psrcImageTitle, CV_WINDOW_AUTOSIZE);
cvNamedWindow(pdstImageTitle, CV_WINDOW_AUTOSIZE);

//在指定窗口中显示图像
cvShowImage(psrcImageTitle, psrcImage);
cvShowImage(pdstImageTitle, pdstImage);

//保存图片
cvSaveImage(pdstImageName, pdstImage);
//等待按键事件
cvWaitKey();

cvDestroyWindow(psrcImageTitle);
cvDestroyWindow(pdstImageTitle);
cvReleaseImage(&psrcImage);
cvReleaseImage(&pdstImage);
return 0;

}
程序运行结果如下:



二、Canny边缘检测

图像的边缘检测的原理是检测出图像中所有灰度值变化较大的点,而且这些点连接起来就构成了若干线条,这些线条就可以称为图像的边缘。

    Canny边缘检测算子是John F. Canny于 1986 年开发出来的一个多级边缘检测算法。Canny 边缘检测的数学原理和算法实现这里就不说了,有兴趣的读者可以查阅专业书籍,本文主要介绍如何在OpenCV中对图像进行Canny 边缘检测,下面就来看看这个函数的原型。

1.主要函数

1.1 cvCanny

函数功能:采用Canny方法对图像进行边缘检测

函数原型:

/* Runs canny edge detector */
CVAPI(void) cvCanny( const CvArr* image, CvArr* edges, double threshold1,
double threshold2, int aperture_size CV_DEFAULT(3) );函数说明:

第一个参数表示输入图像,必须为单通道灰度图。

第二个参数表示输出的边缘图像,为单通道黑白图。

第三个参数和第四个参数表示阈值,这二个阈值中当中的小阈值用来控制边缘连接,大的阈值用来控制强边缘的初始分割即如果一个像素的梯度大与上限值,则被认为是边缘像素,如果小于下限阈值,则被抛弃。如果该点的梯度在两者之间则当这个点与高于上限值的像素点连接时我们才保留,否则删除。

第五个参数表示Sobel 算子大小,默认为3即表示一个3*3的矩阵。Sobel 算子与高斯拉普拉斯算子都是常用的边缘算子,详细的数学原理可以查阅专业书籍。

为了更好的使用cvCanny()函数,下面再介绍二个实用的函数,这二个函数对后面的程序实现非常有帮助。

1.2 cvCreateTrackbar

函数功能:创建trackbar并添加到指定窗口

函数原型:
/* create trackbar and display it on top of given window, set callback */
CVAPI(int) cvCreateTrackbar( const char* trackbar_name, const char* window_name,
int* value, int count, CvTrackbarCallback on_change CV_DEFAULT(NULL));函数说明:

第一个参数表示该trackbar的名称。

第二个参数表示窗口名称,该trackbar将显示在这个窗口内。

第三个参数表示创建时滑块的位置。

第四个参数表示滑块位置的最大值,最小值固定为0。

第五个参数表示回调函数。当滑块位置有变化时,系统会调用该回调函数。

注:被创建的trackbar默认显示在指定窗口的顶端,可以通过函数cvGetTrackbarPos()来获取trackbar显示的位置信息,以及通过函数cvSetTrackbarPos()来重新设置trackbar的显示位置。

1.3  CvTrackbarCallback

函数功能:cvCreateTrackbar()函数所使用的回调函数

函数定义:

typedef void (CV_CDECL *CvTrackbarCallback)(int pos)

函数说明:

当trackbar位置被改变的时,系统会调用这个回调函数,并将参数pos设置为表示trackbar位置的数值。
2.示例程序代码

//图像的Canny边缘检测
#include <opencv2/opencv.hpp>
using namespace std;
IplImage *g_pSrcImage, *g_pCannyImg;
const char *pstrWindowsCannyTitle = "边缘检测图";
//cvCreateTrackbar的回调函数
void on_trackbar(int threshold)
{
//canny边缘检测
cvCanny(g_pSrcImage, g_pCannyImg, threshold, threshold * 3, 3);
cvShowImage(pstrWindowsCannyTitle, g_pCannyImg);
}
int main()
{
const char *pstrImageName = "girl.jpg";
const char *pstrWindowsSrcTitle = "原图";
const char *pstrWindowsToolBar = "Threshold";

//从文件中载入图像的灰度图CV_LOAD_IMAGE_GRAYSCALE - 灰度图
g_pSrcImage = cvLoadImage(pstrImageName, CV_LOAD_IMAGE_GRAYSCALE);
g_pCannyImg = cvCreateImage(cvGetSize(g_pSrcImage), IPL_DEPTH_8U, 1);

//创建窗口
cvNamedWindow(pstrWindowsSrcTitle, CV_WINDOW_AUTOSIZE);
cvNamedWindow(pstrWindowsCannyTitle, CV_WINDOW_AUTOSIZE);

//创建滑动条
int nThresholdEdge = 1;
cvCreateTrackbar(pstrWindowsToolBar, pstrWindowsCannyTitle, &nThresholdEdge, 100, on_trackbar);

//在指定窗口中显示图像
cvShowImage(pstrWindowsSrcTitle, g_pSrcImage);
on_trackbar(1);

//等待按键事件
cvWaitKey();

cvDestroyWindow(pstrWindowsSrcTitle);
cvDestroyWindow(pstrWindowsCannyTitle);
cvReleaseImage(&g_pSrcImage);
cvReleaseImage(&g_pCannyImg);
return 0;
}程序运行结果:



三、图像的二值化

上面介绍了使用Canny算子对图像进行边缘检测。与边缘检测相比,轮廓检测有时能更好的反映图像的内容。而要对图像进行轮廓检测,则必须要先对图像进行二值化,图像的二值化就是将图像上的像素点的灰度值设置为0或255,这样将使整个图像呈现出明显的黑白效果。在数字图像处理中,二值图像占有非常重要的地位,图像的二值化使图像中数据量大为减少,从而能凸显出目标的轮廓。

1.关键函数介绍

下面就介绍OpenCV中对图像进行二值化的关键函数——cvThreshold()。

函数功能:采用Canny方法对图像进行边缘检测函数原型:

CVAPI(double)  cvThreshold( const CvArr*  src, CvArr*  dst,
double  threshold, double  max_value,
int threshold_type );
函数说明:

第一个参数表示输入图像,必须为单通道灰度图。

第二个参数表示输出的边缘图像,为单通道黑白图。

第三个参数表示阈值

第四个参数表示最大值。

第五个参数表示运算方法。

/* Threshold types */
enum
{
CV_THRESH_BINARY      =0,  /* value = value > threshold ? max_value : 0       */
CV_THRESH_BINARY_INV  =1,  /* value = value > threshold ? 0 : max_value       */
CV_THRESH_TRUNC       =2,  /* value = value > threshold ? threshold : value   */
CV_THRESH_TOZERO      =3,  /* value = value > threshold ? value : 0           */
CV_THRESH_TOZERO_INV  =4,  /* value = value > threshold ? 0 : value           */
CV_THRESH_MASK        =7,
CV_THRESH_OTSU        =8  /* use Otsu algorithm to choose the optimal threshold value;
combine the flag with one of the above CV_THRESH_* values */
};
2.示例代码

#include <opencv2/opencv.hpp>
using namespace std;

IplImage *g_pGrayImage = NULL;
IplImage *g_pBinaryImage = NULL;
const char *pstrWindowsBinaryTitle = "二值图";

void on_trackbar(int pos)
{
// 转为二值图
cvThreshold(g_pGrayImage, g_pBinaryImage, pos, 255, CV_THRESH_BINARY);
// 显示二值图
cvShowImage(pstrWindowsBinaryTitle, g_pBinaryImage);
}

int main(int argc, char** argv)
{
const char *pstrWindowsSrcTitle = "原图";
const char *pstrWindowsToolBarName = "二值图阈值";

// 从文件中加载原图
IplImage *pSrcImage = cvLoadImage("Baboon.jpg", CV_LOAD_IMAGE_UNCHANGED);

// 转为灰度图
g_pGrayImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 1);
cvCvtColor(pSrcImage, g_pGrayImage, CV_BGR2GRAY);

// 创建二值图
g_pBinaryImage = cvCreateImage(cvGetSize(g_pGrayImage), IPL_DEPTH_8U, 1);

// 显示原图
cvNamedWindow(pstrWindowsSrcTitle, CV_WINDOW_AUTOSIZE);
cvShowImage(pstrWindowsSrcTitle, pSrcImage);

// 创建二值图窗口
cvNamedWindow(pstrWindowsBinaryTitle, CV_WINDOW_AUTOSIZE);

// 滑动条
int nThreshold = 0;
cvCreateTrackbar(pstrWindowsToolBarName, pstrWindowsBinaryTitle, &nThreshold, 254, on_trackbar);

on_trackbar(1);

cvWaitKey(0);

cvDestroyWindow(pstrWindowsSrcTitle);
cvDestroyWindow(pstrWindowsBinaryTitle);
cvReleaseImage(&pSrcImage);
cvReleaseImage(&g_pGrayImage);
cvReleaseImage(&g_pBinaryImage);
return 0;
}
运行结果如下所示,自己动手调试下阈值大小,看看生成的二值图有什么变化。



OpenCV还有个cvAdaptiveThreshold()函数,这个函数会使用Otsu算法(大律法或最大类间方差法)(注1)来计算出一个全局阈值,然后根据这个阈值进行二值化。当然直接使用cvCanny()函数也可以对图像进行二值化(想到怎么传参数了吗?)。

注1.调用cvThreshold()时传入参数CV_THRESH_OTSU也是使用Otsu算法来自动生成一个阈值。

Reference:
http://blog.csdn.net/morewindows/article/details/8239560 http://blog.csdn.net/morewindows/article/details/8239625 http://blog.csdn.net/morewindows/article/details/8239678
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: