Category Archives: .Net

F# Image Processing – Get Background Color

I recently had the need to get the background color of an image. The algorithm used to perform this is simple:

Get the image and find the color that occurs at least 3/4 of the time more than the next most occurring color in the image.

Here are some examples of images and what we would expect as a result.

image

The background image color is white.

image

The background image color is red.

image

The background image color is white.

Now, without further ado, here is the F# code. It should be relatively easy to follow.

Main.fs

open System
open System.Text.RegularExpressions
open System.IO
open System.Windows.Forms
open System.Windows.Forms.DataVisualization.Charting
open System.Diagnostics

[<EntryPoint>]
let main (args: string[]) = 

    let sw = new System.Diagnostics.Stopwatch()
    sw.Start()
    for i = 21 to 21 do
        let img = "C:\\Temp\\ImageSamples\\" + Convert.ToString(i) + ".jpg"
        // get the image
        let bitmap = new System.Drawing.Bitmap(img)
        // process image
        let background = AboutDev.ImageProcessing.GetBackgroundColor(bitmap)
        printfn "%A is: %i, %i, %i" i background.R background.G background.B
        bitmap.Dispose()

    sw.Stop()
    printfn "Time elapsed: %A" sw.Elapsed
    0

 

ImageProcessing.fs

namespace AboutDev

    #light
    #nowarn "9"
    open System
    open Microsoft.FSharp.NativeInterop
    open Microsoft.FSharp.Collections
    open System.Drawing
    open System.Drawing.Imaging 
    open System.Collections.Generic

    module ImageProcessing = begin

        let GetBackgroundColor (image:Bitmap) =

            // Get a Color from RGB values
            let GetColor x  = Color.FromArgb(Convert.ToInt32(int16 (NativePtr.get x 0)) , Convert.ToInt32(int16 (NativePtr.get x 1)) , Convert.ToInt32(int16 (NativePtr.get x 2)))

            // Check for grayscale images
            let IsGrayscale (x:Color) = x.R < 128uy && x.G < 128uy && x.B < 128uy

            // Create a thumbnail only if the image is more that the allowable size of 300 * 300 pixels
            let ToThumbnailOrNot (b:Bitmap) = 
                let maxAllowedDimensions = 300

                // Create a thumbnail that is sized proportionately to the original
                let CreateThumbnail (b:Bitmap) = 
                    let maxPixels = 100.0

                    // compute the scaling factor of the original image to our max allowed pixels
                    let scaling = if(b.Width > b.Height) then maxPixels / Convert.ToDouble(b.Width)
                                  else maxPixels / Convert.ToDouble(b.Height)
                    // compute the size of the new image as a sequence
                    let size = (Convert.ToInt32(Convert.ToDouble(b.Width) * scaling), Convert.ToInt32(Convert.ToDouble(b.Height) * scaling))
                    // create the thumbnail
                    new System.Drawing.Bitmap(b.GetThumbnailImage(fst size, snd size, null, IntPtr.Zero))

                if b.Width > maxAllowedDimensions && b.Height > maxAllowedDimensions then CreateThumbnail b
                else b

            // Get a thumbnail of the image if it is big or use the original image
            let img =  ToThumbnailOrNot image

            // dispose the original image because a copy was made in the previous statement
            //image.Dispose()

            // The array that is going to contain argb values to then do counts on
            let items = List<int32>()

            // lockbits on image so that the image can be processed quicker using unsafe means
            let bd = img.LockBits(Rectangle(0,0,img.Width,img.Height),ImageLockMode.ReadWrite,PixelFormat.Format32bppArgb)

            // pointer to use to go through the image
            let mutable (p:nativeptr<byte>) = NativePtr.ofNativeInt (bd.Scan0)
            for i=0 to img.Height-1 do
                for j=0 to img.Width-1 do
                    // Get the color of the [x,y] pixel
                    let colo = (GetColor p).ToArgb()
                    // add the ARGB value to our list
                    items.Add(colo)
                    // move to the next pixel on the row
                    p <- NativePtr.add p 4
                done
                // The stride - the whole length (multiplied by four to account for the fact that we are looking at 4 byte pixels
                p <- NativePtr.add p (bd.Stride - bd.Width*4)
            done

            // Unlock the image bytes
            img.UnlockBits(bd)

            // test code to see the image we worked on
            //img.Save("C:\\temp\\result.jpg",  System.Drawing.Imaging.ImageFormat.Jpeg)

            // dispose the image that we worked on
            img.Dispose()

            //List.ofSeq items |> Seq.countBy id |> Seq.sortBy (fun x -> (~-)(snd x) ) |> Seq.take 10 |> Seq.iter (printfn "%A")

            // get the first two item that occur the most in the array as a sequence
            let res = List.ofSeq items |> Seq.countBy id |> Seq.sortBy (fun x -> (~-)(snd x) )

            // Check to see that we have at least 2 colors
            if ( (Seq.length res) < 2) then res |> Seq.head |> fst |> Color.FromArgb
            else

                let zero = Seq.head res     // first item in the sequence
                let one = Seq.nth 1 res     // second item in the sequence

                // Get the most prominent color
                let background = fst zero |> Color.FromArgb
                let background2 = fst one |> Color.FromArgb

                // Make sure the image is not grayscale and
                // the background color occurs at least 3/4 as much as the next closest color

                if( (IsGrayscale background) || (((Convert.ToDouble (snd zero)) * 0.75) < (Convert.ToDouble (snd one)))) 
                    then //printfn "Cannot determine color"
                         //printfn "First color is: %A, %A, %A" background.R background.G background.B
                         //printfn "Second color is: %A, %A, %A" background2.R background2.G background2.B
                         Color.Empty
                else               
                    //printfn "%A, %A, %A" background.R background.G background.B
                    // Return the color
                    background

    end // End Module
NOTE: The sample code above is just that, a sample. You will need to play with it to do your bidding.

To set this up this comparison, I had a sample size of 20 images. The original code without my algorithm optimizations took 31.62 seconds to run. The F# code took 0.78 seconds.

Original Code F# Code
image image

Optimizations I made over the original code:

1. Use of LockBits

2. Creating thumbnails of the original image to work on instead of the original image when that image is large.

During my testing, I also created an image that was 13,648 * 7,912 and it took [00:00:01.2340651] to process it in my F# code. I had to stop the original C# code running on that image after 10 min! When I implemented my algorithm in C#, I was able to get the speed of the 20 images to 7.88 seconds. Still faster in F#.

image

 

F# allowed me to play with the algorithm very easily and tweak away until I got it just right.

You have to love the power of a language that lets you focus on the algorithm rather than on the minutiae of the language.

Tagged , , , , , , ,

Presentation Slides – An introduction to F#

On Saturday 5th November 2011, I presented a talk on F# and Functional Programming at Desert Code Camp. It was my first time at DCC and I must admit I thoroughly enjoyed interacting with people who enjoy technology and learning new things like me.I got to meet some great attendees and speakers. Lets not forget the immense time and effort given by the volunteers and organizers of Desert Code Camp as well.

I think the best part of my speech was getting people excited about F# and hearing the wows and praises for F# and my presentation after. You guys rock!

Also, congratulations to the two F# book giveaway winners.

I wanted to post the presentation slides for anyone who wanted it. I have tried to add the sample code to the presentation slides as well. Feel free to contact me if you have any questions.

An Introduction to F# – Sushant Bhatia (.PPTX)
An Introduction to F# – Sushant Bhatia (.PDF)

Edit: The presentation is not looking nice in Google Docs. I will try and get a PDF of the entire presentation up tonight. It should also contain the notes that I put so that you can try out the code.

Tagged , , , , ,

ASP.NET MVC Caching Dynamically generated JavaScript

One of the things you may occasionally have to do while using JavaScript is show dialogs and react to your users inputs. These could be in the form of alert boxes that are built into the language, growls, loading panels or even just a message added to an element. (Side note: The jQuery BlockUI plugin seems very promising).

The discerning user would realize that a website that targets a global audience has to be able to localize, globalize and internationalize to their language and a good starting place is to look at Scott Hanselman’s post on this very topic.

Globalization, Internationalization and Localization in ASP.NET MVC 3, JavaScript and jQuery – Part 1

One hacky way to get localized strings in JavaScript when they are in separate files is to have a localized file with all the localized text in it. Then based on the users language preference, load up the appropriate file and use the strings from there. But what if the strings come from a database and you need to generate this at runtime to be able to handle change without deployment again. Well here is how you can do it.

Read the article on JavaScriptView by elegantcode for more details. However, to summarize here are their steps:

  1. Create a controller method that return the view as a JavaScriptFileResult preferably in your home controller.
  2. Create a view that contains the localized strings in an array. I used a helper method to get the contents from the database dynamically. You may wish to add this to your home controllers view folder as well.
  3. Add a script block in the shared layout’s header to the URL for the JavaScript file.

All well and good. The file will now come down with the rest of the content as a JavaScript file and you can use the array of localized strings in your other JavaScript code.

BUT! The one problem you may notice is that the JavaScript source file is retrieved every time a request is made to the server. Thus you will need to cache it. To do so, we just need to add the OutputCacheAttribute onto the controller method that returns the JavaScript file.

[OutputCache(Location = System.Web.UI.OutputCacheLocation.ServerAndClient, Duration = 900, VaryByParam = "none")]

The only problem here is that the VaryByParam is set to none. That’s because we don’t have any parameters being passed into the method. This is a problem because two different requests can come in for varying locales and now the second one may get the cached value of the first one. Therefore, we need to pass in the locale as a parameter and then VaryByParam on that field. This will ensure that every locale has the file cached and changes made can go out without requiring a deployment of files to the server.

JsConstants

The script block in the _Layouts.cshtml file.

<script src="@Url.Content("~/Home/JsConstants?lcid=" + System.Threading.Thread.CurrentThread.CurrentCulture.LCID)" type="text/javascript"></script>

But of course, who wants to keep sending these Id’s over all the time for all our script files. So, the easiest way to do this would be to create an identifier that can be used to check language automatically. And then we can write, “lang” in the VaryByParam attribute option and remove the lcid parameter from JsConstants.

[OutputCache(Location = System.Web.UI.OutputCacheLocation.ServerAndClient, Duration = 900, VaryByParam = "lang")]

The code to make this work is as follows. [Sorry but I’m not quite sure where I found this gem from]

public override string GetVaryByCustomString(HttpContext context, string value)
{
	if (value.Equals("lang"))
	{
		return Thread.CurrentThread.CurrentUICulture.Name;
	}
	return base.GetVaryByCustomString(context,value);
}

fidllerJsConstants

As you can see from the image above, the first request for the JsConstants file containing the JavaScript returned 918bytes of data. Whereas, the subsequent call returned 0 bytes. The raw message returned reads as follows:

HTTP/1.1 304 Not Modified
Cache-Control: private, max-age=863
Expires: Sat, 03 Sep 2011 22:57:26 GMT
Last-Modified: Sat, 03 Sep 2011 22:42:26 GMT
Vary: *
Server: Microsoft-IIS/7.5
X-Powered-By: ASP.NET
Date: Sat, 03 Sep 2011 22:43:03 GMT

This indicates that we are able to cache the contents of the JavaScript file that was being generated dynamically and it will be refreshed after the Duration we set (900).

Happy Coding.

kick it on DotNetKicks.com

Generating Object Classes from XML

I ran into a need for generating classes that xml data can be deserialized into. I generally write this myself but today, I needed to do it faster.

Along came the Visual Studio XSD tool.

Open a VS command prompt.
Type ‘xsd file.xml’. This will generate a file.xsd.
Then type, ‘xsd file.xsd /classes’. This will generate a file.cs file that you can then use to deserialize into.

For more details, check out this cool link http://sharpertutorials.com/using-xsd-tool-to-generate-classes-from-xml/

Poor Man’s Validation

Does your validation drive you crazy? Are you writing too much validator code? Have you lost your sense of humor?

image

Well, not to worry because now, there’s a little hack to make Validation easier.

Lets say I had a Company class as defined by:

    public class Company
    {
        public string Title
        {
            get;
            set;
        }
    }

Now, say I wanted to add validation to this so that the

  • Title is Required
  • Title must be up to 10 characters
  • Title can only be Alpha and space

In order to achieve this quickly, you can add the System.ComponentModel.DataAnnotations.dll file to your project (Make sure its the latest one from Codeplex). Then update your class definition as follows:

    public class Company
    {
        [Required]
        [StringLength(10)]
        [RegularExpression("[A-Za-z\\s]+")]
        public string Title
        {
            get;
            set;
        }
    }

Now you can run the following code to validate your class instance as follows:

    //
    // Test instantiation
    ValidationContext vc = null;
    bool bCanCreate = false;
    List<ValidationResult> validationResults = new List<ValidationResult>();
    Company _company = new Company();

    //
    // Test 1 : Acceptable test undeo 10 characters and alpha.
    _company.Title = "The Title";
    vc = new ValidationContext(_company, null, null);
    bCanCreate = Validator.TryValidateObject(_company, vc, validationResults, true);
    Debug.Assert(bCanCreate == true);

    //
    // Test 2: Failure test 
    _company.Title = "32 Pan";
    vc = new ValidationContext(_company, null, null);
    bCanCreate = Validator.TryValidateObject(_company, vc, validationResults, true);
    Debug.Assert(bCanCreate == false);

    //
    // Test 3: Failure test 
    _company.Title = "";
    vc = new ValidationContext(_company, null, null);
    bCanCreate = Validator.TryValidateObject(_company, vc, validationResults, true);
    Debug.Assert(bCanCreate == false);

    //
    // Test 4: Failure test 
    _company.Title = "abcdefghijklm nopqrstuvwxyz";
    vc = new ValidationContext(_company, null, null);
    bCanCreate = Validator.TryValidateObject(_company, vc, validationResults, true);
    Debug.Assert(bCanCreate == false);

So now you’re bound to be validator approved.

image

Tagged , , , , ,