OpenCV 图像金字塔+通道分离+Canny边缘的一个实例
学习OpenCV上一个不太完整的例子,对图像做两次金字塔缩小,做一次三通道分离得到一通道,再做Canny算子求边缘。把它完整填补了一下,写一下心得:
// CannyWay.cpp -- Try Canny to find the contours
#include <iostream>
#include <opencv2/opencv.hpp>
#include <ctime>
#include <opencv/cv.h>
#define _CRT_SECURE_NO_WARNINGS
using namespace std;
using namespace cv;
IplImage* doCanny(
IplImage* in,
double lowThresh,
double highThresh,
int aperture
){
if (in->nChannels != 1)
return(0); //Canny only handles gray scale images
IplImage* out = cvCreateImage(
cvSize(in->width, in->height),
IPL_DEPTH_8U,
1);
cvCanny(in, out, lowThresh, highThresh, aperture);
return(out);
}
IplImage* doPyrDown(
IplImage* in,
int filter = IPL_GAUSSIAN_5x5
){
// Best to make sure input image is divisable by two.
//
assert(in->width % 2 == 0 && in->height % 2 == 0);
IplImage* out = cvCreateImage(
cvSize(in->width / 2, in->height / 2),
in->depth,
in->nChannels);
cvPyrDown(in, out);
return(out);
};
int main()
{
IplImage* img0 = cvLoadImage("timg.jpg");
IplImage* img1 = doPyrDown(img0, IPL_GAUSSIAN_5x5);
IplImage* img2 = doPyrDown(img1, IPL_GAUSSIAN_5x5);
IplImage* bimg2 = cvCreateImage(cvSize(img2->width, img2->height), 8, 1);
IplImage* gimg2 = cvCreateImage(cvSize(img2->width, img2->height), 8, 1);
IplImage* rimg2 = cvCreateImage(cvSize(img2->width, img2->height), 8, 1);
cvSplit(img2, bimg2, gimg2, rimg2, 0);
IplImage* img3 = doCanny(bimg2, 10, 100, 3);
cvNamedWindow("OriginalPic", CV_WINDOW_AUTOSIZE);
cvShowImage("OriginalPic", img0);
cvNamedWindow("ZoomOUT1", CV_WINDOW_AUTOSIZE);
cvShowImage("ZoomOUT1", img1);
cvNamedWindow("ZoomOUT2", CV_WINDOW_AUTOSIZE);
cvShowImage("ZoomOUT2", img2);
cvNamedWindow("ZoomOUT3", CV_WINDOW_AUTOSIZE);
cvShowImage("ZoomOUT3", img3);
cvWaitKey(0);
cvReleaseImage(&img0);
cvReleaseImage(&img1);
cvReleaseImage(&img2);
cvReleaseImage(&img3);
cvReleaseImage(&bimg2);
cvReleaseImage(&gimg2);
cvReleaseImage(&rimg2);
cvDestroyAllWindows;
return 0;
}
图像金字塔要点
每次缩小之前做一次判断,如果长宽不都能被2整除,就放弃进行缩小。原因是cvPyrDown只能对可整除的长宽进行处理。
*这里有一些可以优化的地方,如果不能被2整除,可以考虑把不能被2整除的长或宽切掉一个像素。
IplImage* doPyrDown(
IplImage* in,
int filter = IPL_GAUSSIAN_5x5
){
// Best to make sure input image is divisable by two.
//
assert(in->width >= 2 && in->height >= 2);
IplImage* in2 = cvCreateImage(cvSize(floor(in->width/2)*2,floor(in->height/2)*2), in->depth, in->nChannels);
CvRect Rect = cvRect(0, 0, floor(in->width/2)*2, floor(in->height/2)*2);
cvSetImageROI(in, Rect);
cvCopy(in, in2);
IplImage* out = cvCreateImage(
cvSize(in2->width / 2, in2->height / 2),
in2->depth,
in2->nChannels);
cvPyrDown(in2, out);
return(out);
};
如下图所示大小变化
通道分离要点
注意到三个通道的命名,是反过来的,蓝色通道在前,红色通道在最后。
cvSplit(img2, bimg2, gimg2, rimg2, 0);
Canny算子求边缘要点
Canny只能对单通道图像直接运算,如果图像本身含有多个通道需要首先进行分离。