C++ Opencv——影象特徵——Hu、Mom、Glcm
阿新 • • 發佈:2018-12-21
/* 第一步:建立類 #include <opencv2/opencv.hpp> #include <iostream> #include <vector> #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, 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); 第四步: // 特徵集合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<uchar>(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, img.cols, CV_8U); Mat g(img.rows, img.cols, 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<double>(0, 0); Mom[3] = tmp_sd.at<double>(0, 0); Mom[6] = calc3orderMom(b); // cout << Mom[0] << " " << Mom[1] << " " << Mom[2] << " " << endl; //計算g通道的顏色矩 meanStdDev(g, tmp_m, tmp_sd); Mom[1] = tmp_m.at<double>(0, 0); Mom[4] = tmp_sd.at<double>(0, 0); Mom[7] = calc3orderMom(g); // cout << Mom[3] << " " << Mom[4] << " " << Mom[5] << " " << endl; //計算r通道的顏色矩 meanStdDev(r, tmp_m, tmp_sd); Mom[2] = tmp_m.at<double>(0, 0); Mom[5] = tmp_sd.at<double>(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, hu_dst, 0, 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_dst, 0, 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 { return false; } } // 紋理 const int gray_level = 16;//紋理區域塊的大小,通常將影象劃分成若干個紋理塊計算 vector<double> 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<int>(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<int>(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<int>(i); for (int j = 0; j < width - 1; j++) { int rows = srcdata[j]; int cols = srcdata[j + 1]; dst.ptr<int>(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<int>(i); for (int j = 0; j < width - 1; j++) { int rows = srcdata[j]; int cols = srcdata[j + 1]; dst.ptr<int>(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<int>(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<int>(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 - 1; i++) { int*srcdata = src.ptr<int>(i); int*srcdata1 = src.ptr<int>(i + 1); for (int j = 0; j < width - 1; j++) { int rows = srcdata[j]; int cols = srcdata1[j + 1]; dst.ptr<int>(rows)[cols]++; } } } else { dst.create(max_gray_level, max_gray_level, CV_32SC1); dst = Scalar::all(0); for (int i = 0; i < height - 1; i++) { int*srcdata = src.ptr<int>(i); int*srcdata1 = src.ptr<int>(i + 1); for (int j = 0; j < width - 1; j++) { int rows = srcdata[j]; int cols = srcdata1[j + 1]; dst.ptr<int>(rows)[cols]++; } } } } void getglcm_90(Mat& input, Mat& dst)//90度灰度共生矩陣 { 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<int>(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<int>(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 - 1; i++) { int*srcdata = src.ptr<int>(i); int*srcdata1 = src.ptr<int>(i + 1); for (int j = 0; j < width; j++) { int rows = srcdata[j]; int cols = srcdata1[j]; dst.ptr<int>(rows)[cols]++; } } } else { dst.create(max_gray_level, max_gray_level, CV_32SC1); dst = Scalar::all(0); for (int i = 0; i < height - 1; i++) { int*srcdata = src.ptr<int>(i); int*srcdata1 = src.ptr<int>(i + 1); for (int j = 0; j < width; j++) { int rows = srcdata[j]; int cols = srcdata1[j]; dst.ptr<int>(rows)[cols]++; } } } } void getglcm_135(Mat& input, Mat& dst)//135度灰度共生矩陣 { 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<int>(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<int>(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 - 1; i++) { int*srcdata = src.ptr<int>(i); int*srcdata1 = src.ptr<int>(i + 1); for (int j = 1; j < width; j++) { int rows = srcdata[j]; int cols = srcdata1[j - 1]; dst.ptr<int>(rows)[cols]++; } } } else { dst.create(max_gray_level, max_gray_level, CV_32SC1); dst = Scalar::all(0); for (int i = 0; i < height - 1; i++) { int*srcdata = src.ptr<int>(i); int*srcdata1 = src.ptr<int>(i + 1); for (int j = 1; j < width; j++) { int rows = srcdata[j]; int cols = srcdata1[j - 1]; dst.ptr<int>(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<int>(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<int>(i); float*copydata = copy.ptr<float>(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<float>(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_45, asm_90, asm_135 }; float COM[4] = { con_0, con_45, con_90, con_135 }; float ENT[4] = { ent_0, ent_45, ent_90, ent_135 }; float IDM[4] = { idm_0, idm_45, idm_90, idm_135 }; float glcm_data[16] = { asm_0, asm_45, asm_90, asm_135, con_0, con_45, con_90, con_135, ent_0, ent_45, ent_90, ent_135, idm_0, idm_45, idm_90, 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<cv::String> fn; glob(pattern, fn, false);//OpenCV自帶一個函式glob()可以遍歷檔案 size_t count = fn.size(); //number of png files in images folder return count; }