Newer
Older
CasicIrisIdentify / casic / iris / CasicSegPostProcess.cpp
tanyue on 16 Dec 2023 9 KB 20231216 debug on ubuntu arm
#include "CasicSegPostProcess.h"

#include <math.h>
#include <QDateTime>
#include <QString>
#include "utils/LogUtil.h"

namespace iristrt
{

std::vector<cv::Mat> CasicSegPostProcess::getConnections(cv::Mat input, int connectivity) {
	cv::Mat output;
    int nLabels = cv::connectedComponents(input, output, connectivity);
	output.convertTo(output, CV_8UC1, 1);

	std::vector<cv::Mat> conns;
	for (int i = 1; i <= nLabels; i++) {
		cv::Mat dst = cv::Mat::zeros(output.size(), output.type());
		for (int row = 0; row < output.rows; row++) {
			for (int col = 0; col < output.cols; col++) {
				uchar label = output.at<uchar>(row, col);
				if (label == i) {
					dst.at<uchar>(row, col) = 255;
				}
			}
		}
		conns.push_back(dst);
	}
	return conns;
}

void CasicSegPostProcess::showConnections(std::vector<cv::Mat> conns) {
	for (int i = 0; i < conns.size(); i++) {
		cv::imshow("con", conns[i]);
		cv::waitKey(0);
	}
	cv::destroyAllWindows();
}

std::vector<CasicTriplet>  CasicSegPostProcess::getTripleSet(std::vector<cv::Mat> maskConns,
															std::vector<cv::Mat> irisConns, 
															std::vector<cv::Mat> pupilConns,
															int chessboardDistance) {
    std::vector<CasicTriplet> triplet_set;
    for (auto maskConn : maskConns) {
        for (auto irisConn : irisConns) {
			int maskIrisDis = getChessboardDistance(maskConn, irisConn, chessboardDistance);
            for (auto pupilConn : pupilConns) {
				int maskPupilDis = getChessboardDistance(maskConn, pupilConn, chessboardDistance);
				if (maskIrisDis <= chessboardDistance && maskPupilDis <= chessboardDistance) {
                    CasicTriplet triplet;
                    triplet.maskConn = maskConn;
                    triplet.irisConn = irisConn;
                    triplet.pupilConn = pupilConn;
					triplet_set.push_back(triplet);
				}
			}
		}
	}
	return triplet_set;
}

void CasicSegPostProcess::showTriple(CasicTriplet triple) {
	/*cv::Mat tripleImage;
	cv::add(std::get<0>(triple), std::get<1>(triple), tripleImage);
	cv::add(std::get<2>(triple), tripleImage, tripleImage);
	cv::imshow("tripleImage", tripleImage);
	cv::waitKey(0);*/

    cv::Mat mask = triple.maskConn;
    cv::Mat iris = triple.irisConn;
    cv::Mat pupil = triple.pupilConn;

	cv::imshow("triple-mask", mask);
	cv::waitKey(0);

	cv::imshow("triple-iris", iris);
	cv::waitKey(0);

	cv::imshow("triple-pupil", pupil);
	cv::waitKey(0);
}

int CasicSegPostProcess::getChessboardDistance(cv::Mat con1, cv::Mat con2, int chessboardDistance) {
	// mask contours
	std::vector<std::vector<cv::Point>> c1;
    cv::findContours(con1, c1,cv:: RETR_TREE, cv::CHAIN_APPROX_SIMPLE, cv::Point());
	//cout << "c1.size() " << c1.size() << endl;
	std::vector<cv::Point> c1All;
	for (auto c : c1) {
		//cout << "c.size()" << c.size() << endl;
		c1All.insert(c1All.end(), c.begin(), c.end());
	}
	//cout << "c1All.size()	" << c1All.size() << endl;

	// other contours
	std::vector<std::vector<cv::Point>> c2;
    cv::findContours(con2, c2, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE, cv::Point());
	//cout << "c2.size() " << c2.size() << endl;
	std::vector<cv::Point> c2All;
	for (auto c : c2) {
		//cout << "c.size()" << c.size() << endl;
		c2All.insert(c2All.end(), c.begin(), c.end());
	}
	//cout << "c2All.size()	" << c2All.size() << endl;

	int distance = 1000;
	for (auto p1 : c1All) {
		for (auto p2 : c2All) {
			int tempDistance = std::max(abs(p1.x - p2.x), abs(p1.y - p2.y));
			if (tempDistance < distance) {
				distance = tempDistance;
			}
			if (distance <= chessboardDistance) {
				break;
			}
		}
	}
	return distance;


}

CasicTriplet CasicSegPostProcess::getMaxTriple(std::vector<CasicTriplet> tripleSet) {
	long maxCount = 0;
	int maxIndex = -1;
	for (int i = 0; i < tripleSet.size(); i++) {
        CasicTriplet triplet = tripleSet[i];
        long count = cv::countNonZero(triplet.maskConn)
            + cv::countNonZero(triplet.irisConn)
            + cv::countNonZero(triplet.pupilConn);
		if (count > maxCount) {
			maxCount = count;
			maxIndex = i;
		}
	}
	return tripleSet[maxIndex];
}

std::vector<int> CasicSegPostProcess::leastSquareCircleFitting(std::vector<cv::Point> counter) {

	std::vector<int> result;
	int center_x, center_y, radius = 0;

	if (counter.size() < 3) {
		result.push_back(center_x);
		result.push_back(center_y);
		result.push_back(radius);
		return result;
	}

	double sum_x, sum_y = 0.0;
	double sum_x2, sum_y2 = 0.0;
	double sum_x3, sum_y3 = 0.0;
	double sum_xy, sum_x1y2, sum_x2y1 = 0.0;

	for (auto point : counter) {
		double x = (double)point.x;
		double y = (double)point.y;
		double x2 = x * x;
		double y2 = y * y;
		sum_x += x;
		sum_y += y;
		sum_x2 += x2;
		sum_y2 += y2;
		sum_x3 += x2 * x;
		sum_y3 += y2 * y;
		sum_xy += x * y;
		sum_x1y2 += x * y2;
		sum_x2y1 += x2 * y;
	}

	double N = counter.size();
	double	C = N * sum_x2 - sum_x * sum_x;
	double	D = N * sum_xy - sum_x * sum_y;
	double	E = N * sum_x3 + N * sum_x1y2 - (sum_x2 + sum_y2) * sum_x;
	double	G = N * sum_y2 - sum_y * sum_y;
	double	H = N * sum_x2y1 + N * sum_y3 - (sum_x2 + sum_y2) * sum_y;
	double	a = (H * D - E * G) / (C * G - D * D);
	double	b = (H * C - E * D) / (D * D - G * C);
	double	c = -(a * sum_x + b * sum_y + sum_x2 + sum_y2) / N;

	center_x = (int)(a / (-2));
	center_y = (int)(b / (-2));
	radius = (int)(sqrt(a * a + b * b - 4 * c) / 2);

	result.push_back(center_x);
	result.push_back(center_y);
	result.push_back(radius);
	return result;
}

bool CasicSegPostProcess::postProcess(cv::Mat & mask, cv::Mat & iris, cv::Mat & pupil, std::vector<int> & irisCircle, std::vector<int> & pupilCircle) {
	int chessboard_distance = 15;

	// cv::Mat mask,iris,pupil;
    mask.convertTo(mask, CV_8UC1);
    iris.convertTo(iris, CV_8UC1);
    pupil.convertTo(pupil, CV_8UC1);

    cv::threshold(mask, mask, 127, 255, cv::THRESH_BINARY);
    cv::threshold(iris, iris, 90, 255, cv::THRESH_BINARY);
    cv::threshold(pupil, pupil, 0, 255, cv::THRESH_BINARY + cv::THRESH_OTSU);

    cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5));
    cv::morphologyEx(iris, iris, cv::MORPH_CLOSE, element);
/*
    std::string pupilSeg = QString("%1/%2/%3-pupil-thre.bmp").arg("/home/casic/irisLogs").arg(QDate::currentDate().toString("yyyyMMdd")).arg(QTime::currentTime().toString("HHmmss")).toStdString();
    std::string maskSeg = QString("%1/%2/%3-mask-thre.bmp").arg("/home/casic/irisLogs").arg(QDate::currentDate().toString("yyyyMMdd")).arg(QTime::currentTime().toString("HHmmss")).toStdString();
    std::string irisSeg = QString("%1/%2/%3-iris-thre.bmp").arg("/home/casic/irisLogs").arg(QDate::currentDate().toString("yyyyMMdd")).arg(QTime::currentTime().toString("HHmmss")).toStdString();
    cv::imwrite(pupilSeg, pupil);
    cv::imwrite(maskSeg, mask);
    cv::imwrite(irisSeg, iris);
*/
//    cv::imshow("mask",mask);
//    cv::imshow("iris",iris);
//    cv::imshow("pupil",pupil);
//    cv::waitKey(0);

//    std::cout << "get connection ..."  << std::endl;
	
	std::vector<cv::Mat> maskCons = getConnections(mask, 8);
	std::vector<cv::Mat> irisCons = getConnections(iris, 8);
	std::vector<cv::Mat> pupilCons = getConnections(pupil, 8);

	if(maskCons.size() <= 0 || irisCons.size() <= 0 || pupilCons.size() <= 0)
	{
		return false;
	}

//    std::cout << "get triple set ..."  << std::endl;

    std::vector<CasicTriplet> tripleSet = getTripleSet(maskCons, irisCons, pupilCons, chessboard_distance);

	if (tripleSet.size() < 1) {
		return false;
	}

//    std::cout << "get max triple ..." << std::endl;

    CasicTriplet maxTriple = getMaxTriple(tripleSet);
	//showTriple(maxTriple);

//    std::cout << "least Square Circle Fitting ..."  << std::endl;

    cv::Mat bestIris = maxTriple.irisConn;
	std::vector<cv::Point> outPoints;
    cv::findNonZero(bestIris, outPoints);
	irisCircle = leastSquareCircleFitting(outPoints);
	int iris_x = irisCircle[0];
	int	iris_y = irisCircle[1];
	int	iris_r = irisCircle[2];

//    LOG_INFO(QString("outPoints size: %1").arg(outPoints.size()).toStdString());

    cv::Mat bestPupil = maxTriple.pupilConn;
	std::vector<std::vector<cv::Point>> innerCounter;
    cv::findContours(bestPupil, innerCounter, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
	std::vector<cv::Point> innerPoints;

//    LOG_INFO(QString("innerPoints size: %1, %2").arg(innerPoints.size()).arg(innerCounter.size()).toStdString());

    for (auto c : innerCounter) {
		innerPoints.insert(innerPoints.end(), c.begin(), c.end());
//        LOG_INFO(QString("innerPoints: %1, %2, %3, %4").arg(c.begin()->x).arg(c.begin()->y).arg(c.end()->x).arg(c.end()->y).toStdString());
	}
	pupilCircle = leastSquareCircleFitting(innerPoints);
	int pupil_x = pupilCircle[0];
	int pupil_y = pupilCircle[1];
	int	pupil_r = pupilCircle[2];

//    LOG_INFO(QString("innerPoints size: %1").arg(innerPoints.size()).toStdString());
/*
    std::string pupilbest = QString("%1/%2/%3-pupil-best.bmp").arg("/home/casic/irisLogs").arg(QDate::currentDate().toString("yyyyMMdd")).arg(QTime::currentTime().toString("HHmmss")).toStdString();
    std::string irisbest = QString("%1/%2/%3-iris-best.bmp").arg("/home/casic/irisLogs").arg(QDate::currentDate().toString("yyyyMMdd")).arg(QTime::currentTime().toString("HHmmss")).toStdString();
    cv::imwrite(pupilbest, bestPupil);
    cv::imwrite(irisbest, bestIris);
*/
//    std::cout << "iris: " << iris_x << " " << iris_y << " " << iris_r << std::endl;
//    std::cout << "pupil:" << pupil_x << " " << pupil_y << " " << pupil_r << std::endl;
//    LOG_INFO(QString("iris: %1, %2, %3").arg(iris_x).arg(iris_y).arg(iris_r).toStdString());
//    LOG_INFO(QString("pupil: %1, %2, %3").arg(pupil_x).arg(pupil_y).arg(pupil_r).toStdString());

//    std::cout << "bitwise_and ..."  << std::endl;

	cv::Mat circleMask = cv::Mat::zeros(mask.size(), CV_8UC1);
    cv::circle(circleMask,cv::Point(iris_x, iris_y), iris_r, 255, -1);
    cv::circle(circleMask,cv::Point(pupil_x, pupil_y), pupil_r, 0, -1);
	cv::bitwise_and(mask, circleMask, mask);

	return true;
}

} // end of namespace iristrt