 |
|
 |
Hello, could you please post here a link to an article about the luminance segmentation? In the intro you wrote, that it's easily "Googleable", but I'm so dum , that I can't find anything useful. I'm playing around with OpenCV and I'm trying to make my own cartoonizer just for fun and this luminance thing seems to be very useful and I would like to know more about it in general (not reverse engineer your code ).
Thanks man, I would really appreciate it. Have a nice day
|
|
|
|
 |
|
 |
how to remove border style in the result of cartoonizer....thanks ron
|
|
|
|
 |
|
 |
Hi Ron,
me again.
Topic 1
=======
The performance of the code: In the main procedure zEFF_BilateralFilter, non RGB Part, I see 5 nested loops. Ok, this is the algorithmen, using gausina, predifed data etc.
But: The array COMPUTEsingle contains values of type single, this values are later used to access the array Fast_ExpIntensity, here i can see implicit type converts from single to integer. Have you examid the influece of converting single to integer?
I don't know anything about the performace of converting single to integer in .NET.
Topic 2
=======
The code COMPUTEsingle(2, X, Y) is executed twice in the inner loop of the 4 nested loops. Isn't it better to do this once before the third loop starts? Or is this done by compileroptimacation features? Do you have any information about implicit .NET compiler optimizations?
We/You/I should check this .....
Added: Topic1, Topic2, doesn't realy help ....., the 5 loops (with removed logic in the inner loop) are slow .....
regards,
bauer
modified on Monday, April 18, 2011 7:42 AM
|
|
|
|
 |
|
 |
I actually have a CUDA version of this.
NVidia released a bilateral filter in their CUDA SDK.
It is a command line executable that takes a BMP file and outputs a PPM file.
I make a crude wrapper (Image save as BMP ---> send to EXE ---> load resulting PPM file ---> Apply Countour ---> Return Bitmap).
It can do 20 passes of bilateral filtering in a few seconds.
I will be releasing an article in the next month or so for a Movie Cartoonizer (1 hour per minute at 30 fps for 720p resolution).
I would like to use Interop to keep the bitmap bytes in memory and pass them to the C++ DLL and get back the processed byte array, but I have not had much success. I could really use somebody who is talented in C++ Interop with .NET.
|
|
|
|
 |
|
 |
Hi Ron,
yes, it makes sense to transfer the algorithm to C, C++ and check, if it's faster. My attempts to improve the performance with the .NET coding where not very successful. No idea, what happens inside the compiled .NET coding. The problem seems not to be the typeconverts from single to integer accessing the arrays, the loops in general are are little bit slow using large images or a large number of iterations.
But on the other hand: Handling a picture with resolution 3000 * 4000 with radius = 5 and iterations 4 are a lot of operations to be done.
To transfer data from .NET to C++ (and back) is in general no problem, should work. I did it with strings and integers in some database projects. It should work as well with other datatypes, like single's, double etc. and datastructures like arrays.
regards,
bauer
|
|
|
|
 |
|
 |
GPU acceleration is the only way to make a bilateral filter faster.
When I release the CUDA version, you will a big difference in the performance time.
You just need an Nvidia Chipset with driver that supports CUDA.
|
|
|
|
 |
|
 |
Hi Ron,
if I'm processing a image with Image.Width mod 8 <> 0 the program produces pretty poor results, for example image width 400 works pretty good, image width 433 doesn't work.
The problem is in the image helper class, procedure GetBitmapBits.
Converting the 1 dimensioanl byte array to the 3 dimensional byte array (the 3 nested loops) doesn't work in this way, if width of image mod 8 <> 0, because in this situation the m_BitmapData = m_Bitmap.LockBits(bounds, _
Imaging.ImageLockMode.ReadWrite, _
m_Bitmap.PixelFormat) code returns with padding bytes for each line in the bitmap. The resulting m_BitmapData array contains Stride * Image.Heigth bytes and NOT Width * Height * 3 Bytes.
See stride property of the bitmap data class.
This happens using the net 2.0 framework, Windows XP.
regards,
bauer
modified on Friday, April 15, 2011 3:30 PM
|
|
|
|
 |
|
 |
Thanks for finding that bug.
I'll fix the code in the next few days.
|
|
|
|
 |
|
 |
Hi Ron,
have a look to the following class. This is part of code, I use for my own graphic routines. This class may replace your ImageHelper class to fix the problem.
Thank you for your post and the job for converting the VB 6.0 Coding.
regards,
bauer
Imports System.Runtime.InteropServices
Imports System.Drawing
Imports System.Drawing.Imaging
Public Class FastBitmapAccess
Implements IDisposable
Private _BytesMatrix As Byte(,,)
Private _bm As Bitmap
#Region "Constructors"
Public Sub New(ByVal pBM As Bitmap)
Me._bm = pBM
Me.GetBytesFromBitmap()
End Sub
#End Region
#Region "Desctructor"
Private disposedValue As Boolean = False
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
Me.PutBytesToBitmap()
End If
End If
Me.disposedValue = True
End Sub
#Region " IDisposable Support "
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
#End Region
#End Region
#Region "Support routines"
Private Sub GetBytesFromBitmap()
Dim l_StartIndexForLine As Integer
Dim l_StartIndexNextPixel As Integer
Dim l_BytesVector() As Byte
Dim l_BitmapData As BitmapData
Dim l_BytesPerLine As Integer
Dim l_BytesTotal As Integer
Dim l_ByteDepth As Integer
l_ByteDepth = Image.GetPixelFormatSize(_bm.PixelFormat) \ 8
If l_ByteDepth = 3 Then
l_BitmapData = Me._bm.LockBits(New Rectangle(0, 0, Me._bm.Width, Me._bm.Height), Imaging.ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb)
l_BytesPerLine = l_BitmapData.Stride
l_BytesTotal = l_BytesPerLine * l_BitmapData.Height
ReDim l_BytesVector(l_BytesTotal - 1)
ReDim Me._BytesMatrix(l_ByteDepth - 1, Me._bm.Width - 1, Me._bm.Height - 1)
Marshal.Copy(l_BitmapData.Scan0, l_BytesVector, 0, l_BytesTotal)
For y As Integer = 0 To Me._bm.Height - 1
l_StartIndexNextPixel = l_StartIndexForLine
For x As Integer = 0 To Me._bm.Width - 1
Me._BytesMatrix(0, x, y) = l_BytesVector(l_StartIndexNextPixel)
l_StartIndexNextPixel = l_StartIndexNextPixel + 1
Me._BytesMatrix(1, x, y) = l_BytesVector(l_StartIndexNextPixel)
l_StartIndexNextPixel = l_StartIndexNextPixel + 1
Me._BytesMatrix(2, x, y) = l_BytesVector(l_StartIndexNextPixel)
l_StartIndexNextPixel = l_StartIndexNextPixel + 1
Next
l_StartIndexForLine = l_StartIndexForLine + l_BytesPerLine
Next
Me._bm.UnlockBits(l_BitmapData)
Else
Throw New Exception("ByteDepth not supported")
End If
End Sub
Private Sub PutBytesToBitmap()
Dim l_StartIndexForLine As Integer
Dim l_StartIndexNextPixel As Integer
Dim l_BytesVector() As Byte
Dim l_BitmapData As BitmapData
Dim l_BytesPerLine As Integer
Dim l_BytesTotal As Integer
Dim l_byteDepth As Integer
l_byteDepth = Image.GetPixelFormatSize(Me._bm.PixelFormat) \ 8
If l_byteDepth = 3 Then
l_BitmapData = _bm.LockBits(New Rectangle(0, 0, Me._bm.Width, Me._bm.Height), Imaging.ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb)
l_BytesPerLine = l_BitmapData.Stride
l_BytesTotal = l_BytesPerLine * l_BitmapData.Height
ReDim l_BytesVector(l_BytesTotal - 1)
For y As Integer = 0 To Me._bm.Height - 1
l_StartIndexNextPixel = l_StartIndexForLine
For x As Integer = 0 To Me._bm.Width - 1
l_BytesVector(l_StartIndexNextPixel) = Me._BytesMatrix(0, x, y)
l_StartIndexNextPixel = l_StartIndexNextPixel + 1
l_BytesVector(l_StartIndexNextPixel) = Me._BytesMatrix(1, x, y)
l_StartIndexNextPixel = l_StartIndexNextPixel + 1
l_BytesVector(l_StartIndexNextPixel) = Me._BytesMatrix(2, x, y)
l_StartIndexNextPixel = l_StartIndexNextPixel + 1
Next
l_StartIndexForLine = l_StartIndexForLine + l_BytesPerLine
Next
Marshal.Copy(l_BytesVector, 0, l_BitmapData.Scan0, l_BytesTotal)
Me._bm.UnlockBits(l_BitmapData)
ReDim Me._BytesMatrix(-1, -1, -1)
Else
Throw New Exception("ByteDepth not supported")
End If
End Sub
#End Region
#Region "Propertys / Methods"
Public Function GetPixel(ByVal x As Integer, ByVal y As Integer) As Color
Return Color.FromArgb(0, Me._BytesMatrix(2, x, y), Me._BytesMatrix(1, x, y), Me._BytesMatrix(0, x, y))
End Function
Public Sub SetPixel(ByVal x As Integer, ByVal y As Integer, ByVal Color As Color)
Me._BytesMatrix(0, x, y) = Color.B
Me._BytesMatrix(1, x, y) = Color.G
Me._BytesMatrix(2, x, y) = Color.R
End Sub
Public ReadOnly Property BytesMatrix() As Byte(,,)
Get
Return Me._BytesMatrix
End Get
End Property
#End Region
End Class
|
|
|
|
 |
|
 |
I have added your code to the repository and the zip archive in this article should be updated in the next day or two.
Thanks for the fix.
I tried multiple times to track down the cause of the "pseudo scanline interlace effect" that was occurring on certain images. I just never thought to look at the bitmap byte access code.
|
|
|
|
 |
|
 |
Hi Ron,
your update by adding my code snippet works, I just downloaded it, tested it, perfect.
regards,
bauer
|
|
|
|
 |
|
|
 |
|
 |
Nice post Ron
|
|
|
|
 |
|