#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
//#include <opencv2/nonfree/nonfree.hpp>
#include <opencv2/features2d/features2d.hpp>
//#include <opencv2/legacy/legacy.hpp>
#include <iostream>
using namespace std;
using namespace cv;
cv:: Mat img;
int Threhold = 160;
int ErodeOrDilateNum = 0;
int StructElementSize = 3;
Mat srcImage, dstImage;
void process();
void on_ErodeOrDilateChange(int, void*);
void on_StructElementSizeChange(int, void*);
vector<Point> vecPoint;
vector<vector<Point>> vec2Point;
Point stPoint(-1, -1);
Point curPoint(-1, -1);
void on_mouse(int event, int x, int y, int flags, void *ustc);
static void on_trackbar(int, void*)
{
Mat bw = (Threhold < 128) ? (img < Threhold) : (img > Threhold);
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours( bw, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
//初始化dst
Mat dst = Mat::zeros(img.size(), CV_8UC3);
//开始处理
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, CV_FILLED, 8, hierarchy );
}
}
//显示窗口
imshow( "TrackImage", dst );
}
int main()
{
// 1.滑动条 和 contours
/*img = cv::imread("./open_test.jpg", 0);
if(!img.data)
{
cout<< "Open image failed!"<<endl;
return -1;
}
namedWindow("Image", 1);
imshow("Image", img);
namedWindow("TrackImage", 1);
createTrackbar("Trackbar", "TrackImage", &Threhold, 255, on_trackbar);
on_trackbar(Threhold, 0);*/
// 2. Canny 边缘检测
/*srcImage = cv::imread("./open_test.jpg", 1);
Mat src_cp = srcImage.clone();
if(!srcImage.data)
{
cout<< "Open image failed!"<<endl;
return -1;
}
Mat gray, edge, dst;
dst.create(src_cp.size(), src_cp.type());
cvtColor(srcImage, gray, CV_BGR2GRAY);
blur(gray, edge, Size(3, 3));
Canny(edge, edge, 3, 9, 3);
dst = Scalar::all(0);
src_cp.copyTo(dst, edge);
imshow("【效果图】Canny边缘检测", dst); */
// 3.erode and dilate
/*srcImage = cv::imread("./open_test.jpg", 1);
Mat src_cp = srcImage.clone();
if(!srcImage.data)
{
cout<< "Open image failed!"<<endl;
return -1;
}
namedWindow("ErodeOrDilate", 1);
//获取自定义核
Mat element = getStructuringElement(MORPH_RECT, Size(2*StructElementSize+1,2*StructElementSize+1), Point(StructElementSize, StructElementSize));
erode(srcImage, dstImage, element);
imshow("ErodeOrDilate", dstImage);
//createTrackbar param: 1. 滑动条的名称 2. 依附窗口的名称 3. 当前滑动条位置 4. 总的位置大小 5. 回调函数, 只要滑动条位置改变,就会自动触发回调函数
createTrackbar("ErodeOrDilateChange", "ErodeOrDilate", &ErodeOrDilateNum, 1, on_ErodeOrDilateChange);
//on_ErodeOrDilateChange(ErodeOrDilateNum, 0);
createTrackbar("StructElementSizeChange", "ErodeOrDilate", &StructElementSize, 21, on_StructElementSizeChange);
//on_StructElementSizeChange(StructElementSize, 0);*/
//4. Hough Transform
/*srcImage = cv::imread("./open_test.jpg", 1);
Mat midImage;
if(!srcImage.data)
{
cout<< "Open image failed!"<<endl;
return -1;
}
namedWindow("srcImage", 1);
imshow("srcImage", srcImage);
namedWindow("HoughImage", 1);
Canny(srcImage, midImage, 3, 9, 3);
cvtColor(midImage, dstImage, CV_GRAY2BGR);
vector<Vec4i> lines;//定义一个矢量结构lines用于存放得到的线段矢量集合
HoughLinesP(midImage, lines, 1, CV_PI/180, 80, 50, 10 );
for(int i = 0; i < lines.size(); i++)
{
line(dstImage, Point(lines[i][0], lines[i][1]), Point(lines[i][2], lines[i][3]), Scalar(186, 88, 256), 1, CV_AA);
}
imshow("GrayImage", midImage);
imshow("HoughImage", dstImage);*/
// SURF nonfree.hpp
/*srcImage = cv::imread("./open_test.jpg", 1);
Mat srcImage2 = cv::imread("./open_test2.jpg", 1);
if(!srcImage.data || !srcImage2.data)
{
cout<< "Open image failed!"<<endl;
return -1;
}
//【2】使用SURF算子检测关键点
int minHassia = 700;
SurfFeatureDetector detector(minHassia);
vector<KeyPoint> keyPoint1, keyPoint2;
detector.detect(srcImage, keyPoint1);
detector.detect(srcImage2, keyPoint2);
//【4】计算描述符(特征向量)
SurfDescriptorExtractor extractor;
Mat descriptor1, descriptor2;
extractor.compute(srcImage, keyPoint1, descriptor1);
extractor.compute(srcImage2, keyPoint2, descriptor2);
//【5】使用BruteForce进行匹配
// 实例化一个匹配器
BruteForceMatcher< L2<float> > matcher;
std::vector< DMatch > matches;
matcher.match(descriptor1, descriptor2, matches);
//【6】绘制从两个图像中匹配出的关键点
Mat imgMatches;
drawMatches(srcImage, keyPoint1, srcImage2, keyPoint2, matches, imgMatches);
imshow("SURFImage", imgMatches);*/
//void polylines(Mat& img, const Point** pts, const int* npts, int ncontours, bool isClosed, const Scalar& color, int thickness=1, int lineType=8, int shift=0 );
// img:在img表示的图像上绘制
// pts:是指向多边形数组的指针,必须是const修饰的
// npts:是多边形顶点个数的数组名
// ncontours:绘制多边形的个数
// isClosed:表示多边形是否闭合,1表示闭合,0表示不闭合
// color:是填充的颜色
srcImage = cv::imread("./open_test.jpg", 1);
if(!srcImage.data)
{
cout<< "Open image failed!"<<endl;
return -1;
}
namedWindow("srcImage", 1);
setMouseCallback("srcImage", on_mouse, 0); // 只要鼠标点击,就会自动调用
cout<<"enter q to exit!"<<endl;
while(char(waitKey(0))!='q')
{
}
return 0;
}
// event
// CV_EVENT_MOUSEMOVE =0, //鼠标移动
// CV_EVENT_LBUTTONDOWN =1, //按下左键
// CV_EVENT_RBUTTONDOWN =2, //按下右键
// CV_EVENT_MBUTTONDOWN =3, //按下中键
// CV_EVENT_LBUTTONUP =4, //放开左键
// CV_EVENT_RBUTTONUP =5, //放开右键
// CV_EVENT_MBUTTONUP =6, //放开中键
// CV_EVENT_LBUTTONDBLCLK =7, //左键双击
// CV_EVENT_RBUTTONDBLCLK =8, //右键双击
// CV_EVENT_MBUTTONDBLCLK =9, //中键双击
// CV_EVENT_MOUSEWHEEL =10, //滚轮滚动
// CV_EVENT_MOUSEHWHEEL =11 //横向滚轮滚动
// flags
// CV_EVENT_FLAG_LBUTTON =1, //左键拖拽
// CV_EVENT_FLAG_RBUTTON =2, //右键拖拽
// CV_EVENT_FLAG_MBUTTON =4, //中键拖拽
// CV_EVENT_FLAG_CTRLKEY =8, //按住CTRL拖拽
// CV_EVENT_FLAG_SHIFTKEY =16, //按住Shift拖拽
// CV_EVENT_FLAG_ALTKEY =32 //按住ALT拖拽
// 原型 void putText( Mat& img, const string& text, Point org, int fontFace,double fontScale, Scalar color, int thickness=1, int lineType=8 );
// 参数1:, Mat& img,待写字的图片,我们写在img图上
// 参数2:,const string& text,待写入的字,我们下面写入Hello
// 参数3:, Point org, 第一个字符左下角坐标,我们设定在图片的Point(50,60)坐标。表示x = 50,y = 60。
// 参数4:,int fontFace,字体类型,FONT_HERSHEY_SIMPLEX ,FONT_HERSHEY_PLAIN ,FONT_HERSHEY_DUPLEX 等等等。
// 参数5:,double fontScale,字体大小,我们设置为2号
// 参数6:,Scalar color,字体颜色,颜色用Scalar()表示,不懂得去百度。
// 参数7:, int thickness,字体粗细,我们下面代码使用的是4号
// 参数8:, int lineType,线型,我们使用默认值8.
//首先使用鼠标点击事件,鼠标点击事件的函数为:
void on_mouse(int event, int x, int y, int flags, void *ustc)//event鼠标事件代号,x,y鼠标坐标,flags拖拽和键盘操作的代号
{
if(event == CV_EVENT_LBUTTONDOWN)
{
stPoint = Point(x, y);
vecPoint.push_back(stPoint);
circle(srcImage, stPoint, 1, cv::Scalar(255, 0, 255), CV_FILLED, CV_AA, 0);
imshow("srcImage", srcImage);
}else if(event == CV_EVENT_MOUSEMOVE)// && (flags & CV_EVENT_FLAG_LBUTTON))
{
curPoint = Point(x, y);
stringstream ss;
ss << "x = " << curPoint.x << " y = " << curPoint.y;
putText(srcImage,ss.str(),Point(50, 50),FONT_HERSHEY_SIMPLEX,2,Scalar(0,0,255),4,8);
ss.clear();
/*line(srcImage,vecPoint.back(), curPoint, Scalar(255, 255, 255), 1, 8, 0);
circle(srcImage, curPoint, 1, cv::Scalar(255, 0, 255), CV_FILLED, CV_AA, 0);
vecPoint.push_back(curPoint);*/
imshow("srcImage", srcImage);
}else if(event == CV_EVENT_RBUTTONDOWN)
{
if(vecPoint.size() <=1)
{
vecPoint.clear();
return;
}
vec2Point.push_back(vecPoint);
/*for(auto i : vec2Point)
for(auto j : i)
{
line(srcImage, j, )
}*/
for(int i = 0; i < vec2Point.size(); i++)
for(int j = 1; j < vec2Point[i].size(); j++)
{
line(srcImage, vec2Point[i][j-1], vec2Point[i][j], Scalar(255, 255, 255), 1, 8, 0);
}
imshow("srcImage", srcImage);
cout<<"vec2Point size = " << vec2Point.size() <<endl;
vecPoint.clear();
}else if(event == CV_EVENT_MBUTTONDOWN)
{
if(vecPoint.size() > 0)
{
vecPoint.pop_back();
cout<< "vecPoint size = " << vecPoint.size()<<endl;
}
imshow("srcImage", srcImage);
}
}
void on_ErodeOrDilateChange(int, void*)
{
process();
}
void on_StructElementSizeChange(int, void*)
{
process();
}
void process()
{
Mat element = getStructuringElement(MORPH_RECT, Size(2*StructElementSize+1,2*StructElementSize+1), Point(StructElementSize, StructElementSize));
if(ErodeOrDilateNum == 0)
{
erode(srcImage, dstImage, element);
}
else
{
dilate(srcImage,dstImage, element);
}
imshow("ErodeOrDilate", dstImage);
}
参考文献:
毛星云opencv专栏