¬ернутьс€ к разделу "–еализаци€ проекта BookScanLib".


33. Ѕинаризаци€ Bernsen Thresholding

Ѕинаризаци€ Bernsen Thresholding из проекта gamera примен€етс€ дл€ преобразовани€ серой (8-битной) растровой картинки в чЄрно-белую (1-битна€).

јлгоритм Bernsen Thresholding анализирует обрабатываемую картинку и автоматически вычисл€ет порог бинаризации - индивидуальный дл€ каждого пиксел€ (т.е это локальна€ или адаптивна€ бинаризаци€). Ќайденный порог используетс€ дл€ обыкновенной пороговой бинаризации в отношении текущего пиксел€.

я написал простейшую консольную программу дл€ демонстрации работы Bernsen Thresholding. Ќа входе она принимает следующие параметры:

bernsen_thres <input_file> <region_size (int)> <contrast_limit (unsigned)> <set_doubt_to_low (bool)>

region_size - размер окна усредн€ющего фильтра. ѕо умолчанию 3 (€ поставил 8).

contrast_limit - предел контраста при выборе порога. ѕо умолчанию 128.

set_doubt_to_low - выбор цвета бинаризации дл€ пикселей за пределом контраста. ѕо умолчанию 0.

Ќа выходе программа выдаЄт этот же файл, обработанный этим алгоритмом.

ѕрограмма работает только с серыми изображени€ми.

¬сЄ необходимое дл€ тестировани€ этой программы (компил€ционный проект, готовый экзешник, файл-пример и bat-файлы дл€ тестировани€ программы) € оформил в небольшой пакет:

—качать пакет bernsen_thres (36  Ѕ)

(ƒл€ работы программы требуетс€ FreeImage dll-библиотека из пакета FreeImage DLL v3.9.2 - см. статью 1. «накомство с FreeImage).

–ассмотрим исходные коды этой программы:


/*
*
* Copyright (C) 2001-2005 Ichiro Fujinaga, Michael Droettboom, and Karl MacMillan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

/*
References:
&'John Bernsen'
"Dynamic thresholding of grey-level images", 
Proc. 8th International Conference on Pattern 
Recognition (ICPR8), pp 1251-1255, Paris, France, 
October 1986.

 Original author:
 √Шivind Due Trier
*/

/*
 Creates a binary image by using the Bernsen algorithm.

 *region_size* : default = 3
 The size of each region in which to calculate a threshold
  
 *contrast_limit* : default = 128
 The minimum amount of contrast required to threshold.
	
 *set_doubt_to_low* : default = 0
 The color choice for the doubt pixels
*/

// This algorithm was taken from the gamera.sf.net sourcecodes
// and adopted for the FreeImage library
//
//	Copyright (C) 2007-2008:
//	monday2000	monday2000@yandex.ru

#include "FreeImage.h"
#include "Utilities.h"

////////////////////////////////////////////////////////////////////////////////

inline void SetPixel(BYTE *bits, unsigned x, BYTE* value)
{   // this function is simplified from FreeImage_SetPixelIndex
	
	*value ? bits[x >> 3] |= (0x80 >> (x & 0x7)) : bits[x >> 3] &= (0xFF7F >> (x & 0x7));
}

////////////////////////////////////////////////////////////////////////////////

FIBITMAP* ProcessFilter(FIBITMAP* src_dib, int region_size, unsigned contrast_limit, BOOL set_doubt_to_low)
{
	unsigned width = FreeImage_GetWidth(src_dib);
	
	unsigned height = FreeImage_GetHeight(src_dib);
	
	unsigned src_pitch = FreeImage_GetPitch(src_dib);
	
	unsigned bpp = FreeImage_GetBPP(src_dib);
	
	FIBITMAP* dst_dib = FreeImage_Allocate(width, height, 1);
	
	// Build a monochrome palette
	RGBQUAD *pal = FreeImage_GetPalette(dst_dib);
	pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 0;
	pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255;
	
	unsigned dst_pitch = FreeImage_GetPitch(dst_dib);
	
	BYTE* src_bits = (BYTE*)FreeImage_GetBits(src_dib); // The image raster
	
	BYTE* dst_bits = (BYTE*)FreeImage_GetBits(dst_dib); // The image raster
	
	unsigned x, y, i, j;
	
	int k_index;
	
	BYTE* src_end_row = src_bits + (height-1) * src_pitch;
	
	int end_col = width - 1;
	
	BYTE* lines, *linek, *lined;	
	
	BYTE confused, val, c;
	
	BYTE minimum;
	BYTE maximum;
	
	if (set_doubt_to_low)
		confused = 0; //black
	else
		confused = 255; // white
	
	for (y = 0; y < height; y++)
	{
		lines = src_bits + y * src_pitch;
		
		lined = dst_bits + y * dst_pitch;
		
		for (x = 0; x < width; x++)
		{
			minimum = 255;
			maximum = 0;
			
			// kernel processing
			for (i = 0; i < region_size; i++)
				for (j = 0; j < region_size; j++)
				{					
					linek = lines + (i-1) * src_pitch;
					
					if (linek < src_bits) linek = src_bits;
					if (linek > src_end_row) linek = src_end_row;
					
					k_index = x+j-1;
					
					if (k_index < 0) k_index = 0;
					if (k_index > end_col) k_index = end_col;
					
					minimum = MIN(minimum, linek[k_index]);
					maximum = MAX(maximum, linek[k_index]);
				}
				
				c = maximum - minimum;
				
				if (c < contrast_limit)
					val = confused;
				
				else
				{
					long t = (maximum + minimum) / 2;
					
					if (lines[x] >= t)
						val = 255; // white
					else
						val = 0; // black				
				}
				
				SetPixel(lined, x, &val);
		}
	}
	// Copying the DPI...
	
	FreeImage_SetDotsPerMeterX(dst_dib, FreeImage_GetDotsPerMeterX(src_dib));
	
	FreeImage_SetDotsPerMeterY(dst_dib, FreeImage_GetDotsPerMeterY(src_dib));
	
	return dst_dib;
}

////////////////////////////////////////////////////////////////////////////////

/**
FreeImage error handler
@param fif Format / Plugin responsible for the error 
@param message Error message
*/
void FreeImageErrorHandler(FREE_IMAGE_FORMAT fif, const char *message) {
	printf("\n*** "); 
	printf("%s Format\n", FreeImage_GetFormatFromFIF(fif));
	printf(message);
	printf(" ***\n");
}

////////////////////////////////////////////////////////////////////////////////

/** Generic image loader

  @param lpszPathName Pointer to the full file name
  @param flag Optional load flag constant
  @return Returns the loaded dib if successful, returns NULL otherwise
*/

FIBITMAP* GenericLoader(const char* lpszPathName, int flag)
{	
	FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
	// check the file signature and deduce its format
	// (the second argument is currently not used by FreeImage)
	
	fif = FreeImage_GetFileType(lpszPathName, 0);
	
	FIBITMAP* dib;
	
	if(fif == FIF_UNKNOWN)
	{
		// no signature ?
		// try to guess the file format from the file extension
		fif = FreeImage_GetFIFFromFilename(lpszPathName);
	}
	
	// check that the plugin has reading capabilities ...
	if((fif != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(fif))
	{
		// ok, let's load the file
		dib = FreeImage_Load(fif, lpszPathName, flag);
		
		// unless a bad file format, we are done !
		if (!dib)
		{
			printf("%s%s%s\n","File \"", lpszPathName, "\" not found.");
			return NULL;
		}
	}	
	
	return dib;
}

////////////////////////////////////////////////////////////////////////////////

int main(int argc, char *argv[]) {
	
	// call this ONLY when linking with FreeImage as a static library
#ifdef FREEIMAGE_LIB
	FreeImage_Initialise();
#endif // FREEIMAGE_LIB
	
	// initialize your own FreeImage error handler
	
	FreeImage_SetOutputMessage(FreeImageErrorHandler);
	
	if(argc != 5) {
		printf("Usage : bernsen_thres <input_file> <region_size (int)> <contrast_limit (unsigned)> <set_doubt_to_low (int)>\n");
		return 0;
	}
	
	FIBITMAP *dib = GenericLoader(argv[1], 0);
	
	int region_size = atoi(argv[2]);
	
	unsigned contrast_limit = atoi(argv[3]);
	
	int set_doubt_to_low = atoi(argv[4]);
	
	if (dib)
	{		
		// bitmap is successfully loaded!
		
		if (FreeImage_GetImageType(dib) == FIT_BITMAP)
		{
			if (FreeImage_GetBPP(dib) == 8)
			{
				FIBITMAP* dst_dib = ProcessFilter(dib, region_size, contrast_limit, set_doubt_to_low);
				
				if (dst_dib)
				{					
					// save the filtered bitmap
					const char *output_filename = "filtered.tif";
					
					// first, check the output format from the file name or file extension
					FREE_IMAGE_FORMAT out_fif = FreeImage_GetFIFFromFilename(output_filename);
					
					if(out_fif != FIF_UNKNOWN)
					{
						// then save the file
						FreeImage_Save(out_fif, dst_dib, output_filename, 0);
					}
					
					// free the loaded FIBITMAP
					FreeImage_Unload(dst_dib);					
				}
			}
			
			else
				
				printf("%s\n", "Unsupported color mode.");
		}
		
		else // non-FIT_BITMAP images are not supported.
			
			printf("%s\n", "Unsupported color mode.");
		
		FreeImage_Unload(dib);
	}	 
	
	// call this ONLY when linking with FreeImage as a static library
#ifdef FREEIMAGE_LIB
	FreeImage_DeInitialise();
#endif // FREEIMAGE_LIB
	
	return 0;
}

 раткое описание алгоритма:

ќбычна€ квадратна€ апертура 3х3 пробегает в цикле по всем пиксел€м исходного изображени€. Ќа каждом шаге находим минимум и максимум и среднюю по ним величину. ≈сли текущий пиксель больше среднего - он становитс€ белым, иначе - чЄрным. ≈сли среднее меньше порога контраста - то текущий пиксель становитс€ того цвета, который задавалс€ параметром "цвет сомнительного пиксел€".


јлгоритм, конечно, не ахти - но зато у него есть иные оригинальные применени€, кроме бинаризации. ≈сли поставить радиус = 6 - то получитс€ необычный эффект "контурных букв". ≈сли поставить сомнительный цвет = 1 - то получим выделение контура букв.

Hosted by uCoz