关于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_(3,3)<<0,-1,0,-1,5,-1,0,-1,0);
cout<<"C = "<
【方法七】为已存在的对象创建新信息头
Mat RowClone = C.row(1).clone();
cout<<"RowClone = "<
获取图像像素指针
掩码操作解释
代码演示
像素处理范围 saturate_cast
这个函数的功能是确保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
#include
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" <(row - 1);
const uchar* current = src.ptr(row);
const uchar* next = src.ptr(row +1);
//创建核的数组
uchar* output = dst.ptr(row);
for (int col = offsetx; col < cols; col++) {
output[col] = saturate_cast(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_
#include
#include
#include
#include
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_(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
#include
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" <(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
或者
Scalar intensity = img.at
Vec3f intensity = img.at(y,x);
float blue = intensity.val[0];
float green = intensity.val[1];
float red = intensity.val[2];
获取像素的练习
#include
#include
#include
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 (row,col);
//dst.at(row,col) = 255 - gray;
int b = src.at(row, col)[0];
int g = src.at(row, col)[1];
int r = src.at(row, col)[2];
dst.at(row, col)[0]=255-b;
dst.at(row, col)[1] = 255 -g;
dst.at(row, col)[2] = 255 - r;
//另一种转换成灰度图像的方法:
//dst.at(row,col)=max(r,max(b,g));
//dst.at(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
#include
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(row, col)[0];
float g = src.at(row, col)[1];
float r = src.at(row, col)[2];
dst.at(row, col)[0] = saturate_cast(b * alpha + beta);
dst.at(row, col)[1] = saturate_cast(g * alpha + beta);
dst.at(row, col)[2] = saturate_cast(r * alpha + beta);
}
else if (src.channels() 1) {
int v = src.at(row, col);
dst.at(row, col) = saturate_cast(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
#include
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
#include
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
#include
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
#include
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
#include
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
#include
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
#include
#include
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
#include
#include
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
#include
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
#include
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
#include
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
#include
#include
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
#include
#include
#include
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_(3, 3) << 1000, 0, 320, 0, 1000, 240, 0, 0, 1);
Mat distCoeffs = (Mat_(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
#include
#include
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
#include
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> contours;
vector 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
#include
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> contours;
vector 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> 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
#include
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>contours;
vector 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>contours_ploy(contours.size());
vectorploy_rects(contours.size());
vector ccs(contours.size());
vector radius(contours.size());
vector minRect(contours.size());
vector 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);
}
持续更新…
自用整理,仅为了记录,如需转载请标明出处。