Friday, 31 December 2010

Histogram equalization

I have added histogram equalization to the Image Algorithms demo. This method scans through an image, inspecting each pixel and creates a histogram. If a pixel p_q of grayscale intensity g_q is found at location (x,y), the Histogram H is incremented at position g_q for all grayscale levels L = 0 .. G-1, where G = 256 for grayscale images. A cumulative histogram is then calculated and the resulting pixel value is the ratio between the cumulative histogram and the total amounts of pixels in the image multiplied with G - 1.

More formally.

ALGORITHM - Histogram equalization.

1. For an NxM image of G gray levels, create an array H (histogram) of length G initialized with default intensity value 0.

2. Form the image histogram. Scan every pixel and increment relevant position in the histogram H. If pixel p has intensity g_p, perform:
H[g_p] = H[g_p + 1.

3. Form the cumulative image histogram H_c. Set:
H_c[0] = H[0]
H_c[p] = H_c[p-1] + H[p] for all pixel intensities p where p = 0,1,2... G-1

4. Rescan the image and calculate the corrected intensity, which it output.
Let T[p] = round(((G-1)/(N*M)) * H_c[p]. For a pixel of intensity p in the image
at position x,y, use T[p] to find the correct adjusted value.

5. Display image results.

END.

Note about step 4. Use the (double) cast when doing the math.. In general, histogram equalization is all about creating a Histogram of an image, then form a cumulative histogram, and then use the ratio between the total amount of pixels N*M and multiply with the cumulative histogram H_c[p] and then multiply with (G-1), usually 255.. This will set the most luminous pixels in the image near full intensity, will the less luminous pixels towards zero intensity, increasing the dynamic range and contrast in the image.

Note about the demo, I have added also Hough transform (tested some basic images) and
filters for displaying histogram of the histogram equalization. Test them out. Hough transform shown the sinusoidal images in the parameter space and should be considered as not finished code.

A demonstration follows.

This is equalized to:

Image algorithms demo [2,7 Mb zip]

To summarize, to understand histogram equalization is to consider the cumulative histogram and scale this with the ratio with the total amount of pixels multiplied with 255 (G-1).. The result is that the brightest pixels are moved towards full intensity 255 and the darkest pixels are moved towards 0, increasing the contras and dynamic range.

Wednesday, 29 December 2010

Test out iterative optimal treshold algorithm on images?

Merry Xmas

Image algorithms demo [2,6 MB zip]

Iterative optimal tresholding

I have tested out and implemented another filter in my image algorithms demo. I follow the Iterative (optimal) treshold selection algorithm from the "Image Processing, Analysis and Machine Vision" book from my Computer Vision course, which I took when studying to my Master of Science (Siv. ing datateknikk) degree at NTNU, Trondheim. It is a simple algorithm, consisting of these steps.

ALGORITHM - Iterative optimal tresholding.

GOAL: Separate an image into two regions, background and foreground.
DEFINITIONS: Background is pixels
which got intensity below the current treshold, calculated in the algorithm's iterations. Foreground pixels got intensity above the current treshold.

STEPS:
```1.Calculate the initial average of the current treshold value. Set this value to the
average of the four corner pixels average value.```
2. Traverse the image. If a pixel is above the current treshold value, it is added to the sum of object pixels
(foreground pixels). Incremement the count of foreground pixels. Also, vice versa for the background pixels. Add to the sum of background pixels and increment the background pixels if the pixel's intensity is below the treshold value.

3. Calculate the average of the background average and object (foreground average) and set this to the next treshold value.

4. If not the next treshold is the same as current treshold, iterate the image again, but now set current treshold to next treshold. When the next and current treshold is same, the treshold calculated is the optimal treshold value. End iteration or break at 100 iterations.

5. After calculation is complete, display result. Set the object pixels to full pixel intensity (255). Background
pixels are set to 0, creating a binary image showing foreground and background.

It took five iterations to calculate the iterative optimal treshold value for the infamous Lenna image, calculated to be 162 in pixel intensity. For an average picture one would expect the value to be above 140 - 180, if the picture is grayscale image with good contrast.
```Result: ```
```
```
`IMPLEMENTATION - OptimalTresholdFilter.cs `
```

```
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ImageAlgorithms.Filters.Treshold
{
public class OptimalTresholdFilter : ImageFilterBase
{

int objectPixelSum = 0;
int backgroundPixelSum = 0;
int currentTresholdValue = 0;
int nextTresholdValue = 0;
int objectPixelsCount = 0;
int backgroundPixelCount = 0;

public OptimalTresholdFilter()
{
FilterType = FilterTypeEnum.TresholdFilter;
}

public override void FilterProcessImage(int width, int height)
{
//base.FilterProcessImage(width, height);

//Read first four pixels (edges of image)
//Calculate the average of object pixels and background pixels
//Let avg+1 = average of background pixels and object pixels
//if avg+1 and avg is the same, stop, else continue.
CalculateAverage(width, height, 0);
DisplayTresholdImage(width, height);
}

private void DisplayTresholdImage(int width, int height)
{
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
int position = (j*width) + i;
if (TemporaryImageData[i, j] > nextTresholdValue)
{
ResultingImageData[position] = 255;
}
else
{
ResultingImageData[position] = 0;
}
}
}

}

private void CalculateAverage(int width, int height, int iteration)
{
InitFilterIteration();
CheckInitialStep(width, height, iteration);
TraverseImageBackgroundForeground(width, height, iteration);
CheckPixelCounts();
CalculateNextTreshold();
if (nextTresholdValue != currentTresholdValue && iteration < 100)
{
currentTresholdValue = nextTresholdValue;
CalculateAverage(width, height, iteration + 1);
}
}

private void CalculateNextTreshold()
{
nextTresholdValue = ((objectPixelSum / objectPixelsCount) +
(backgroundPixelSum / backgroundPixelCount)) / 2;
}

private void TraverseImageBackgroundForeground(int width, int height, int iteration)
{
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
if (TemporaryImageData[i, j] > currentTresholdValue)
{
}
else
{
if (iteration > 0)
{
}
}
}
}
}

private void AddToBackgroundPixels(int i, int j)
{
backgroundPixelSum += TemporaryImageData[i, j];
backgroundPixelCount++;
}

private void AddToObjectPixels(int i, int j)
{
objectPixelSum += TemporaryImageData[i, j];
objectPixelsCount++;
}

private void CheckInitialStep(int width, int height, int iteration)
{
if (iteration == 0)
{
backgroundPixelSum = (TemporaryImageData[0, 0] + TemporaryImageData[width - 1, 0] +
TemporaryImageData[0, height - 1] +
TemporaryImageData[width - 1, height - 1]);
backgroundPixelCount = 4;
currentTresholdValue = backgroundPixelSum / backgroundPixelCount;
}
}

private void CheckPixelCounts()
{
objectPixelsCount = Math.Max(1, objectPixelsCount);
backgroundPixelCount = Math.Max(1, backgroundPixelCount);
}

private void InitFilterIteration()
{
backgroundPixelCount = 0;
objectPixelsCount = 0;
backgroundPixelSum = 0;
objectPixelSum = 0;
}
}
}

```
```

Download the latest version of the algorithms demo (v1.1.) to test out the optimal treshold filter. As you can see in the code above, the class inherits from ImageFilterBase, which handles some of the "logistics" around the image filter (loading the filter and showing the result).

Sunday, 26 December 2010

Image algorithms demo

At last an update to my blog! This has been a busy year for me with my work, I am now a developer in Helse Midt-Norge IT since May, earlier this year I worked as an independent consultant for Artsdatabanken (NTNU). I work with WPF and C# mainly presently.

I will now present a new hobby project of mine.

This WPF application demo of image algorithms demonstrates different techniques towards
blur, sharpen, edge detection and other filtering techniques, all relying on the general concept of Convolution in image processing. 8-bits level grayscale images (256 levels, 1 bpp) are supported.

I have worked with an image algorithms demo the last days. The
demo is a small WPF application that demonstrates image algorithms used in
the Microsoft Visual Studio 2010 project with source code.

Examples of edge operators are sobel edge operator and Prewitt, Laplacian, Roberts and
Horizontal and Vertical Sobel, blur difference operator, shown above. There are additional
filters included.

The resulting images can be inverted. The application works with 8-bit grayscale images (256 levels). The BitmapSource class must be able to import the image (BMP or GIF should work).

Right now the demo is in v1.1. I will add more features soon. There are a few issues with double-edges, noise and normalization in the demo, but I hope I will complete the demo in a more stable version later. Feel free to unzip the zip file linked below and provide comments of the code. Perhaps you can add new features to my code and discuss optimizations, corrections?

I will state that already there is very little code to make a new filter, so this source code could be used as a basis for developing filters for applications needing to provide basic blur, sharpen and edge detection capabilities.

Sobel operator, horisontal komponent (3x3 convolution kernel).

Comment:

Image algorithms v1.1 (Zip-fil, ca. 2,4 MB compressed)

Last update 28th of December 2010.

Future stuff:
• improve the speed of the filtering
• support greater than 8 bpp (e.g. RGB)
• support more operators. Canny edge and more advanced filters are desired
• improve code, add tests to the test project
• even friendlier GUI, more feedback and information
• document code
• share code with the community when v2.0 is done.
The goal is that this demo should be a good starter demo of edge analysis in digital image algorithms, that can be used in courses at universities and the likes. The demo demonstrates pixel manipulation in WPF-application and filtering also with up to date .NET 4.0 code. Often one only finds C or C++ code when looking for these kinds of algorithms..

Sunday, 14 February 2010

ASP.NET MVC og jQuery Grid

Jeg har testet ASP.NET MVC i Visual Web Developer Express og jQuery Grid. Det er kraftig teknologi som gir gode muligheter for å jobbe strukturert med utvikling i ASP.NET MVC (et rammeverk og paradigme som oppfordrer til strukturert og modularisert webutvikling, optimert mot TDD, test-drevet utvikling), samtidig som man vha. jQuery og jQuery grid kan vise data i en grid.

Jeg vil begynne med å vise et skjermbilde av hva som testløsningen min inneholder.

- ASP.NET MVC er en ny teknologi som ASP.NET kan benytte for å tilby en mer strukturert måte å jobbe på. Man går vekk fra code-behind og rammeverket er meget
datasentrisk. Man har en oppkobling, gjerne til Sql Server (.mdf filer og tilsvarende), altså MS-SQL, hvor man definerer raskt en datamodell. Man bruker så Linq-to-sql for å generere klasser for datalag for å jobbe mot dataene. Videre har man både Model og Model-View klasser etter behov, samt .aspx filer er "View". Partielle view er av typen MVC Web User control (.ascx filer).

For de som har jobbet lenge i ASP.NET vet man farene ved store prosjekter. Det blir fort spaghettikode og monolittisk kode. MVC tvinger en til å jobbe strukturert og modulrisert, samt unngår spaghetti på en mye mer streng måte enn standard ASP.NET.

En stor ulempe med MVC i ASP.NET er mangelen på en skikkelig grid-kontroll m.m., da vanlige ASP.NET kontroller ikke nødvendigvis vil virke i MVC..

Jeg har derfor testet ut jQuery Grid som er en meget bra måte å erstatte ASP.NET GridView. Best av alt, denne javascript baserte kontrollen kan benyttes i MVC-baserte løsninger!

Bortsett fra å tilby interesserte en nedlasting kan jeg kort si hva jQuery Grid er for noe. Det er en javascript plugin til jQuery og en klientbasert kontroll som er lik ASP.NET GridView, men har innebygd støtte for Ajax m.m.

Det tar en tid til å venne seg til å implementer en jQuery Grid. Man har ikke drag and drop på denne komponenten. Men det går temmelig raskt å få opp en løsning. I mitt demoprosjekt har jeg benyttet meg at Dynamisk Linq, som Scott Guthrie (en av de prinsipielle arkitektene bak ASP.NET) har laget. Dere finner implementasjonen i klassen Dynamic.cs. Jeg har i mitt testprosjekt laget en servermetode som spør en tabell i en .mdf fil om innholdet i tabellen Countries, som har alle hovedsteder og land i verden. Videre har jeg laget en Country dataklasse automagisk med Linq-To-Sql. I min HomeController (Controller er C-en i MVC) har jeg en Index funksjon som henter opp tabelldataene vha. Ajax og Json. Testfunksjonen min håndterer både paginering og sortering av databasen og json-dataene overføres tilbake til klienten, som viser dem i jQuery Griden. Denne kontrollen abonnerer på data fra server-side funksjonen som returnerer et ActionResult av type JsonResult.

MVC har en læringskurve og det er noe vanskelig å forstå hva alt dette er vits i å sette seg inn i. Men det vil spare en utvikler i ASP.NETfor mye arbeid, da det støtter TDD og unit testing på en mye bedre måte enn ASP.NET. Endelig går det an å utvikle nettsider profesjonelt og dele opp oppgaver til testere og verifisere at det man lager faktisk virker. Dette har vært enklere i applikasjonsutvikling enn i webutvikling, men med ASP.NET MVC så er det like enkelt å lage unit tester som for f.eks. WPF og WCF..

Ulempen med MVC er som sagt at vanlige ASP.NET serverkontroller ikke er vanligvis støttet. Men jQuery og jQuery Grid er sentral i MVC. Man har kontroller som er mer klient-orienterte enn de klassiske ASP.NET server-kontrollene. Med Json som kommunikasjon er det minimalt med data som går mellom klienten og serveren. Serveren leverer selvsagt data fortsatt ut til klient, men klienten "drar" dataene fra serveren oftere. Dermed blir det oftere requests, men disse er mindre i størrelse..

Dette gjør det mulig å utvikle webapplikasjoner som er repsonsive og tillater et vell av interaksjon. MVC i ASP.NET er en alternativ modell til Silverlight og den lekre jQuery Grid viser at dette er absolutt tilfelle.

I mitt demoprosjekt så er paginering og sortering støttet. Jeg har ikke testet enda hvordan man får til redigering i jQuery Grid eller har templates for celler, column reordering og annen avansert funksjonalitet, men dette er altså støttet i jQuery Grid. Dere finner jQuery Grid lett med et kjapt søkt med Google. Jeg anbefaler å sjekke ut vedlagte .zip fil for å se hele koden..

Til slutt før lenken til nedlastingen, så legger jeg ved koden for server-funksjonen i ASP.NET MVC som gir paginering og sortering. Den benytter som sagt Scott Guthrie sin Dynamic Linq klasse, som gir noen tilleggsfunksjoner som spytter inn SQL i linq-spørringer og gir det man trenger for akkurat dette..

` public ActionResult DynamicGridData (string sidx, string sord, int page, int rows) { var context = new GeografiTestDbDataContext(); int pageIndex = Convert.ToInt32(page) - 1; int pageSize = rows; int totalRecords = context.Countries.Count(); int totalPages = (int)Math.Ceiling((float)totalRecords / (float)pageSize); var countries = context.Countries.OrderBy(sidx + " " + sord) .Skip(pageIndex * pageSize) .Take(pageSize); var jsonData = new { total = totalPages, page = page, records = totalRecords, rows = ( from c in countries select new { i = c.Id, cell = new string[] { c.Id.ToString(), c.Capital, c.Country1 } }).ToArray() }; return Json(jsonData); }`

Linq-spørringene over virker ikke uten at man har Dynamics.cs filen som Scott Guthrie har laget, 81 kB stor. Her er det masse extension methods som gjør det mulig å spørre databasen inne i Linq-spørringer.. Dynamic Linq er helt vilt bra for de som tenker på hvordan det faktisk virker..

Til slutt, slik ser .aspx filen ut hvor man lager et jQuery Grid objekt:

` jQuery(document).ready(function() { jQuery("#list").jqGrid({ url: '/Home/DynamicGridData/', datatype: 'json', mtype: 'GET', colNames: ['Uniktnummer', 'Hovedstad', 'Land'], colModel: [ { name: 'Id', index: 'Id', width: 120, align: 'left' }, { name: 'Capital', index: 'Capital', width: 120, align: 'left' }, { name: 'Country1', index: 'Country1', width: 220, align: 'left' } ], pager: jQuery('#gridpager'), pgtext: "Side {0} av {1}", pginput: true, recordpos: 'left', rowNum: 20, width: 900, multiSelect:true, hidegrid: false, rowList: [5, 10, 20, 50], sortname: 'Id', sortorder: "asc", viewrecords: true, imgpath: '/scripts/themes/redmond/images', caption: 'Hovedsteder i ulike land. Demotest.' }); }); `

Man ser i json-egenskapen url hvordan jQuery Griden kobles mot server metoden
Index i HomeController.cs, som er tilgjengelig i route /Home/Index. MVC er litt
spesielt for ASP.NET utviklere, men etter å ha brukt det kun noen få dager ser
jeg vesentlige fordeler med det. En ulempe er at det kan bli litt vanskeligere på
klienten siden, men implementasjonen på server siden blir mye mer strukturert. Utfordringene ligger i at ferdige komponenter som ASP.NET GridView ikke er tilgjengelig. Skal man bruke MVC må man lære seg javascript godt og benytte jQuery
og nye komponenter. Dette er noe av den mest spennende teknologien, sammen med Linq, som Microsoft har laget på år og dag.

Visual Studio 2008 løsning:
Last ned prosjekt [Zip-fil, 711 kB] her.

Framgangsmåte for å kjøre mitt demoprosjekt:
1. Lagre zip fil på C:\minmappe
2. Pakk ut zip fil fra pkt 1.
3. Dobbeltklikk på .sln fil og se at Visual Studio laster..
4. Når pkt 3. er ferdig, trykk på knappen F5 på tastaturet ditt.
5. Be amazed.

:o)

Sunday, 7 February 2010

Godbiten Javascript

Javascript er et fantastisk herlig programmeringsspråk.

Her er grunnene til at jeg liker javascript:
- Ingen klasser! Alt er objekter.
- Dynamisk tolket språk som ikke er strengt typet, full fleksibilitet mht utvidelse.
- Intet behov for generics eller innviklede mønstre for å oppnå det javascript
greier på en elegant måte.
- Det programmeringsspråket i verden flest mennesker har tilgang til, nemlig som
en tolker i en nettleser.
- Innebygd støtte for lambda-uttrykk og avansert funksjonalitet som Javascript har
arvet fra Scheme.
- Det herligste, mest elegante språket i verden!

Jeg håper Ecmascript 5 ikke lager en stor bloatware ut av Javascript, men at språket
sin nette eleganse og enkelhet bevares som i dag. Det er nettopp enkelheten og
fleksibiliteten som gjør Javascript så kraftig.

Jeg anbefaler å se videoene av Douglas Crockford på Yahoo! sin video side.

Spesielt følgende video anbefales!

JavaScript: The Good Parts.

Javascript har selvsagt sine "flaws" også og Douglas Crockford går gjennom disse på en hysterisk morsom måte. (Man må være innvidd i denne bransjen for å sette pris på slike ting da..).

Mvh Tore A

Jeg har undersøkt litt om man får kjøre raskere Javascript vha. document-fragments. Sentralt i denne teknikken er å benytte document.createDocumentFragment(). Dette er en "construct" eller byggekloss som tillater en å klargjøre store modifikasjoner i HTML DOM treet i en operasjon. Dermed slipper man "reflow", dvs. at nettleseren forsøker å tegne opp html dom treet, hver gang man setter inn et nytt element.

Jeg har testet teknikken ved å lage en Javascript kode som regner ut tiden det tar i antall millisekunder å sette inn 1000 elementer i et HTML nedtrekksliste, etter først å ha slettet 1000 elementer, hvis nødvendig, i samme nedtrekksliste. Enten ved å bruke document-fragments, eller ved å direkte manipulere HTML dom treet for hver iterasjon. Resultatene viser seg at effekten er mindre enn mange andre tester har vist, men det er størst effekt i Internet Explorer. IE er helt klart også den nettleseren med dårligst Javascript-ytelse for akkurat dette.

Resultatene ble som følger (målt i antall millisekunder, mindre er bedre=raskere!):
With Fragment Without Fragment
IE 8.0 608 1070
Firefox 3.6 77 100
Safari 4.0 69 74
Opera 10.5 77 76
Chrome 4.0 87 92

Resultatene er etter kjøring av Javascript som setter inn 1000 elementer og sletter hvis nødvendig de 1000 elementene først og hvert case er kjørt 10 ganger og tatt gjennomsnitt av. IE 8.0 er nesten dobbelt så rask med document-fragment teknikken som uten. Likevel er IE 8.0 i sin egen liga i å være tregere enn de andre nettleserne. Som man ser av tallene over er Safari 4.0 9x-10x raskere med fragment teknikken. Safari 4.0 er mer enn 12x raskere enn IE 8.0 uten fragment teknikken. Safari er forøvrig den raskeste browseren, både med og uten document-fragment. Opera, Safari og Chrome viser små hastighetendringer med document-fragment. Opera 10.5 er faktisk litt raskere uten.. Chrome og Safari har små bedringer, ca. 5-10% raskere. Etter Safari er Opera raskest, Chrome og Firefox er ganske jevne. Chrome er tregere enn Firefox med document-fragment, men kjøringen uten document-fragment viser at Chrome er raskere enn Firefox 3.6. Firefox har ca. 30% raskere utførelse med document-fragment.

Konklusjonen må derfor være at document-fragment må absolutt brukes. IE 8.0 er meget treg i sin Javascript-ytelse og doblingen i hastighet (100% raskere) er nødvendig å utføre. Er du opptatt av hastigheten til webapplikasjonene dine i IE 8.0 er document-fragment meget viktig å bemerke seg med andre ord. For de andre nettleserne er det Firefox 3.6som er mest følsom for document-fragment, med 30% raskere utførelse. De andre browserne har 10-5% økning i raskere utførelse, men for dette caset hadde Opera 10.5 Alpha -1 til -5% økning i hastighet.. Safari er forøvrig den aller raskeste nettleseren. Det at Safari 4.0 skal med en slik enkel test med HTML DOM manipulasjon i javascript være mellom 9x-12x raskere enn IE 8.0: Dette er for dårlig Microsoft! Hvis IE 9 skal bli tatt seriøst som en nettleser og tatt i betraktning Microsoft sine enorme finansielle muskler, må de seriøst fikse Javascript hastigheten sin. Er du på utkikk etter den aller raskeste browseren gir denne testen en klar indikasjon på at JS-ytelsen i Safari er best. Opera og Chrome er hakk i hæl, Firefox sist av disse fire, men langt foran IE 8.0. Det skal nevnes at Opera 10.5 Alpha er en Alpha-versjon og kanskje kan nå opp til Safari 4.0.4 sine høyder i nær framtid..

Legg merke til den dramatisk raskere utførelsen i IE 8.0 med document-fragment. Ikke alle nettlesere har spesiell stor ytelsesforbedring, ca. 5-30%, med Firefox som den nettleseren som nyter best av å benytte document-fragment.

Her er testen vist under kjøring i Google Chrome 4.0:

Jeg vil nå oppsummere resultatene fra denne testen:
- Kjører man IE 8.0 må nesten document.createDocumentFragment() benyttes når store
HTML DOM manipulasjoner kjører i nettleseren, pga IE 8.0 sin dårlige hastighet.
- IE 8.0 er 9x-12x tregere enn Safari 4.0.4 i JS-ytelse. Dette er ikke bra Microsoft..
- For de andre nettleserne er det også bra å bruke document.createDocumentFragment(), forbedringen er 5-30%, men Opera hadde ikke noen ytelsesforbedring..
- Generelt sett, benytt document-fragment likevel, evt. unngå det for Opera med
oppdaging av klientens nettleser..
- Testen viser at Safari 4.0.4. er aller raskest, Opera 10.5 og Chrome 4.0 er hakk i hæl. Firefox 3.6 er nest tregest, men milevis foran IE 8.0 i JS-ytelse.

For de som ønsker å teste ut selv, kan de laste ned en zippet versjon av løsningen som jeg laget i Visual Web Developer Express 2008 her:
Document Fragment Demo Test Solution.

For å teste gjør følgende:
1. Pakk ut .zip filen
2. Åpne .sln filen
3. Når Visual Studio er startet, trykk F5 for å starte.

Klikk på de to knappene for å kjøre tester med document-fragment i ulike nettlesere.

Da skulle vel Microsoft-utviklere der ute ha noen pekepinner om hvor skoen trykker i
JS-ytelse for neste versjon av IE 9.x! De øvrige nettleserne er mindre følsomme for document.createFragment() men man bør unngå reflow inne i iterasjoner i javascript, eller spesifisere det enklere på en måte som er optimert for hastighet. Problemet ligger her i at nettleseren ønsker å holde GUI-visuelt oppdatert hele tiden. I en iterasjon er ikke det nødvendigvis en god teknikk for en nettleser. Klienten vil jo helst ha innholdet sitt og starte å jobbe videre, nettlesere er jo som kjent single-threaded miljø når det kommer til GUI. Da bør nettlesere unngå reflow inne i iterasjonen og først starte med en reflow rett etter en slik for-loop slik at man slipper å gjøre rene hacks for å få nettleseren til å være rask og responsiv.

Jeg limer inn javascript-koden her til slutt:
`///Runs a desired function, returns amount of millisecond the function took to perform before completing.function timedFunction(func) {if (typeof func == 'function') {var startTime = (new Date()).getTime();func();var endTime = (new Date()).getTime();return (endTime - startTime);} //ifreturn 0;}function generate_thousand_option_elements_in_dropdown_with_document_fragment() {var optionsFragment = document.createDocumentFragment();var ddltest = document.getElementById("ddlTest");var len = 0;while (len = ddltest.options.length) {ddltest.options[len-1] = null;} for (var i = 1; i <= 1000; i++) { var optiontoadd = document.createElement("option"); optiontoadd.value = i; optiontoadd.appendChild(document.createTextNode("Option " + i)); optionsFragment.appendChild(optiontoadd); } ddltest.appendChild(optionsFragment); } var withoutFragmentTest = 0; function generate_thousand_option_elements_in_dropdown_without_document_fragment() { withoutFragmentTest++; var ddltest = document.getElementById("ddlTest"); var len = 0; while (len = ddltest.options.length) { ddltest.options[len-1] = null; } for (var i = 1; i <= 1000; i++) { var optiontoadd = document.createElement("option"); optiontoadd.value = i; optiontoadd.appendChild(document.createTextNode("Option " + i)); ddltest.appendChild(optiontoadd); } }generate_thousand_option_elements_in_dropdown_without_document_fragment var withFragmentTest = 0; function testDocumentFragment() { withFragmentTest++; var resultRun = timedFunction(generate_thousand_option_elements_in_dropdown_with_document_fragment); if (resultRun != 'undefined') { var resultParagraphNode = document.createElement("p"); var resultParagraphTextNode = document.createTextNode("Ran test #"+ withFragmentTest + " with document fragment. Test took: " + resultRun + " milliseconds."); resultParagraphNode.appendChild(resultParagraphTextNode); document.getElementById("resultList").appendChild(resultParagraphNode); } //if }testDocumentFragment () function testWithoutDocumentFragment() { var resultRun = timedFunction(generate_thousand_option_elements_in_dropdown_without_document_fragment); if (resultRun != 'undefined') { var resultParagraphNode = document.createElement("p"); var resultParagraphTextNode = document.createTextNode("Ran test #" + withoutFragmentTest + " without document fragment. Test took: " + resultRun + " milliseconds."); resultParagraphNode.appendChild(resultParagraphTextNode); document.getElementById("resultList").appendChild(resultParagraphNode); } } testWithoutDocumentFragment `

Thursday, 28 January 2010

Slider-kontroll på web

Jeg har testet ut Scriptaculous, som er et javascript bibliotek myntet på gui og effekter i gui. Det har blant annet en slider kontroll, som jeg har laget et testprosjekt for. Slideren ser meget elegant ut og er vel så god som den som
Silverlight kan tilby. Best av alt er at man har tilgang til HTML DOM-treet og lett kan lese ut og sette verdier til Slideren.

For å laste ned testprosjektet, last ned her [ZIP-fil,101kB].

Start prosjektet på følgende måte:
* Pakk ut Zip-filen TestSliderScriptaculous.zip i en midlertidig mappe.
* Åpne denne mappen og dobbeltklikk på .sln filen.
* Når Visual Studio er lastet (Jeg har anvendt Visual Web Developer 2008 Express):
* Trykk på F5 for å snurre film.
* Standard nettleser skal så åpne og man presenteres siden Default.aspx hvor jeg har
implementert testprosjektet.

Øverst i denne artikkelen ser du et skjermbilde hvordan slideren ser ut. Like elegant som den du ser i Mac OS X, eller hva? Slideren er selvsagt interaktiv. Klikk og dra på slider handelen (håndtaket) og slipp for å sette en verdi for slideren. For dette testprosjektet har jeg satt 0 og 100 som verdiintervallet og alle titallsverdier som diskrete verdier. Hvis man ikke setter noen verdier her vil man med slideren spesifisere en verdi mellom 0 og 1 som et flyttall.

Dette er en meget kraftig måte å presentere en slider på i web. Man benytte denne kontrollen i for eksempel en Ajax-aktivert Web 2.0. applikasjon, for eksempel for å sette en tallverdi, e.g. 0 til 100 prosent gjennomsiktighet i en bilde-applikasjon eller parametere inn til et filter i en bilde-applikasjon.

Script.aculo.us inneholder nok mange andre godbiter, jeg har ikke fått testet ut rammeverket noe mye enda. Sliderkontrollen var meget lett å få til å virke, det tok meg kun 2-3 timer å få ferdigstilt testprosjektet. Om noen kjenner andre gode demoer av Script.aculo.us, si i fra. Litt kjapt nettsøk viser at det er tonnevis av demoer der ute.

Dette testprosjektet inneholder Script.aculo.us i Script mappen, som er rett og slett noen få .js filer.

Script.aculo.us nettside (inkluderer nedlasting):

Friday, 8 January 2010

Stor suksess med tidligere prosjekt hos NOIS!

Jeg søkte nettopp på nettet etter 'NOIS' og 'WORM' som er et akronym for 'Web Office Resource Management'. Jeg kom over en artikkel skrevet av Thor Hestnes i InnoDesign med tittel "Hull i veien? Klag på nettet!". Den tar for seg Samferdselsetaten i Oslo sin webløsning WORM, som er skrevet av meg når jeg jobbet som konsulent i NOIS i 10 måneder. Nå viser det seg at Samferdselsetaten har hatt stor glede av denne webløsningen! Ikke verst!

Løsningen er publisert her:
http://melding.samferdselsetaten.oslo.kommune.no/

Artikkelen er så rosende og full av lovord om webapplikasjonen jeg laget at jeg nesten datt av stolen :-)

Løsningen er laget med ASP.NET, programmert i VB.NET og Javascript er anvendt en god del.

Litt skryt kan man bare se her!

"Hull i veien? Klag på nettet!
Thor Hestnes
02.09.2009 20:11

Noe i veien der du ferdes i Oslo?
Meld fra til samferdselsetaten på nettet!

Samferdsels-etaten i Oslos satsing på en tettere kommunikasjon med byens borgere, er online. Etatens kundetorg på nettet er i ferd med å bli en suksess etter bare noen måneders drift.

Ved hjelp av Norconsult Informasjonssystemers WinMap-baserte, skreddersydde meldingssystem kan Oslos innbyggere nå på en enkel måte gå inn på nettet og melde fra om kommunale samferdselsproblemer som opptar dem.

Ekstraservice, det er samferdselsetaten det

Men ikke bare det, forteller etatens prosjektleder Stein Arild Sandnes: ― Folk kan også følge med om noe fysisk blir gjort med «klagen». Det være seg reparasjoner av hull i veien, gatelys, signalanlegg, eller brøyting, strøing, salting osv. Denne ekstraservicen er vi ganske alene om på kommunalt plan. Selvbetjeningen innfører en mye tettere brukerdialog og fremmer bedre tilfredshet med kommunens tjenester.

Ambisiøs orm

WORM heter programnyvinningen. Web Office Resource Management står det for og beskriver egentlig godt ambisjonen med kommunens satsing. Systemet er nemlig ment å være mye mer enn bare et meldingssystem. I WORM ligger også moduler for planlegging av graving, asfaltering, mindre byggearbeider osv. Det er med andre ord et oppfølgings-, kontroll- og beslutningsstøttesystem for kommunen. Et system som de kan bruke til å styre og utnytte ressursene bedre med.

Kartbasert nettløsning

― Det hele startet i 2005, forteller Sandnes. ― Etaten ønsket et nytt meldingssystem for å kunne forbedre kommunikasjonen med publikum og entreprenørene som utfører arbeidet på vegne av kommunen. Etaten bestemte seg for å bruke et kartsystem som informasjonsbærer for å gjøre brukerdialogen og oppfølgingen enklest mulig.

Valget falt på NOIS (Norconsult Informasjonssystemer) som utviklingspartner og WinMap som kartmotor i løsningen.

― Ved å klikke deg inn på den veiviserbaserte kartapplikasjonen på etatens nettside velger du først meldingstypen fra en meny, forklarer Sandnes og prøver å tegne et bilde av hvordan systemet fungerer. ― Dernest spesifiserer du nøyaktig hvor på kartet problemet ligger, gir en kort beskrivelse av hva saken dreier seg om, og klikker til slutt meldingen direkte til etatens kundetorg. Her blir de løpende behandlet i henhold til gitte behandlingsregler og formidlet til rette ansvarlige i etaten, som til slutt utsteder arbeidsordre til avtalefestet entreprenør som utfører oppdraget. Alt er helt dynamisk.

Genialt enkelt, helt enkelt

― Når jobben så er gjort er det entreprenørens plikt å gå inn på det samme systemet og endre status slik at det røde merket på kartet endres til grønn, som beskriver at jobben er utført. Noe også publikum kan se, poengterer Sandnes.

Og alle hjerter gleder seg… Ja, for dette har i følge Sandnes ført til mange konstruktive tilbakemeldinger fra publikum i løpet av vinteren og våren. Og samtidig positive erfaringer for samferdselsetaten.

Synliggjør arbeidet

Nesten 2800 meldinger ble registrert i løpet av 3 ½ måned i vinter. Mye snøfall voldte selvsagt mange henvendelser. Nesten 1800 dreide seg om brøyting, ca 600 rapporterte om hull i veien…

― Systemet gir oss mye mer korrekt innrapportering og det synliggjør jobben som gjøres av entreprenørene, fortsetter Stein Arild Sandnes. ― Med oversiktlig statistikk kan vi enkelt sammenstille og kontrollere arbeidsområder og tiltak.

Lønnsom pionervirksomhet

― Systemet er ganske komplisert med avansert filtreringslogikk, fortsetter han. ― Det ligger en stor applikasjon rundt kartmotoren. Systemet er unikt. Det er rett og slett pionervirksomhet det vi gjør.

― Men det fungerer utmerket. Vi har nesten ikke hatt nedetid siden oppstarten. Og publikumstilbakemeldingen er veldig bra. De er imponert over ekstraservicen vi gir dem.

― For kommunens del får vi nå en mye bedre totaloversikt og sparer ressurser både på den ene og andre måten, mener Sandnes. ― Effektiviteten og kontrollen er bedret betraktelig. Ikke minst ved enkel gjenfinning av informasjon og gjennom verdifull statistikk. For kontrollseksjonen, som er en hyppig bruker av systemet, er det betydelig enklere å følge opp og kontrollere at tingene utføres i henhold til kontrakt.

Enklere hverdag

― Kundetorget som til daglig jobber mest med meldingssystemet, har for øvrig fått fordelen av kun én applikasjon å forholde seg til. Et stort pluss og en drastisk bedring av situasjonen, slutter Stein Arild Sandnes og ser frem til å tilfredsstille enda flere, nye behov som underveis har dukket opp.

Mandatet er nemlig utviklet ytterligere etter de gode resultatene. Oslos ansatte og borgere kan forhåpentlig vente seg en stadig enklere hverdag…"

Må si meg fornøyd med en slik omtale.

Og det er visst mer skryt i vente, les bare Aftenposten...

http://www.aftenposten.no/nyheter/oslo/article3317321.ece

Det har visst blitt bedre veger i Oslo, blant annet pga. meg.