Newer
Older
BleedingDetectionKimura-sanMethod / extravasation_detect.cpp
#include "extravasation_detect.h"
//using namespace cv;
#define MAXW 400
#define MINW 2
#define MINA 600
#define THRESHOLDCENTER 425
#define FAI -999

//骨抽出関連
array3<uchar> Extravasation_detect::Artificial_Segmentation(Raw_image<short>& ct)
{
	auto Artficial = mist::array3<uchar>(ct.data.Width, ct.data.Height, ct.data.Depth, ct.data.reso, ct.data.reso, ct.data.reso, 0);
	auto Artf = mist::array3<uchar>(ct.data.Width, ct.data.Height, ct.data.Depth, ct.data.reso, ct.data.reso, ct.data.reso, 0);
	auto result = mist::array3<uchar>(ct.data.Width, ct.data.Height, ct.data.Depth, ct.data.reso, ct.data.reso, ct.data.reso, 0);
	std::vector<mist::vector3<int>> Points;

	for (int z = 0; z < ct.data.Depth; z++) {
		for (int y = 0; y < ct.data.Height; y++)
			for (int x = 0; x < ct.data.Width; x++) {
				int point = z * ct.data.IMAGESIZE + y * ct.data.Height + x;

				if (ct.image[point] > 600) {
					Artficial[point] = 180;
				}

				if (ct.image[point] > 3500) {
					Artf[point] = 255;
					Points.push_back(mist::vector3<int>(x, y, z));

				}
			}
	}

	mist::region_growing_utility::equal<int> equal(180);
	mist::region_growing_utility::sphere component(1);
	array3<uchar> Artregion;

	auto count = mist::region_growing(Artficial, Artregion, Points, 255, component, equal);

	for (int i = 0; i < ct.data.VOXELS; i++) {
		if (Artregion[i] != 0)
			result[i] = 180;
	}
	return result;
}
int Extravasation_detect::Adaptive_Threshold(Raw_image<short>& ct)
{

	array3<uchar> art = Artificial_Segmentation(ct);

	short* tempCT = new short[ct.data.VOXELS];
	for (int i = 0; i < ct.data.VOXELS; i++) {
		if (art[i] != 0) {
			tempCT[i] = 0;
		}
		else {
			tempCT[i] = ct.image[i];
		}
	}

	array3<short> Upper = array3<short>(ct.data.Width, ct.data.Height, ct.data.Depth, ct.data.reso,
		ct.data.reso, ct.data.reso,
		&tempCT[0], sizeof(short) * ct.data.IMAGESIZE * ct.data.Depth);

	int hist[500];
	for (int i = 0; i < 500; i++)
		hist[i] = 0;

	unsigned long All = 0;

	for (int i = 0; i < Upper.size(); i++) {
		if (Upper[i] > 50) {
			All++;
			if (Upper[i] >= 500) {
				hist[499]++;
			}
			else {
				hist[Upper[i]]++;
			}
		}
	}

	int thre = 499;

	for (int i = thre; i > 50; i--) {
		double bone = 0;
		for (int j = 499; j >= i; j--) {
			bone += hist[j];
		}
		double p = bone * 100 / (double)All;
		if (p > 8.5) {
			thre = i;
			break;
		}
	}

	delete[] tempCT;
	return thre;
}
array3<uchar> Extravasation_detect::Watershed(short* ct, array3<uchar> prebone, int thre)
{
	array3<uchar> Return(prebone.width(), prebone.height(), prebone.depth(), prebone.reso1(), prebone.reso2(), prebone.reso3(), 0);


	for (int slice = 0; slice < prebone.depth(); slice++) {
		cv::Mat image(512, 512, CV_16S, (short*)(ct + slice * 512 * 512));
		cv::Mat image_w;
		cv::Mat image_disp;
		//printf("%d\n",slice);
		cv::Mat front(512, 512, CV_8U, (uchar*)&prebone[slice * 512 * 512]);
		cv::Mat backmarker(512, 512, CV_8U, cv::Scalar::all(255));

		cv::Mat dfront;
		cv::Mat elemental(3, 3, CV_8U, cv::Scalar::all(255));
		morphologyEx(front, dfront, cv::MORPH_DILATE, elemental, cv::Point(-1, -1), 25);
		//imshow("dfront", dfront);
		backmarker = backmarker - dfront;
		cv::Mat Bone = front.clone();
		array2<uchar> thinf(512, 512, prebone.reso1(), prebone.reso2(), (uchar*)front.ptr<uchar>(0), sizeof(uchar) * 512 * 512);
		mist::hilditch::thinning(thinf, thinf);
		uchar* pf = front.ptr<uchar>(0);
		for (int i = 0; i < 512 * 512; i++, pf++) {
			if (thinf[i] != 0) {
				*pf = 255;
			}
			else
				*pf = 0;
		}

		cv::Mat fL = front.clone();

		cv::Mat disp(512, 512, CV_8UC3, cv::Scalar::all(0));
		disp.setTo(cv::Scalar(255, 255, 255), backmarker);

		cv::Mat Marker;
		int Label = cv::connectedComponents(fL, Marker, 8, CV_32S);

		float grad = 255.0 / 300.0;
		float dispg = 255.0 / 400;
		float rg = 255.0 / 600;
		cv::Mat aho;
		image.convertTo(image_w, CV_8U, grad, 127.5 - ((double)thre * grad));
		image.convertTo(image_disp, CV_8U, dispg, 127.5 - (155.0 * dispg));
		image.convertTo(aho, CV_8U, rg, 127.5 - (900.0 * rg));
		cv::GaussianBlur(image_w.clone(), image_w, cv::Size(3, 3), 1.2);

		short* imp = image.ptr<short>(0);
		uchar* imwp = image_w.ptr<uchar>(0);
		for (int i = 0; i < 512 * 512; i++) {
			if (imp[i] <= -2040) {
				imwp[i] = 255;
			}
		}

		cv::Mat Laplacian;
		cv::Laplacian(image_w, Laplacian, CV_8U, 3);
		cv::cvtColor(Laplacian.clone(), Laplacian, cv::COLOR_GRAY2BGR);
		cv::cvtColor(image_w.clone(), image_w, cv::COLOR_GRAY2BGR);

		backmarker.convertTo(backmarker, CV_32S);
		Marker = Marker + backmarker;
		watershed(Laplacian, Marker);

		std::vector<cv::Vec3b> colors;
		colors.push_back(cv::Vec3b(0, 0, 0));
		srand((unsigned int)time(NULL));
		for (int i = 1; i <= Label; i++) {
			colors.push_back(cv::Vec3b(rand() % 255, rand() % 255, rand() % 255));
		}

		cv::Mat DstU(Marker.size(), CV_8U);
		cv::Mat Dst(Marker.size(), CV_8UC3);
		for (int i = 0; i < Dst.rows; ++i) {
			int* lb = Marker.ptr<int>(i);
			cv::Vec3b* pix = Dst.ptr<cv::Vec3b>(i);
			uchar* rix = DstU.ptr<uchar>(i);
			for (int j = 0; j < Dst.cols; ++j) {
				if (lb[j] == 255) {
					rix[j] = 0;
					pix[j] = cv::Vec3b(255, 255, 255);
				}
				else {
					rix[j] = 255;
					pix[j] = colors[lb[j]];
				}
			}
		}

		uchar* Up = DstU.ptr<uchar>(0);

		for (int i = 0; i < 512 * 512; i++, Up++) {
			if (i % 512 == 0 || i < 512 || i > 512 * 511 || i % 512 == 511)
				Return[slice * 512 * 512 + i] = 0;
			else
				Return[slice * 512 * 512 + i] = *Up;
		}

	}

	return Return;
}
array3<uchar>Extravasation_detect::Old_BoneExtractMethod(Raw_image<short>& ct, BODYTYPE type)
{
	short* Bone = new short[ct.data.VOXELS];
	array3<uchar> gets(ct.data.Width, ct.data.Height, ct.data.Depth, ct.data.reso, ct.data.reso, ct.data.reso, 0);
	int exstaract, region;
	if (type == LOWER) {
		exstaract = 350; region = 340;
	}
	else if (type == HEAD) {
		exstaract = 350; region = 340;
	}
	else {
		exstaract = 350; region = 340;
	}


	for (int i = 0; i < ct.data.VOXELS; i++) {
		if (ct.image[i] > exstaract)
			Bone[i] = ct.image[i];
		else
			Bone[i] = 0;

		if (ct.image[i] > region)
			gets[i] = 180;
	}

	array3<uchar> art = Artificial_Segmentation(ct);

	if (type != HEAD) {
		for (int i = 0; i < ct.data.VOXELS; i++) {
			if (art[i] != 0) {
				Bone[i] = 0;
			}
		}
	}

	auto BoneOnly = mist::array3<uchar>(ct.data.Width, ct.data.Height, ct.data.Depth, ct.data.reso, ct.data.reso, ct.data.reso, 0);

#pragma omp parallel for
	for (int i = 0; i < ct.data.VOXELS; i++) {
		if (Bone[i] > 0)
			BoneOnly[i] = 255;
		else
			BoneOnly[i] = 0;
	}

	return BoneOnly;

	auto BoneLabel = mist::array3<unsigned int>(ct.data.Width, ct.data.Height, ct.data.Depth, ct.data.reso, ct.data.reso, ct.data.reso, 0);
	size_t BoneCount = mist::labeling6(BoneOnly, BoneLabel);

	//骨の体積
	std::vector<LabelData> CTV = std::vector<LabelData>(BoneCount + 1);

	int* high = new int[BoneCount + 1];
	int* maxthre = new int[BoneCount + 1];

	for (int i = 0; i < BoneCount + 1; i++) {
		high[i] = 0;
		maxthre[i] = 0;
	}

	for (int slice = 0; slice < ct.data.Depth; slice++)
		for (int j = 50; j < 450; j++)
			for (int x = 0; x < ct.data.Width; x++) {

				//検出結果からラベリングされた領域を発見
				if (BoneLabel[slice * ct.data.IMAGESIZE + j * ct.data.Width + x] != 0) {
					int pointer = slice * ct.data.IMAGESIZE + j * ct.data.Width + x;
					//体積の情報を入手
					CTV[BoneLabel[pointer]].Area++;
					if (CTV[BoneLabel[pointer]].Area == 1) {
						CTV[BoneLabel[pointer]].x = x;
						CTV[BoneLabel[pointer]].y = j;
						CTV[BoneLabel[pointer]].z = slice;
					}

					CTV[BoneLabel[pointer]].CTValue += ct.image[pointer];
					if (ct.image[pointer] > 800)
						high[BoneLabel[pointer]] ++;
					if (ct.image[pointer] > 2200)
						maxthre[BoneLabel[pointer]]++;
				}

			}

	//骨判定
	bool* BoneCheck = new bool[BoneCount + 1];
	std::vector<mist::vector3<int>> Points;
	int bonedetect = 0;

	for (int i = 1; i < BoneCount + 1; i++) {
		BoneCheck[i] = true;

		//判定条件
		if (CTV[i].Area < 10000) {
			//if (high[i] < 1500 || maxthre[i] > 50) {
				//判定条件外のラベルはfalseとしておく
			BoneCheck[i] = false;
			bonedetect++;
			//}
		}
		else {
			Points.push_back(mist::vector3<int>(CTV[i].x, CTV[i].y, CTV[i].z));
			bonedetect++;
		}
	}

	auto BoneDelete = array3<uchar>(ct.data.Width, ct.data.Height, ct.data.Depth, ct.data.reso, ct.data.reso, ct.data.reso, 0);
	auto BoneOut = array3<uchar>(ct.data.Width, ct.data.Height, ct.data.Depth, ct.data.reso, ct.data.reso, ct.data.reso, 0);

#pragma omp parallel for
	for (int i = 0; i < BoneLabel.size(); i++) {
		if (BoneLabel[i] != 0) {
			//bonecheckがfalseの領域は除去
			if (!BoneCheck[BoneLabel[i]]) {
				BoneOut[i] = 0;
				BoneDelete[i] = 1;
			}
			else {
				BoneOut[i] = 255;
				gets[i] = 180;
			}
		}

	}

	if (type == LOWER) {

		for (int slice = 0; slice < ct.data.Depth; slice++) {
			cv::Mat original(ct.data.Height, ct.data.Width, CV_8U, cv::Scalar(0));

			uchar* pm = original.ptr<uchar>(0);
			for (int i = 0; i < ct.data.IMAGESIZE; i++, pm++) {
				if (BoneOut[slice * ct.data.IMAGESIZE + i] != 0)
					*pm = BoneOut[slice * ct.data.IMAGESIZE + i];
			}

			cv::Mat elemental(3, 3, CV_8U, cv::Scalar::all(255));
			morphologyEx(original.clone(), original, cv::MORPH_CLOSE, elemental, cv::Point(-1, -1), 6);
			morphologyEx(original.clone(), original, cv::MORPH_DILATE, elemental, cv::Point(-1, -1), 2);
			morphologyEx(original.clone(), original, cv::MORPH_CLOSE, elemental, cv::Point(-1, -1), 2);

			//外輪郭抽出
			std::vector<std::vector<cv::Point>> contours;
			cv::Mat maskb(ct.data.Height, ct.data.Width, CV_8U, cv::Scalar(0));
			cv::findContours(original, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
			for (int i = 0; i < contours.size(); i++)
				cv::drawContours(maskb, contours, i, cv::Scalar(255), cv::FILLED);

			original = maskb;

			pm = original.ptr<uchar>(0);
			for (int i = 0; i < ct.data.IMAGESIZE; i++, pm++) {
				BoneOut[slice * ct.data.IMAGESIZE + i] = *pm;

				if (ct.image[slice * ct.data.IMAGESIZE + i] > 600 || art[slice * ct.data.IMAGESIZE + i] != 0) {
					BoneOut[slice * ct.data.IMAGESIZE + i] = 255;
				}
			}

		}

		mist::closing(BoneOut, 2, 0);
	}
	if (type == HEAD) {
		mist::region_growing_utility::equal<int> get(180);
		mist::region_growing_utility::sphere component(1);
		array3<uchar> Boneregion;
		mist::region_growing(gets, Boneregion, Points, 140, component, get);
		for (int i = 0; i < ct.data.VOXELS; i++) {
			if (Boneregion[i] == 140)
				BoneOut[i] = 255;
		}


		for (int slice = 0; slice < ct.data.Depth; slice++) {
			cv::Mat original(ct.data.Height, ct.data.Width, CV_8U, cv::Scalar(0));

			uchar* pm = original.ptr<uchar>(0);
			for (int i = 0; i < ct.data.IMAGESIZE; i++, pm++) {
				if (BoneOut[slice * ct.data.IMAGESIZE + i] != 0)
					*pm = BoneOut[slice * ct.data.IMAGESIZE + i];
			}

			cv::Mat elemental(3, 3, CV_8U, cv::Scalar::all(255));
			morphologyEx(original.clone(), original, cv::MORPH_CLOSE, elemental, cv::Point(-1, -1), 5);
			morphologyEx(original.clone(), original, cv::MORPH_DILATE, elemental, cv::Point(-1, -1), 2);

			pm = original.ptr<uchar>(0);
			for (int i = 0; i < ct.data.IMAGESIZE; i++, pm++) {
				BoneOut[slice * ct.data.IMAGESIZE + i] = *pm;

				if (ct.image[slice * ct.data.IMAGESIZE + i] > 600) {
					BoneOut[slice * ct.data.IMAGESIZE + i] = 255;
				}
			}

		}
		//mist::dilation(BoneOut, 2, 0);
	}
	if (type == UPPER) {
		for (int slice = 0; slice < ct.data.Depth; slice++) {
			cv::Mat original(ct.data.Height, ct.data.Width, CV_8U, cv::Scalar(0));

			uchar* pm = original.ptr<uchar>(0);
			for (int i = 0; i < ct.data.IMAGESIZE; i++, pm++) {
				if (BoneOut[slice * ct.data.IMAGESIZE + i] != 0)
					*pm = BoneOut[slice * ct.data.IMAGESIZE + i];
			}

			cv::Mat elemental(3, 3, CV_8U, cv::Scalar::all(255));
			morphologyEx(original.clone(), original, cv::MORPH_CLOSE, elemental, cv::Point(-1, -1), 5);
			morphologyEx(original.clone(), original, cv::MORPH_DILATE, elemental, cv::Point(-1, -1), 2);
			morphologyEx(original.clone(), original, cv::MORPH_CLOSE, elemental, cv::Point(-1, -1), 3);


			//外輪郭抽出
			std::vector<std::vector<cv::Point>> contours;
			cv::Mat maskb(ct.data.Height, ct.data.Width, CV_8U, cv::Scalar(0));
			cv::findContours(original, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
			for (int i = 0; i < contours.size(); i++)
				cv::drawContours(maskb, contours, i, cv::Scalar(255), cv::FILLED);

			original = maskb;

			pm = original.ptr<uchar>(0);
			for (int i = 0; i < ct.data.IMAGESIZE; i++, pm++) {
				BoneOut[slice * ct.data.IMAGESIZE + i] = *pm;

				//if (ct.image[slice * ct.data.IMAGESIZE + i] > 600 || art[slice * ct.data.IMAGESIZE + i] != 0) {
				//	BoneOut[slice * ct.data.IMAGESIZE + i] = 255;
				//}
			}

		}
		mist::closing(BoneOut, 3, 0);
		//mist::closing(BoneOut, 3, 0);
	}

	delete[] maxthre;
	delete[] high;
	delete[] Bone;
	delete[] BoneCheck;
	return(BoneOut);
}
array3<uchar> Extravasation_detect::Bone_Extract(Raw_image<short>& ct, BODYTYPE type, int threshold)
{

	short* Bone = new short[ct.data.VOXELS];
	array3<uchar> gets(ct.data.Width, ct.data.Height, ct.data.Depth, ct.data.reso, ct.data.reso, ct.data.reso, 0);
	int exstaract = threshold;

	for (int i = 0; i < ct.data.VOXELS; i++) {
		if (ct.image[i] > exstaract)
			Bone[i] = ct.image[i];
		else
			Bone[i] = 0;

	}

	array3<uchar> art = Artificial_Segmentation(ct);

	if (type != HEAD) {
		for (int i = 0; i < ct.data.VOXELS; i++) {
			if (art[i] != 0) {
				Bone[i] = 0;
			}
		}
	}

	auto BoneOnly = mist::array3<uchar>(ct.data.Width, ct.data.Height, ct.data.Depth, ct.data.reso, ct.data.reso, ct.data.reso, 0);

#pragma omp parallel for
	for (int i = 0; i < ct.data.VOXELS; i++) {
		if (Bone[i] > 0)
			BoneOnly[i] = 255;
		else
			BoneOnly[i] = 0;
	}

	mist::closing(BoneOnly, 1);

	auto BoneLabel = mist::array3<unsigned int>(ct.data.Width, ct.data.Height, ct.data.Depth, ct.data.reso, ct.data.reso, ct.data.reso, 0);
	size_t BoneCount = mist::labeling6(BoneOnly, BoneLabel);

	//骨の体積
	std::vector<LabelData> CTV = std::vector<LabelData>(BoneCount + 1);


	for (int slice = 0; slice < ct.data.Depth; slice++)
		for (int j = 0; j < ct.data.Height; j++)
			for (int x = 0; x < ct.data.Width; x++) {

				//検出結果からラベリングされた領域を発見
				if (BoneLabel[slice * ct.data.IMAGESIZE + j * ct.data.Width + x] != 0) {
					int pointer = slice * ct.data.IMAGESIZE + j * ct.data.Width + x;
					//体積の情報を入手
					CTV[BoneLabel[pointer]].Area++;
					if (CTV[BoneLabel[pointer]].Area == 1) {
						CTV[BoneLabel[pointer]].x = x;
						CTV[BoneLabel[pointer]].y = j;
						CTV[BoneLabel[pointer]].z = slice;
					}

				}

			}

	//骨判定
	bool* BoneCheck = new bool[BoneCount + 1];
	std::vector<mist::vector3<int>> Points;
	int bonedetect = 0;

	for (int i = 1; i < BoneCount + 1; i++) {
		BoneCheck[i] = true;

		//判定条件
		if (CTV[i].Area < 7000) {
			BoneCheck[i] = false;
			bonedetect++;
		}
		else {
			Points.push_back(mist::vector3<int>(CTV[i].x, CTV[i].y, CTV[i].z));
			bonedetect++;
		}
	}

	auto BoneDelete = array3<uchar>(ct.data.Width, ct.data.Height, ct.data.Depth, ct.data.reso, ct.data.reso, ct.data.reso, 0);
	auto BoneOut = array3<uchar>(ct.data.Width, ct.data.Height, ct.data.Depth, ct.data.reso, ct.data.reso, ct.data.reso, 0);

#pragma omp parallel for
	for (int i = 0; i < BoneLabel.size(); i++) {
		if (BoneLabel[i] != 0) {
			//bonecheckがfalseの領域は除去
			if (!BoneCheck[BoneLabel[i]]) {
				BoneOut[i] = 0;
				BoneDelete[i] = 1;
			}
			else {
				BoneOut[i] = 255;
				gets[i] = 180;
			}
		}

	}

	if (type == LOWER) {

		BoneOut = Watershed(ct.image,BoneOut, threshold);

		for (int slice = 0; slice < ct.data.Depth; slice++) {
			cv::Mat original(ct.data.Height, ct.data.Width, CV_8U, cv::Scalar(0));

			uchar* pm = original.ptr<uchar>(0);
			for (int i = 0; i < ct.data.IMAGESIZE; i++, pm++) {
				if (BoneOut[slice * ct.data.IMAGESIZE + i] != 0)
					*pm = BoneOut[slice * ct.data.IMAGESIZE + i];
			}

			cv::Mat elemental(3, 3, CV_8U, cv::Scalar::all(255));
			//morphologyEx(original.clone(), original, MORPH_CLOSE, elemental, cv::Point(-1, -1), 6);
			//morphologyEx(original.clone(), original, MORPH_DILATE, elemental, cv::Point(-1, -1), 2);
			morphologyEx(original.clone(), original, cv::MORPH_CLOSE, elemental, cv::Point(-1, -1), 2);

			//外輪郭抽出
			std::vector<std::vector<cv::Point>> contours;
			cv::Mat maskb(ct.data.Height, ct.data.Width, CV_8U, cv::Scalar(0));
			cv::findContours(original, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
			for (int i = 0; i < contours.size(); i++)
				cv::drawContours(maskb, contours, i, cv::Scalar(255), cv::FILLED);

			original = maskb;

			pm = original.ptr<uchar>(0);
			for (int i = 0; i < ct.data.IMAGESIZE; i++, pm++) {
				BoneOut[slice * ct.data.IMAGESIZE + i] = *pm;
			}

		}

		mist::closing(BoneOut, 1, 0);
	}
	if (type == HEAD) {
		for (int slice = 0; slice < ct.data.Depth; slice++) {
			cv::Mat original(ct.data.Height, ct.data.Width, CV_8U, cv::Scalar(0));

			uchar* pm = original.ptr<uchar>(0);
			for (int i = 0; i < ct.data.IMAGESIZE; i++, pm++) {
				if (BoneOut[slice * ct.data.IMAGESIZE + i] != 0)
					*pm = BoneOut[slice * ct.data.IMAGESIZE + i];
			}

			cv::Mat elemental(3, 3, CV_8U, cv::Scalar::all(255));
			morphologyEx(original.clone(), original, cv::MORPH_CLOSE, elemental, cv::Point(-1, -1), 2);
			morphologyEx(original.clone(), original, cv::MORPH_DILATE, elemental, cv::Point(-1, -1), 2);

			pm = original.ptr<uchar>(0);
			for (int i = 0; i < ct.data.IMAGESIZE; i++, pm++) {
				BoneOut[slice * ct.data.IMAGESIZE + i] = *pm;

			}

		}
		//mist::dilation(BoneOut, 2, 0);
	}
	if (type == UPPER) {
		BoneOut = Watershed(ct.image, BoneOut, threshold);

		for (int slice = 0; slice < ct.data.Depth; slice++) {
			cv::Mat original(ct.data.Height, ct.data.Width, CV_8U, cv::Scalar(0));

			uchar* pm = original.ptr<uchar>(0);
			for (int i = 0; i < ct.data.IMAGESIZE; i++, pm++) {
				if (BoneOut[slice * ct.data.IMAGESIZE + i] != 0)
					*pm = BoneOut[slice * ct.data.IMAGESIZE + i];
			}

			cv::Mat elemental(3, 3, CV_8U, cv::Scalar::all(255));
			//morphologyEx(original.clone(), original, MORPH_CLOSE, elemental, cv::Point(-1, -1), 5);
			//morphologyEx(original.clone(), original, MORPH_DILATE, elemental, cv::Point(-1, -1), 1);
			morphologyEx(original.clone(), original, cv::MORPH_CLOSE, elemental, cv::Point(-1, -1), 2);


			//外輪郭抽出
			std::vector<std::vector<cv::Point>> contours;
			cv::Mat maskb(ct.data.Height, ct.data.Width, CV_8U, cv::Scalar(0));
			cv::findContours(original, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
			for (int i = 0; i < contours.size(); i++)
				cv::drawContours(maskb, contours, i, cv::Scalar(255), cv::FILLED);

			original = maskb;

			pm = original.ptr<uchar>(0);
			for (int i = 0; i < ct.data.IMAGESIZE; i++, pm++) {
				BoneOut[slice * ct.data.IMAGESIZE + i] = *pm;

				//if (ct[slice * ct.data.IMAGESIZE + i] > 600 || art[slice * ct.data.IMAGESIZE + i] != 0) {
				//	BoneOut[slice * ct.data.IMAGESIZE + i] = 255;
				//}
			}

		}
		mist::closing(BoneOut, 3, 0);

	}

	delete[] Bone;
	delete[] BoneCheck;
	return(BoneOut);
}

//候補領域抽出関連
array3<uchar> Extravasation_detect::double_thresholding(Raw_image<short>& ct, array3<uchar>& bone, BODYTYPE type)
{
	array3<uchar> Return(ct.data.Width, ct.data.Height, ct.data.Depth, ct.data.reso, ct.data.reso, ct.data.reso, 0);

	short* DataL = new short[ct.data.VOXELS];
	short* DataH = new short[ct.data.VOXELS];
	Parameter PL, PH;
	if (type == LOWER) {
		PL = Parameter{ 1000,160,100,15,90,3,2.0,10000 };
		PH = Parameter{ 1000,180,115,30,114,3,5,75000 };		
	}
	else if (type == HEAD) {
		PL = Parameter{ 1000,155,105,20,102,3,2.0,10000 };
		PH = Parameter{ 1000,265,180,30,162,3,5,75000 };		
	}
	else {
		PL = Parameter{ 1000,185,95,20,86,3,2.0,10000 };
		PH = Parameter{ 1000,300,140,30,136,3,5,75000 };		
	}

	for (int i = 0; i < ct.data.VOXELS; i++) {
		DataL[i] = DataH[i] = ct.image[i];
	}

	//CT値調整
	for (int i = 0; i < ct.data.VOXELS; i++) {
		if (DataL[i] > PL.HighCut)
			DataL[i] = 0;


		if (bone[i] != 0)
			DataL[i] = 0;

		if (DataL[i] < -500)
			DataL[i] = -2000;

		if (DataH[i] > PH.HighCut)
			DataH[i] = 0;


		if (bone[i] != 0)
			DataH[i] = 0;

		if (DataH[i] < -500)
			DataH[i] = -2000;
	}

	//候補領域抽出
	array3<uchar> VenoOnlyL = array3<uchar>(ct.data.Width, ct.data.Height, ct.data.Depth, ct.data.reso, ct.data.reso, ct.data.reso);
	array3<uchar> VenoOnlyH = array3<uchar>(ct.data.Width, ct.data.Height, ct.data.Depth, ct.data.reso, ct.data.reso, ct.data.reso);
	array3<uchar> LV = array3<uchar>(ct.data.Width, ct.data.Height, ct.data.Depth, ct.data.reso, ct.data.reso, ct.data.reso);
	array3<uchar> HV = array3<uchar>(ct.data.Width, ct.data.Height, ct.data.Depth, ct.data.reso, ct.data.reso, ct.data.reso);


	//静脈時相格納用のコンテナ
	//静脈のカットオフ
	for (int slice = 0; slice < ct.data.Depth; slice++) {
		cv::Mat blurL(ct.data.Height, ct.data.Width, CV_16S, (short*)(DataL + ct.data.Width * ct.data.Height * slice));
		cv::Mat blurH(ct.data.Height, ct.data.Width, CV_16S, (short*)(DataH + ct.data.Width * ct.data.Height * slice));
		cv::Mat getblurL, getblurH;
		//ガウシアンフィルタ
		GaussianBlur(blurL, getblurL, cv::Size(PL.ExtractKarnel, PL.ExtractKarnel), (float)PL.sigma);
		GaussianBlur(blurH, getblurH, cv::Size(PH.ExtractKarnel, PH.ExtractKarnel), (float)PH.sigma);
		short* p = getblurL.ptr<short>(0);
		short* p2 = getblurH.ptr<short>(0);
		for (int i = 0; i < ct.data.IMAGESIZE; i++, p++, p2++) {

			//座標
			int point = i + slice * ct.data.IMAGESIZE;
			if (*p < PL.CutVeno || bone[point] != 0)
				LV[point] = VenoOnlyL[point] = 0;
			else
				LV[point] = VenoOnlyL[point] = 255;

			if (*p2 < PH.CutVeno || bone[point] != 0)
				HV[point] = VenoOnlyH[point] = 0;
			else
				HV[point] = VenoOnlyH[point] = 255;
		}
	}

	//誤検出除去
	//ラベリング
	array3<unsigned int> VenoLabelL;
	array3<unsigned int> VenoLabelH;
	size_t VenoCountL = mist::labeling6(VenoOnlyL, VenoLabelL);
	size_t VenoCountH = labeling6(VenoOnlyH, VenoLabelH);
	//初期設定
	auto VenoPointL = std::vector<LabelData>(VenoCountL + 1);
	auto VenoPointH = std::vector<LabelData>(VenoCountH + 1);

	VenoPointL[0].Delete = VenoPointH[0].Delete = false;
	VenoPointL[0].Detectcheck = VenoPointH[0].Detectcheck = false;

	for (int i = 0; i < ct.data.Depth; i++)
		for (int j = 20; j < 500; j++)
			for (int x = 0; x < ct.data.Height; x++) {

				//座標
				int point = i * ct.data.IMAGESIZE + j * ct.data.Width + x;
				if (VenoLabelL[point] != 0) {
					VenoPointL[VenoLabelL[point]].Area++;
					VenoPointL[VenoLabelL[point]].CTValue += DataL[point];
					VenoPointL[VenoLabelL[point]].xCount += x;
					VenoPointL[VenoLabelL[point]].yCount += j;
					VenoPointL[VenoLabelL[point]].zCount += i;
					if (VenoPointL[VenoLabelL[point]].minz == 0 || VenoPointL[VenoLabelL[point]].minz > i)
						VenoPointL[VenoLabelL[point]].minz = i;
					if (VenoPointL[VenoLabelL[point]].maxz == 0 || VenoPointL[VenoLabelL[point]].maxz < i)
						VenoPointL[VenoLabelL[point]].maxz = i;
				}
				if (VenoLabelH[point] != 0) {
					VenoPointH[VenoLabelH[point]].Area++;
					VenoPointH[VenoLabelH[point]].CTValue += DataH[point];
					VenoPointH[VenoLabelH[point]].xCount += x;
					VenoPointH[VenoLabelH[point]].yCount += j;
					VenoPointH[VenoLabelH[point]].zCount += i;
					if (VenoPointH[VenoLabelH[point]].minz == 0 || VenoPointH[VenoLabelH[point]].minz > i)
						VenoPointH[VenoLabelH[point]].minz = i;
					if (VenoPointH[VenoLabelH[point]].maxz == 0 || VenoPointH[VenoLabelH[point]].maxz < i)
						VenoPointH[VenoLabelH[point]].maxz = i;
				}
			}

	//判定
	for (int i = 1; i < VenoCountL + 1; i++) {
		//判定条件
		if (VenoPointL[i].Area < PL.MINV || VenoPointL[i].Area > PL.MaxVolume || VenoPointL[i].CTValue / VenoPointL[i].Area > PL.MaxCTValue || VenoPointL[i].CTValue / VenoPointL[i].Area < PL.MinCTValue) {
			VenoPointL[i].Delete = false;
			VenoPointL[i].Detectcheck = false;
		}
	}

	for (int i = 1; i < VenoCountH + 1; i++) {
		//判定条件
		if (VenoPointH[i].Area < PH.MINV || VenoPointH[i].Area > PH.MaxVolume || VenoPointH[i].CTValue / VenoPointH[i].Area > PH.MaxCTValue || VenoPointH[i].CTValue / VenoPointH[i].Area < PH.MinCTValue) {
			VenoPointH[i].Delete = false;
			VenoPointH[i].Detectcheck = false;
		}
	}

	for (int i = 1; i < VenoCountL + 1; i++) {
		if (VenoPointL[i].Delete) {
			VenoPointL[i].x = (int)(VenoPointL[i].xCount / VenoPointL[i].Area);
			VenoPointL[i].y = (int)(VenoPointL[i].yCount / VenoPointL[i].Area);
			VenoPointL[i].z = (int)(VenoPointL[i].zCount / VenoPointL[i].Area);

			int width = VenoPointL[i].maxz - VenoPointL[i].minz;

			if (width == 0) {
				VenoPointL[i].Delete = false;
				VenoPointL[i].Detectcheck = false;
			}
			else {
				int AveArea = VenoPointL[i].Area / width;

				if (VenoPointL[i].y > THRESHOLDCENTER || width > MAXW || width < MINW || AveArea > MINA) {
					VenoPointL[i].Delete = false;
					VenoPointL[i].Detectcheck = false;
				}

				if (width > 120 && AveArea < 80) {
					VenoPointL[i].Delete = false;
					VenoPointL[i].Detectcheck = false;
				}
			}

		}
	}

	for (int i = 1; i < VenoCountH + 1; i++) {
		if (VenoPointH[i].Delete) {
			VenoPointH[i].x = (int)(VenoPointH[i].xCount / VenoPointH[i].Area);
			VenoPointH[i].y = (int)(VenoPointH[i].yCount / VenoPointH[i].Area);
			VenoPointH[i].z = (int)(VenoPointH[i].zCount / VenoPointH[i].Area);

			int width = VenoPointH[i].maxz - VenoPointH[i].minz;

			if (width == 0) {
				VenoPointH[i].Delete = false;
				VenoPointH[i].Detectcheck = false;
			}
			else {
				int AveArea = VenoPointH[i].Area / width;

				if (VenoPointH[i].y > THRESHOLDCENTER || width > MAXW || width < MINW || AveArea > MINA) {
					VenoPointH[i].Delete = false;
					VenoPointH[i].Detectcheck = false;
				}

				if (width > 120 && AveArea < 80) {
					VenoPointH[i].Delete = false;
					VenoPointH[i].Detectcheck = false;
				}
			}

		}
	}

#pragma omp parallel for
	for (int i = 0; i < VenoLabelL.size(); i++) {
		if (VenoLabelL[i] != 0 || VenoLabelH[i] != 0) {
			if (!VenoPointL[VenoLabelL[i]].Delete && !VenoPointH[VenoLabelH[i]].Delete) {
				Return[i] = 0;
			}
			else {
				Return[i] = 255;
			}
		}
		else {
			Return[i] = 0;
		}
	}

	delete[] DataL;
	delete[] DataH;
	return (Return);
}

template<typename Type>
inline array3<float> Extravasation_detect::unshape(array3<Type>& input)
{
	array3<float> CTb, laplace;
	mist::gaussian_filter(input, CTb);
	array3<float> sub(input.width(), input.height(), input.depth(), 0.5, 0.5, 0.5, 0);
	for (int i = 0; i < input.size(); i++) {
		sub[i] = 2 * input[i] - CTb[i];
	}

	return sub;
}
std::vector<mist::vector3<int>> Extravasation_detect::reduction_point(array3<short> ct, std::vector<mist::vector3<int>>& point, float rate)
{
	{
		float max = (float)point.size();
		int hist[600];
		std::vector<mist::vector3<int>> result;
		for (int i = 0; i < 600; i++) hist[i] = 0;

		for (int i = 0; i < max; i++) {
			int p = ct.width() * ct.height() * point[i].z + ct.width() * point[i].y + point[i].x;
			if (ct[p] >= 600) hist[599]++;
			else if (ct[p] < 0) hist[0] ++;
			else hist[ct[p]]++;
		}

		float count = 0;
		int thre;
		for (int i = 599; i > 0; i--) {
			count += hist[i];

			if (count / max > rate) {
				thre = i;
				break;
			}
		}
		printf("peeklimit:%d\n", thre);

		for (int i = 0; i < max; i++) {
			int p = ct.width() * ct.height() * point[i].z + ct.width() * point[i].y + point[i].x;
			if (ct[p] >= thre) {
				result.push_back(point[i]);
			}
		}

		return result;
	}
}
array3<uchar> Extravasation_detect::dencity_vertex(Raw_image<short>& ct, array3<uchar>& bone)
{
	std::vector<int> element;
	for (int z = -1; z < 2; z++)
		for (int y = -1; y < 2; y++)
			for (int x = -1; x < 2; x++)
				element.push_back(z * ct.data.IMAGESIZE + y * ct.data.Width + x);

	array3<short> sub(ct.data.Width, ct.data.Height, ct.data.Depth, ct.data.reso, ct.data.reso, ct.data.reso, ct.image, ct.data.VOXELS);
	auto CT = unshape(sub);
	array3<float> CTb2, CTb, CTba, laplacea, laplaceb;
	mist::gaussian_filter(CT, CTb, 0.5);
	mist::laplacian_filter(sub, laplacea);
	std::vector<mist::vector3<int>> Points;
	float nearlaplace = 0;
	array3<uchar> region(ct.data.Width, ct.data.Height, ct.data.Depth, ct.data.reso, ct.data.reso, ct.data.reso, 0);

	for (int z = 1; z < ct.data.Depth - 1; z++)
		for (int y = 1; y < ct.data.Height - 1; y++)
			for (int x = 1; x < ct.data.Width - 1; x++) {
				int point = z * ct.data.IMAGESIZE + y * ct.data.Width + x;
				if (CTb[point] > 0) {

					bool check = true;

					for (int k = 0; k < 27; k++) {
						if (CTb[point] < CTb[point + element[k]]) {
							check = false;
							break;
						}
					}

					if (check) {

						Points.push_back(mist::vector3<int>(x, y, z));

					}
				}
			}

	//return points;
	auto rpoint = reduction_point(sub, Points, 0.1);

	mist::region_growing_utility::less<float> condi(-50);
	mist::region_growing_utility::sphere component(1);
	mist::region_growing(laplacea, region, rpoint, 255, component, condi);
	laplacea.clear();
	Points.clear();

	array3<unsigned int> label;
	auto count = mist::labeling6(region, label);

	//初期設定
	auto VenoPointL = std::vector<LabelData>(count + 1);

	VenoPointL[0].Delete = false;
	VenoPointL[0].Detectcheck = false;

	for (int i = 0; i < ct.data.Depth; i++)
		for (int j = 0; j < ct.data.Height; j++)
			for (int x = 0; x < ct.data.Width; x++) {

				//座標
				int point = i * ct.data.IMAGESIZE + j * ct.data.Width + x;
				if (label[point] != 0) {
					VenoPointL[label[point]].Area++;
					VenoPointL[label[point]].CTValue += sub[point];
					VenoPointL[label[point]].xCount += x;
					VenoPointL[label[point]].yCount += j;
					VenoPointL[label[point]].zCount += i;

					if (VenoPointL[label[point]].minz == 0 || VenoPointL[label[point]].minz > i)
						VenoPointL[label[point]].minz = i;
					if (VenoPointL[label[point]].maxz == 0 || VenoPointL[label[point]].maxz < i)
						VenoPointL[label[point]].maxz = i;
				}
			}

	//判定
	for (int i = 1; i < count + 1; i++) {
		//判定条件
		if (VenoPointL[i].Area < 20 || VenoPointL[i].Area > 2000 || VenoPointL[i].CTValue / VenoPointL[i].Area < 40) {
			VenoPointL[i].Delete = false;
			VenoPointL[i].Detectcheck = false;
		}
	}

	for (int i = 0; i < ct.data.VOXELS; i++) {
		if (region[i] != 0)
			region[i] = VenoPointL[label[i]].Delete ? region[i] : 0;
	}

	CTb.clear();
	label.clear();

	return region;
}

//評価方法
Extravasation_detect::Result Extravasation_detect::Evaluation(array3<unsigned int>& InputLabel, size_t& VenoCount, 
	array3<uchar>& Mask,int SIZE1, int SIZE2)
{
	array3<unsigned int> MaskLabel;
	size_t TrueCount = mist::labeling6(Mask, MaskLabel);
	auto TruePoint = std::vector<LabelData>(TrueCount + 1);

	struct TrueGET
	{
		float MIND = FAI;
		int VenoNumber = 0;
	};

	std::vector<TrueGET> Get(TrueCount + 1);
	int ImageSize = Mask.width() * Mask.height();
	for (int i = 0; i < Mask.depth(); i++)
		for (int j = 0; j < Mask.height(); j++)
			for (int x = 0; x < Mask.width(); x++) {
				int point = i * ImageSize + j * Mask.width() + x;
				if (MaskLabel[point] != 0) {
					TruePoint[MaskLabel[point]].Area++;
					TruePoint[MaskLabel[point]].xCount += x;
					TruePoint[MaskLabel[point]].yCount += j;
					TruePoint[MaskLabel[point]].zCount += i;
				}
			}

	for (int i = 1; i < TrueCount + 1; i++) {

		if (TruePoint[i].Area < 30) {
			TruePoint[i].Delete = false;
		}

		if (TruePoint[i].Delete) {
			TruePoint[i].x = (int)(TruePoint[i].xCount / TruePoint[i].Area);
			TruePoint[i].y = (int)(TruePoint[i].yCount / TruePoint[i].Area);
			TruePoint[i].z = (int)(TruePoint[i].zCount / TruePoint[i].Area);
		}
	}

	Result Return;
	auto VenoPoint = std::vector<LabelData>(VenoCount + 1);

	for (int i = 0; i < VenoCount + 1; i++) {
		VenoPoint[i].Delete = VenoPoint[i].Detectcheck = false;
	}

	for (int i = 0; i < Mask.depth(); i++)
		for (int j = 0; j < Mask.height(); j++)
			for (int x = 0; x < Mask.width(); x++) {
				int point = i * ImageSize + j * Mask.width() + x;
				if (InputLabel[point] != 0) {
					VenoPoint[InputLabel[point]].Area++;
					VenoPoint[InputLabel[point]].xCount += x;
					VenoPoint[InputLabel[point]].yCount += j;
					VenoPoint[InputLabel[point]].zCount += i;

					if (MaskLabel[point] != 0) {
						VenoPoint[InputLabel[point]].Delete = true;
						VenoPoint[InputLabel[point]].Detectcheck = true;
					}
				}
			}

	int dcount = 0;

	for (int i = 1; i < VenoCount + 1; i++) {
		VenoPoint[i].x = (int)(VenoPoint[i].xCount / VenoPoint[i].Area);
		VenoPoint[i].y = (int)(VenoPoint[i].yCount / VenoPoint[i].Area);
		VenoPoint[i].z = (int)(VenoPoint[i].zCount / VenoPoint[i].Area);
		if (VenoPoint[i].Detectcheck)
			dcount++;
	}
	printf("candi:%d\n", dcount);


	for (int i = 1; i < VenoCount + 1; i++) {
		bool TPcheck = false;
		for (int j = 1; j < TrueCount + 1; j++) {

			if (VenoPoint[i].Detectcheck) {
				float dx = (TruePoint[j].x - VenoPoint[i].x) * Mask.reso1();
				float dy = (TruePoint[j].y - VenoPoint[i].y) * Mask.reso1();
				float dz = (TruePoint[j].z - VenoPoint[i].z) * Mask.reso1();

				//距離チェック,正解領域との重心間距離を調べる
				if (TruePoint[j].Delete)
					if (sqrt(pow(dx, 2) + pow(dy, 2) + pow(dz, 2)) < 7.5) {
						if (Get[j].MIND == FAI) {
							TPcheck = true;
							TruePoint[j].Detectcheck = false;
							Get[j].VenoNumber = i;
							Get[j].MIND = (float)sqrt(pow(dx, 2) + pow(dy, 2) + pow(dz, 2));
						}
						else if (Get[j].MIND > sqrt(pow(dx, 2) + pow(dy, 2) + pow(dz, 2))) {
							Get[j].MIND = (float)sqrt(pow(dx, 2) + pow(dy, 2) + pow(dz, 2));
							Get[j].VenoNumber = i;
						}
					}
			}
		}
	}

	for (int i = 1; i < VenoCount + 1; i++) {
		if (VenoPoint[i].Detectcheck) {
			bool TPcheck = false;
			for (int j = 1; j < TrueCount + 1; j++) {
				if (!TruePoint[j].Detectcheck) {
					if (i == Get[j].VenoNumber)
						TPcheck = true;
				}
			}

			//どの正解ラベルとも近くない場合,FPに追加
			if (!TPcheck) {
				Return.FP++;
				VenoPoint[i].Detectcheck = false;
				if (VenoPoint[i].z < SIZE1) {
					Return.HFP++;
				}
				else if (VenoPoint[i].z < SIZE2) {
					Return.UFP++;
				}
				else {
					Return.LFP++;
				}

			}
		}
		else {
			Return.FP++;
			if (VenoPoint[i].z < SIZE1) {
				Return.HFP++;
			}
			else if (VenoPoint[i].z < SIZE2) {
				Return.UFP++;
			}
			else {
				Return.LFP++;
			}
		}
	}

	for (int i = 0; i < ImageSize * Mask.depth(); i++) {

	}

	for (int i = 1; i < VenoCount + 1; i++)
		if (VenoPoint[i].Detectcheck) {
			Return.TP++;
		}


	for (int i = 1; i < TrueCount + 1; i++) {
		if (TruePoint[i].Delete) {
			Return.OriginalP++;
			if (TruePoint[i].z < SIZE1) {
				Return.HEADP++;
			}
			else if (TruePoint[i].z < SIZE2) {
				Return.UPPERP++;
			}
			else {
				Return.LOWERP++;
			}

			if (TruePoint[i].Detectcheck) {
				Return.MissCount++;
				if (TruePoint[i].z < SIZE1) {
					Return.MissH++;
				}
				else if (TruePoint[i].z < SIZE2) {
					Return.MissU++;
				}
				else {
					Return.MissL++;
				}
			}
		}
	}

	Return.region = (int)VenoCount;

	//結果の出力
	Return.Evalu_Array = array3<uchar>(Mask.width(), Mask.height(), Mask.depth(), Mask.reso1(), Mask.reso1(), Mask.reso1(), 0);

#pragma omp parallel for
	for (int i = 0; i < InputLabel.size(); i++) {
		if (InputLabel[i] != 0) {
			if (!VenoPoint[InputLabel[i]].Detectcheck)
				Return.Evalu_Array[i] = 255; //FP
			else
				Return.Evalu_Array[i] = 140; //TP

		}

		if (MaskLabel[i] != 0)
			if (TruePoint[MaskLabel[i]].Delete && TruePoint[MaskLabel[i]].Detectcheck) {
				Return.Evalu_Array[i] = 0; //FN
			}
	}

	return(Return);
}

//分割した画像を人つなぎに戻す
array3<uchar> Extravasation_detect::ArrayLink(array3<uchar>& FirstArray, array3<uchar>& SecondArray)
{
	array3<uchar> Return(FirstArray.width(), FirstArray.height(), FirstArray.depth() + SecondArray.depth(), 0.5, 0.5, 0.5, 0);

	int VOXELS = (int)(FirstArray.width() * FirstArray.height() * (FirstArray.depth() + SecondArray.depth()));

	for (int i = 0; i < VOXELS; i++) {
		if (i < FirstArray.size()) {
			Return[i] = FirstArray[i];
		}
		else {
			Return[i] = SecondArray[i - FirstArray.size()];
		}
	}
	return(Return);
}

//結果の表示
void Extravasation_detect::Result::ToString(int casenum)
{
	if (casenum != 0) {
		printf("症例:%d総検出数:%d正解領域の数:%dTP:%dFP:%d頭部:%d胴体:%d下半身:%d未検出領域:%d頭部:%d胴体:%d下半身:%d\n", casenum,
			region, OriginalP, TP, FP, HFP, UFP, LFP, MissCount, MissH, MissU, MissL);
	}
	else {
		printf("総検出数:%d正解領域の数:%dTP:%dFP:%d頭部:%d胴体:%d下半身:%d未検出領域:%d頭部:%d胴体:%d下半身:%d\n",
			region, OriginalP, TP, FP, HFP, UFP, LFP, MissCount, MissH, MissU, MissL);
	}
}