algorytm.org

Implementacja w JavaScript



Baza Wiedzy
wersja offline serwisu przeznaczona na urządzenia z systemem Android
Darowizny
darowiznaWspomóż rozwój serwisu
Nagłówki RSS
Artykuły
Implementacje
Komentarze
Forum
Bookmarki






Sonda
Implementacji w jakim języku programowania poszukujesz?

Retinex - Implementacja w JavaScript
Ocena użytkownikóww: *****  / 2
SłabyŚwietny
Nadesłany przez Tomasz Lubiński, 18 lutego 2013 22:28
Kod przedstawiony poniżej przedstawia główną część rozwiązania problemu.
Pobierz pełne rozwiązanie.

Jeżeli nie odpowiada Ci sposób formatowania kodu przez autora skorzystaj z pretty printer'a i dostosuj go automatycznie do siebie.

retinex.js:
//Retinex
//(c) 2013 by Tomasz Lubinski
//www.algorytm.org

/* Data	of the image */
var imageData;

/* Papers:  "Recursive Implementation of the gaussian filter.",
            Ian T. Young , Lucas J. Van Vliet, Signal Processing 44, Elsevier 1995. */
function gaussian_coefs(sigma)
{
	var result = new Array();
	var q = 0;
	if (sigma >= 2.5)
		q = 0.98711 * sigma - 0.96330;
	else if ((sigma >= 0.5) && (sigma < 2.5))
		q = 3.97156 - 4.14554 * Math.sqrt(1.0 - 0.26891 * sigma);
	else
		q = 0.1147705018520355224609375;

	var q2 = q * q;
	var q3 = q * q2;
	result.push(1.57825+(2.44413*q)+(1.4281 *q2)+(0.422205*q3));
  	result.push(        (2.44413*q)+(2.85619*q2)+(1.26661 *q3));
  	result.push(                   -((1.4281*q2)+(1.26661 *q3)));
	result.push(                                 (0.422205*q3));
  	result.push(1.0-((result[1]+result[2]+result[3])/result[0]));
  	return result;
}
function gausssmooth(imgIn, imgOut, shift, rowstride, size, coefs)
{
	// forward pass
	var w1 = new Array();
	var w2 = new Array();
	w1[0] = imgIn[shift];
	w1[1] = imgIn[shift];
	w1[2] = imgIn[shift];
	for(var i=0, n=3; i<size; i++, n++)
	{
		w1[n] = (coefs[4]*imgIn[shift+i*rowstride] +
			((coefs[1]*w1[n-1] +
			coefs[2]*w1[n-2] +
			coefs[3]*w1[n-3] ) / coefs[0]));
	}
	w1[size+0] = w1[size-1];
	w1[size+1] = w1[size-2];
	w1[size+2] = w1[size-3];

	// backward pass
	w2[size+0]= w1[size+0];
	w2[size+1]= w1[size+1];
	w2[size+2]= w1[size+2];
	w2[size+3]= w1[size+2];
	w2[size+4]= w1[size+2];
	w2[size+5]= w1[size+2];	
	for(var i=size-1, n=i+3; i>=0; i--, n--)
	{
		w2[n] = imgOut[shift+i*rowstride] = (coefs[4]*w1[n] +
			((coefs[1]*w2[n+1] +
			coefs[2]*w2[n+2] +
			coefs[3]*w2[n+3] ) / coefs[0]));
	}
}

/* Retinex */
function retinex(sigmas, weights, alfa, beta)
{
	var canvas = document.getElementById("canvas");
	var ctx	= canvas.getContext("2d");

	//read the width and height of the canvas
	var width = canvas.width;
	var height = canvas.height;
	
	var bluredImageData = ctx.createImageData(width, height).data;
	var imageDataData = imageData.data;
	
	//initialize result
	var retinexResult = new Array();
	//for each channel (R, G, B)
	retinexResult[0] = new Array();
	retinexResult[1] = new Array();
	retinexResult[2] = new Array();
	//for each line
	for (var i=0; i<height; i++)
	{
		retinexResult[0][i] = new Array();
		retinexResult[1][i] = new Array();
		retinexResult[2][i] = new Array();
		for (var j=0; j<width; j++)
		{
			retinexResult[0][i][j] = 0;
			retinexResult[1][i][j] = 0;
			retinexResult[2][i][j] = 0;
		}
	}	
	
	//for all requested scales (MSR - multi scale retinex)
	for (var s=0; s<sigmas.length; s++)
	{
		//gaussian blur coefs
		var coefs = gaussian_coefs(sigmas[s])
	
		//Gaussian blur horizontal
		for (var i=0; i<height; i++)
		{
			gausssmooth(imageDataData, bluredImageData, i*width*4+0, 4, width, coefs);
			gausssmooth(imageDataData, bluredImageData, i*width*4+1, 4, width, coefs);
			gausssmooth(imageDataData, bluredImageData, i*width*4+2, 4, width, coefs);
		}
	
		//Gaussian blur vertical
		for (var i=0; i<width; i++)
		{
			gausssmooth(bluredImageData, bluredImageData, i*4+0, 4*width, height, coefs);
			gausssmooth(bluredImageData, bluredImageData, i*4+1, 4*width, height, coefs);
			gausssmooth(bluredImageData, bluredImageData, i*4+2, 4*width, height, coefs);
		}
		
		//Retinex (SSR - single scale retinex)
		for (var i=0; i<height; i++)
		{
			for (var j=0; j<width; j++)
			{	
				var index = (i*width+j)*4;	
				retinexResult[0][i][j] += weights[s] * Math.log((imageDataData[index+0] + 1.0) / (bluredImageData[index+0] + 1.0));
				retinexResult[1][i][j] += weights[s] * Math.log((imageDataData[index+1] + 1.0) / (bluredImageData[index+1] + 1.0));
				retinexResult[2][i][j] += weights[s] * Math.log((imageDataData[index+2] + 1.0) / (bluredImageData[index+2] + 1.0));
			}
		}
		
	}
	
	//Normalize result
	var min = retinexResult[0][0][0];
	var max = min;
	for (var i=0; i<height; i++)
	{
		for (var j=0; j<width; j++)
		{
			if (min > retinexResult[0][i][j])
				min = retinexResult[0][i][j];
			else if (max < retinexResult[0][i][j])
				max = retinexResult[0][i][j];
			if (min > retinexResult[1][i][j])
				min = retinexResult[1][i][j];
			else if (max < retinexResult[1][i][j])
				max = retinexResult[1][i][j];
			if (min > retinexResult[2][i][j])
				min = retinexResult[2][i][j];
			else if (max < retinexResult[2][i][j])
				max = retinexResult[2][i][j];
		}
	}
	
	//Put result to the new image
	var newImageData = ctx.createImageData(width, height);	
	var newImageDataData = newImageData.data;
	var range = (max - min) / 255.0;
	for (var i=0; i<height; i++)
	{
		for (var j=0; j<width; j++)
		{
			//color restoration (MSRCR - multiscale retinex with color restoration)				
			var index = (i*width+j)*4;
			var sum = imageDataData[index+0] + imageDataData[index+1] + imageDataData[index+2] + 3.0;			
			
			value = retinexResult[0][i][j] * beta*Math.log(alfa*(imageDataData[index+0] + 1.0) / sum);
			value = (value - min) / range;
			if (value > 255)
				newImageDataData[index+0] = 255;
			else if (value < 0)
				newImageDataData[index+0] = 0;
			else
				newImageDataData[index+0] = value;

			value = retinexResult[1][i][j] * beta*Math.log(alfa*(imageDataData[index+1] + 1.0) / sum);
			value = (value - min) / range;
			if (value > 255)
				newImageDataData[index+1] = 255;
			else if (value < 0)
				newImageDataData[index+1] = 0;
			else
				newImageDataData[index+1] = value;

			value = retinexResult[2][i][j] * beta*Math.log(alfa*(imageDataData[index+2] + 1.0) / sum);
			value = (value - min) / range;
			if (value > 255)
				newImageDataData[index+2] = 255;
			else if (value < 0)
				newImageDataData[index+2] = 0;
			else
				newImageDataData[index+2] = value;
		}
		
	}

	//set as no trasparent
	for (var i=0; i<height; i++)
	{
		for (var j=0; j<width; j++)
		{
			var index = (i*width+j)*4;
			newImageDataData[index+3] = 255;
		}
	}	
	
	// copy	the image data back onto the canvas
	ctx.putImageData(newImageData, 0, 0);
}

/* load	image pointed by param_file to canvas */
function loadImage(imgSrc)
{
	var canvas = document.getElementById("canvas");
	var ctx	= canvas.getContext("2d");

	// add file:// if user specified local path
	if (imgSrc.indexOf("//") == -1 && imgSrc.indexOf(".") != 0)
	{
		imgSrc = "file:///" + imgSrc;
	}

	// load	file into canvas
	var img	= new Image();
	img.onload = function(){
		var width = img.width;
		var height = img.height;
		canvas.width = width;
		canvas.height =	height;
		ctx.drawImage(img,0,0);
		// replace transparent with white
		try
		{
			imageData = ctx.getImageData(0,	0, width, height);
		} catch(e)
		{
			netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
			imageData = ctx.getImageData(0,	0, width, height);
		}
		for (var i=0; i<height;	i++)
		{
			for (var j=0; j<width; j++)
			{
				index =	(i*width+j)*4;
				if (imageData.data[index+3] == 0)
				{
					imageData.data[index+3]	= 255;
					imageData.data[index+0]	= 255;
					imageData.data[index+1]	= 255;
					imageData.data[index+2]	= 255;
				}
			}
		}
	}
	img.src	= imgSrc;
}
Dodaj komentarz