cv1.0入门
作者 群号 C语言交流中心 240137450 微信 15013593099
环境
VS2010UltimTrial1.iso
http://pan.baidu.com/s/1dEL85kl
VS2010UltimTrialCHS版注冊码 YCFHQ-9DWCY-DKV88-T2TMH-G7BHP
opencv-2.4.9.exe
http://pan.baidu.com/s/1kVaVwoR
图片地址: f:\img\
操作系统:
XP
http://pan.baidu.com/s/1bY5SHS
SP3
http://pan.baidu.com/s/1bAPuGY
执行在虚拟机中 VM10.0.3 build-1895310
http://pan.baidu.com/s/1dEQsno1
VMKEY 5F29M-48312-8ZDF9-A8A5K-2AM0Z
1Y0W5-0W205-7Z8J0-C8C5M-9A6MF
读取文件
#include <opencv2\highgui\highgui.hpp> #include <iostream> using namespace cv; using namespace std; int main(int argc, const char** argv) { Mat img = imread("f:\\img\\lena.jpg"); if (img.empty()) { cout << "图像载入失败!" << endl; return -1; } //创建一个名字为MyWindow的窗体 namedWindow("MyWindow", CV_WINDOW_AUTOSIZE); //在MyWindow的窗中中显示存储在img中的图片 imshow("MyWindow", img); //等待直到有键按下 waitKey(0); //销毁MyWindow的窗体 destroyWindow("MyWindow"); return 0; }
sobel laplace canny
#include <opencv2\opencv.hpp> #include <iostream> using namespace cv; using namespace std; int main(int argc, char* argv[]) { Mat src = imread("f:\\img\\QQ.png"); Mat dst; //输入图像 //输出图像 //输入图像颜色通道数 //x方向阶数 //y方向阶数 Sobel(src,dst,src.depth(),1,1); imwrite("sobel.jpg",dst); imshow("sobel",dst); imshow("src",src); //输入图像 //输出图像 //输入图像颜色通道数 Laplacian(src,dst,src.depth()); imwrite("laplacian.jpg",dst); imshow("laplacian",dst); //输入图像 //输出图像 //彩色转灰度 cvtColor(src,src,CV_BGR2GRAY); //canny仅仅处理灰度图 //输入图像 //输出图像 //低阈值 //高阈值,opencv建议是低阈值的3倍 //内部sobel滤波器大小 Canny(src,dst,50,150,3); imwrite("canny.jpg",dst); imshow("canny",dst); waitKey(); return 0; }
轮廓
#include <opencv2\opencv.hpp> #include <iostream> using namespace cv; using namespace std; int main() { const char* inputImage = "f:\\img\\circle.jpg"; Mat img; int threshval =100; img = imread(inputImage,0); if (img.empty()) { cout << "Could not read input image file: " << inputImage << endl; return -1; } img = img >110; //namedWindow("Img", 1); imshow("Img", img); vector<vector<Point> > contours; vector<Vec4i>hierarchy; Mat dst = Mat::zeros(img.rows, img.cols, CV_8UC3); findContours(img, contours,hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE); if( !contours.empty() && !hierarchy.empty() ) { int idx = 0; for( ; idx >= 0; idx = hierarchy[idx][0] ) { Scalar color( (rand()&255), (rand()&255), (rand()&255) ); drawContours( dst, contours, idx, color, 1, 8, hierarchy ); } } //namedWindow("Connected Components", 1); imshow( "Connected Components", dst ); waitKey(0); return 0; }
findContours函数。这个函数的原型为:
void findContours(InputOutputArray image, OutputArrayOfArrayscontours, OutputArray hierar-
chy, int mode, int method, Point offset=Point())
參数说明
输入图像image必须为一个2值单通道图像
contours參数为检測的轮廓数组。每个轮廓用一个point类型的vector表示
hiararchy參数和轮廓个数同样,每个轮廓contours[ i ]相应4个hierarchy元素hierarchy[ i ][0 ] ~hierarchy[ i ][ 3]。分别表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号。假设没有相应项。该值设置为负数。
mode表示轮廓的检索模式
CV_RETR_EXTERNAL表示仅仅检測外轮廓
CV_RETR_LIST检測的轮廓不建立等级关系
CV_RETR_CCOMP建立两个等级的轮廓。上面的一层为外边界,里面的一层为内孔的边界信息。假设内孔内另一个连通物体,这个物体的边界也在顶层。
CV_RETR_TREE建立一个等级树结构的轮廓。详细參考contours.c这个demo
method为轮廓的近似办法
CV_CHAIN_APPROX_NONE存储全部的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
CV_CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,仅仅保留该方向的终点坐标,比如一个矩形轮廓仅仅需4个点来保存轮廓信息
CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain近似算法
offset表示代表轮廓点的偏移量,能够设置为随意值。对ROI图像中找出的轮廓,并要在整个图像中进行分析时,这个參数还是非常实用的。
findContours后会对输入的2值图像改变,所以假设不想改变该2值图像,需创建新mat来存放,findContours后的轮廓信息contours可能过于复杂不平滑。能够用approxPolyDP函数对该多边形曲线做适当近似
contourArea函数能够得到当前轮廓包括区域的大小,方便轮廓的筛选
hough找直线
hough变换
#include <opencv2\opencv.hpp> #include <iostream> using namespace cv; using namespace std; #include <math.h> #define PI 3.14159265358979 int main(int argc, char *argv[]) { cv::Mat image = cv::imread("f:\\img\\line.png"); //resize(image,image,Size(image.rows/2, image.cols/2),0,0,CV_INTER_LINEAR); cv::Mat contours; cv::cvtColor(image, contours, cv::COLOR_BGR2GRAY); cv::bitwise_not(contours, contours); //cv::Canny(image, contours, 155, 350); std::vector<cv::Vec2f> lines; cv::HoughLines(contours, lines, 1, PI/180, 180); //cv::imshow("cany",contours ); std::vector<cv::Vec2f>::const_iterator it= lines.begin(); Mat dst = Mat::zeros(image.rows, image.cols, CV_8UC3); while (it!=lines.end()) { float rho= (*it)[0]; // first element is distance rho float theta= (*it)[1]; // second element is angle theta if (theta < PI/4. || theta > 3.*PI/4.)// ~vertical line { // point of intersection of the line with first row cv::Point pt1(rho/cos(theta), 0); // point of intersection of the line with last row cv::Point pt2((rho - image.rows * sin(theta))/cos(theta), image.rows); // draw a white line cv::line( dst, pt1, pt2, cv::Scalar(255), 1); } else { // ~horizontal line // point of intersection of the // line with first column cv::Point pt1(0,rho/sin(theta)); // point of intersection of the line with last column cv::Point pt2(image.cols, (rho - image.cols * cos(theta))/sin(theta)); // draw a white line cv::line(dst, pt1, pt2, cv::Scalar(255), 1); } ++it; } cv::imshow("src", image); cv::imshow("dst", dst); waitKey(0); return 0; }
概率hough变换
#include <opencv2\opencv.hpp> #include <iostream> using namespace cv; using namespace std; #include <math.h> #define PI 3.14159265358979 class LineFinder { private: cv::Mat img; // original image std::vector<cv::Vec4i> lines; double deltaRho; double deltaTheta; int minVote; double minLength; // min length for a line double maxGap; // max allowed gap along the line public: // Default accumulator resolution is 1 pixel by 1 degree // no gap, no mimimum length LineFinder() : deltaRho(1), deltaTheta(PI/180), minVote(10), minLength(0.), maxGap(0.) {} // Set the resolution of the accumulator void setAccResolution(double dRho, double dTheta) { deltaRho= dRho; deltaTheta= dTheta; } // Set the minimum number of votes void setMinVote(int minv) { minVote= minv; } // Set line length and gap void setLineLengthAndGap(double length, double gap) { minLength= length; maxGap= gap; } // Apply probabilistic Hough Transform std::vector<cv::Vec4i> findLines(cv::Mat& binary) { lines.clear(); cv::HoughLinesP(binary, lines, deltaRho, deltaTheta, minVote, minLength, maxGap); return lines; } // Draw the detected lines on an image void drawDetectedLines(cv::Mat &image, cv::Scalar color = cv::Scalar(255, 255, 255)) { // Draw the lines std::vector<cv::Vec4i>::const_iterator it2 = lines.begin(); while (it2 != lines.end()) { cv::Point pt1((*it2)[0],(*it2)[1]); cv::Point pt2((*it2)[2],(*it2)[3]); cv::line( image, pt1, pt2, color, 2); ++it2; } } }; int main(int argc, char *argv[]) { cv::Mat image = cv::imread("f:\\img\\line.png"); cv::Mat contours; cv::cvtColor(image, contours, cv::COLOR_BGR2GRAY); cv::bitwise_not(contours, contours); //cv::Canny(image, contours, 155, 350); LineFinder finder; // Set probabilistic Hough parameters finder.setLineLengthAndGap(100, 20); finder.setMinVote(80); // Detect lines and draw them std::vector<cv::Vec4i> lines = finder.findLines(contours); finder.drawDetectedLines(image, cv::Scalar(0, 0, 255)); //cv::namedWindow("Detected Lines with HoughP"); cv::imshow("Detected Lines with HoughP",image); waitKey(0); }
找圆 hough
#include <opencv2/opencv.hpp> using namespace cv; using namespace std; const int kvalue = 15;//双边滤波邻域大小 int main() { Mat src_color = imread("f:\\img\\c1.png");//读取原彩色图 imshow("原图-彩色", src_color); //声明一个三通道图像,像素值全为0。用来将霍夫变换检測出的圆画在上面 Mat dst(src_color.size(), src_color.type()); dst = Scalar::all(0); Mat src_gray;//彩色图像转化成灰度图 cvtColor(src_color, src_gray, COLOR_BGR2GRAY); imshow("原图-灰度", src_gray); imwrite("src_gray.png", src_gray); Mat bf;//对灰度图像进行双边滤波 bilateralFilter(src_gray, bf, kvalue, kvalue*2, kvalue/2); imshow("灰度双边滤波处理", bf); imwrite("src_bf.png", bf); vector<Vec3f> circles;//声明一个向量,保存检測出的圆的圆心坐标和半径 HoughCircles(bf, circles, CV_HOUGH_GRADIENT, 1.5, 20, 130, 38, 10, 50);//霍夫变换检測圆 cout << "x=\ty=\tr=" << endl; for(size_t i = 0; i < circles.size(); i++)//把霍夫变换检測出的圆画出来 { Point center(cvRound(circles[i][0]), cvRound(circles[i][1])); int radius = cvRound(circles[i][2]); circle( dst, center, 0, Scalar(0, 255, 0), -1, 8, 0 ); circle( dst, center, radius, Scalar(0, 0, 255), 1, 8, 0 ); cout << cvRound(circles[i][0]) << "\t" << cvRound(circles[i][1]) << "\t" << cvRound(circles[i][2]) << endl;//在控制台输出圆心坐标和半径 } imshow("特征提取", dst); imwrite("dst.png", dst); waitKey(); }
膨胀腐蚀
膨胀就是大了一圈 腐蚀就是小了一圈
#include <opencv2/opencv.hpp> using namespace cv; using namespace std; int main(int argc, char *argv[]) { Mat src, erode_dst, dilate_dst; src = imread("f:\\img\\erode.png"); if (!src.data) { cout<<"Read image failure."<<endl; return -1; } erode(src, erode_dst, cv::Mat()); dilate(src, dilate_dst, cv::Mat()); namedWindow("src"); namedWindow("erode"); namedWindow("dilate"); imshow("src",src); imshow("erode",erode_dst); imshow("dilate",dilate_dst); waitKey(0); return 0; }
开闭2
<span style="font-size:14px;">#include <opencv\\cv.h> #include <opencv\\highgui.h> #include <stdlib.h> #include <stdio.h> IplImage* src = 0; IplImage* dst = 0; IplConvKernel* element = 0; int element_shape = CV_SHAPE_RECT; //the address of variable which receives trackbar position update int max_iters = 10; int open_close_pos = 0; int erode_dilate_pos = 0; // callback function for open/close trackbar void OpenClose(int pos) { int n = open_close_pos - max_iters; int an = n > 0 ?n : -n; element = cvCreateStructuringElementEx( an*2+1, an*2+1, an, an, element_shape, 0 ); if( n < 0 ) { cvErode(src,dst,element,1); cvDilate(dst,dst,element,1); } else { cvDilate(src,dst,element,1); cvErode(dst,dst,element,1); } cvReleaseStructuringElement(&element); cvShowImage("Open/Close",dst); } // callback function for erode/dilate trackbar void ErodeDilate(int pos) { int n = erode_dilate_pos - max_iters; int an = n > 0 ? n : -n; element = cvCreateStructuringElementEx( an*2+1, an*2+1, an, an, element_shape, 0 ); if( n < 0 ) { cvErode(src,dst,element,1); } else { cvDilate(src,dst,element,1); } cvReleaseStructuringElement(&element); cvShowImage("Erode/Dilate",dst); } int main( int argc, char** argv ) { char* filename = "f:\\img\\oc.png"; if( (src = cvLoadImage(filename,1)) == 0 ) return -1; printf( "Hot keys: \n" "\tESC - quit the program\n" "\tr - use rectangle structuring element\n" "\te - use elliptic structuring element\n" "\tc - use cross-shaped structuring element\n" "\tENTER - loop through all the options\n" ); dst = cvCloneImage(src); //create windows for output images cvNamedWindow("Open/Close",1); cvNamedWindow("src",1); cvShowImage("src",src); cvNamedWindow("Erode/Dilate",1); open_close_pos = erode_dilate_pos = max_iters; cvCreateTrackbar("iterations", "Open/Close",&open_close_pos,max_iters*2+1,OpenClose); cvCreateTrackbar("iterations", "Erode/Dilate",&erode_dilate_pos,max_iters*2+1,ErodeDilate); for(;;) { int c; OpenClose(open_close_pos); ErodeDilate(erode_dilate_pos); c = cvWaitKey(0); if( (char)c == 27 ) break; if( (char)c == 'e' ) element_shape = CV_SHAPE_ELLIPSE; else if( (char)c == 'r' ) element_shape = CV_SHAPE_RECT; else if( (char)c == 'c' ) element_shape = CV_SHAPE_CROSS; else if( (char)c == '\n' ) element_shape = (element_shape + 1) % 3; } //release images cvReleaseImage(&src); cvReleaseImage(&dst); //destroy windows cvDestroyWindow("Open/Close"); cvDestroyWindow("Erode/Dilate"); return 0; }</span>
距离变换
#include "opencv\\cv.h" #include "opencv\\highgui.h" #include <stdio.h> char wndname[] = "Distance transform"; char tbarname[] = "Threshold"; int mask_size = CV_DIST_MASK_5; int build_voronoi = 0; int edge_thresh = 100; // The output and temporary images IplImage* dist = 0; IplImage* dist8u1 = 0; IplImage* dist8u2 = 0; IplImage* dist8u = 0; IplImage* dist32s = 0; IplImage* gray = 0; IplImage* edge = 0; IplImage* labels = 0; // threshold trackbar callback void on_trackbar( int dummy ) { static const uchar colors[][3] = { {0,0,0}, {255,0,0}, {255,128,0}, {255,255,0}, {0,255,0}, {0,128,255}, {0,255,255}, {0,0,255}, {255,0,255} }; int msize = mask_size; cvThreshold( gray, edge, (float)edge_thresh, (float)edge_thresh, CV_THRESH_BINARY ); if( build_voronoi ) msize = CV_DIST_MASK_5; cvDistTransform( edge, dist, CV_DIST_L2, msize, NULL, build_voronoi ? labels : NULL ); if( !build_voronoi ) { // begin "painting" the distance transform result cvConvertScale( dist, dist, 5000.0, 0 ); cvPow( dist, dist, 0.5 ); cvConvertScale( dist, dist32s, 1.0, 0.5 ); cvAndS( dist32s, cvScalarAll(255), dist32s, 0 ); cvConvertScale( dist32s, dist8u1, 1, 0 ); cvConvertScale( dist32s, dist32s, -1, 0 ); cvAddS( dist32s, cvScalarAll(255), dist32s, 0 ); cvConvertScale( dist32s, dist8u2, 1, 0 ); cvMerge( dist8u1, dist8u2, dist8u2, 0, dist8u ); // end "painting" the distance transform result } else { int i, j; for( i = 0; i < labels->height; i++ ) { int* ll = (int*)(labels->imageData + i*labels->widthStep); float* dd = (float*)(dist->imageData + i*dist->widthStep); uchar* d = (uchar*)(dist8u->imageData + i*dist8u->widthStep); for( j = 0; j < labels->width; j++ ) { int idx = ll[j] == 0 || dd[j] == 0 ? 0 : (ll[j]-1)%8 + 1; int b = cvRound(colors[idx][0]); int g = cvRound(colors[idx][1]); int r = cvRound(colors[idx][2]); d[j*3] = (uchar)b; d[j*3+1] = (uchar)g; d[j*3+2] = (uchar)r; } } } cvShowImage( wndname, dist8u ); } int main( int argc, char** argv ) { char* filename = "f:\\img\\pf.jpg"; if( (gray = cvLoadImage( filename, 0 )) == 0 ) return -1; cvNamedWindow( "src", 1 ); cvShowImage( "src", gray ); printf( "Hot keys: \n" "\tESC - quit the program\n" "\t3 - use 3x3 mask\n" "\t5 - use 5x5 mask\n" "\t0 - use precise distance transform\n" "\tv - switch Voronoi diagram mode on/off\n" "\tENTER - loop through all the modes\n" ); dist = cvCreateImage( cvGetSize(gray), IPL_DEPTH_32F, 1 ); dist8u1 = cvCloneImage( gray ); dist8u2 = cvCloneImage( gray ); dist8u = cvCreateImage( cvGetSize(gray), IPL_DEPTH_8U, 3 ); dist32s = cvCreateImage( cvGetSize(gray), IPL_DEPTH_32S, 1 ); edge = cvCloneImage( gray ); labels = cvCreateImage( cvGetSize(gray), IPL_DEPTH_32S, 1 ); cvNamedWindow( wndname, 1 ); cvCreateTrackbar( tbarname, wndname, &edge_thresh, 255, on_trackbar ); for(;;) { int c; // Call to update the view on_trackbar(0); c = cvWaitKey(0); if( (char)c == 27 ) break; if( (char)c == '3' ) mask_size = CV_DIST_MASK_3; else if( (char)c == '5' ) mask_size = CV_DIST_MASK_5; else if( (char)c == '0' ) mask_size = CV_DIST_MASK_PRECISE; else if( (char)c == 'v' ) build_voronoi ^= 1; else if( (char)c == '\n' ) { if( build_voronoi ) { build_voronoi = 0; mask_size = CV_DIST_MASK_3; } else if( mask_size == CV_DIST_MASK_3 ) mask_size = CV_DIST_MASK_5; else if( mask_size == CV_DIST_MASK_5 ) mask_size = CV_DIST_MASK_PRECISE; else if( mask_size == CV_DIST_MASK_PRECISE ) build_voronoi = 1; } } cvReleaseImage( &gray ); cvReleaseImage( &edge ); cvReleaseImage( &dist ); cvReleaseImage( &dist8u ); cvReleaseImage( &dist8u1 ); cvReleaseImage( &dist8u2 ); cvReleaseImage( &dist32s ); cvReleaseImage( &labels ); cvDestroyWindow( wndname ); return 0; }