houghiris.cpp

来自「barcode readers [ from Image]」· C++ 代码 · 共 239 行

CPP
239
字号
//
// HoughIris -- Iris detection using Hough transform.
//
// Copyright (C) 2003, 2006 by Jon A. Webb (Contact via GMail; username is jonawebb)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

#include "HoughIris.h"

#include "BoxSmooth.h"
#include "HistMod.h"
#include "HoughCircle.h"
#include "HysterisisThreshold.h"
#include "Image.h"
#include "RgbAvg2Gray.h"
#include "RgbMin2Gray.h"
#include "Reduce.h"
#include "Sequence.h"
#include "Sobel.h"
#include "Threshold.h"

#include <coecntrl.h>
#include <coemain.h>

using namespace Core;

namespace Algorithm
{

	EXPORT_C CHoughIris* CHoughIris::NewL()
	{	
		return new (ELeave) CHoughIris();	
	}

	CHoughIris::~CHoughIris()
	{
	}

	CHoughIris::CHoughIris() 
	{
	}

	//
	// The pipeline begins by discarding 
	// color information from the input image, converting it to a gray image by averaging the RGB values. 
	// The next step is to reduce the image size horizontally and vertically, in order 
	// to speed up processing time in later steps. The histogram of the image is then stretched to increase 
	// the contrast in the dark areas of the image and reduce the contrast in the light areas. The result 
	// is then smoothed with a square operator. A Sobel edge detector is used to identify the edge pixels between 
	// the pupil and the iris. Next, hysteresis thresholding is used to extract connected edge pixels that 
	// are at some point above a relatively high threshold, but everywhere above a relatively low threshold. 
	// The resulting edges are then passed to a Hough transform that counts the number of pixels that could 
	// lie on a circle centered at a particular center and radius. The result is the circle center and radius.
    bool CHoughIris::FindPupilL(int& cx, int& cy, int& r, CImage image,
            int nReduce, int nStretchLow, int nSmooth, int nThreshLow, int nThreshHi,
            int nRadiusMin, int nRadiusMax)
    {
		// save image size for later
        IImageSize rSize(image);
		int nHeight = rSize.Height();
		int nWidth = rSize.Width();

		// Construct the image processing pipeline.
		// Sequence is CRgbAvg2Gray, CReduce, CHistMod, CBoxSmooth, CSobel, CHysterisisThreshold
        CRgbAvg2Gray* pRgbAvg2Gray = CRgbAvg2Gray::NewL();
        CleanupStack::PushL(pRgbAvg2Gray);
		CSequence* pSequence = CSequence::NewL(pRgbAvg2Gray);
		CleanupStack::Check(pRgbAvg2Gray);
		CleanupStack::Pop(); // owned by pSequence
		CleanupStack::PushL(pSequence);		// when this is deleted everything in the sequence is, too

		CReduce* pReduce = CReduce::NewL(nReduce, nReduce);
		pSequence->AddL(pReduce);

        float fTargetHist[256];
        HistStretchLow(fTargetHist, nStretchLow);

		CHistMod* pHistMod = CHistMod::NewL(fTargetHist);
		pSequence->AddL(pHistMod);

        CBoxSmooth* pSmooth = CBoxSmooth::NewL(nSmooth, nSmooth);
		pSequence->AddL(pSmooth);

		CSobel* pSobel = CSobel::NewL();
		pSequence->AddL(pSobel);

		CHysterisisThreshold* pThreshold = CHysterisisThreshold::NewL(nThreshLow, nThreshHi);
		pSequence->AddL(pThreshold);

		// Actually process the image
        pSequence->PushL(image);
		// There should be a result...
		if (pSequence->Empty()) {
			User::Leave(KErrGeneral);
		}
		CImage resultImage = pSequence->FrontL();
		// Now apply the FindCircle function to locate the pupil center
		CHoughCircle* pHough = CHoughCircle::NewL();
		CleanupStack::PushL(pHough);		
		int nPeak = 0;
		pHough->FindCircleL(resultImage, nRadiusMin, nRadiusMax, cx, cy, r, nPeak);
		// Compensate for image reduction factor
		cx *= nReduce;
		cy *= nReduce;
        r *= nReduce;

		// Free objects this routine is responsible for
		CleanupStack::Check(pHough);
		CleanupStack::PopAndDestroy(/* pHough */);
		CleanupStack::Check(pSequence);
        CleanupStack::PopAndDestroy(/* pSequence */);

		// See if the pupil center is not too close to the image edge. The
		// pupil should be between 25% and 75% of the image width and height.
        if (cy < nWidth / 4 || cy > nWidth * 3 / 4 ||
            cx < nHeight / 4 || cx > nHeight * 3 / 4) {
				// too close -- we failed
                return false;
            } else {
				// looks OK
                return true;
            }
    }

	// FindScleraL attempts to find the iris-sclera edge using a similar procedure to the FindPupilL
	// routine above. Performance was not so good so a different routine is used now. But I left
	// FindScleraL in case it becomes useful at some point in the future.
	// The overall structure is similar to FindPupilL. Instead of taking the average RGB value to
	// convert to gray we use the minimum -- this is intended to enhance the contrast between the
	// colored iris (which will have at least one low R, G, or B value) and the white or near-white
	// sclera (which should have all high values). We stretch the high histogram values, again to
	// increase the contrast between the iris and the light sclera. 
	// We use a Hough circle routine that assumes a given center value because the pupil
	// is assumed to be the center of the iris-sclera circle.
    bool CHoughIris::FindScleraL(int cx, int cy, int& r, CImage image,
            int nReduce, int nStretchHi, int nSmooth, int nThreshLow, int nThreshHi,
            int nRadiusMin, int nRadiusMax)
    {
		// Build the pipeline.
		// Order is CRgbMin2Gray, CReduce, CHistMod, CBoxSmooth, CSobel, CHysterisisThreshold
        CRgbMin2Gray* pRgbMin2Gray = CRgbMin2Gray::NewL();
        CleanupStack::PushL(pRgbMin2Gray);
		CSequence* pSequence = CSequence::NewL(pRgbMin2Gray);
        CleanupStack::Pop(); // pSequence takes responsibility for pRgbMin2Gray
		CleanupStack::PushL(pSequence);		// when this is deleted everything in the sequence is, too

		CReduce* pReduce = CReduce::NewL(nReduce, nReduce);
		pSequence->AddL(pReduce);

        float fTargetHist[256];
        HistStretchHi(fTargetHist, nStretchHi);

		CHistMod* pHistMod = CHistMod::NewL(fTargetHist);
		pSequence->AddL(pHistMod);

        CBoxSmooth* pSmooth = CBoxSmooth::NewL(nSmooth, nSmooth);
		pSequence->AddL(pSmooth);

		CSobel* pSobel = CSobel::NewL();
		pSequence->AddL(pSobel);

		CHysterisisThreshold* pThreshold = CHysterisisThreshold::NewL(nThreshLow, nThreshHi);
		pSequence->AddL(pThreshold);

		// Process the image
        pSequence->PushL(image);
		// There should be a result...
		__ASSERT_ALWAYS(!pSequence->Empty(), User::Leave(KErrGeneral));
		CImage resultImage = pSequence->FrontL();

		// Apply Hough circle finder given center from pupil routine
		CHoughCircle* pHough = CHoughCircle::NewL();
		CleanupStack::PushL(pHough);		
		int nPeak = 0;
		// Adjust for image reduction
        cx /= nReduce;
        cy /= nReduce;
		// Find the radius
		pHough->FindCircleGivenCenterL(resultImage, nRadiusMin, nRadiusMax, cx, cy, r, nPeak);
		// Adjust for image reduction
        r *= nReduce;

		// Destroy the objects this routine is responsible for.
		CleanupStack::PopAndDestroy(); // pHough
        CleanupStack::PopAndDestroy(); // pSequence

        return true;
    }

	// Create a new target histogram that will stretch all values
	// up to nStretchLow so they cover the full 0-255 range. Everything
	// else is assigned 255.
    void CHoughIris::HistStretchLow(float* pHist, int nStretchLow) 
    {
        int i=0;
        float fRemaining = 1.0f;
        float fValue = 1.0f / (nStretchLow * 16.0f);
        for (; i<nStretchLow; i++) {
            pHist[i] = fValue;
            fRemaining -= pHist[i];
        }
        for (; i<256; i++) {
            pHist[i] = 0.0f;
        }
        pHist[255] = fRemaining;
    }

	// Create a new target histogram that will stretch all values
	// above nStretchHigh so they cover the full 0-255 range. Everything
	// else is assigned 0.
    void CHoughIris::HistStretchHi(float* pHist, int nStretchHi) 
    {
        int i=255;
        float fRemaining = 1.0f;
        float fValue = 1.0f / ((256-nStretchHi) * 16.0f);
        for (; i>nStretchHi; i--) {
            pHist[i] = fValue;
            fRemaining -= pHist[i];
        }
        for (; i>0; i--) {
            pHist[i] = 0.0f;
        }
        pHist[0] = fRemaining;
    }
};

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?