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
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="ImagePath" value="C:\Path\To\My\Images\"/>
<add key="PaddingLeft" value="10" />
<add key="PaddingRight" value="10" />
<add key="PaddingBottom" value="100" />
<add key="PaddingTop" value="0" />
</appSettings>
</configuration>
