#include "opencv2/opencv.hpp"
#include "CameraCalibration.h"
using namespace cv;
using namespace std;
Size SampleSize(60,60); //训练正样本尺寸
uchar TrainSample = 200; //每个种类的样本数
uchar Classes = 5; //样本种类
Mat Train_data,TrainClasses; //声明训练数据和响应数据
string str0 = "Hollow Cylinder"; //空心圆柱
string str1 = "Cube"; //正方体
string str2 = "Cone"; //圆锥
string str3 = "Cylindrical"; //圆柱
string str4 = "Cuboid"; //长方体
string Picture_Name;
int Picture_NameCounter=1;
Mat CalibrationImage;
Mat element = getStructuringElement(MORPH_RECT,Size(9,9));
void Get_TrainData(void);
void ReadImage_to_SaveBoundingRect(const Mat& Image,vector<Rect>& TemRectangle);
Mat Background_separation(const Mat& Image);
void main()
{
Mat GrayImage,BinaryImage,TestImage;
CameraCalibration_Init();
namedWindow("【CalibrationImage】",WINDOW_AUTOSIZE);
CvSVMParams SVM_Params;
SVM_Params.svm_type = CvSVM::C_SVC; //SVM类型(允许用异常值惩罚因子C进行不完全分类)
SVM_Params.kernel_type = CvSVM::LINEAR; //SVM的内核类型
SVM_Params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER,10000,1e-6);//指定迭代终止的条件
printf("\t\t\t\t开始获取训练集数据\n");
Get_TrainData();
printf("\t\t\t\t成功获取训练集数据\n");
printf("\t\t\t\tSVM训练样本开始\n");
CvSVM SVM_Classifier;
SVM_Classifier.train_auto(Train_data,TrainClasses,Mat(),Mat(),SVM_Params);//自动训练并优化参数
SVM_Classifier.save("svm.xml");
printf("\t\t\t\tSVM训练样本结束\n");
while(1)
{
ReturnCameraCalibration(CalibrationImage);
imshow("【CalibrationImage】",CalibrationImage);
cvtColor(CalibrationImage,GrayImage,COLOR_BGR2GRAY);
GaussianBlur(GrayImage,GrayImage,Size(7,7),0,0);
BinaryImage = Background_separation(CalibrationImage);
vector<Rect> TemRectangle;
ReadImage_to_SaveBoundingRect(BinaryImage,TemRectangle);
for (unsigned int i=0;i<TemRectangle.size();i++)
{
TestImage = GrayImage(TemRectangle[i]);
Mat imageNewSize;
resize(TestImage, imageNewSize, SampleSize); //统一摄像头画面里面采集到的轮廓图像的尺寸
TestImage.release(); //把image的矩阵信息释放(清除)
TestImage = imageNewSize.reshape(0, 1); //图像深度不变,把图片矩阵转为一行储存
TestImage.convertTo(TestImage, CV_32FC1);
int Response = static_cast<int>(SVM_Classifier.predict(TestImage));
switch (Response)
{
case 0:
rectangle(CalibrationImage,TemRectangle[i],Scalar(0,0,255),1,8);
putText(CalibrationImage, str0, Point(TemRectangle[i].x + TemRectangle[i].width / 2, TemRectangle[i].y + TemRectangle[i].height / 2),
FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 255), 1, 8);
break;
case 1:
rectangle(CalibrationImage,TemRectangle[i],Scalar(0,0,255),1,8);
putText(CalibrationImage, str1, Point(TemRectangle[i].x + TemRectangle[i].width / 2, TemRectangle[i].y + TemRectangle[i].height / 2),
FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 255), 1, 8);
break;
case 2:
rectangle(CalibrationImage,TemRectangle[i],Scalar(0,0,255),1,8);
putText(CalibrationImage, str2, Point(TemRectangle[i].x + TemRectangle[i].width / 2, TemRectangle[i].y + TemRectangle[i].height / 2),
FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 255), 1, 8);
break;
case 3:
rectangle(CalibrationImage,TemRectangle[i],Scalar(0,0,255),1,8);
putText(CalibrationImage, str3, Point(TemRectangle[i].x + TemRectangle[i].width / 2, TemRectangle[i].y + TemRectangle[i].height / 2),
FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 255), 1, 8);
break;
case 4:
rectangle(CalibrationImage,TemRectangle[i],Scalar(0,0,255),1,8);
putText(CalibrationImage, str4, Point(TemRectangle[i].x + TemRectangle[i].width / 2, TemRectangle[i].y + TemRectangle[i].height / 2),
FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 255), 1, 8);
break;
default: break;
}
}
imshow("【效果图】",CalibrationImage);
uchar keyValue = (uchar)waitKey(1);
if (keyValue == 27) break;
else if(keyValue == 'q')
{
printf("\t\t已成功保存%d张图片至工程文件夹\n",Picture_NameCounter);
Picture_Name = to_string(static_cast<long double>(Picture_NameCounter++))+".jpg"; //to_string:将数值转化为字符串。返回对应的字符串
imwrite(Picture_Name,CalibrationImage);
}
}
}
void Get_TrainData(void)
{
Train_data.create(TrainSample*Classes+2000,SampleSize.height*SampleSize.width,CV_32FC1);//每个种类的样本数为TrainSample,种类为Classes,
TrainClasses.create(TrainSample*Classes+2000, 1, CV_32FC1); //创建TrainSample*Classes行、SampleSize.width*SampleSize.height列的矩阵存储信息(将一副图像的信息转为一行储存),训练数据必须是CV_32FC1
Mat TemparyImage,ImageNewSize;
char file[255];
for (unsigned int i=0;i<Classes;i++)
{
for (unsigned int j=1;j<=TrainSample;j++)//训练集标号从1开始
{
sprintf(file,"samples/positive/s%d/%d.jpg",i,j);
TemparyImage = imread(file,IMREAD_GRAYSCALE);
if (TemparyImage.empty())
{
printf("\t\t\tError: Cant load image %s\n", file);
continue;
}
resize(TemparyImage,ImageNewSize,SampleSize); //统一训练集尺寸
TemparyImage.release(); //把TemparyImage的矩阵信息释放(清除)
TemparyImage = ImageNewSize.reshape(0,1); //图像深度不变,把图片矩阵转为一行储存
TemparyImage.convertTo(Train_data(Range(i*Classes+j-1,i*Classes+j),Range(0,Train_data.cols)),CV_32FC1);//Range为定义ROI的方式之一,表示从起始到终止索引(不包括终止索引)的连续序列
TrainClasses.at<float>(i*Classes+j-1,0) = i;
}
}
for (unsigned int i =1;i<=200;i++)
{
sprintf(file, "samples/negative/%d.jpg",i);
Mat SrcImage = imread(file,IMREAD_GRAYSCALE);
if (SrcImage.empty())
{
printf("\t\t\tError: Cant load image %s\n", file);
continue;
}
resize(SrcImage,ImageNewSize,SampleSize); //统一训练集尺寸
SrcImage.release(); //把TemparyImage的矩阵信息释放(清除)
SrcImage = ImageNewSize.reshape(0,1); //图像深度不变,把图片矩阵转为一行储存
SrcImage.convertTo(Train_data(Range(999+i,999+i+1),Range(0,Train_data.cols)),CV_32FC1);//Range为定义ROI的方式之一,表示从起始到终止索引(不包括终止索引)的连续序列
TrainClasses.at<float>(999+i,0) = -1;
}
}
/*-------背景分离-----*/
Mat Background_separation(const Mat& Image)
{
Mat HSVimage,BinaryImage;
cvtColor(Image,HSVimage,COLOR_BGR2HSV);
GaussianBlur(HSVimage,HSVimage,Size(7,7),0,0);
inRange(HSVimage,Scalar(0,0,30),Scalar(180,85,255),BinaryImage);
morphologyEx(BinaryImage,BinaryImage,MORPH_OPEN,element);
morphologyEx(BinaryImage,BinaryImage,MORPH_CLOSE,element);
return BinaryImage;
}
/*-------寻找目标几何体的外包围矩形-----*/
void ReadImage_to_SaveBoundingRect(const Mat& Image,vector<Rect>& TemRectangle)
{
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(Image,contours,hierarchy,RETR_TREE,CHAIN_APPROX_SIMPLE,Point(0,0));
if(!contours.data()) return;
Rect Rectangle;
double MINcontoursArea = 500,MAXcontoursArea = 8000;
for (unsigned int i=0;i<contours.size();i++)
{
if (fabs(contourArea(contours[i]))>MINcontoursArea && fabs(contourArea(contours[i]))<MAXcontoursArea)
{
Rectangle = boundingRect(contours[i]);
/*-----防止矩形越界,出现图像崩溃问题-----*/
if(Rectangle.x >= 5) Rectangle.x = Rectangle.x -5;
if(Rectangle.y >= 12) Rectangle.y = Rectangle.y -12;
if((Rectangle.y+Rectangle.height + 18) >= CalibrationImage.rows) Rectangle.height = Rectangle.height + 18-(Rectangle.y+Rectangle.height + 18- CalibrationImage.rows);
else Rectangle.height = Rectangle.height + 18;
if((Rectangle.x+Rectangle.width + 10) >= CalibrationImage.cols) Rectangle.width = Rectangle.width + 10-(Rectangle.x+Rectangle.width + 10-Calibr