Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. .NET (Core and Framework)
  4. Execution time difference between VB.Net and C# code

Execution time difference between VB.Net and C# code

Scheduled Pinned Locked Moved .NET (Core and Framework)
graphicscsharpdata-structuresperformance
5 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • T Offline
    T Offline
    TnTinMn
    wrote on last edited by
    #1

    A few weeks ago there I seen a question regarding converting colors to grayscale equivalents and it caught my interest. I found an article that presented various methods and decided to give it a try in VB.Net. This is my code.

    <System.Runtime.CompilerServices.Extension()> _
    Public Function ToGrayScale(ByVal img As Image, ByVal method As Methods) As Image
    If Not [Enum].IsDefined(GetType(Methods), method) Then
    Return Nothing
    End If

    ' set the grayscale function to use for conversion
    Dim gsfunc As Func(Of Color, Color) = Nothing
    Select Case method
    Case Methods.Average : gsfunc = AddressOf Average
    Case Methods.CorrectingForTheHumanEye_Gimp : gsfunc = AddressOf Gimp
    Case Methods.CorrectingForTheHumanEye_BT_601 : gsfunc = AddressOf BT_601
    Case Methods.CorrectingForTheHumanEye_BT_709 : gsfunc = AddressOf BT_709
    Case Methods.Desaturation : gsfunc = AddressOf Desaturation
    Case Methods.DecompositionMax : gsfunc = AddressOf DecompositionMax
    Case Methods.DecompositionMin : gsfunc = AddressOf DecompositionMin
    Case Methods.SingleColorRed : gsfunc = AddressOf SingleColorRed
    Case Methods.SingleColorGreen : gsfunc = AddressOf SingleColorGreen
    Case Methods.SingleColorBlue : gsfunc = AddressOf SingleColorBlue
    End Select

    ' create a 32bppArgb bitmap from source image
    Dim bm As New Bitmap(img.Width, img.Height, Imaging.PixelFormat.Format32bppArgb)
    Dim g As Graphics = Graphics.FromImage(bm)
    g.DrawImageUnscaled(img, Point.Empty)
    g.Dispose()

    Dim bmdata As System.Drawing.Imaging.BitmapData

    ' convert 1 row of pixels at a time
    Dim pixelcolors(0 To bm.Width - 1) As Int32
    For row As Int32 = 0 To bm.Height - 1

      ' lock the row in memory
      bmdata = bm.LockBits(New Rectangle(0, row, bm.Width, 1), \_
                           Drawing.Imaging.ImageLockMode.ReadWrite, \_
                           bm.PixelFormat)
    
      ' get row data as array integer color
      System.Runtime.InteropServices.Marshal.Copy(bmdata.Scan0, pixelcolors, 0, bm.Width)
    
      ' convert each pixel color to grayscale using selected method
      For col As Int32 = 0 To bm.Width - 1
         pixelcolors(col) = gsfunc(Color.FromArgb(pixelcolors(col))).ToArgb()
      Next col
    
      System.Runtime.InteropServices.Marshal.Copy(pixelcolors, 0, bmdata.Scan0, bm.Width)
    
      bm.UnlockBits(bmdata) ' release memory lock
      bmdata = Nothing
    

    Next row

    Return bm

    End Function

    Every

    B R 2 Replies Last reply
    0
    • T TnTinMn

      A few weeks ago there I seen a question regarding converting colors to grayscale equivalents and it caught my interest. I found an article that presented various methods and decided to give it a try in VB.Net. This is my code.

      <System.Runtime.CompilerServices.Extension()> _
      Public Function ToGrayScale(ByVal img As Image, ByVal method As Methods) As Image
      If Not [Enum].IsDefined(GetType(Methods), method) Then
      Return Nothing
      End If

      ' set the grayscale function to use for conversion
      Dim gsfunc As Func(Of Color, Color) = Nothing
      Select Case method
      Case Methods.Average : gsfunc = AddressOf Average
      Case Methods.CorrectingForTheHumanEye_Gimp : gsfunc = AddressOf Gimp
      Case Methods.CorrectingForTheHumanEye_BT_601 : gsfunc = AddressOf BT_601
      Case Methods.CorrectingForTheHumanEye_BT_709 : gsfunc = AddressOf BT_709
      Case Methods.Desaturation : gsfunc = AddressOf Desaturation
      Case Methods.DecompositionMax : gsfunc = AddressOf DecompositionMax
      Case Methods.DecompositionMin : gsfunc = AddressOf DecompositionMin
      Case Methods.SingleColorRed : gsfunc = AddressOf SingleColorRed
      Case Methods.SingleColorGreen : gsfunc = AddressOf SingleColorGreen
      Case Methods.SingleColorBlue : gsfunc = AddressOf SingleColorBlue
      End Select

      ' create a 32bppArgb bitmap from source image
      Dim bm As New Bitmap(img.Width, img.Height, Imaging.PixelFormat.Format32bppArgb)
      Dim g As Graphics = Graphics.FromImage(bm)
      g.DrawImageUnscaled(img, Point.Empty)
      g.Dispose()

      Dim bmdata As System.Drawing.Imaging.BitmapData

      ' convert 1 row of pixels at a time
      Dim pixelcolors(0 To bm.Width - 1) As Int32
      For row As Int32 = 0 To bm.Height - 1

        ' lock the row in memory
        bmdata = bm.LockBits(New Rectangle(0, row, bm.Width, 1), \_
                             Drawing.Imaging.ImageLockMode.ReadWrite, \_
                             bm.PixelFormat)
      
        ' get row data as array integer color
        System.Runtime.InteropServices.Marshal.Copy(bmdata.Scan0, pixelcolors, 0, bm.Width)
      
        ' convert each pixel color to grayscale using selected method
        For col As Int32 = 0 To bm.Width - 1
           pixelcolors(col) = gsfunc(Color.FromArgb(pixelcolors(col))).ToArgb()
        Next col
      
        System.Runtime.InteropServices.Marshal.Copy(pixelcolors, 0, bmdata.Scan0, bm.Width)
      
        bm.UnlockBits(bmdata) ' release memory lock
        bmdata = Nothing
      

      Next row

      Return bm

      End Function

      Every

      B Offline
      B Offline
      Bram van Kampen
      wrote on last edited by
      #2

      Well, Converting between languages in ASP.Net projects, cannnot ever produce a runtime performance. The reason is simple: they all compile to the same CRL module. You could compile it in C++(unmanaged),with significant improvements in speed, but I am not sure if the latest C++/MFC version supportsthe language constructs you use in your source code. Regards, :)

      Bram van Kampen

      T 1 Reply Last reply
      0
      • B Bram van Kampen

        Well, Converting between languages in ASP.Net projects, cannnot ever produce a runtime performance. The reason is simple: they all compile to the same CRL module. You could compile it in C++(unmanaged),with significant improvements in speed, but I am not sure if the latest C++/MFC version supportsthe language constructs you use in your source code. Regards, :)

        Bram van Kampen

        T Offline
        T Offline
        TnTinMn
        wrote on last edited by
        #3

        Thank you for the response. This is currently a WinForm project. I did not expect to observe a significant difference or any at all. However, I did and that is what prompted me to post my question. There does appear to be some difference in IL generated from C# and that from the VB code when viewed using Reflector. However I do not understand IL, so I don't know what those differences amount to. I was mainly wondering if anyone else had ever observed such behavior and if there was a reason for it. I am sure you correct that writing it in C++ would give a significant performance boost, and this might be another excuse to venture into C land again. It has been 8 months since my last vist and I think all the wounds to my ego have healed. :sigh:

        1 Reply Last reply
        0
        • T TnTinMn

          A few weeks ago there I seen a question regarding converting colors to grayscale equivalents and it caught my interest. I found an article that presented various methods and decided to give it a try in VB.Net. This is my code.

          <System.Runtime.CompilerServices.Extension()> _
          Public Function ToGrayScale(ByVal img As Image, ByVal method As Methods) As Image
          If Not [Enum].IsDefined(GetType(Methods), method) Then
          Return Nothing
          End If

          ' set the grayscale function to use for conversion
          Dim gsfunc As Func(Of Color, Color) = Nothing
          Select Case method
          Case Methods.Average : gsfunc = AddressOf Average
          Case Methods.CorrectingForTheHumanEye_Gimp : gsfunc = AddressOf Gimp
          Case Methods.CorrectingForTheHumanEye_BT_601 : gsfunc = AddressOf BT_601
          Case Methods.CorrectingForTheHumanEye_BT_709 : gsfunc = AddressOf BT_709
          Case Methods.Desaturation : gsfunc = AddressOf Desaturation
          Case Methods.DecompositionMax : gsfunc = AddressOf DecompositionMax
          Case Methods.DecompositionMin : gsfunc = AddressOf DecompositionMin
          Case Methods.SingleColorRed : gsfunc = AddressOf SingleColorRed
          Case Methods.SingleColorGreen : gsfunc = AddressOf SingleColorGreen
          Case Methods.SingleColorBlue : gsfunc = AddressOf SingleColorBlue
          End Select

          ' create a 32bppArgb bitmap from source image
          Dim bm As New Bitmap(img.Width, img.Height, Imaging.PixelFormat.Format32bppArgb)
          Dim g As Graphics = Graphics.FromImage(bm)
          g.DrawImageUnscaled(img, Point.Empty)
          g.Dispose()

          Dim bmdata As System.Drawing.Imaging.BitmapData

          ' convert 1 row of pixels at a time
          Dim pixelcolors(0 To bm.Width - 1) As Int32
          For row As Int32 = 0 To bm.Height - 1

            ' lock the row in memory
            bmdata = bm.LockBits(New Rectangle(0, row, bm.Width, 1), \_
                                 Drawing.Imaging.ImageLockMode.ReadWrite, \_
                                 bm.PixelFormat)
          
            ' get row data as array integer color
            System.Runtime.InteropServices.Marshal.Copy(bmdata.Scan0, pixelcolors, 0, bm.Width)
          
            ' convert each pixel color to grayscale using selected method
            For col As Int32 = 0 To bm.Width - 1
               pixelcolors(col) = gsfunc(Color.FromArgb(pixelcolors(col))).ToArgb()
            Next col
          
            System.Runtime.InteropServices.Marshal.Copy(pixelcolors, 0, bmdata.Scan0, bm.Width)
          
            bm.UnlockBits(bmdata) ' release memory lock
            bmdata = Nothing
          

          Next row

          Return bm

          End Function

          Every

          R Offline
          R Offline
          Ron Beyer
          wrote on last edited by
          #4

          This is a really good job for a profiler, the difference may be something subtle like the way the C# compiler generates MSIL versus the VB one. Yes, even a line-for-line translation of exactly the same code as you've done above will have different MSIL (in contrast to what your other answer has given). There are some performance improvements you can implement above. You convert the pixel data from an integer, to a color, back to an integer, then back to a color, then back to an integer Pixel Data->ToARGB->BT_601->Convert.ToInt32->FromARGB->ToArgb In my mind it would be simpler to use bit level math for this. Make the BT_601 take the integer data, like:

          private static int BT_601(int c)
          {
          int gs = (((0x00FF0000 & c) >> 16) * 0.299) << 16) +
          (((0x0000FF00 & c) >> 8 ) * 0.587) << 8) +
          (((0x000000FF & c) * 0.114);
          return (0xFF000000 & c) | (gs << 16) | (gs << 8) | gs;
          }

          Which is much faster compiler wise than trying to use all those conversions and function calls. You may also want to do LockBits twice, once with read permission (not read/write) and the next time with write permission (not read). The one-way access helps optimize access to the buffer. You can also get about a 2 time increase by using pointers and unsafe code. You can also try to wrap your for loop in an unchecked block, which will keep the framework from doing bounds checks each time you access the array.

          T 1 Reply Last reply
          0
          • R Ron Beyer

            This is a really good job for a profiler, the difference may be something subtle like the way the C# compiler generates MSIL versus the VB one. Yes, even a line-for-line translation of exactly the same code as you've done above will have different MSIL (in contrast to what your other answer has given). There are some performance improvements you can implement above. You convert the pixel data from an integer, to a color, back to an integer, then back to a color, then back to an integer Pixel Data->ToARGB->BT_601->Convert.ToInt32->FromARGB->ToArgb In my mind it would be simpler to use bit level math for this. Make the BT_601 take the integer data, like:

            private static int BT_601(int c)
            {
            int gs = (((0x00FF0000 & c) >> 16) * 0.299) << 16) +
            (((0x0000FF00 & c) >> 8 ) * 0.587) << 8) +
            (((0x000000FF & c) * 0.114);
            return (0xFF000000 & c) | (gs << 16) | (gs << 8) | gs;
            }

            Which is much faster compiler wise than trying to use all those conversions and function calls. You may also want to do LockBits twice, once with read permission (not read/write) and the next time with write permission (not read). The one-way access helps optimize access to the buffer. You can also get about a 2 time increase by using pointers and unsafe code. You can also try to wrap your for loop in an unchecked block, which will keep the framework from doing bounds checks each time you access the array.

            T Offline
            T Offline
            TnTinMn
            wrote on last edited by
            #5

            Ron, Thank you for the well deserved kick in the pants on optimizing the individual grayscale calculations. :) I was too pleased with myself for figuring out that I could read/write the color as an integer versus the separate alpha, red, green, blue bytes and performance boost that yielded as those individual bytes are then re-assembled to recreate that integer value in the Color structure. As I am writing this, I have realized that my logic (and attempt to optimize) was completely flawed from the start as it was all premised on creating and using a Color structure. There is absolutely no need for this structure other than as a pretty box. Oh-well, back to the drawing board. :-O I have never used a profiler, but I will look into it. Unless someone else has an explanation, I will have to chalk this up to the VB compiler optimizing this code segment better than the C# compiler. Thanks again, you made me re-think this and also made me realize that I have become susceptible to falling for the shiny box.:~

            1 Reply Last reply
            0
            Reply
            • Reply as topic
            Log in to reply
            • Oldest to Newest
            • Newest to Oldest
            • Most Votes


            • Login

            • Don't have an account? Register

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • World
            • Users
            • Groups