Hi,
I am writing a program that uses content aware resizing (http://en.wikipedia.org/wiki/Seam_carving) to resize an image. As I understand it, this type of resizing essentially comes down to adding/removing slices from an image with the lowest amount of detail.
Any way, the code works except for the fact that is rather slow. Reducing the width for an image of 1024x768 pixels by half takes about 3 minutes! :eek: And for some reason, the method I use only works when adding/removing vertical slices (to change the width). I eventually decided to simply rotate the image before and after resizing. It doesn't take much code or processing time, but it's a bit odd.
Below is the program's main module which contains everything required for resizing an image.
I did a search on the internet for code optimization in vb.net, but as far I can tell I either already did what was suggested or it didn't apply to my code. Does any one has any ideas of how to optimize my code?
I also attached the complete program in a .zip file. Usage:
-The program will display a file dialog at start up to allow the user to select an image.
-Press the "H" and "V" keys to select horizontal or vertical resizing.
-Specifying positive values will increase an image's size, and negative values will decrease the size.
I am writing a program that uses content aware resizing (http://en.wikipedia.org/wiki/Seam_carving) to resize an image. As I understand it, this type of resizing essentially comes down to adding/removing slices from an image with the lowest amount of detail.
Any way, the code works except for the fact that is rather slow. Reducing the width for an image of 1024x768 pixels by half takes about 3 minutes! :eek: And for some reason, the method I use only works when adding/removing vertical slices (to change the width). I eventually decided to simply rotate the image before and after resizing. It doesn't take much code or processing time, but it's a bit odd.
Below is the program's main module which contains everything required for resizing an image.
Code:
'This module's imports and settings.
Option Compare Binary
Option Explicit On
Option Infer Off
Option Strict On
Imports System
Imports System.Collections.Generic
Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.Linq
Imports System.Math
Imports System.Runtime.InteropServices.Marshal
Imports System.Windows.Forms
'This module contains this program's core procedures.
Public Module CAIRModule
'This enumeration contains a list of the supported seam directions.
Private Enum DirectionsE As Integer
Horizontal
Vertical
End Enum
'This structure defines a seam.
Private Structure SeamStr
Dim Energy As Integer 'Contains the seam's energy.
Dim Indexes As List(Of Integer) 'Contains the indexes of the seam's pixels.
End Structure
Private Const ARGBSize As Integer = 4 'The number of bytes in an alpha, red, green, and blue color value.
'This procedure adds/cuts the specified seam from the specified image.
Private Function AddOrCutSeam(ByRef Pixels As List(Of Byte), ByRef Seam As SeamStr, ByRef Add As Boolean) As List(Of Byte)
Try
With Seam
.Indexes.Sort()
.Indexes.Reverse()
If Add Then
For Each Index As Integer In .Indexes
Pixels.InsertRange(Index + ARGBSize, Pixels.GetRange(Index, ARGBSize))
Next Index
Else
For Each Index As Integer In .Indexes
Pixels.RemoveRange(Index, ARGBSize)
Next Index
End If
End With
Return Pixels
Catch ExceptionO As Exception
HandleError(ExceptionO)
End Try
Return Nothing
End Function
'This procedure returns the best vertical seam.
Private Function BestVerticalSeam(ByRef Pixels As List(Of Byte), ByRef Stride As Integer, ByRef Height As Integer) As SeamStr
Try
Dim BestSeam As SeamStr = VerticalSeam(Pixels, Stride, Height, 0)
Dim Seam As New SeamStr With {.Energy = 0, .Indexes = New List(Of Integer)}
If BestSeam.Energy = 0 Then Return BestSeam
For x As Integer = ARGBSize To Stride - ARGBSize Step ARGBSize
Seam = VerticalSeam(Pixels, Stride, Height, x)
If Seam.Energy < BestSeam.Energy Then BestSeam = Seam
Next x
Return BestSeam
Catch ExceptionO As Exception
HandleError(ExceptionO)
End Try
Return Nothing
End Function
'This procedure returns the difference between the two specified colors.
Private Function ColorDifference(ByRef Color1() As Byte, ByRef Color2() As Byte) As Integer
Try
Dim Difference As Integer = 0
For Index As Integer = Color1.GetLowerBound(0) To Color1.GetUpperBound(0)
Difference += Abs(CInt(Color2(Index)) - CInt(Color1(Index)))
Next Index
Return CInt(Difference / 3)
Catch ExceptionO As Exception
HandleError(ExceptionO)
End Try
Return Nothing
End Function
'This procedure returns the index of the lowest difference.
Private Function GetLowest(ByRef Differences() As Integer) As Integer
Try
Dim Lowest As Integer = 1
For Index As Integer = Differences.GetLowerBound(0) To Differences.GetUpperBound(0)
If Differences(Index) < Differences(Lowest) Then Lowest = Index
Next Index
Return Lowest
Catch ExceptionO As Exception
HandleError(ExceptionO)
End Try
Return Nothing
End Function
'This procedure handles any errors that occur.
Public Sub HandleError(ByRef ExceptionO As Exception)
Try
If MessageBox.Show(ExceptionO.Message, My.Application.Info.Title, MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation) = DialogResult.Cancel Then
InterfaceWindow.Close()
End If
Catch
InterfaceWindow.Close()
End Try
End Sub
'This procedure resizes the specified image.
Public Function ResizeImage(ByRef ResizedImage As Bitmap, ByRef Resizes As Integer) As Bitmap
Try
Dim BitmapDataO As BitmapData = Nothing
Dim BitmapStride As Integer = Nothing
Dim Buffer() As Byte = Nothing
Dim ImagePixels As New List(Of Byte)
If ResizedImage.Width + Resizes < 1 Then Resizes = -(ResizedImage.Width - 1)
With ResizedImage
BitmapDataO = .LockBits(New Rectangle(0, 0, .Width, .Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppPArgb)
ReDim Buffer(BitmapDataO.Stride * .Height)
Copy(BitmapDataO.Scan0, Buffer, Buffer.GetLowerBound(0), Buffer.GetUpperBound(0))
BitmapStride = BitmapDataO.Stride
.UnlockBits(BitmapDataO)
ImagePixels = Buffer.ToList
End With
For Resize As Integer = 1 To Abs(Resizes)
ImagePixels = AddOrCutSeam(ImagePixels, BestVerticalSeam(ImagePixels, BitmapStride, ResizedImage.Height), Add:=(Resizes > 0))
BitmapStride += If(Resizes > 0, ARGBSize, -ARGBSize)
Next Resize
ResizedImage = New Bitmap(CInt(BitmapStride / ARGBSize), ResizedImage.Height)
With ResizedImage
Buffer = ImagePixels.ToArray
BitmapDataO = .LockBits(New Rectangle(0, 0, .Width, .Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppPArgb)
Copy(Buffer, Buffer.GetLowerBound(0), BitmapDataO.Scan0, Buffer.GetUpperBound(0))
.UnlockBits(BitmapDataO)
End With
Return ResizedImage
Catch ExceptionO As Exception
HandleError(ExceptionO)
End Try
Return Nothing
End Function
'This procedure returns a vertical seam through the specified locked bitmap.
Private Function VerticalSeam(ByRef Pixels As List(Of Byte), ByRef Stride As Integer, ByRef Height As Integer, ByVal x As Integer) As SeamStr
Try
Dim CurrentIndex As Integer = Nothing
Dim Differences(0 To 2) As Integer
Dim NextIndex As Integer = Nothing
Dim Lowest As Integer = Nothing
Dim Seam As New SeamStr With {.Energy = 0, .Indexes = New List(Of Integer)}
For y As Integer = 0 To Height - 1
CurrentIndex = (y * Stride) + x
NextIndex = (y * Stride) + (x - ARGBSize)
Differences(0) = If(x >= ARGBSize, ColorDifference({Pixels(CurrentIndex), Pixels(CurrentIndex + 1), Pixels(CurrentIndex + 2)}, {Pixels(NextIndex), Pixels(NextIndex + 1), Pixels(NextIndex + 2)}), Byte.MaxValue)
NextIndex = ((y + 1) * Stride) + x
Differences(1) = If(y < Height - 1, ColorDifference({Pixels(CurrentIndex), Pixels(CurrentIndex + 1), Pixels(CurrentIndex + 2)}, {Pixels(NextIndex), Pixels(NextIndex + 1), Pixels(NextIndex + 2)}), Byte.MaxValue)
NextIndex = (y * Stride) + (x + ARGBSize)
Differences(2) = If(x + ARGBSize < Stride, ColorDifference({Pixels(CurrentIndex), Pixels(CurrentIndex + 1), Pixels(CurrentIndex + 2)}, {Pixels(NextIndex), Pixels(NextIndex + 1), Pixels(NextIndex + 2)}), Byte.MaxValue)
Lowest = GetLowest(Differences)
Seam.Energy += Differences(Lowest)
Seam.Indexes.Add(CurrentIndex)
If Lowest = 0 Then
x -= ARGBSize
ElseIf Lowest = 2 Then
x += ARGBSize
End If
Next y
Return Seam
Catch ExceptionO As Exception
HandleError(ExceptionO)
End Try
Return Nothing
End Function
End Module
I also attached the complete program in a .zip file. Usage:
-The program will display a file dialog at start up to allow the user to select an image.
-Press the "H" and "V" keys to select horizontal or vertical resizing.
-Specifying positive values will increase an image's size, and negative values will decrease the size.