cannyhoriz.cpp

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

CPP
190
字号
//
// CannyHoriz
//   Applies the horizontal Canny operator to an unsigned byte image. The 
//   output is signed byte.
//   The coefficients of the Canny operator were calculated using the formula
//   from http://homepages.inf.ed.ac.uk/rbf/CVonline/LOCAL_COPIES/MARBLE/low/edges/canny.htm
//
// Copyright (C) 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 "Array.h"
#include "CannyHoriz.h"
#include "Debug.h"
#include "Image.h"
#include "GrayImageIter.h"
#include "GrayIndex.h"
#include "ImageSize.h"
#include "Replicate.h"

#include <e32math.h>
#include <e32std.h>
#include <fbs.h>

using namespace Core;

namespace Algorithm
{

	EXPORT_C CCannyHoriz* CCannyHoriz::NewL(TReal sigma)
	{	
		CCannyHoriz* pMe = new (ELeave) CCannyHoriz(sigma);
		CleanupStack::PushL(pMe);
		pMe->ConstructL();
		CleanupStack::Pop();
		return pMe;
	}

	CCannyHoriz::~CCannyHoriz()
	{
		if (ipfCoeff) {
			ipfCoeff->Reset();
			delete ipfCoeff;
		}
		delete ipnCoeff;
	}

	CCannyHoriz::CCannyHoriz(TReal sigma) :
		ibEmpty(true),
		ifSigma(sigma),
		ipfCoeff(NULL),
		ipnCoeff(NULL)
	{
	}

	void CCannyHoriz::ConstructL()
	{
		ComputeCoefficientsL();
	}

	CImage CCannyHoriz::FrontL() 
	{
		if (ibEmpty) {
			User::Leave(KErrGeneral);
			return CImage();
		}
		ibEmpty = true;
		return iImage;
	}

	void CCannyHoriz::PushL(CImage image)
	{
		IReplicate rRepl(image);
		rRepl.CastL(iImage);
		image.LockLC();
		IGrayImageIter itIn(image);
		IGrayImageIter itOut(iImage);
		IImageSize size(image);

		int nWidth = ipfCoeff->Count();
		for (; !itIn.End(); itIn.NextRow(), itOut.NextRow()) {
			// initially assign 0 (as signed char) to the output row
			Mem::Fill(&itOut(), size.Width(), 128);
			for (; !itIn.REnd(); itIn++, itOut++) {
				IGrayImageIter itIn2 = itIn;
				IGrayImageIter itOut2 = itOut;
				// first step in the width of the Canny filter, accumulating the 
				// sum on the left side of the filter
				TInt32 sum = 0;
				int nPos;
				for (nPos=nWidth-1; nPos>0; nPos--, ++itIn2, ++itOut2) {
					if (itIn2.REnd()) {
						break;
					}
					sum += TInt32((*ipnCoeff)[nPos]) * itIn2();
				}
				// now step through the right side of the Canny filter
				for (nPos = 0; nPos < nWidth; nPos++, ++itIn2) {
					if (itIn2.REnd()) {
						break;
					}
					sum += TInt32((*ipnCoeff)[nPos]) * itIn2();
				}
				sum /= 256; // coefficients are scaled when converted to int
				// convert to unsigned (really, signed) character
				if (sum > 127) sum = 127;
				if (sum < -128) sum = -128;
				itOut2() = (unsigned char) (sum + 128);
			}

		}
		CleanupStack::PopAndDestroy(); // unlock bitmaps
		CDebug::ShowImage(iImage);
		ibEmpty = false;
	}

	bool CCannyHoriz::Empty() const
	{
		return ibEmpty;
	}
	// operations
	void CCannyHoriz::ComputeCoefficientsL()
	{
		ipfCoeff = new CArrayFixFlat<TReal>(128);
		const TReal threshold = 0.05;
		// = Sqrt(2*Pi)
		const TReal Sqrt2Pi = 2.506628274631000;
		TReal denom1 = 1.0 / (Sqrt2Pi * ifSigma * ifSigma * ifSigma);
		TReal denom2 = 1.0 / (2.0 * ifSigma * ifSigma);
		TReal denom3 = 1.0 / (ifSigma * ifSigma);
		int x = 0;
		int nMinTail = 99;
		TReal coeff;
		do {
			TReal exp;
			Math::Exp(exp, -x * x * denom2);
			coeff = - denom1 * exp * (1 - x * x * denom3);
			ipfCoeff->AppendL(coeff);
			x += 1;
			if (coeff > 0 && nMinTail == 99) {
				nMinTail = 2*x;
			}
			// note on condition below: the coefficients start out negative, then
			// turn positive and tail off to zero. We don't know the exact shape of
			// the curve but look for the zero crossing above and keep generating coefficients
			// until we reach twice that point. Then we look for the point where the
			// coefficients fall below the threshold.
		} while (coeff < 0 || x < nMinTail || coeff > threshold); // track through end of negative tail
		// normalize so sum is zero. remember that element 0
		// is the central element so counted once the others twice
		int i;
		TReal sum = ipfCoeff->At(0);
		for (i=1; i<ipfCoeff->Count(); i++) {
			sum += ipfCoeff->At(i) * 2;
		}
		sum /= 1 + 2*(ipfCoeff->Count() - 1);
		for (i=0; i<ipfCoeff->Count(); i++) {
			ipfCoeff->At(i) -= sum;
		}
		// now normalize so the sum of absolute values is 1
		sum = Abs(ipfCoeff->At(0));
		for (i=1; i<ipfCoeff->Count(); i++) {
			sum += Abs(ipfCoeff->At(i) * 2);
		}
		for (i=0; i<ipfCoeff->Count(); i++) {
			ipfCoeff->At(i) /= sum;
		}
		// finally, convert to int (we do computation in int
		// to avoid floating point)
		ipnCoeff = CArray<TInt16>::NewL(ipfCoeff->Count());
		for (i=0; i<ipfCoeff->Count(); i++) {
			Math::Int((*ipnCoeff)[i], ipfCoeff->At(i) * 256.0);
		}

	}
};

⌨️ 快捷键说明

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