from:https://blog.csdn.net/akadiao/article/details/79278072
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/akadiao/article/details/79278072
问题描述:
现对6种不同颜色药品(胶囊)分别进行图像采集,并进行类别标注(0-5)。如图所示(文末附有图像源文件链接):
现使用胶囊的RGB通道的均值作为特征,利用SVM建立分类器模型并进行训练,然后利用训练好的模型,在多个样本混合的图像中将各类样本标记出位置并识别出其所属类别。
具体详细处理过程见代码及注释。
示例代码:
#include <iostream>
#include<opencv2/opencv.hpp>
#include<opencv2/ml.hpp>
using namespace cv;
using namespace ml;void findSamplecontours(InputArray src, OutputArrayOfArrays contours);//使用SVM进行胶囊分类
int main()
{ //样本总类别数const int classSum = 6;//每个样本选取的特征个数const int featureSum = 3;//训练样本总数const int sampleSum = 57;//每种类别对应的名称const std::string labelName[6] = {"green_peru", "brown", "darkcyan", "black", "white_brown", "saddlebrown"};//训练数据及标签Mat trainDataMat = Mat::zeros(sampleSum, featureSum, CV_32FC1);Mat labelsMat = Mat::zeros(sampleSum, 1, CV_32SC1);int k = 0;========================创建训练数据==================================for (int label = 0; label < classSum; label++){//训练图像所在文件夹std::string path = "E:/image/image/classification/capsule/pills_class_";char temp[256];sprintf_s(temp, "%d", label);path = path + temp + ".png";Mat src = imread(path);if (src.empty()){std::cout<<"can not load image. \n"<<std::endl;return -1;}//imshow("input", src);//获取每个胶囊的轮廓std::vector<std::vector<Point>>contours;findSamplecontours(src, contours);for(int i = 0; i < contours.size(); i++){if(contourArea(contours[i]) > 50){//建立掩模MASKMat mask = Mat::zeros(src.size(), src.type());drawContours(mask, contours, i, Scalar(255, 255, 255), -1);//获得MASK对应区域的图像src.copyTo(mask,mask);//求各个通道的均值Scalar maskSum = sum(mask);maskSum = maskSum/contourArea(contours[i]);//取前三个通道即BGR通道的均值作为特征for (int j = 0; j < featureSum; j++){trainDataMat.at<float>(k,j) = maskSum[j];}labelsMat.at<int>(k,0) = label;k++;}}}std::cout<<"trainDataMat: \n"<<trainDataMat<<"\n"<<std::endl;std::cout<<"labelsMat: \n"<<labelsMat<<"\n"<<std::endl;========================使用SVM训练部分==================================Ptr<SVM> model = SVM::create(); model->setType(SVM::C_SVC); model->setKernel(SVM::POLY);model->setDegree(1.0);model->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER,100,1e-6)); model->train(trainDataMat,ROW_SAMPLE,labelsMat); ========================测试部分==================================Mat testImg = imread("E:/image/image/classification/capsule/pills_test.png");if (testImg.empty()){std::cout<<"can not load image. \n"<<std::endl;return -1;}std::vector<std::vector<Point>>testContours;findSamplecontours(testImg, testContours);//对测试图像中的样本进行逐个判断for(int i = 0; i < testContours.size(); i++){if(contourArea(testContours[i]) > 50){Mat testDataMat = Mat::zeros(1, featureSum, CV_32FC1);Mat testLabelsMat;Mat testMask = Mat::zeros(testImg.size(), testImg.type());drawContours(testMask, testContours, i, Scalar(255, 255, 255), -1);testImg.copyTo(testMask,testMask);//求各个通道的均值Scalar testMaskSum = sum(testMask);testMaskSum = testMaskSum/contourArea(testContours[i]);//取前三个通道即BGR通道的均值作为特征for (int j = 0; j < featureSum; j++){testDataMat.at<float>(0,j) = testMaskSum[j];}//使用训练好的SVM模型进行预测model->predict(testDataMat, testLabelsMat);//预测结果int testLabel = testLabelsMat.at<float>(0,0);std::cout <<"testLabel:\n"<<labelName[testLabel]<<std::endl;//在测试图像上绘制出预测结果RotatedRect minRect = minAreaRect(testContours[i]); //使用对应颜色的矩形框将样本框选中rectangle(testImg, minRect.boundingRect(),testMaskSum,2,8);putText(testImg, labelName[testLabel],Point(minRect.boundingRect().x,minRect.boundingRect().y),1, 1.5,Scalar(0,255,0),2);imshow("test image", testImg);waitKey(2000);}}waitKey();return 0;
} void findSamplecontours(InputArray src, OutputArrayOfArrays contours)
{Mat dst,blueChannels, redChannels;std::vector<Mat>channels;//将原图像分成多个单通道图像split(src, channels);blueChannels = channels.at(0);redChannels = channels.at(2);//分别在R通道和B通道使用不同的阈值进行二值化threshold(redChannels, redChannels, 60, 255, THRESH_BINARY_INV);threshold(blueChannels, blueChannels, 100, 255, THRESH_BINARY_INV);//合并两个二值化后的区域add(blueChannels,redChannels, dst);//对获得区域进行闭操作,去除中心的小孔Mat kernel = getStructuringElement(MORPH_RECT, Size(5,5), Point(-1,-1));morphologyEx(dst,dst,CV_MOP_CLOSE,kernel);//腐蚀操作,去除部分过渡边缘Mat kernel2 = getStructuringElement(MORPH_RECT, Size(5,5), Point(-1,-1));erode(dst, dst,kernel2);//imshow("00", dst);//waitKey();Canny(dst, dst, 20, 100, 3, false);std::vector<Vec4i>hierarchy;//获取轮廓findContours(dst, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0,0));
}
识别结果:
训练数据、标签及测试样本标签:
相关链接:
图片及代码下载
--------------------- 作者:阿卡蒂奥 来源:CSDN 原文:https://blog.csdn.net/akadiao/article/details/79278072?utm_source=copy 版权声明:本文为博主原创文章,转载请附上博文链接!