Remove Surrounding White Space From An Image

February 14, 2010

The following is from my post on StackOverflow.com

I have a block of product images we received from a customer. Each product image is a picture of something and it was taken with a white background. I would like to crop all the surrounding parts of the image but leave only the product in the middle. Is this possible?

As an example: http://www.5dnet.de/media/catalog/product/d/r/dress_shoes_5.jpg

I don’t want all white pixels removed, however I do want the image cropped so that the top-most row of pixels contains one non-white pixel, the left-most vertical row of pixels contains one non-white pixel, bottom-most horizontal row of pixels contains one non-white pixel, etc.

Below is the solution to my problem. It is not the most glamorous approach, but it works. I could have use Bitmap.Lockbits() to lock the bitmap in memory and do my processing there, but this approach below sufficed my needs. It is a pixel by pixel scan of the image.

Some recommended additions/changes if you are feeling inclined:

  • Use Bitmap.Lockbits() to improve performance
  • Perform image resizing after the trimming is completed.
  • Instead of looking for straight white pixels, you could also exclude near-white pixels (for any shadows).

Start.vb

Imports System.Drawing
Imports System.IO
Imports System.Configuration.ConfigurationManager

Module Start

       Sub Main()
       	   Try
	       Console.WriteLine("")
	       Console.WriteLine("Begin:  Crop Images")
               CropAllImages()
           Catch e As Exception
               Console.WriteLine("Error Message: " & e.Message)
               Console.WriteLine("----------")
               Console.WriteLine("Error Stack: " & e.StackTrace)
           End Try
       End Sub

       Sub CropAllImages()
           Dim iTopMostPixel As Integer, iLeftMostPixel As Integer, iRightMostPixel As Integer, iBottomMostPixel As Integer
           Dim objBmp As Bitmap, objNewBmp As Bitmap
           Dim rect As Rectangle
           For Each oFile As FileInfo In New DirectoryInfo(AppSettings("ImagePath")).GetFiles("*.jpg")
               objBmp = CType(Bitmap.FromFile(AppSettings("ImagePath") & oFile.Name), Image)
               iTopMostPixel = GetNonWhitePixel(objBmp, 1) + AppSettings("PaddingTop") ' Get the top most pixel and add any optional padding
               iLeftMostPixel = GetNonWhitePixel(objBmp, 2) + AppSettings("PaddingLeft") ' Get the left most pixel and add any optional padding
               iBottomMostPixel = GetNonWhitePixel(objBmp, 3) + AppSettings("PaddingBottom")
               iRightMostPixel = GetNonWhitePixel(objBmp, 4) + AppSettings("PaddingRight")
               rect = New Rectangle(iLeftMostPixel, iTopMostPixel, iRightMostPixel - iLeftMostPixel, iBottomMostPixel - iTopMostPixel)
               objNewBmp = objBmp.Clone(rect, objBmp.PixelFormat)
               objNewBmp.Save(AppSettings("ImagePath") & Replace(oFile.Name, oFile.Extension, "_cropped" & oFile.Extension), Imaging.ImageFormat.Jpeg)
               Console.WriteLine("Saved: " & AppSettings("ImagePath") & Replace(oFile.Name, oFile.Extension, "_cropped" & oFile.Extension))
               objNewBmp.Dispose()
               objBmp.Dispose()
           Next
       End Sub

       Function GetNonWhitePixel(ByVal objBmp As Bitmap, ByVal iPixelType As Integer) As Integer
           Dim objColor As Color
             Select Case iPixelType
               Case 1
                     ' Top pixel
                   For y = 0 To objBmp.Height - 1
                       For x = 0 To objBmp.Width - 1
                           objColor = objBmp.GetPixel(x, y)
                           If Hex(objColor.R) & Hex(objColor.G) & Hex(objColor.B) <> "FFFFFF" Then Return y
                       Next
                   Next
                 Case 2
                     ' Left pixel
                   For x = 0 To objBmp.Width - 1
                       For y = 0 To objBmp.Height - 1
                           objColor = objBmp.GetPixel(x, y)
                           If Hex(objColor.R) & Hex(objColor.G) & Hex(objColor.B) <> "FFFFFF" Then Return x
                       Next
                   Next
                 Case 3
                     ' Bottom pixel
                   For y = objBmp.Height - 1 To 0 Step -1
                       For x = 0 To objBmp.Width - 1
                           objColor = objBmp.GetPixel(x, y)
                           If Hex(objColor.R) & Hex(objColor.G) & Hex(objColor.B) <> "FFFFFF" Then Return y
                       Next
                   Next
                 Case 4
                     ' Right pixel
                   For x = objBmp.Width - 1 To 0 Step -1
                       For y = 0 To objBmp.Height - 1
                           objColor = objBmp.GetPixel(x, y)
                           If Hex(objColor.R) & Hex(objColor.G) & Hex(objColor.B) <> "FFFFFF" Then Return x
                       Next
                   Next
             End Select
             ' Nothing found
           Return 0
       End Function
   End Module

app.config


   
       
           
             
           
           
           
       
   
Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)

posted in Uncategorized by admin

Follow comments via the RSS Feed| Trackback URL

 
Powered by Wordpress and MySQL. Theme by Shlomi Noach, openark.org