//---------------------------------【头文件、命名空间包含部分】----------------------------
// 描述:包含程序所使用的头文件和命名空间
//------------------------------------------------------------------------------------------------
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
//-----------------------------------【宏定义部分】--------------------------------------------
// 描述:定义一些辅助宏
//------------------------------------------------------------------------------------------------
#define WINDOW_NAME1 "【原始图】" //为窗口标题定义的宏
#define WINDOW_NAME2 "【图像外界矩形轮廓】" //为窗口标题定义的宏
#define WINDOW_NAME3 "【轮廓提取图像】"
//-----------------------------------【全局变量声明部分】--------------------------------------
// 描述:全局变量的声明
//-----------------------------------------------------------------------------------------------
Mat g_srcImage; Mat g_grayImage;
RNG g_rng(12345);
Mat g_cannyMat_output;
vector<vector<Point> > g_vContours;
vector<Vec4i> g_vHierarchy;
vector<Point> contour;
int g_nThick = 0;
Scalar color;
Mat dst = Mat::zeros(g_cannyMat_output.rows, g_cannyMat_output.cols, CV_8UC3);
vector<vector<Point> > contours_poly(g_vContours.size());
//-----------------------------------【全局变量声明部分】--------------------------------------
// 描述:全局变量的声明
//-----------------------------------------------------------------------------------------------
void on_ThreshChange(int, void*);
//-----------------------------------【main( )函数】--------------------------------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始执行
//-----------------------------------------------------------------------------------------------
int main(int argc, char** argv)
{
//【0】改变console字体颜色
system("color 9F");
// 读入原图像, 返回3通道图像数据
g_srcImage = imread("32.jpg", 1);
if (!g_srcImage.data) { printf("读取图片错误,请确定目录下是否有imread函数指定图片存在~! \n"); return false; }
imshow(WINDOW_NAME1, g_srcImage);
imwrite("原始图.jpg", g_srcImage);
// 把原图像转化成灰度图像并进行平滑
cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);
//二值化
threshold(g_grayImage, g_grayImage, 145, 255, 1);
//imshow("二值化", g_grayImage);
//imwrite("二值化.jpg", g_grayImage);
//膨胀操作
Mat element = getStructuringElement(MORPH_RECT, Size(3, 3)); erode(g_grayImage, g_grayImage, element);
dilate(g_grayImage, g_grayImage, element);
dilate(g_grayImage, g_grayImage, element);
dilate(g_grayImage, g_grayImage, element);
//去噪操作
blur(g_grayImage, g_grayImage, Size(3, 3));
imshow("腐膨", g_grayImage);
//调用on_ThreshChange函数
on_ThreshChange(0, 0);
waitKey(0);
return(0);
}
//-----------------------------------【on_ThreshChange( )函数】-------------------------------
// 描述:回调函数
//-----------------------------------------------------------------------------------------------
void on_ThreshChange(int, void*)
{
// 使用Canndy检测边缘
Canny(g_grayImage, g_cannyMat_output, 150, 255, 3);
namedWindow("边缘检测", WINDOW_AUTOSIZE);
imshow("边缘检测", g_cannyMat_output);
// imwrite("最终轮廓.jpg", g_cannyMat_output);
Mat dst = Mat::zeros(g_cannyMat_output.rows, g_cannyMat_output.cols, CV_8UC3);
// 找到轮廓
findContours(g_cannyMat_output, g_vContours, g_vHierarchy, RETR_EXTERNAL, CHAIN_APPROX_NONE, Point(0, 0));
int m = g_vContours.size();//得到轮廓的数量
int n = 0;
vector<RotatedRect> minRect(g_vContours.size());
Mat DstImg;
for (int i = 0; i < m; ++i)
{
n = g_vContours[i].size();
for (int j = 0; j<n; ++j)
{
contour.push_back(g_vContours[i][j]);//读取每个轮廓的点
}
double Length = arcLength(g_vContours[i], true); //取得轮廓周长
minRect[i] = minAreaRect(Mat(g_vContours[i]));
if (Length>1000 && Length < 1200)//只画出符合周长范围的轮廓
{
Scalar color(255, 255, 255);
drawContours(dst, g_vContours, i, color, 1, 8, g_vHierarchy);//绘制轮廓
Point2f rect_points[4]; minRect[i].points(rect_points);
/* for (int j = 0; j < 4; j++)
{
line(dst, rect_points[j], rect_points[(j + 1) % 4], color, 1, 8);
}*/
CvPoint2D32f rectpoints[4];
cvBoxPoints(minRect[i], rectpoints);
cout << "angle:\n" << (float)minRect[i].angle << endl;//输出角度
cout << "center:\n" << minRect[i].center << endl;//输出外接矩形的中心
cout << "size:\n" << minRect[i].size << endl;//矩形的宽和高
cout << "(x0,y0):\n" << rect_points[0] << endl;//获取矩形的四个点
cout << "(x1,y1):\n" << rect_points[1] << endl;
cout << "(x2,y2):\n" << rect_points[2] << endl;
cout << "(x3,y3):\n" << rect_points[3] << endl;
float a = rect_points[0].x;//获取外接矩形的左上X坐标的值
float b = rect_points[0].y;
float c = rect_points[1].x;
float d = rect_points[1].y;
float e = rect_points[2].x;
float f = rect_points[2].y;
float g = rect_points[3].x;
float h = rect_points[3].y;
float angle = minRect[i].angle;
Rect brect = minRect[i].boundingRect();
rectangle(g_srcImage, brect, Scalar(255, 0, 0));
imshow(WINDOW_NAME2, g_srcImage);
// namedWindow("DstImg", 1);
g_srcImage(brect).copyTo(DstImg);
imwrite("DstImg.jpg", DstImg);
imshow(WINDOW_NAME3, DstImg);
}
contour.clear();
}
namedWindow("src", 1);
imshow("src", dst);
}
输出的外接矩形信息图
符合周长范围的轮廓
在原图上标出最小外接矩形以及输出最小外接矩形
根据 findContours 函数写的一个小程序,可能有许多不到位的,期待大家批评指正,相互交流!