第六章 学习OpenCV——图像变换
目录
例6-1 使用霍夫变换寻找直线、圆和其他简单形状
本例完成的工作如下:
1. 使用cvHoughCircles返回灰度图中找到的圆序列(例6-1);
2. 载入一个包括清晰直线和圆的图像,比如一辆侧面看的自行车,调用霍夫直线变换和霍夫圆变换处理这幅图像(第六章 练习8);
3. 利用霍夫变换识别不同周长的任意形状(第六章 练习9);
具体代码如下:
#include <cv.h>
#include <highgui.h>
#include <math.h>
using namespace std;
int main(int argc, char* argv[])
{
IplImage *Image,*Ihough; //图像
IplImage *Input1, *Ihough_line, *Ihough_circle; //图像
IplImage *Input2, *IHough; //图像
if ((Image = cvLoadImage("D:\\Template\\OpenCV\\Template37_Hough_Circle_Line\\Debug\\2.jpg", CV_LOAD_IMAGE_GRAYSCALE)) == 0)
return -1;
if ((Input1 = cvLoadImage("D:\\Template\\OpenCV\\Template37_Hough_Circle_Line\\Debug\\1.jpg", CV_LOAD_IMAGE_GRAYSCALE)) == 0)
return -2;
if ((Input2 = cvLoadImage("D:\\Template\\OpenCV\\Template37_Hough_Circle_Line\\Debug\\7.jpg", CV_LOAD_IMAGE_GRAYSCALE)) == 0)
return -3;
Ihough=cvCreateImage(cvGetSize(Image), Image->depth, Image->nChannels);
Ihough_line = cvCreateImage(cvGetSize(Input1), Image->depth, Image->nChannels);
Ihough_circle = cvCreateImage(cvGetSize(Input1), Image->depth, Image->nChannels);
IHough = cvCreateImage(cvGetSize(Input2), Image->depth, Image->nChannels);
CvMemStorage *storage0 = cvCreateMemStorage(0); //分配存储区域
CvMemStorage *storage1 = cvCreateMemStorage(0); //分配存储区域
CvMemStorage *storage2 = cvCreateMemStorage(0); //分配存储区域
CvMemStorage *storage3 = cvCreateMemStorage(0); //分配存储区域
CvMemStorage *storage4 = cvCreateMemStorage(0); //分配存储区域
//cvSmooth(Image, Image, CV_GAUSSIAN, 3, 3); //高斯平滑
cvCanny(Image, Ihough, 50, 150); //边缘检测
cvCanny(Input1, Ihough_line, 50, 150); //边缘检测
cvCanny(Input1, Ihough_circle, 50, 150); //边缘检测
cvCanny(Input2, IHough, 50, 150); //边缘检测
CvSeq *results = cvHoughCircles(Ihough, storage0, CV_HOUGH_GRADIENT, 2, Ihough->width / 10, 50, 200, 0, 0);
//CvSeq *results = cvHoughCircles(Image, storage, CV_HOUGH_GRADIENT, 2, Image->width / 10);
//输入 存储区域 霍夫变换方式 累加器分辨率 两圆间隔最小值 边缘阈值 累加器阈值(认定为圆)半径最小值 最大值
for (int i = 0; i <= results->total; i++) //序列元素个数
{
float *p = (float*)cvGetSeqElem(results, i); //提取序列元素
CvPoint pt1 = cvPoint(cvRound(p[0]),cvRound(p[1])); //四舍五入取整
cvCircle(Ihough, pt1, cvRound(p[2]), CV_RGB(100, 100, 100), 8); //画圆
}
CvSeq *result1 = cvHoughLines2(Ihough_line, storage1, CV_HOUGH_PROBABILISTIC, 1, CV_PI / 180, 50, 100, 10);
//输入 存储区域 霍夫变换方式 累加器分辨率(像素) 累加器分辨率(弧度) 累加器阈值(认定为直线)
//直线最小长度 分离线段分隔点数
//对于SHT和MSHT方法来说,返回的是Rho值和theta值,如下还原
//for (int i = 0; i < MIN(line->total, 100); i++)
//{
// float* lines = (float*)cvGetSeqElem(line, i);
// float rho = lines[0];
// float theta = lines[1];
// CvPoint pt1, pt2;
// double a = cos(theta), b = sin(theta);
// double x0 = a*rho, y0 = b*rho;
// pt1.x = cvRound(x0 + 1000 * (-b));
// pt1.y = cvRound(y0 + 1000 * (a));
// pt2.x = cvRound(x0 - 1000 * (-b));
// pt2.y = cvRound(y0 - 1000 * (a));
// cvLine(result, pt1, pt2, CV_RGB(255, 0, 0));
//}
//对于PPHT方法,返回的就是直线端点的坐标
for (int i = 0; i <= result1->total; i++) //序列元素个数
{
CvPoint* line = (CvPoint*)cvGetSeqElem(result1, i);
cvLine(Ihough_line, line[0], line[1], CV_RGB(100,100,100), 4); //画线
cout << "2 : " << line[0].x << " " << line[0].y << endl;
cout << line[1].x << " " << line[1].y << endl << endl;
}
CvSeq *result2 = cvHoughCircles(Ihough_line, storage2, CV_HOUGH_GRADIENT, 2, Ihough->width / 10, 50, 200, 50, 100);
//输入 存储区域 霍夫变换方式 累加器分辨率 两圆间隔最小值 边缘阈值 累加器阈值(认定为圆)半径最小值 最大值
for (int i = 0; i <= result2->total; i++) //序列元素个数
{
float *circle = (float*)cvGetSeqElem(result2, i); //提取序列元素
CvPoint pt2 = cvPoint(cvRound(circle[0]), cvRound(circle[1])); //四舍五入取整
cvCircle(Ihough_circle, pt2, cvRound(circle[2]), CV_RGB(100, 100, 100), 8); //画圆
}
CvSeq *result3 = cvHoughLines2(IHough, storage3, CV_HOUGH_PROBABILISTIC, 1, CV_PI / 180,1);
//输入 存储区域 霍夫变换方式 累加器分辨率(像素) 累加器分辨率(弧度) 累加器阈值(认定为直线)
//(直线最小长度 分离线段分隔点数)
//对于PPHT方法,返回的就是直线端点的坐标
for (int i = 0; i <= result3->total; i++) //序列元素个数
{
CvPoint* Line = (CvPoint*)cvGetSeqElem(result3, i);
cvLine(IHough, Line[0], Line[1], CV_RGB(100, 100, 100), 4); //画线
}
cvNamedWindow("Image", 1);
cvNamedWindow("cvHoughCircles", 1);
cvNamedWindow("Input1", 1);
cvNamedWindow("Ihough_line", 1);
cvNamedWindow("Ihough_circle", 1);
cvNamedWindow("Input2", 1);
cvNamedWindow("IHough", 1);
cvShowImage("Image", Image);
cvShowImage("cvHoughCircles", Ihough);
cvShowImage("Input1", Input1);
cvShowImage("Ihough_line", Ihough_line);
cvShowImage("Ihough_circle", Ihough_circle);
cvShowImage("Input2", Input2);
cvShowImage("IHough", IHough);
cvWaitKey(0);
cvReleaseImage(&Image);
cvReleaseImage(&Ihough);
cvReleaseImage(&Input1);
cvReleaseImage(&Ihough_line);
cvReleaseImage(&Ihough_circle);
cvReleaseImage(&Input2);
cvReleaseImage(&IHough);
cvDestroyWindow("Image");
cvDestroyWindow("cvHoughCircles");
cvDestroyWindow("Input1");
cvDestroyWindow("Ihough_line");
cvDestroyWindow("Ihough_circle");
cvDestroyWindow("Input2");
cvDestroyWindow("IHough");
return 0;
}
运行结果如下图:
例6-2 使用仿射、透视变换、对数极变换
本例完成的工作如下:
1. 使用cvWarpAffine实现仿射变换(例6-2);
2. 使用cvWarpPerspective实现透视变换(例6-3);
3. 使用cvLogPolar实现对数极变换(例6-4);
4. 载入一幅图像,进行透视变换,然后旋转,在一步之内完成,与本例2在同一图像中实现(第六章 练习17);
具体代码如下:
#include <cv.h>
#include <highgui.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
using namespace std;
int main(int argc, char* argv[])
{
IplImage* src, *Iaffine, *Irot, *Iperspective; //变换图像与原图像
IplImage*Ipolar, *Ipolar_inverse; //极坐标变换图像
CvPoint2D32f srcTri[3], dstTri[3]; //仿射变换的两个点集
CvPoint2D32f srcQuad[4], dstQuad[4]; //透视变换的两个点集
CvMat* rot_matrix = cvCreateMat(2, 3, CV_32FC1); //仿射变换矩阵(旋转)
CvMat* affine_matrix = cvCreateMat(2, 3, CV_32FC1); //仿射变换矩阵
CvMat* perspective_matrix = cvCreateMat(3, 3, CV_32FC1); //透视变换矩阵
if (!(src = cvLoadImage("D:\\Template\\OpenCV\\Template38_Affine_Perspective_Polar\\Debug\\3.jpg")))
return -1;
Iaffine = cvCloneImage(src); //克隆图像
Iaffine->origin = src->origin; //设置相同原点
cvZero(Iaffine); //清零
Irot = cvCloneImage(src); //克隆图像
Irot->origin = src->origin; //设置相同原点
cvZero(Irot); //清零
Iperspective = cvCloneImage(src); //克隆图像
Iperspective->origin = src->origin; //设置相同原点
cvZero(Iperspective); //清零
Ipolar = cvCloneImage(src); //克隆图像
Ipolar->origin = src->origin; //设置相同原点
cvZero(Ipolar); //清零
Ipolar_inverse = cvCloneImage(src); //克隆图像
Ipolar_inverse->origin = src->origin; //设置相同原点
cvZero(Ipolar_inverse); //清零
//旋转参数
double angle = -35.0;
double scale = 0.75;
CvPoint2D32f center = cvPoint2D32f(src->width / 2, src->height / 2);
//极坐标变换参数
double M =25; //缩放比例
//仿射变换点
srcTri[0].x = 0; //左上
srcTri[0].y = 0;
srcTri[1].x = src->width - 1; //右上
srcTri[1].y = 0;
srcTri[2].x = 0; //左下
srcTri[2].y = src->height - 1;
dstTri[0].x = src->width*0.05; //左上
dstTri[0].y = src->height*0.33;
dstTri[1].x = src->width*0.9; //右上
dstTri[1].y = src->height*0.25;
dstTri[2].x = src->width*0.2; //左下
dstTri[2].y = src->height*0.7;
//透视变换点
srcQuad[0].x = 0; //左上
srcQuad[0].y = 0;
srcQuad[1].x = src->width - 1; //右上
srcQuad[1].y = 0;
srcQuad[2].x = 0; //左下
srcQuad[2].y = src->height - 1;
srcQuad[3].x = src->width - 1; //右下
srcQuad[3].y = src->height - 1;
dstQuad[0].x = src->width*0.9; //左上
dstQuad[0].y = src->height*0.25;
dstQuad[1].x = src->width*0.8; //右上
dstQuad[1].y = src->height*0.9;
dstQuad[2].x = src->width*0.05; //左下
dstQuad[2].y = src->height*0.33;
dstQuad[3].x = src->width*0.2; //右下
dstQuad[3].y = src->height*0.7;
//dstQuad[0].x = src->width*0.05; //左上
//dstQuad[0].y = src->height*0.33;
//dstQuad[1].x = src->width*0.9; //右上
//dstQuad[1].y = src->height*0.25;
//dstQuad[2].x = src->width*0.2; //左下
//dstQuad[2].y = src->height*0.7;
//dstQuad[3].x = src->width*0.8; //右下
//dstQuad[3].y = src->height*0.9;
cvGetAffineTransform(srcTri, dstTri, affine_matrix); //仿射变换矩阵
cv2DRotationMatrix(center,angle,scale,rot_matrix); //仿射(旋转)变换矩阵
cvGetPerspectiveTransform(srcQuad, dstQuad, per