//学习OPENCV第6章 图像变换
//霍夫线检测\圆检测
//仿射变换、透射变换、对数极坐标变换
#include<stdio.h>
#include<cv.h>
#include<highgui.h>
#include<stdio.h>
#include<opencv2/legacy/legacy.hpp>
#include<math.h>
#define affine
char* HOUGH_TYPE = "CV_HOUGH_PROBABILISTIC";//CV_HOUGH_PROBABILISTIC/CV_HOUGH_STANDARD
//CV_HOUGH_STANDARD模式下,绘制直线有问题
int main(int argc, char** argv)
{
//-------------------------------------------------------------------
//霍夫线检测cvHoughLines2
//http://www.cnblogs.com/justiner/archive/2011/12/20/2294614.html
const char* filename = "D:\\AI_Proj\\OPENCV\\dog.jpg";
//cvLoadImage参数2表示是否加载有颜色的图像,0表示单通道图像
IplImage* src = cvLoadImage(filename,0);
IplImage* dst = NULL;
IplImage* color_dst = NULL;
//保存结果的位置指针
CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* lines = 0;
int i;
if(!src)
return -1;
dst = cvCreateImage(cvGetSize(src),8,1);
color_dst = cvCreateImage(cvGetSize(src),8,3);
//canny算子P173
cvCanny(src,//输入图像,为单通道图像
dst,//输出灰度图(2值化边缘)
100,//下限阈值,小于此像素被抛弃
200,//上限阈值,像素梯度高于此阈值为边缘
3);//算子大小
//cvCvtColor,颜色空间转换函数
//可以实现RGB颜色向HSV,HSI等颜色空间的转换,也可以转换为灰度图像
cvCvtColor(dst,color_dst,CV_GRAY2BGR);
cvNamedWindow("src",1);
cvNamedWindow("dst",1);
cvNamedWindow("color_dst",1);
cvShowImage("src",src);
cvShowImage("dst",dst);
cvShowImage("color_dst",color_dst);
cvWaitKey();
cvDestroyWindow("src");
cvDestroyWindow("dst");
cvDestroyWindow("color_dst");
//hough线变换P175
if(HOUGH_TYPE == "CV_HOUGH_STANDARD")
{
//返回指向内存块中的序列指针
lines = cvHoughLines2(dst,//输入Image,8位二值化图像
storage,//保存结果位置的指针,此处为内存块
CV_HOUGH_STANDARD,//标准霍夫变换
1,//设置直线所需要的分辨率:分别表示像素个数与弧度
CV_PI/180,
100,//阈值认定一条直线时在累计平面中必须达到的值
0,
0);
for(i = 0;i < MIN(lines->total,100);i++)
{
float* line = (float*)cvGetSeqElem(lines,i);//从序列中得到每一条直线或线段
float rho = line[0];
float theta = line[1];
CvPoint pt1, pt2;
double a = cos(theta), b = sin(theta);
if(fabs(a)<0.001)
{
pt1.x = pt2.x = cvRound(rho);
pt1.y = 0;
pt2.y = color_dst->height;
}
else if(fabs(b)<0.001)
{
pt1.y = pt2.y = cvRound(rho);
pt1.x = 0;
pt2.x = color_dst->width;
}
else
{
pt1.x = 0;
pt1.y = cvRound(rho/b);
pt2.x = cvRound(rho/a);
pt2.y = 0;
}
cvLine(color_dst,pt1,pt2,CV_RGB(255,0,0),1,8);
/*
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));*/
//OPENCV绘制连接两个点的线段函数原型
//cvLine(color_dst,pt1,pt2,CV_RGB(255,0,0),3,CV_AA,0);
}
}
else
if(HOUGH_TYPE == "CV_HOUGH_PROBABILISTIC")
{
lines = cvHoughLines2(dst,storage,CV_HOUGH_PROBABILISTIC,1,CV_PI/180,50,
50,//将要返回的线段的最小长度
15);//一条直线上分离线段不能连成一条直线的分隔像素点
for(i = 0;i < lines->total;i++ )
{
CvPoint* line = (CvPoint*)cvGetSeqElem(lines,i);
cvLine(color_dst,line[0],line[1],CV_RGB(255,0,0),3,CV_AA,0);
}
}
cvNamedWindow("Source",1);
cvShowImage("Source",src);
cvNamedWindow("Hough",1);
cvShowImage("Hough",color_dst);
cvWaitKey(0);
cvReleaseImage(&src);
cvReleaseImage(&color_dst);
cvDestroyWindow("Source");
cvDestroyWindow("Hough");
//-------------------------------------------------------------------
//霍夫圆检测 P182
IplImage* image = cvLoadImage("D:\\AI_Proj\\OPENCV\\stuff.jpg",CV_LOAD_IMAGE_GRAYSCALE);
IplImage* src1 = cvLoadImage("D:\\AI_Proj\\OPENCV\\stuff.jpg"); //Changed for prettier show in color
CvMemStorage* storage1 = cvCreateMemStorage(0);
cvSmooth(image,image,CV_GAUSSIAN,5,5);
//参数不同,结果显示有很大不同
CvSeq* results = cvHoughCircles(image,//不需要cvCanny,内部调用cvSobel,计算每个像素梯度的方向,提供更加普通的灰度图
storage1,//
CV_HOUGH_GRADIENT,//
4,//累加器图像的分辨率,>=1
image->width/10,//2个不同圆之间的最小距离
120,//边缘阈值
80,//累加器阈值
10,//圆半径最小值
80);//半径最大值
for(int i = 0;i < results->total;i++ )
{
float* p = (float*)cvGetSeqElem(results,i);
CvPoint pt = cvPoint(cvRound(p[0]),cvRound(p[1]));
cvCircle(src1,pt,cvRound(p[2]),CV_RGB(0xff,0,0));
}
cvNamedWindow("cvHoughCircles",1);
cvShowImage("cvHoughCircles",src1);
cvWaitKey(0);
cvReleaseImage(&src1);
cvDestroyWindow("cvHoughCircles");
cvWaitKey();
//-------------------------------------------------------------------
//仿射变换:稠密仿射变换p187
//http://blog.csdn.net/lxy201700/article/details/19689407
//像素必须是稠密表现形式:意味着图像扭曲必须进行一些插值运算以使输出图像平滑并且看起来自然
CvPoint2D32f srcTri[3], dstTri[3]; //
CvMat* rot_mat = cvCreateMat(2,3,CV_32FC1);
CvMat* warp_mat = cvCreateMat(2,3,CV_32FC1);
IplImage *src2, *dst2,*dst21;
src2=cvLoadImage("D:\\AI_Proj\\OPENCV\\dog.jpg",1);
dst2 = cvCloneImage(src2);
dst2->origin = src2->origin;
cvZero(dst2);
dst21 = cvCloneImage(src2);
dst21->origin = src2->origin;
cvZero(dst21);
//COMPUTE WARP MATRIX P188
//src Top left
srcTri[0].x = 0;
srcTri[0].y = 0;
//src Top right
srcTri[1].x = src2->width - 1;
srcTri[1].y = 0;
//src Bottom left
srcTri[2].x = 0;
srcTri[2].y = src2->height - 1;
//具体映射有dst决定
//dst Top left
dstTri[0].x = src2->width*0.0;
dstTri[0].y = src2->height*0.33;
//dst Top right
dstTri[1].x = src2->width*0.85;
dstTri[1].y = src2->height*0.25;
//dst Bottom left
dstTri[2].x = src2->width*0.15;
dstTri[2].y = src2->height*0.7;
//由三对点计算仿射变换,生成映射矩阵
//输入图像的三角形顶点坐标/输出图像的相应的三角形顶点坐标/指向2×3输出矩阵的指针
cvGetAffineTransform(srcTri,dstTri,warp_mat);
//对图像做仿射变换:输入输出矩阵、变换矩阵
cvWarpAffine(src2,dst2,warp_mat);
cvCopy(dst2,src2);
//计算map_matrix的第二种方法:cv2DRotationMatrix
//计算围绕任意点旋转的映射矩阵和一个可选择的尺度
CvPoint2D32f center = cvPoint2D32f(src2->width/2,src2->height/2);
double angle = -50.0;//旋转角度
double scale = 0.6;//缩放尺度
//计算围绕center点的旋转的映射矩阵,以及一个可选的尺度
//输出映射矩阵rot_mat
cv2DRotationMatrix(center,angle,scale,rot_mat);
cvWarpAffine(src2,dst21,rot_mat);
//DO THE TRANSFORM:
cvNamedWindow("Affine_Transform1",1);
cvShowImage("Affine_Transform1",dst2);
cvNamedWindow("Affine_Transform2",1);
cvShowImage("Affine_Transform2",dst21);
cvWaitKey();
cvReleaseImage(&dst2);
cvReleaseImage(&dst21);
cvReleaseMat(&rot_mat);
cvReleaseMat(&warp_mat);
cvDestroyWindow("Affine_Transform1");
cvDestroyWindow("Affine_Transform2");
cvWaitKey();
//-------------------------------------------------------------------
//透视变换:采用4个点映射
CvPoint2D32f srcQuad[4], dstQuad[4];
CvMat* warp_matrix = cvCreateMat(3,3,CV_32FC1);//映射矩阵必须为3x3
IplImage *src3, *dst3;
if(((src3=cvLoadImage("D:\\AI_Proj\\OPENCV\\dog.jpg",1)) != 0))
{
dst3 = cvCloneImage(src3);
dst3->origin = src3->origin;
cvZero(dst3);
//src Top left
srcQuad[0].x = 0;
srcQuad[0].y = 0;
//src Top right
srcQuad[1].x = src3->width - 1;
srcQuad[1].y = 0;
//src Bottom left
srcQuad[2].x = 0;
srcQuad[2].y = src3->height - 1;
//src Bot right
srcQuad[3].x = src3->width - 1;
srcQuad[3].y = src3->height - 1;
//dst Top left
dstQuad[0].x = src3->width*0.05;
dstQuad[0].y = src3->height*0.33;
//dst Top right
dstQuad[1].x = src3->width*0.9;
dstQuad[1].y = src3->height*0.25;
//dst Bottom left
dstQuad[2].x = src3->width*0.2;
dstQuad[2].y = src3->height*0.7;
//dst Bot right
dstQuad[3].x = src3->width*0.8;
dstQuad[3].y = src3->height*0.9;
//计算透视映射矩阵
cvGetPerspectiveTransform(srcQuad,dstQuad,warp_matrix);
cvWarpPerspective(src3,dst3,warp_matrix);
cvNamedWindow("Perspective_Warp",1);
cvShowImage( "Perspective_Warp", dst3 );
cvNamedWindow("src",1);
cvShowImage( "src", src3 );
cvWaitKey();
}
cvReleaseImage(&dst3);
cvReleaseImage(&src3);
cvReleaseMat(&warp_matrix);
cvDestroyWindow("Perspective_Warp");
cvDestroyWindow("src");
cvWaitKey();
//-------------------------------------------------------------------
//cvLogPolar:对数极坐标转换 P198
//用于物体识别的是检测物体周围的而一些关键点:
//利用关键点中心-->将其作为对数极坐标中心-->创建局部特征
IplImage* src4;
double scaler; //受scaler影响大
if(((src4=cvLoadImage("D:\\AI_Proj\\OPENCV\\dog.jpg",1)) != 0 ))
{
scaler = 25; //atof(argv[2]);
IplImage* dst = cvCreateImage(cvGetSize(src4),8,3);
IplImage* src5 = cvCreateImage(cvGetSize(src4),8,3);
cvLogPolar(src4,dst, //单通道/三通道,彩色/灰度图像
cvPoint2D32f(src4->width/2,src4->height/2),//对数极坐标变换中心
scaler,//缩放因子,应该事先设置使得ROI区域占主导
CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS);//插值方式
cvLogPolar(dst,src5,cvPoint2D32f(src4->width/2,src4->height/2),
scaler,CV_INTER_LINEAR+CV_WARP_INVERSE_MAP);
cvNamedWindow("src",1);
cvShowImage("src",src4);
cvNamedWindow("log-polar",1);
cvShowImage("log-polar",dst);
cvNamedWindow("inverse log-polar",1);
cvShowImage("inverse log-polar",src5);
cvWaitKey();
cvReleaseImage(&src4);
cvReleaseImage(&dst);
cvReleaseImage(&src5);
cvDestroyWindow("src");
cvDestroyWindow("log-polar");
cvDestroyWindow("inverse log-polar");
}
cvWaitKey();
return 0;
}
效果图
canny算子边缘检测
hough线检测
hough圆检测
三点仿射变换
4点透视变换
对数极坐标变换与复原
继续学习傅里叶和DCT