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 版權聲明:本文為博主原創文章,轉載請附上博文鏈接!