C# · 12月 20, 2021

C++ Opencv——色形纹分类检测综合

目录

主函数 

子程序

子函数 

主函数 

#include

#include

#include

#include

#include

#include “Water_Cut.h”

#include “Feature.h”

using namespace cv;

using namespace std;

using namespace cv::ml;

Feature feature_class;

int main()

{

// 训练——训练时候关闭测试

#if 0

// 遍历图片——为了循环提取特征用

string train_img_dir = “C:\Users\Administrator\Desktop\样品\训练”;

string train_img_namehead = “test”;

string train_img_type = “bmp”;

//size_t train_img_num = 4;

string img_name = train_img_dir + “\” + “*.” + train_img_type; //cout << img_name << endl;

int train_img_num = feature_class.read_images_in_folder(img_name);

cout << "训练图个数:" << train_img_num << endl;

// 训练用的输入和标签

Mat trainmat;

trainmat = cv::Mat::zeros(train_img_num,32,CV_32FC1);

Mat labelmat;

labelmat = cv::Mat::zeros(train_img_num,1,CV_32SC1);

// 遍历图并提取特征

vector train_img = feature_class.data_search(train_img_dir,train_img_namehead,train_img_type,train_img_num);

for (size_t i = 0; i < train_img_num; i++)

{

resize(train_img[i],train_img[i],Size(train_img[i].cols / 2,train_img[i].rows / 2));

namedWindow(“vetmat”,0);

imshow(“vetmat”,train_img[i]);//train_img[i].clone();

waitKey(0);

// 图像分割

Mat src = train_img[i].clone();

Mat dst = Mat::zeros(train_img[i].size(),CV_8UC3);

Mat edge = Mat::zeros(train_img[i].size(),CV_8UC3);

Water_Cut(src,dst,edge);

// 图像特征_HU

Mat hu_dst = dst.clone();

double Hu[7] = { 0 };

feature_class.feature_hu(hu_dst,Hu);

// 图像特征_COLOR

Mat color_dst = dst.clone();

float Mom[9] = { 0 };

feature_class.feature_color(color_dst,Mom);

// 图像特征_GLCM

Mat glcm_dst = dst.clone();

cv::cvtColor(glcm_dst,glcm_dst,CV_RGB2GRAY);

float glcm_data[16] = { 0 };

feature_class.feature_glcm(glcm_dst,glcm_data);

float train_data[32] = { 0 };

for (size_t j = 0; j < 7; j++)

{

train_data[j] = (float)Hu[j];

}

for (size_t j = 0; j < 9; j++)

{

train_data[7 + j] = (float)Mom[j];

}

for (size_t j = 0; j < 16; j++)

{

train_data[16 + j] = (float)glcm_data[j];

}

vector traindata; // 特征值——一类(一张图)的特征

for (size_t k = 0; k < 32; k++)

{

traindata.push_back(train_data[k]);

}

std::cout << "traindata size:";

std::cout << traindata.size() << endl;

for (size_t j = 0; j < traindata.size(); j++)

{

trainmat.at(i,j) = traindata[j];

}

labelmat.at(i,0) = i + 1; //每张一类

}

// 训练的初始化

Ptr svm = SVM::create();

svm->setType(SVM::C_SVC);

svm->setKernel(SVM::LINEAR);

svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER,100,1e-6));

std::cout << "开始训练" << endl;

svm->train(trainmat,ROW_SAMPLE,labelmat);

std::cout << "开始结束" << endl;

svm->save(“svm.xml”);

#endif

// 测试——测试时候关闭训练

#if 1

// 遍历测试文件

// 遍历图片——为了循环提取特征用

//string test_img_dir = “C:\Users\Administrator\Desktop\样品\测试\方格1号”;

//string test_img_dir = “C:\Users\Administrator\Desktop\样品\测试\花纹2号”;

//string test_img_dir = “C:\Users\Administrator\Desktop\样品\测试\空纹理3号”;

//string test_img_dir = “C:\Users\Administrator\Desktop\样品\测试\条纹4号”;

string test_img_dir = “C:\Users\Administrator\Desktop\样品\测试\”;

string test_img_namehead = “test”;

string test_img_type = “bmp”;

string img_name = test_img_dir + “\” + “*.” + test_img_type; //cout << img_name << endl;

int test_img_num = feature_class.read_images_in_folder(img_name);

std::cout << "测试图个数:" << test_img_num << endl;

// 训练用的输入和标签

Mat testmat;

testmat = cv::Mat::zeros(test_img_num,CV_32F);

// 遍历图并提取特征

vector test_img = feature_class.data_search(test_img_dir,test_img_namehead,test_img_type,test_img_num);

for (size_t i = 0; i < test_img_num; i++)

{

resize(test_img[i],test_img[i],Size(test_img[i].cols / 2,test_img[i].rows / 2));

cv::namedWindow(“vetmat”,0);

cv::imshow(“vetmat”,test_img[i]);//test_img[i].clone();

// 图像分割

Mat src = test_img[i].clone();

Mat dst = Mat::zeros(test_img[i].size(),CV_8UC3);

Mat edge = Mat::zeros(test_img[i].size(),glcm_data);

cv::waitKey();

float test_data[32] = { 0 };

for (size_t j = 0; j < 7; j++)

{

test_data[j] = (float)Hu[j];

}

for (size_t j = 0; j < 9; j++)

{

test_data[7 + j] = (float)Mom[j];

}

for (size_t j = 0; j < 16; j++)

{

test_data[16 + j] = (float)glcm_data[j];

}

vector testdata; // 特征值——一类(一张图)的特征

for (size_t k = 0; k < 32; k++)

{

testdata.push_back(test_data[k]);

}

std::cout << "testdata size:";

std::cout << testdata.size() << endl;

for (size_t j = 0; j < testdata.size(); j++)

{

testmat.at(i,j) = testdata[j];

}

}

Ptr svmtest = Algorithm::load(“svm.xml”); // SVM::load()是一个静态函数,不能单独用

Mat result;

float temp = svmtest->predict(testmat,result);

std::cout << "分类结果" << endl;

std::cout << result << endl;

for (size_t i = 0; i < test_img_num; i++)

{

int a = result.at(i,0).x;

std::cout << "最终分类为:" << "第" << a << "号瓷砖" << endl;

}

#endif

system(“pause”);

return 0;

}

子程序

#include

#include

#include

#include “time.h”

using namespace cv;

using namespace std;

using namespace cv::ml;

class Feature

{

public:

/*

第一步:建立类

#include

#include

#include

#include “time.h”

using namespace cv;

using namespace std;

第二步:包含类

Feature feature_class;

第三步:

集合颜色+形状+纹理

// 图像特征_HU

Mat hu_dst = dst.clone();

double Hu[7] = { 0 };

feature_class.feature_hu(hu_dst,glcm_data);

第四步:

// 特征集合7+9+16

float test_data[32] = { 0 };

for (size_t j = 0; j < 7; j++)

{

test_data[j] = (float)Hu[j];

}

for (size_t j = 0; j < 9; j++)

{

test_data[7 + j] = (float)Mom[j];

}

for (size_t j = 0; j < 16; j++)

{

test_data[16 + j] = (float)glcm_data[j];

}

*/

/* 【颜色】 */

// 颜色 计算三阶矩

double calc3orderMom(Mat &channel) //计算三阶矩

{

uchar *p;

double mom = 0;

double m = mean(channel)[0]; //计算单通道图像的均值

int nRows = channel.rows;

int nCols = channel.cols;

if (channel.isContinuous()) //连续存储有助于提升图像扫描速度

{

nCols *= nRows;

nRows = 1;

}

for (int i = 0; i < nRows; i++) //计算立方和

{

p = channel.ptr(i);

for (int j = 0; j < nCols; j++)

mom += pow((p[j] – m),3);

}

float temp;

temp = cvCbrt((float)(mom / (nRows*nCols))); //求均值的立方根

mom = (double)temp;

return mom;

}

// 颜色 计算9个颜色矩:3个通道的1、2、3阶矩

double *colorMom(Mat &img)

{

double *Mom = new double[9]; //存放9个颜色矩

if (img.channels() != 3)

std::cout << "Error,input image must be a color image" << endl;

Mat b(img.rows,img.cols,CV_8U);

Mat r(img.rows,CV_8U);

Mat g(img.rows,CV_8U);

Mat channels[] = { b,g,r };

split(img,channels);

//cv::imshow(“r”,channels[0]);

//cv::imshow(“g”,channels[1]);

//cv::imshow(“b”,channels[2]);

//waitKey(0);

Mat tmp_m,tmp_sd;

//计算b通道的颜色矩

meanStdDev(b,tmp_m,tmp_sd);

Mom[0] = tmp_m.at(0,0);

Mom[3] = tmp_sd.at(0,0);

Mom[6] = calc3orderMom(b);

// cout << Mom[0] << " " << Mom[1] << " " << Mom[2] << " " << endl;

//计算g通道的颜色矩

meanStdDev(g,tmp_sd);

Mom[1] = tmp_m.at(0,0);

Mom[4] = tmp_sd.at(0,0);

Mom[7] = calc3orderMom(g);

// cout << Mom[3] << " " << Mom[4] << " " << Mom[5] << " " << endl;

//计算r通道的颜色矩

meanStdDev(r,tmp_sd);

Mom[2] = tmp_m.at(0,0);

Mom[5] = tmp_sd.at(0,0);

Mom[8] = calc3orderMom(r);

// cout << Mom[6] << " " << Mom[7] << " " << Mom[8] << " " << endl;

return Mom;//返回颜色矩数组

}

// 颜色

bool feature_color(Mat src,float Mom[9])

{

if (src.channels() == 3)

{

// 图像特征_COLOR

Mat color_dst = src.clone();

cv::cvtColor(color_dst,color_dst,CV_RGB2HSV);

double *MOM;

MOM = colorMom(color_dst);

for (int i = 0; i < 9; i++)

{

std::cout << (float)MOM[i] << endl;

Mom[i] = (float)MOM[i];

}

return true;

}

else

{

std::cout << "channels!=3";

return false;

}

}

/* 【形状】 */

bool feature_hu(Mat src,double Hu[7])

{

if (src.channels() == 3)

{

// 图像特征_HU

Mat hu_dst = src.clone();

cv::cvtColor(hu_dst,hu_dst,CV_RGB2GRAY);

Canny(hu_dst,120);

//double Hu[7]; //存储得到的Hu矩阵

Moments mo = moments(hu_dst);//矩变量

HuMoments(mo,Hu);

for (int i = 0; i < 7; i++)

{

std::cout << (float)Hu[i] << endl;

}

return true;

}

else if ((src.channels() == 1))

{

Mat hu_dst = src.clone();

Canny(hu_dst,Hu);

for (int i = 0; i < 7; i++)

{

std::cout << (float)Hu[i] << endl;

}

return true;

}

else

{

return false;

}

}

// 纹理

const int gray_level = 16;//纹理区域块的大小,通常将图像划分成若干个纹理块计算

vector glamvalue;//全局变量

//【】第一步:j计算共生矩阵

void getglcm_0(Mat& input,Mat& dst)//0度灰度共生矩阵

{

Mat src = input;

CV_Assert(1 == src.channels());

src.convertTo(src,CV_32S);

int height = src.rows;

int width = src.cols;

int max_gray_level = 0;

for (int j = 0; j < height; j++)//寻找像素灰度最大值

{

int* srcdata = src.ptr(j);

for (int i = 0; i < width; i++)

{

if (srcdata[i] > max_gray_level)

{

max_gray_level = srcdata[i];

}

}

}

max_gray_leveL++;//像素灰度最大值加1即为该矩阵所拥有的灰度级数

if (max_gray_level > 16)//若灰度级数大于16,则将图像的灰度级缩小至16级,减小灰度共生矩阵的大小。

{

for (int i = 0; i < height; i++)

{

int*srcdata = src.ptr(i);

for (int j = 0; j < width; j++)

{

srcdata[j] = (int)srcdata[j] / gray_level;

}

}

dst.create(gray_level,gray_level,CV_32SC1);

dst = Scalar::all(0);

for (int i = 0; i < height; i++)

{

int*srcdata = src.ptr(i);

for (int j = 0; j < width – 1; j++)

{

int rows = srcdata[j];

int cols = srcdata[j + 1];

dst.ptr(rows)[cols]++;

}

}

}

else//若灰度级数小于16,则生成相应的灰度共生矩阵

{

dst.create(max_gray_level,max_gray_level,CV_32SC1);

dst = Scalar::all(0);

for (int i = 0; i < height; i++)

{

int*srcdata = src.ptr(i);

for (int j = 0; j < width – 1; j++)

{

int rows = srcdata[j];

int cols = srcdata[j + 1];

dst.ptr(rows)[cols]++;

}

}

}

}

void getglcm_45(Mat& input,Mat& dst)//45度灰度共生矩阵

{

Mat src = input;

CV_Assert(1 == src.channels());

src.convertTo(src,CV_32S);

int height = src.rows;

int width = src.cols;

int max_gray_level = 0;

for (int j = 0; j < height; j++)

{

int* srcdata = src.ptr(j);

for (int i = 0; i < width; i++)

{

if (srcdata[i] > max_gray_level)

{

max_gray_level = srcdata[i];

}

}

}

max_gray_leveL++;

if (max_gray_level > 16)

{

for (int i = 0; i < height; i++)//将图像的灰度级缩小至16级,减小灰度共生矩阵的大小。

{

int*srcdata = src.ptr(i);

for (int j = 0; j < width; j++)

{

srcdata[j] = (int)srcdata[j] / gray_level;

}

}

dst.create(gray_level,CV_32SC1);

dst = Scalar::all(0);

for (int i = 0; i < height – 1; i++)

{

int*srcdata = src.ptr(i);

int*srcdata1 = src.ptr(i + 1);

for (int j = 0; j < width – 1; j++)

{

int rows = srcdata[j];

int cols = srcdata1[j + 1];

dst.ptr(rows)[cols]++;

}

}

}

else

{

dst.create(max_gray_level,CV_32SC1);

dst = Scalar::all(0);

for (int i = 0; i < height – 1; i++)

{

int*srcdata = src.ptr(i);

int*srcdata1 = src.ptr(i + 1);

for (int j = 0; j < width – 1; j++)

{

int rows = srcdata[j];

int cols = srcdata1[j + 1];

dst.ptr(rows)[cols]++;

}

}

}

}

void getglcm_90(Mat& input,Mat& dst)//90度灰度共生矩阵

{

Mat src = input;

CV_Assert(1 == src.channels());

src.convertTo(src,CV_32SC1);

dst = Scalar::all(0);

for (int i = 0; i < height – 1; i++)

{

int*srcdata = src.ptr(i);

int*srcdata1 = src.ptr(i + 1);

for (int j = 0; j < width; j++)

{

int rows = srcdata[j];

int cols = srcdata1[j];

dst.ptr(rows)[cols]++;

}

}

}

else

{

dst.create(max_gray_level,CV_32SC1);

dst = Scalar::all(0);

for (int i = 0; i < height – 1; i++)

{

int*srcdata = src.ptr(i);

int*srcdata1 = src.ptr(i + 1);

for (int j = 0; j < width; j++)

{

int rows = srcdata[j];

int cols = srcdata1[j];

dst.ptr(rows)[cols]++;

}

}

}

}

void getglcm_135(Mat& input,Mat& dst)//135度灰度共生矩阵

{

Mat src = input;

CV_Assert(1 == src.channels());

src.convertTo(src,CV_32SC1);

dst = Scalar::all(0);

for (int i = 0; i < height – 1; i++)

{

int*srcdata = src.ptr(i);

int*srcdata1 = src.ptr(i + 1);

for (int j = 1; j < width; j++)

{

int rows = srcdata[j];

int cols = srcdata1[j – 1];

dst.ptr(rows)[cols]++;

}

}

}

else

{

dst.create(max_gray_level,CV_32SC1);

dst = Scalar::all(0);

for (int i = 0; i < height – 1; i++)

{

int*srcdata = src.ptr(i);

int*srcdata1 = src.ptr(i + 1);

for (int j = 1; j < width; j++)

{

int rows = srcdata[j];

int cols = srcdata1[j – 1];

dst.ptr(rows)[cols]++;

}

}

}

}

// 【】第二步:计算纹理特征 // 特征值计算—— double& Asm,double& Con,double& Ent,double& Idm

void feature_computer(Mat&src,float& Asm,float& Con,float& Ent,float& Idm)//计算特征值

{

int height = src.rows;

int width = src.cols;

int total = 0;

for (int i = 0; i < height; i++)

{

int*srcdata = src.ptr(i);

for (int j = 0; j < width; j++)

{

total += srcdata[j];//求图像所有像素的灰度值的和

}

}

Mat copy;

copy.create(height,width,CV_64FC1);

for (int i = 0; i < height; i++)

{

int*srcdata = src.ptr(i);

float*copydata = copy.ptr(i);

for (int j = 0; j < width; j++)

{

copydata[j] = (float)srcdata[j] / (float)total;//图像每一个像素的的值除以像素总和

}

}

for (int i = 0; i < height; i++)

{

float*srcdata = copy.ptr(i);

for (int j = 0; j < width; j++)

{

Asm += srcdata[j] * srcdata[j]; //能量

if (srcdata[j]>0)

{

Ent -= srcdata[j] * log(srcdata[j]); //熵

}

Con += (float)(i – j)*(float)(i – j)*srcdata[j]; //对比度

Idm += srcdata[j] / (1 + (float)(i – j)*(float)(i – j)); //逆差矩

}

}

}

// 【】融合第一、二步

/*

Mat src_gray;

float data[16] = {0};

*/

void feature_glcm(Mat src_gray,float data[16])

{

Mat dst_0,dst_90,dst_45,dst_135;

getglcm_0(src_gray,dst_0);

float asm_0 = 0,con_0 = 0,ent_0 = 0,idm_0 = 0;

feature_computer(dst_0,asm_0,con_0,ent_0,idm_0);

getglcm_45(src_gray,dst_45);

float asm_45 = 0,con_45 = 0,ent_45 = 0,idm_45 = 0;

feature_computer(dst_45,asm_45,con_45,ent_45,idm_45);

getglcm_90(src_gray,dst_90);

float asm_90 = 0,con_90 = 0,ent_90 = 0,idm_90 = 0;

feature_computer(dst_90,asm_90,con_90,ent_90,idm_90);

getglcm_135(src_gray,dst_135);

float asm_135 = 0,con_135 = 0,ent_135 = 0,idm_135 = 0;

feature_computer(dst_135,asm_135,con_135,ent_135,idm_135);

float AMS[4] = { asm_0,asm_135 };

float COM[4] = { con_0,con_135 };

float ENT[4] = { ent_0,ent_135 };

float IDM[4] = { idm_0,idm_45,idm_90,idm_135 };

float glcm_data[16] = {

asm_0,

con_0,

ent_0,

idm_0,idm_135

};

/*std::cout << "特征数据:" << endl;*/

for (size_t i = 0; i < 16; i++)

{

data[i] = glcm_data[i];

//std::cout << data[i] << " ";

}

}

// 读取当前文件夹图片的个数子程序

/*

cv::String pattern = “./save/*.bmp”;

int cout = read_images_in_folder(pattern);

*/

size_t read_images_in_folder(cv::String pattern)//读取当前指定目录的图片的个数

{

vector fn;

glob(pattern,fn,false);//OpenCV自带一个函数glob()可以遍历文件

size_t count = fn.size(); //number of png files in images folder

return count;

}

// 【】文件检索

/*

string train_img_dir = “C:\Users\Administrator\Desktop\样品\训练”;

string train_img_namehead = “test”;

string train_img_type = “bmp”;

size_t train_img_num = 4;

vector train_img = data_search(train_img_dir,train_img_num);

for (size_t i = 0; i < train_img_num; i++)

{

namedWindow(“vetmat”,train_img[i]);

waitKey(0);

}

*/

vector data_search(string &img_dir,string &img_namehead,string &img_type,size_t n)

{

float train_data[4][16] = { 0 };

vector src;

for (int i = 0; i < n; i++)

{

string pos;

stringstream ss;

ss << i;

ss >> pos;

string img_name = img_dir + “\” + img_namehead + pos + “.” + img_type; //cout << img_name << endl;

Mat outsrc = imread(img_name);

src.push_back(outsrc);

}

return src;

}

private:

};

子函数 

#include

#include

using namespace cv;

using namespace std;

/*遗留问题:两点的确立*/

void Water_Cut(InputArray& src,OutputArray& dst,OutputArray& edge)

{

Mat srcImage;

src.copyTo(srcImage);

//cv::resize(srcImage,srcImage,Size(srcImage.cols / 2,srcImage.rows / 2));

cv::namedWindow(“resImage”,0);

cv::imshow(“resImage”,srcImage);

//waitKey();

// 【mask两点】

//mask的第一点 maskImage

Mat maskImage;

maskImage = Mat(srcImage.size(),CV_8UC1); // 掩模,在上面做标记,然后传给findContours

maskImage = Scalar::all(0);

Point point1(0,0),point2(100,10);

//line(maskImage,point1,point2,Scalar::all(255),5,8,0);

circle(maskImage,10,100);

//mask的第二点 maskImage

Point point3(srcImage.cols / 2,srcImage.rows / 2),point4(srcImage.cols / 2+200,srcImage.rows / 2);

//line(maskImage,point3,point4,100);

/*namedWindow(“resImage”,0);

imshow(“resImage”,maskImage);

waitKey();*/

// 【轮廓】

vector contours;

vector hierarchy;

findContours(maskImage,contours,hierarchy,RETR_CCOMP,CHAIN_APPROX_SIMPLE);

// 【分水岭】

// 参数二:maskWaterShed(CV_32S)

Mat maskWaterShed; // watershed()函数的参数

maskWaterShed = Mat(maskImage.size(),CV_32S);//空白掩码 maskWaterShed

maskWaterShed = Scalar::all(0);

/* 在maskWaterShed上绘制轮廓 */

for (int index = 0; index < contours.size(); index++)

drawContours(maskWaterShed,index,Scalar::all(index + 1),-1,INT_MAX);

/* 如果imshow这个maskWaterShed,我们会发现它是一片黑,原因是在上面我们只给它赋了1,2,3这样的值,通过代码80行的处理我们才能清楚的看出结果 */

// 参数一:srcImage(CV_8UC3)

watershed(srcImage,maskWaterShed); //int index = maskWaterShed.at(row,col);操作

// 【随机生成几种颜色】

vector colorTab;

for (int i = 0; i < contours.size(); i++)

{

int b = theRNG().uniform(0,255);

int g = theRNG().uniform(0,255);

int r = theRNG().uniform(0,255);

colorTab.push_back(Vec3b((uchar)b,(uchar)g,(uchar)r));

}

Mat dst_ = Mat::zeros(maskWaterShed.size(),CV_8UC3);

Mat dst_edge = Mat::zeros(maskWaterShed.size(),CV_8UC3);

int index = maskWaterShed.at(maskWaterShed.rows / 2,maskWaterShed.cols / 2);

int index_temp = 0;

for (int i = 0; i < maskWaterShed.rows; i++)

{

for (int j = 0; j < maskWaterShed.cols; j++)

{

index_temp = maskWaterShed.at(i,j);

//cout << index_temp << endl;

if (index_temp == index)//取中心的标签区域

{

dst_edge.at(i,j) = Vec3b((uchar)255,(uchar)255,(uchar)255); //colorTab[index – 1];

dst_.at(i,j) = srcImage.at(i,j);

}

}

}

cv::namedWindow(“分割结果”,0);

cv::imshow(“分割结果”,dst_);

imwrite(“条纹1.bmp”,dst_);

/*Mat dst_add;

addWeighted(dst_edge,0.3,0.7,dst_add);

namedWindow(“加权结果”,0);

imshow(“加权结果”,dst_add);*/

cv::namedWindow(“连通域”,0);

cv::imshow(“连通域”,dst_edge);

imwrite(“条纹1_.bmp”,dst_edge);

dst_.copyTo(dst);

dst_edge.copyTo(edge);

}