1. 程式人生 > >C++ Opencv——影象特徵——Hu、Mom、Glcm

C++ Opencv——影象特徵——Hu、Mom、Glcm

/*
	第一步:建立類
	#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;
	}