赞
踩
关于Mat类,我们首先要知道的是:
(1)不必再手动为其开辟空间。
(2)不必再在不需要时立即将空间释放
总结:
Mat B(A)
只复制信息头clone()
或者 copyTo()
来复制一副图像的矩阵【方法一】使用Mat()构造函数
Mat M(2,2,CV_8UC3,Scalar(0,0,255));
//CV_[位数][带符号与否][类型前缀]C[通道数]
//预先定义的通道数可以多达4个
【方法二】在C/C++中通过构造函数进行初始化
int sz[3]={2,2,2};
Mat L(3,sz,cv_8UC,Scalar::all(0));
//上面的例子演示了如何创建一个超过两维的矩阵:指定维数,然后传递给一个指向数组的指针,这个数组包含每个维度的尺寸;后续两个参数与方法一中的相同
【方法三】为已存在的IplImage指针创建信息头
IplImage* img = cvLoadImage("1.jpg",1);
Mat mtx(img);//转换 IplImage*->Mat
【方法四】利用Create()函数
M.create(4,4,CV_8UC(2));
//需要注意的是,此方法不能为矩阵设初值,只是在该百年尺寸时重新为矩阵数据开辟内存而已。
【方法六】对小矩阵使用逗号分隔式初始化函数
Mat C = (Mat_<double>(3,3)<<0,-1,0,-1,5,-1,0,-1,0);
cout<<"C = "<<endl<<" "<C<<endl<<endl;
【方法七】为已存在的对象创建新信息头
Mat RowClone = C.row(1).clone();
cout<<"RowClone = "<<endl<<" "<<RowClone<<endl<<endl;
//方法七为使用成员函数clone()或者copyTo()为一个已存在的Mat对象创建一个新的信息头
获取图像像素指针
掩码操作解释
代码演示
像素处理范围 saturate_cast<uchar>
这个函数的功能是确保RGB值得范围在0~255之间
掩码操作实现图像对比度的调整 I ( i , j ) = 5 ∗ I ( i , j ) − [ I ( i − 1 , j ) + I ( i + 1 , j ) + I ( i , j − 1 ) , I ( i , j + 1 ) ] I(i,j)=5*I(i,j)-[I(i-1,j)+I(i+1,j)+I(i,j-1),I(i,j+1)] I(i,j)=5∗I(i,j)−[I(i−1,j)+I(i+1,j)+I(i,j−1),I(i,j+1)]
#include<iostream> #include<opencv2/opencv.hpp> using namespace cv; int main(int argc,char** argv) { Mat src = imread("test.jpg"); Mat dst; if (!src.data)//如果图像为空,返回 error { std::cout << "can't load this img" <<std::endl; return -1; } namedWindow("input image", WINDOW_AUTOSIZE); imshow("input image", src); //RGB图像按列存储,注意存储顺序是BGR int cols = (src.cols - 1) * src.channels(); //cols 应该用width更为妥当,-1是因为要空出一列像素以防无定义 int offsetx = src.channels(); //偏移量是通道数 int rows = src.rows; //RGB按照列存储,与行数无关 dst = Mat::zeros(src.size(), src.type()); //重新创建一个mat矩阵用于存放输出的图像 //src.copyTo(dst);也可 for (int row = 1; row < rows - 1; row++) { const uchar* previous = src.ptr<uchar>(row - 1); const uchar* current = src.ptr<uchar>(row); const uchar* next = src.ptr<uchar>(row +1); //创建核的数组 uchar* output = dst.ptr<uchar>(row); for (int col = offsetx; col < cols; col++) { output[col] = saturate_cast<uchar>(5 * current[col] - (current[col - offsetx] + current[col + offsetx] + previous[col] + next[col])); } } namedWindow("constrast image", WINDOW_AUTOSIZE); imshow("constrast image", dst); waitKey(0); return 0; }
可直接用opencv的API做掩码操作来提高对比度
filter2D(src,dst,src.depth(),kernel):其中src与dst是Mat类型变量,src.depth表示位图深度,有32、24、8等,直接写-1表示与输入图深度一致。(filter滤波器)
定义掩码: Mat lernel = (Mat_<char>(3,3)<<0,-1,0,-1,5,-1,0,-1,0);
#include <opencv2/opencv.hpp> #include<iostream> #include<math.h> #include<stdlib.h> using namespace cv; int main(int argc, char** argv) { Mat src = imread("C:/Users/admin/Desktop/lenna.png");//读入图片 Mat dst;//提高对比度之后的图片矩阵 if (src.empty()){ // 特判 printf("cannot see\n"); return -1; } namedWindow("opencv setup1", CV_WINDOW_AUTOSIZE); imshow("opencv setup1", src); Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);//定义掩码规则 filter2D(src, dst, src.depth()/*-1*/, kernel); //输出目标图像 namedWindow("opencv setup2", CV_WINDOW_AUTOSIZE); imshow("opencv setup2", dst); waitKey(0); system("pause"); //以便在退出程序前调用系统的暂停命令暂停命令行 //爽得很!! }
mat对象的使用:
Mat F=A.clone();
//或者
Mat G;
A.copyTo(G);
函数用法:
#include<iostream> #include<opencv2/opencv.hpp> using namespace cv; using namespace std; int main(int argc,char** argv) { Mat src = imread("test.jpg"); if (!src.data) { std::cout << "can't load this img" <<std::endl; return -1; } //namedWindow("input image", WINDOW_AUTOSIZE); //imshow("input image", src); /*Mat dst; dst = Mat(src.size(), src.type()); dst = Scalar(255, 0, 255); namedWindow("out put", WINDOW_AUTOSIZE); imshow("out put", dst);*/ /*Mat dst = src.clone(); namedWindow("out put", WINDOW_AUTOSIZE); imshow("out put", dst);*/ //Mat dst; //cvtColor(src, dst, COLOR_BGR2GRAY); //namedWindow("out put", WINDOW_AUTOSIZE); //imshow("out put", dst); //cout << src.channels() << endl;//通道数目 //cout << dst.channels() << endl; //int cols = dst.cols;//全部的列 //int rows = dst.rows;//全部的行 //const uchar* firstRow = dst.ptr<uchar>(0); //printf("%d", *firstRow); Mat M(3, 3, CV_8UC3, Scalar(0, 0, 255)); Mat m1; m1.create(src.size(),src.type()); m1=Scalar(0,0,255); Mat m2 = Mat::zeros(src.size(),src.type()); Mat m2 = Mat::zeros(2,2,CV_8UC1); Mat m2 = Mat::eye(2,2,CV_8UC1); cout << M << endl; waitKey(0); return 0; }
imread
可以指定加载为灰度图像或者RGB图像imwrite
保存图像文件,类型由扩展名决定Scalar intensity = img.at<uchar>(y,x);
或者
Scalar intensity = img.at<uchar>(Point(y,x));
Vec3f intensity = img.at<Vec3f>(y,x);
float blue = intensity.val[0];
float green = intensity.val[1];
float red = intensity.val[2];
获取像素的练习
#include <opencv2/core/utils/logger.hpp> #include<opencv2/opencv.hpp> #include<iostream> using namespace cv; using namespace std; int main(int argc, char** argv) { cv::utils::logging::setLogLevel(utils::logging::LOG_LEVEL_SILENT);//不再输出日志 Mat src = imread("test.jpg"); if (!src.data) { cout << "could not load this image..." << endl; } char output_origin[] = "origin demo"; char output_gray[] = "gray demo"; namedWindow(output_origin, WINDOW_AUTOSIZE); imshow(output_origin, src); Mat dst; cvtColor(src, dst, COLOR_BGR2GRAY); namedWindow(output_gray, WINDOW_AUTOSIZE); imshow(output_gray, dst); dst.create(src.size(), src.type()); for (int row = 0; row < dst.rows; row++) for (int col = 0; col <dst.cols; col++) { //int gray = dst.at<uchar>(row,col); //dst.at<uchar>(row,col) = 255 - gray; int b = src.at<Vec3b>(row, col)[0]; int g = src.at<Vec3b>(row, col)[1]; int r = src.at<Vec3b>(row, col)[2]; dst.at<Vec3b>(row, col)[0]=255-b; dst.at<Vec3b>(row, col)[1] = 255 -g; dst.at<Vec3b>(row, col)[2] = 255 - r; //另一种转换成灰度图像的方法: //dst.at<uchar>(row,col)=max(r,max(b,g)); //dst.at<uchar>(row,col)=min(r,min(b,g)); } namedWindow("anti color demo", WINDOW_AUTOSIZE); imshow("anti color demo", dst); waitKey(0); } //已经有封装好的API干嘛要练习这个 bitwise_not(src,dst);
Vec3b对应的三通道的顺序是blue、green、red的uchar类型的数据
Vec3f对应三通道的float类型数据
把CV_8UC1转换到CV32F1实现如下: src.convertTo(dst,CV_32F);
g ( x ) = ( 1 − α ) f 0 ( x ) + α f 1 ( x ) 其中 α 的取值范围为 0 到 1 之间 g(x)=(1-\alpha)f_0(x)+\alpha f_1(x)\\其中\alpha的取值范围为0到1之间 g(x)=(1−α)f0(x)+αf1(x)其中α的取值范围为0到1之间
相关的API(addWeighted):
addWeight(src1,alpha,src2,beta,gamma(校验值),dst);
d s t ( I ) = s a t u r a t e _ c a s t ( s r c 1 ( I ) ∗ a l p h a + s r c 2 ( I ) ∗ b e t a + g a m m a ) dst(I)=saturate\_cast(src1(I)*alpha+src2(I)*beta+gamma) dst(I)=saturate_cast(src1(I)∗alpha+src2(I)∗beta+gamma)
理论:
图像变换可以看作如下:
调整图像亮度属于像素变换-点操作 g ( i , j ) = α f ( i , j ) + β g(i,j)=\alpha f(i,j)+\beta g(i,j)=αf(i,j)+β其中 α \alpha α>0, β \beta β是增益变量
#include<opencv2/opencv.hpp> #include<iostream> using namespace cv; using namespace std; int main(int argc, char** argv) { Mat src = imread("test.jpg"); char input_win[] = "src image"; if (!src.data) { cout << "could not load the image..." << endl; } namedWindow(input_win, WINDOW_AUTOSIZE); imshow(input_win, src); Mat dst; int height = src.rows; int width = src.cols; dst = Mat::zeros(src.size(), src.type()); double alpha = 1.5; double beta = 10; src.convertTo(src, CV_32F); for (int row = 0; row < height; row++) for (int col = 0; col < width; col++) { if (src.channels() 3) { float b = src.at<Vec3f>(row, col)[0]; float g = src.at<Vec3f>(row, col)[1]; float r = src.at<Vec3f>(row, col)[2]; dst.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(b * alpha + beta); dst.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(g * alpha + beta); dst.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(r * alpha + beta); } else if (src.channels() 1) { int v = src.at<uchar>(row, col); dst.at<uchar>(row, col) = saturate_cast<uchar>(v * alpha + beta); } //else } char output_title[] = "contrast and brightness change demo"; namedWindow(output_title, WINDOW_AUTOSIZE); imshow(output_title, dst); waitKey(0); }
使用Point与Scalar
Point表示2D平面上一个点(x,y)
Point p;
p.x=10;p.y=8;//p=Point(10,8);
Scalar表示四个元素的向量
Scalar(a,b,c);//a=bule,b=green,c=red表示RGB三个通道
在图片中插入线、矩形、椭圆、圆、多边形。
#include<opencv2/opencv.hpp> #include<iostream> using namespace cv; using namespace std; Mat src; void lines(); void myRectangle(); void myEllipse(); void myCircle(); void myPolygon(); int main(int argc, char** argv) { src = imread("test.jpg"); if (!src.data) { cout << "could not liad this image.." << endl; return -1; } lines(); myRectangle(); myEllipse(); myCircle(); myPolygon(); namedWindow("line_demo", WINDOW_AUTOSIZE); imshow("line_demo", src); waitKey(0); } void lines() {//线 Point p1 = Point(20, 30); Point p2 = Point(200, 300); Scalar color =Scalar(0, 0, 255); line(src, p1, p2, color, 5, LINE_AA); } void myRectangle() {//矩形 Rect rect = Rect(200, 100, 300, 300); Scalar color = Scalar(0, 0, 255); rectangle(src, rect, color,1, LINE_8); } void myEllipse() {//椭圆 Scalar color = Scalar(175, 145, 76); ellipse(src, Point(src.cols/ 2, src.rows / 2), Size(src.rows / 4, src.cols / 8), 0, 0, 360, color, 1, LINE_AA); } void myCircle() {//圆 Scalar color = Scalar(175, 146, 76); circle(src, Point(src.cols / 2, src.rows / 2), src.cols / 4, color, 1, LINE_AA); } void myPolygon() {//多边形 Scalar color = Scalar(0, 0, 255); Point pts [1][6]; pts[0][0] = Point(100, 100); pts[0][1] = Point(100, 200); pts[0][2] = Point(200, 200); pts[0][3] = Point(200, 100); pts[0][4] = Point(150, 50); pts[0][5] = Point(100, 100); const Point* ppts[] = { pts[0] }; int npt[] = { 6 }; fillPoly(src, ppts, npt, 1, color, 8); }
在图像中插入文字。putText();
#include<opencv2/opencv.hpp> #include<iostream> using namespace cv; using namespace std; Mat src; int main(int argc, char** argv) { src = imread("test.jpg"); if (!src.data) { cout << "could not liad this image.." << endl; return -1; } putText(src, "hello opencv", Point(src.cols / 2-60, src.rows / 2), FONT_HERSHEY_COMPLEX, 0.8, Scalar(150, 12, 255), 1, 8); namedWindow("line_demo", WINDOW_AUTOSIZE); imshow("line_demo", src); waitKey(0); } //随机生成颜色
随机生成线条
#include<opencv2/opencv.hpp> #include<iostream> using namespace cv; using namespace std; Mat src; void RandowLineDemo(); int main(int argc, char** argv) { src = imread("test.jpg"); if (!src.data) { cout << "could not liad this image.." << endl; return -1; } //putText(src, "hello opencv", Point(src.cols / 2-60, src.rows / 2), FONT_HERSHEY_COMPLEX, 0.8, Scalar(150, 12, 255), 1, 8); RandowLineDemo(); //namedWindow("line_demo", WINDOW_AUTOSIZE); //imshow("line_demo", src); waitKey(0); } void RandowLineDemo() { RNG rng(12346);//RNG 变量(种子数) Mat bg = Mat::zeros(src.size(), src.type()); for (int i = 0; i < 10000; i++) { line(bg, Point(rng.uniform(0, src.cols), rng.uniform(0, src.rows)), Point(rng.uniform(0, src.cols), rng.uniform(0, src.rows)), Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), 1, LINE_AA); //rng.uniform(范围); if (waitKey(50) > 0) { break; } imshow("RandowLineDemo", bg); } }
blur(Mat src,Mat dst,Size(xradius,yradius),Point(-1,-1));
GaussianBlur(Mat src,Mat dst,Size(11,11),sigmax,sigmay);
其中Size(x,y)必须是正数而且是奇数。均值模糊
#include<opencv2/opencv.hpp> #include<iostream> using namespace std; using namespace cv; int main() { Mat src, dst; src = imread("test.jpg"); if (src.empty()) { cout << "could not load this image..." << endl; return -1; } namedWindow("originalDemo", WINDOW_AUTOSIZE); imshow("originalDemo", src); blur(src, dst, Size(3, 3), Point(-1, -1)); namedWindow("blur3Demo", WINDOW_AUTOSIZE); imshow("blur3Demo", dst); blur(src, dst, Size(5, 5), Point(-1, -1)); namedWindow("blur5Demo", WINDOW_AUTOSIZE); imshow("blur5Demo", dst); waitKey(0); }
高斯模糊
#include<opencv2/opencv.hpp> #include<iostream> using namespace std; using namespace cv; int main() { Mat src, dst; src = imread("test.jpg"); if (src.empty()) { cout << "could not load this image..." << endl; return -1; } namedWindow("originalDemo", WINDOW_AUTOSIZE); imshow("originalDemo", src); GaussianBlur(src, dst, Size(11, 11), 5, 5); namedWindow("GaussianBlurDemo", WINDOW_AUTOSIZE); imshow("GaussianBlurDemo", dst); //blur(src, dst, Size(5, 5), Point(-1, -1)); //namedWindow("blur5Demo", WINDOW_AUTOSIZE); //imshow("blur5Demo", dst); waitKey(0); }
medianBlur(Mat src,Mat dest,ksize)
bilateralFilter(src,dest,d=15,150,3);
#include<opencv2/opencv.hpp> #include<iostream> using namespace std; using namespace cv; int main() { Mat src, dst; src = imread("cat1.jpg"); if (src.empty()) { cout << "could not load this image..." << endl; return -1; } namedWindow("originalDemo", WINDOW_AUTOSIZE); imshow("originalDemo", src); //GaussianBlur(src, dst, Size(11, 11), 5, 5); //medianBlur(src, dst, 3); bilateralFilter(src, dst, 15, 150, 3); namedWindow("BilateralFilterDemo", WINDOW_AUTOSIZE); imshow("BilateralFilterDemo", dst); waitKey(0); }
getStructuringElement(int shape,Size ksize,Point anchor)
dilate(src,dst,kernel)
erode(src,dst,kernel)
createTrackbar(constString&trackbarname,winname,int*value,int count,Trackbarcallback func,void* userdata=0)
#include<opencv2/opencv.hpp> #include<iostream> #include<opencv2/imgproc/imgproc.hpp> using namespace std; using namespace cv; void CallBack_Demo(int, void*);//回调函数 int element_size = 3; int Max_size = 21; Mat src, dst; int main() { src = imread("cat1.jpg"); if (!src.data) { cout << "could not load this image.." << endl; return -1; } namedWindow("input image", WINDOW_AUTOSIZE); imshow("input image", src); namedWindow("output image", WINDOW_AUTOSIZE); createTrackbar("Element Size:", "output image", &element_size, Max_size, CallBack_Demo); CallBack_Demo(0, 0); waitKey(0); return 0; } void CallBack_Demo(int, void*) { int s = element_size * 2 + 1; Mat structureElement = getStructuringElement(MORPH_RECT, Size(s, s), Point(-1, -1)); //dilate(src, dst, structureElement, Point(-1, -1), 1);//膨胀 erode(src, dst, structureElement, Point(-1, -1), 1);//腐蚀 imshow("output image", dst); return; }
//深入理解createTrackBar函数 #include<opencv2/opencv.hpp> #include<iostream> #include<opencv2/imgproc/imgproc.hpp> using namespace std; using namespace cv; //void CallBack_Demo(int, void*); int element_size = 3; int Max_size = 21; Mat src, dst; void text(int, void*) { cout << element_size << endl; } int main() { src = imread("cat1.jpg"); if (!src.data) { cout << "could not load this image.." << endl; return -1; } namedWindow("测试窗口", WINDOW_AUTOSIZE); createTrackbar("数字", "测试窗口", &element_size, Max_size, text); text(0, 0); waitKey(0); return 0; }
morphologyEx(src,dest,CV_MOP_BLACKHAT,kernel);
针对二值图像进行处理
膨胀:输出的像素值是结构元素覆盖下输入图像的最大像素值
腐蚀:输出的像素值是结构元素覆盖下输入图像的最小像素值
结构元素
提取步骤
bitwise_not(src,dst):dst=255-src;
代码样例
#include<iostream> #include<opencv2/opencv.hpp> using namespace cv; using namespace std; int main(int argc, char** argv) { Mat src,temp, dst; src = imread("0-1.jpg"); if (src.empty()) { cout << "could not load this img..." << endl; return -1; } imshow("src", src); cvtColor(src, temp, COLOR_BGR2GRAY); adaptiveThreshold(temp, temp, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 15, -2); Mat x_kernel = getStructuringElement(MORPH_RECT, Size(src.cols / 16, 1), Point(-1, -1)); Mat y_kernel = getStructuringElement(MORPH_RECT, Size(1,src.rows/16), Point(-1, -1)); morphologyEx(temp, dst, MORPH_OPEN, x_kernel); bitwise_not(dst, dst); blur(dst,dst,Size(3,3),Point(-1,-1)); namedWindow("x_line", WINDOW_AUTOSIZE); imshow("x_line", dst); waitKey(0); return 0; }
#include<iostream> #include<opencv2/opencv.hpp> using namespace cv; using namespace std; int main(int argc, char** argv) { Mat src,temp, dst; src = imread("ganrao.png"); if (src.empty()) { cout << "could not load this img..." << endl; return -1; } imshow("src", src); cvtColor(src, temp, COLOR_BGR2GRAY); adaptiveThreshold(temp, temp, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 15, -2);//自适应阈值,可以转换为二值图像 Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));//核,getstructingelement获取结构元素 morphologyEx(temp, dst, MORPH_OPEN, kernel); //形态学操作--开--morph——open bitwise_not(dst, dst); imshow("干扰去除", dst); waitKey(0); return 0; }
图像金字塔概念
采样API
如何进行上采样和降采样从而得到高斯金字塔的图像,在一个是如何对每一层进行处理得到它的DOG,归一化,彩色图像通道也可做DOG
#include<iostream> #include<opencv2/opencv.hpp> using namespace cv; using namespace std; int main(int argc, char** argv) { Mat src,temp, g1,g2,dogImg; src = imread("test.jpg"); if (src.empty()) { cout << "could not load this img..." << endl; return -1; } imshow("src", src); //DOG cvtColor(src, temp, COLOR_BGR2GRAY);//转换为灰度图像 GaussianBlur(temp, g1, Size(3, 3), 0, 0);//两次高斯模糊 GaussianBlur(g1, g2, Size(3, 3), 0,0); subtract(g1, g2, dogImg, Mat());//减去 //归一化显示 normalize(dogImg, dogImg, 255, 0, NORM_MINMAX);//用此函数也可化为0-1图像 imshow("DOG Image", dogImg); waitKey(0); return 0; }
阈值二值化(threshold binary)
阈值反二值化(threshold binary Inverted)
阈值截断(threshold trunc)
阈值取零(threshold to zero)
阈值反取零(threshold to zero Inverted)
首先转化为灰度图像
阈值操作
threshold(src,dst,threshold_value,threshold_max,THRESH_TYPE);
#include<iostream> #include<opencv2/opencv.hpp> #include<math.h> using namespace cv; using namespace std; int threshold_value = 127;//阈值 int threshold_max = 255;//最大阈值 Mat src, dst; void threshold_Demo(int, void*);//声明回调函数 int main(int argc, char** argv) { src = imread("test.jpg"); if (src.empty()) { cout << "could not load this img..." << endl; return -1; } namedWindow("input image", WINDOW_AUTOSIZE); namedWindow("output image", WINDOW_AUTOSIZE); imshow("input image", src); createTrackbar("threshold", "output image", &threshold_value, threshold_max, threshold_Demo);//创建滑动条 threshold_Demo(0, 0); waitKey(0); return 0; } void threshold_Demo(int, void*) { cvtColor(src, dst, COLOR_BGR2GRAY);//转换为灰度图 threshold(dst, dst, threshold_value, threshold_max, THRESH_BINARY);//转换为二值图像 imshow("output image", dst); }
XML是使用非常广泛的文件格式,可以利用XML或者YAML格式的文件存储和还原各式各样的数据结构。当然,他们还可以存储和载入任意复杂的数据结构,其中就包括了OpenCV相关周边的数据结构,以及各种原始数据类型,如整数和浮点数字和文本字符串。
过程:
FileStorage
类的对象,用默认带参数的构造函数完成初始化,或者用 FileStorage::open()
成员函数辅助初始化。FileStorage::release()
函数析构掉 FileStorage
类对象,同时关闭文件。#define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<opencv2/opencv.hpp> #include<math.h> #include<time.h> using namespace cv; using namespace std; int main() { //初始化 FileStorage fs("test.yaml", FileStorage::WRITE); fs << "frameCount" << 5; time_t rawtime; time(&rawtime); fs << "calibrationDate" << asctime(localtime(&rawtime)); Mat cameraMatrix = (Mat_<double>(3, 3) << 1000, 0, 320, 0, 1000, 240, 0, 0, 1); Mat distCoeffs = (Mat_<double>(5, 1) << 0.1, 0.01, -0.001, 0, 0); fs << "cameraMatrix" << cameraMatrix << "distCoeffs" << distCoeffs; fs << "features" << "["; for (int i = 0; i < 3; i++) { int x = rand() % 640; int y = rand() % 480; uchar lbp = rand() % 256; fs << "{:" << "x" << x << "y" << y << "lbp" << "[:"; for (int j = 0; j < 8; j++) fs << ((lbp >> j) & 1); fs << "]" << "}"; } fs << "]"; fs.release(); return 0; }
模板也是一个小的图像,用小图像匹配的过程叫做模板匹配
从左到右,从上到下计算匹配度
计算归一化平方不同TM_SQDIFF_NORMED -1
计算归一化相关性TM_CCORR_NORMED ----3
计算归一化相关系数TM_CCOEFF_NORMED -----5
相关API介绍
#include<opencv2/opencv.hpp> #include<iostream> #include<math.h> using namespace cv; using namespace std; int trackbar_value = TM_CCOEFF_NORMED;//阈值, int max_track = 5;//最大阈值/类型数目 Mat src, temp, dst; void templateMatch_demo(int, void*); int main(int argc, char** argv) { src = imread("src.jpg"); temp = imread("template.jpg"); if (!src.data || !temp.data) { cout << "could not load this image..." << endl; return -1; } //namedWindow("input img", WINDOW_AUTOSIZE); namedWindow("output img", WINDOW_AUTOSIZE); createTrackbar("templatemacth", "output img", &trackbar_value, max_track, templateMatch_demo);//创建滑动条 templateMatch_demo(0, 0); waitKey(0); } void templateMatch_demo(int ,void*) { int height = src.rows - temp.rows + 1;//格式要求:大-小+1 int width = src.cols - temp.cols + 1; Mat result(width, height, CV_32FC1);//要求输出32位单通道用于模板匹配 matchTemplate(src, temp, result, trackbar_value,Mat());//模板匹配 normalize(result, result, 0, 1, NORM_MINMAX,-1,Mat());//归一化0-1图像 Point minLoc, maxLoc,temLoc;//定位 src.copyTo(dst);//把源图像给dst double min, max; minMaxLoc(result, &min, &max, &minLoc, &maxLoc,Mat()); if (trackbar_value TM_SQDIFF || trackbar_value TM_SQDIFF_NORMED) { temLoc = minLoc; } else temLoc = maxLoc; rectangle(dst, Rect(temLoc.x, temLoc.y, temp.cols, temp.rows), Scalar(0, 0, 255),2,8);//在dst上画出框 rectangle(result, Rect(temLoc.x, temLoc.y, temp.cols, temp.rows), Scalar(0, 0, 255),2,8); imshow("output img", result); imshow("match", dst); }
#include<iostream> #include<opencv2/opencv.hpp> using namespace cv; using namespace std; int threshold_value = 100; int threshold_max = 255; Mat src, dst; void Demo_Contours(int, void*); RNG rng; int main() { src = imread("cat3.jpg"); if (src.empty()) { cout << "could not load this image..." << endl; return -1; } Demo_Contours(0, 0);//contours轮廓 waitKey(0); return 0; } void Demo_Contours(int, void*) { vector<vector<Point>> contours; vector<Vec4i> hierarchy; Canny(src, dst, threshold_value, threshold_value * 2, 3, false); //Canny(输入,输出,低阈值,高阈值(低阈值的2·3倍),3,false); findContours(dst, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));//寻找轮廓 Mat drawImg = Mat::zeros(dst.size(), CV_8UC3);//8bit3通道的彩色图像 for (size_t i = 0; i < contours.size(); i++) { Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));//RNG rng生成一个随机数。 drawContours(drawImg, contours, i, color, 2, LINE_8, hierarchy, 0, Point(0, 0));//画出轮廓(颜色随机), } imshow("output", drawImg); }
Graham扫描算法
#include<iostream> #include<opencv2/opencv.hpp> using namespace cv; using namespace std; int threshold_value = 100; int threshold_max = 255; Mat src,src_gray; void Thershold_Callback(int, void*); RNG rng(12345); const char* OUTPUT = "output"; const char* TRACKBAR = "trackbar"; int main() { src = imread("cat1.jpg"); if (src.empty()) { cout << "could not load this image..." << endl; return -1; } cvtColor(src, src_gray, COLOR_BGR2GRAY);//先转化为灰度图像 blur(src_gray, src_gray, Size(3, 3), Point(-1, -1));//然后进行模糊,降低噪声,以用来更好的二值化 namedWindow(OUTPUT, WINDOW_AUTOSIZE); createTrackbar(TRACKBAR, OUTPUT, &threshold_value, threshold_max, Thershold_Callback); Thershold_Callback(0, 0); waitKey(0); return 0; } void Thershold_Callback(int, void*) { Mat threshold_output; vector<vector<Point>> contours; vector<Vec4i> hierarchy; threshold(src_gray, threshold_output, threshold_value, threshold_max, THRESH_BINARY);//转化为二值图像 findContours(threshold_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));//通过发现轮廓的到候选点 vector<vector<Point>> hull(contours.size()); for (size_t i = 0; i < contours.size(); i++) { convexHull(Mat(contours[i]), hull[i], false); } Mat dst = Mat::zeros(threshold_output.size(), CV_8UC3); for (size_t i = 0; i < contours.size(); i++) { Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)); drawContours(dst, hull, i, color, 1, LINE_8, hierarchy, 0, Point(0, 0)); drawContours(dst, contours, i, color, 1, LINE_8, hierarchy, 0, Point(0, 0)); } imshow(OUTPUT, dst); }
从彩色图像转化为灰度图像,然后进行模糊,然后进行二值化处理,或者使用Canny边缘检测
approxPolyDP(InputArray curve,OutputArray approxCurve,double epsilon,bool closed)
基于RDP算法实现,目的是减少多边形轮廓点数boundingRect(InputArray points)
得到轮廓周围最小矩形左上角点坐标和右下角点坐标,绘制一个矩形minAreaRect(InputArray points)
得到一个旋转的矩形,返回旋转矩形minEnclosingCircle(InputArray points)
//得到最小区域圆形
fitEllipse(InputArray points)
得到最小椭圆findContours
)//坏代码 #include<iostream> #include<opencv2/opencv.hpp> using namespace cv; using namespace std; int threshold_value = 170; int threshold_max = 255; Mat src, src_gray, dst; void Contours_Callback(int, void*); RNG rng(12345); const char* OUTPUT = "rectangle-Demo"; const char* TRACKBAR = "trackbar"; int main() { src = imread("cat1.jpg"); if (src.empty()) { cout << "could not load this image..." << endl; return -1; } cvtColor(src, src_gray, COLOR_BGR2GRAY);//先转化为灰度图像 blur(src_gray, src_gray, Size(3, 3), Point(-1, -1));//然后进行模糊,降低噪声,以用来更好的二值化 namedWindow(OUTPUT, WINDOW_AUTOSIZE); createTrackbar(TRACKBAR, OUTPUT, &threshold_value, threshold_max, Contours_Callback); Contours_Callback(0, 0); waitKey(0); return 0; } void Contours_Callback(int, void*) { Mat binary_output;//把灰度图像变为二值图像 vector<vector<Point>>contours; vector<Vec4i> hierachy; threshold(src_gray, binary_output, threshold_value, threshold_max, THRESH_BINARY); findContours(binary_output, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(-1, -1)); vector<vector<Point>>contours_ploy(contours.size()); vector<Rect>ploy_rects(contours.size()); vector<Point2f> ccs(contours.size()); vector<float> radius(contours.size()); vector<RotatedRect> minRect(contours.size()); vector<RotatedRect> myellipse(contours.size()); for (size_t i = 0; i < contours.size(); i++) { approxPolyDP(Mat(contours[i]), contours_ploy[i], 3, true);//初始化 /*ploy_rects[i] = boundingRect(contours_ploy[i]); minEnclosingCircle(contours_ploy[i], ccs[i], radius[i]);*/ if (contours_ploy.size() > 5) { myellipse[i] = fitEllipse(contours_ploy[i]); minRect[i] = minAreaRect(contours_ploy[i]); } } src.copyTo(dst); Point2f pts[4]; for (size_t i = 0; i < contours.size(); i++) { Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)); if (contours_ploy.size() > 5) { //rectangle(dst, ploy_rects[i], color, 2, LINE_8); //circle(dst, ccs[i], radius[i], color, 2, LINE_8); ellipse(dst, myellipse[i], color, 1, LINE_8); minRect[i].points(pts); for (int r = 0; r < 4; r++) { line(dst, pts[r], pts[(r + 1) % 4], color, 1, LINE_8); } } } imshow(OUTPUT, dst); }
持续更新…
自用整理,仅为了记录,如需转载请标明出处。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。