Results 1 to 40 of 40

Thread: [RESOLVED] Best way to Smooth/Contour an image (or whatever it's called

  1. #1

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,817

    Resolved [RESOLVED] Best way to Smooth/Contour an image (or whatever it's called

    Ok, here's another one. I haven't committed to doing this, but I thought, if I had time this coming week, I'd try to knock it out.

    The following images are from some other software that is VERY difficult to use, so I'm sort of replicating our needed functionality. One of the things they put on a report is a screen-capture of the coutoured/smoothed version of the peak foot image. The left is what they refer to as "Data", and the right is what they call "Contoured".

    Now, regarding the palette, I can work that one out. However, off the top of my head, I don't know how to do that smoothing.

    I certainly don't mind firing up the GdiPlus if that's the easiest way to get it done. And, for this particular aspect of the report, there really doesn't need to be any precision about it. It's just a visual.

    The original form of the image will be a Byte array, but I can fairly easily get it into any other form needed.

    Name:  Contour.png
Views: 1736
Size:  6.1 KB

    Any/all ideas truly appreciated.

    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  2. #2
    PowerPoster
    Join Date
    Aug 2010
    Location
    Canada
    Posts
    2,401

    Re: Best way to Smooth/Contour an image (or whatever it's called

    Looks a lot like the results of a circular Median filter in PhotoDemon (open source/VB6 code available). Might be worth looking at Tanner's code at GitHub, but there might be licensing issues you'd have to work out.

    Name:  PhotoDemonMedian.jpg
Views: 1660
Size:  20.3 KB

  3. #3
    Fanatic Member
    Join Date
    Sep 2010
    Location
    Italy
    Posts
    678

    Re: Best way to Smooth/Contour an image (or whatever it's called

    I confirm that the median filter should be the simpler way to go.
    I'd omit the term "circular" because a disk-shaped kernel has little influence on the final result.

    This is the output of my software (PhotoModularFX) (on Input image enlarged from 300 to 480pix) using a radius equal to 6 (a 13x13 kernel) and a radius equal to 9 (19x19 kernel)

    Name:  pmFXContour.jpg
Views: 1499
Size:  41.0 KBName:  pmFXContour.jpg
Views: 1561
Size:  40.0 KBName:  pmFXContour 9.jpg
Views: 1493
Size:  35.9 KB

    EDIT:
    That said, the "Marching squares" technique (or similar) is probably used in your example image.
    https://www.youtube.com/watch?v=yOgIncKp0BE

  4. #4

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,817

    Re: Best way to Smooth/Contour an image (or whatever it's called

    Well, truth be told, I also thought of PhotoDemon. But, for reasons very unclear to me, Tanner doesn't like me. So, I've been reluctant to explore that path.

    Also, I haven't really explored the GdiPlus for this type of effect, but I'd be surprised if there's nothing there. I was just hoping someone might come along who's had some experience doing something similar. If/when I get to it, I'll take a good thorough look at what GdiPlus has to offer.

    Also, as suggested above, I don't have to do what the other software did "exactly". I just have to come up with something that's enlarged and then un-pixelated (i.e., prettier).

    Thanks For The Considerations,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  5. #5
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: Best way to Smooth/Contour an image (or whatever it's called

    Well, by default, GDI+ will do some smoothing when enlarging an image, so you could try that fairly quickly to see what it looks like. Just draw the image with one pixel per square, then scale it up using DrawImage.

  6. #6

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,817

    Re: Best way to Smooth/Contour an image (or whatever it's called

    Hi Passel,

    Yeah, I've done some GDI+ work before. It's just not something I spend everyday messing with. I took a quick look, and it seems like InterpolationMode with either the HighQualityBicubic or HighQualityBilinear setting, along with DrawImage might get it done. I've got to finish up the "core" of this work (frame and window cropping of the entire movie), and then I'll start playing around with those GDI+ calls (for the peak image of the cropped movie). I'm guessing they're going to give a fairly good answer.

    Thanks,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  7. #7
    Fanatic Member
    Join Date
    Sep 2010
    Location
    Italy
    Posts
    678

    Re: Best way to Smooth/Contour an image (or whatever it's called

    Quote Originally Posted by passel View Post
    Well, by default, GDI+ will do some smoothing when enlarging an image, so you could try that fairly quickly to see what it looks like. Just draw the image with one pixel per square, then scale it up using DrawImage.
    I think that to enlarging will bring to a (unpleasant) blurred image whatever interpolation used.Name:  Contour[BLUR3.txt].jpg
Views: 1653
Size:  14.5 KB
    (better median filter, not difficult to implement, but keeping in mind that it has the disadvantage of being slow.)

  8. #8
    Hyperactive Member
    Join Date
    Mar 2018
    Posts
    460

    Re: Best way to Smooth/Contour an image (or whatever it's called

    imagemagick might give a decent result: https://imagemagick.org/script/comma....php#statistic

    edit

    magick.exe convert "c:\input.png" -statistic median 5x5 "output.png"

    gives:

    Last edited by DllHell; Apr 8th, 2019 at 11:35 AM.

  9. #9
    PowerPoster
    Join Date
    Aug 2010
    Location
    Canada
    Posts
    2,401

    Re: Best way to Smooth/Contour an image (or whatever it's called

    Quote Originally Posted by Elroy View Post
    Well, truth be told, I also thought of PhotoDemon. But, for reasons very unclear to me, Tanner doesn't like me. So, I've been reluctant to explore that path.
    I won't delve too deeply into your relationship with Tanner, as I'll assume we're looking for a reasonable solution to a problem instead of trying to make friends

    As I recall, the discussion between you two was mainly related to licensing & copyright vs. the VB community's general apathy & shrugging off responsibility in that regard when it comes to ripping code from open source projects. I think the main thing would be ensuring you don't run afoul of the PD open source license, which as BSD is very permissive. Just make sure to leave the copyright in the code you take, and include a copy of the license with your project along with something like (portions of this software Copyright Tanner Helland, used under BSD license - or something along those lines). I get along with Tanner, so if you're reluctant to ask him to clarify the licensing situation then I'd be happy to ask on your behalf.

    Anyway, I did a quick test Circular Median Radius 4 Threshold 50%, followed by a Sharpen at 0.4 strength, followed by another Circular Median Radius 2 Threshold 50%. This produced what looks like a "nice enough" result to me:

    Name:  PhotoDemonMedian2.jpg
Views: 1664
Size:  36.2 KB

    That said, I'd listen to @reexre as he is a knowledgeable graphics guy, and if he says "Marching Squares" is the likely technique, then I'd bet it is.

  10. #10

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,817

    Re: Best way to Smooth/Contour an image (or whatever it's called

    Hi jbpro,

    I tell you what. It does sound like PhotoDemon has a very workable solution. Let me fight my own battles though. Maybe this'll be an opportunity to mend a bridge. Who knows.

    I'll drop him an email and see how he feels about this.

    Thanks,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  11. #11

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,817

    Re: Best way to Smooth/Contour an image (or whatever it's called

    Hey Tanner,

    I've recently been discussing on VBForums for the best way to "smooth" a picture. A couple of people believe that a clip of code out of your PhotoDemon has possibly the best solution. However, because if our run-in a few months back, I've tended to just stay way from your software, although I still believe it's a wonderful endeavor on your part. Here's the thread where it's being discussed, if you'd care to look: http://www.vbforums.com/showthread.php?873373

    Tanner, everything I do is open-source as well, and has been since 1999. However, If you'd rather I not use any of your software to get my work done, I'll honor that as well.

    I would appreciate a response so I can have some clear direction on how to proceed.

    All The Best To You,
    Elroy
    So, we'll see. I'm hoping he'll just post here.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  12. #12
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: Best way to Smooth/Contour an image (or whatever it's called

    Not fancy, maybe not good enough, just brute force:

    Code:
    Option Explicit
    
    Private Const WIN32_FALSE As Long = 0
    Private Const WIN32_TRUE As Long = 1
    Private Const WIN32_NULL As Long = 0
    
    Private Const DIB_RGB_COLORS As Long = 0
    
    Private Enum BiCompressionValues
        BI_RGB = 0 'We're only using this value here.
    End Enum
    
    Private Type BITMAPINFOHEADER
        biSize As Long
        biWidth As Long
        biHeight As Long
        biPlanes As Integer
        biBitCount As Integer
        biCompression As BiCompressionValues
        biSizeImage As Long
        biXPelsPerMeter As Long
        biYPelsPerMeter As Long
        biClrUsed As Long
        biClrImportant As Long
    End Type
    
    Private Type BITMAPINFO_NOPALETTE
        bmiHeader As BITMAPINFOHEADER
    End Type
    
    Private Declare Function GetDIBits Lib "gdi32" ( _
        ByVal hDC As Long, _
        ByVal hBitmap As Long, _
        ByVal nStartScan As Long, _
        ByVal nNumScans As Long, _
        ByRef Bits As Any, _
        ByRef bmi As Any, _
        ByVal wUsage As Long) As Long
    
    Private Declare Function SetDIBits Lib "gdi32" ( _
        ByVal hDC As Long, _
        ByVal hBitmap As Long, _
        ByVal nStartScan As Long, _
        ByVal nNumScans As Long, _
        ByRef Bits As Any, _
        ByRef bmi As Any, _
        ByVal wUsage As Long) As Long
    
    Private Sub Form_Load()
        Dim BITMAPINFO_NOPALETTE As BITMAPINFO_NOPALETTE
        Dim PixWidth As Long
        Dim PixHeight As Long
        Dim OrigPixValues() As Long
        Dim NewPixValues() As Long
        Dim X As Long
        Dim Y As Long
        Dim P0Sum As Long
        Dim P1Sum As Long
        Dim P2Sum As Long
        Dim DX As Long
        Dim DY As Long
        Dim DDX As Long
        Dim DDY As Long
        Dim Pixel As Long
    
        'GET ORIGINAL:
        Set Picture1.Picture = LoadPicture("print.gif")
        'CONDENSE IT:
        With Picture2
            .AutoRedraw = True
            .PaintPicture Picture1.Image, 0, 0, .Width / 4, .Height / 4
        End With
        'SMOOTH IT:
        With BITMAPINFO_NOPALETTE.bmiHeader
            'Retrieve metrics:
            .biSize = LenB(BITMAPINFO_NOPALETTE.bmiHeader)
            .biBitCount = 0 'Don't fetch color table or pixels.
            GetDIBits Picture2.hDC, _
                      Picture2.Image.Handle, _
                      0, _
                      0, _
                      WIN32_NULL, _
                      BITMAPINFO_NOPALETTE, _
                      DIB_RGB_COLORS
            PixWidth = .biWidth
            PixHeight = .biHeight
            'No padding required since we are using 32-bit (DWORD) pixels:
            ReDim OrigPixValues(PixWidth - 1, PixHeight - 1)
            ReDim NewPixValues(PixWidth - 1, PixHeight - 1)
            'Retrieve pixel data as 32-bit xRGB RGBQUAD values (not xBGR COLORREF):
            .biBitCount = 32
            .biCompression = BI_RGB
        End With
        With Picture2
            GetDIBits .hDC, _
                      .Image.Handle, _
                      0, _
                      PixHeight, _
                      OrigPixValues(0, 0), _
                      BITMAPINFO_NOPALETTE, _
                      DIB_RGB_COLORS
            For Y = 0 To PixHeight - 1
                For X = 0 To PixWidth - 1
                    P0Sum = 0
                    P1Sum = 0
                    P2Sum = 0
                    For DY = Y - 1 To Y + 1
                        If DY < 0 Then
                            DDY = PixHeight - 1
                        ElseIf DY >= PixHeight Then
                            DDY = 0
                        Else
                            DDY = DY
                        End If
                        For DX = X - 1 To X + 1
                            If DX < 0 Then
                                DDX = PixWidth - 1
                            ElseIf DX >= PixWidth Then
                                DDX = 0
                            Else
                                DDX = DX
                            End If
                            Pixel = OrigPixValues(DDX, DDY)
                            P0Sum = P0Sum + (Pixel And &HFF&)
                            P1Sum = P1Sum + (Pixel And &HFF00&)
                            P2Sum = P2Sum + (Pixel And &HFF0000)
                        Next
                    Next
                    NewPixValues(X, Y) = (P0Sum \ 9 And &HFF&) _
                                      Or (P1Sum \ 9 And &HFF00&) _
                                      Or (P2Sum \ 9 And &HFF0000)
                Next
            Next
            SetDIBits .hDC, _
                      .Image.Handle, _
                      0, _
                      PixHeight, _
                      NewPixValues(0, 0), _
                      BITMAPINFO_NOPALETTE, _
                      DIB_RGB_COLORS
        
            .AutoRedraw = False 'Note: we have deferred this because we needed access to the
                                '      persistent graphic's hDC and hBitmap above.
        End With
        'EXPAND IT:
        With Picture3
            .AutoRedraw = True
            .PaintPicture Picture2.Image, 0, 0, .Width, .Height, 0, 0, .Width / 4, .Height / 4
            .AutoRedraw = False
        End With
    End Sub
    Name:  sshot.png
Views: 1502
Size:  6.4 KB

    Using a HALFTONE StretchBlt as the final step might give slightly better results.
    Attached Files Attached Files

  13. #13
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: Best way to Smooth/Contour an image (or whatever it's called

    Making two smoothing passes:

    Name:  sshot 2 passes.png
Views: 1521
Size:  7.1 KB

    Not a lot slower, but perhaps too blurry?

  14. #14
    Fanatic Member
    Join Date
    Sep 2010
    Location
    Italy
    Posts
    678

    Re: Best way to Smooth/Contour an image (or whatever it's called

    A little important suggestion:
    It should bring better result doing the main job on grayscale image and THEN apply "heat" / "rainbow" palette map.

    +this way you can gain 2/3 of speed processing 1 channel instead of 3 (RGB)

  15. #15
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: Best way to Smooth/Contour an image (or whatever it's called

    Ok, 2 passes and HALFTONE StretchBlt:

    Name:  sshot 2 passes halftone.png
Views: 1534
Size:  13.5 KB

  16. #16

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,817

    Re: Best way to Smooth/Contour an image (or whatever it's called

    Hmmm, ok, I'm still plugging away at the frame & window cropping part of all this, but I thought I should provide more input.

    I am NOT terribly worried about speed on this one. This will not be done to the whole "movie". It will only occasionally be done on what we call "peak" images (discussed elsewhere). So, if it takes 2ms or 500ms, it doesn't make much difference to me.

    I do appreciate the different ideas, and, when I get to it, I'll definitely explore these different ideas.

    p.s. I've also got a RAGING head cold, so don't breathe my germs. It's mightily fun programming with a brain that feels like it's in a vice.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  17. #17
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: Best way to Smooth/Contour an image (or whatever it's called

    Just for grins I tweaked it a bit. Tried to suppress some bleed into the white background, but mainly cranked the color saturation to the max during smoothing passes:

    Name:  sshot saturation.png
Views: 1656
Size:  14.0 KB

    In case anybody finds this later, here's where I ended up (attached).

    If you don't have any reason to display the intermediate images you could replace Picture1 and Picture2 with memory DCs.
    Attached Files Attached Files
    Last edited by dilettante; Apr 8th, 2019 at 09:21 PM.

  18. #18
    Fanatic Member
    Join Date
    Sep 2010
    Location
    Italy
    Posts
    678

    Re: Best way to Smooth/Contour an image (or whatever it's called

    Now I have not an appropriate grayscale picture, but following my tip ( to use grayscale source and apply heat map at the end ) in my opinion leads to nicer results.
    Example with pixellation 8pix and median filter of radius 6.
    Name:  black-prints-of-feet-on-transparent-paper-black-footprint-isolated-HGHBWD[Elroy 4.txt].jpg
Views: 3191
Size:  65.0 KBName:  carbon-footprint-1[Elroy 4.txt].jpg
Views: 1685
Size:  67.4 KB
    PS: heatmap used
    V = Pixel Value with range 0-1
    R = cos ( V * PI / 2)
    G = sin ( V * PI )
    B = 1- R

    for those who want to try PhotoModularFX, follow a zip file with the projects used to create these images.
    (UnZip them in the Projects folder. They are called Elroy 4 and Elroy 41)
    Attached Files Attached Files

  19. #19

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,817

    Re: Best way to Smooth/Contour an image (or whatever it's called

    Ok, I still haven't looked at any code regarding this. Jpbro & reexre, it looks like y'all are getting some nice results. Dil, I'm just worried about that fuzz (bleeding into white background) that you're getting. I was hoping for something more "crisp" at the edges.

    I'm on the downhill side of the window & frame cropping functions, hoping to get them finished up today. Hopefully, I'll be throwing myself into looking at this smoothing/contouring stuff tomorrow morning.

    All of you have been truly amazing to do all this testing for me. I hope I've returned the favors along the way, and I know I'll continue to try and do so in the future, as I love this stuff.

    Y'all Take Care,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  20. #20
    PowerPoster
    Join Date
    Feb 2017
    Posts
    4,987

    Re: Best way to Smooth/Contour an image (or whatever it's called

    I'm not sure what you want. If you want to get an image similar to the one of your first post, then I think you need a filter.
    But if it could be different, you can try reducing the original to an image where the squares are pixels and then test some algorithms for scaling to see if anyone gets a result that you can use:

    http://www.planetsourcecode.com/vb/s...38979&lngWId=1

    http://www.planetsourcecode.com/vb/s...46515&lngWId=1

  21. #21

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,817

    Re: Best way to Smooth/Contour an image (or whatever it's called

    Hmmm, ok, I'm finally trying to get my head into this thing.

    After exploring and researching, I'm starting to like the results from median noise filters. jpbro, thanks for doing the exploratory work on that.

    I've looked at PhotoDemon as well as PSP and another package, and they all have similar results. I seem to get close with a radius of 3 or 4. With such a small radius (and also that I'll be hard-coding that), I'm not sure circle vs square will make that much difference. I'll probably just hard-code what surrounding pixels I use anyway.

    The idea of doing it on a grayscale (which is basically my starting place) is good too, and then applying the palette (aka heatmap) after the fact seems sound.

    Ok, just as an FYI, I'm not willing to make any calls to a closed source DLL (or some other program). In fact, I don't think this algorithm will be that complex, once I get it all figured out.

    I'll just feed it a two-dimensional byte array (which will represent a bitmap), and let it do its thing. And then I'll apply a palette. reexre, I played around with your proposed palette, and it looks good.

    So now, I just need to get a two-dimensional median cut noise filter sorted out. I've searched, and no code just jumps out at me. Wikipedia has a page on it. I suppose I could start with what they have.

    Thanks To All,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  22. #22

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,817

    Re: Best way to Smooth/Contour an image (or whatever it's called

    Actually, this isn't going to be too bad. I think I'll start with the following configuration of pixels, finding the median, and replacing the target pixel:

    Name:  29Pixels.png
Views: 1440
Size:  731 Bytes

    Now, I think my biggest problem is finding a fairly fast way to sort 29 pixels over and over. I'll start simple, and see how slow it is. I know there are small-N sorting algorithms around.

    EDIT1: For those who are actually pondering this, apparently the target pixel is used for boundary conditions where you don't have pixels over the boundary (or at least that's one approach, and it makes sense to me). It just means that things are less likely to change at the boundaries, which is fine.
    Last edited by Elroy; Apr 9th, 2019 at 09:05 PM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  23. #23
    Hyperactive Member
    Join Date
    Sep 2014
    Posts
    373

    Re: Best way to Smooth/Contour an image (or whatever it's called

    Some of the attempts involving Blur approach in fact seem to have produced quite okay impressions, except that they don't reflect the "outline" concept of Contour. "Sharpen by unsharp" of those images might be an alternative to follow up, just in case you find that Median Filter to be unbearably slow (be prepared it is really slow, as reexre had specifically pointed out) or your current try got stuck somewhere.

    Just a thought. I wish you good luck.

  24. #24

  25. #25
    Fanatic Member
    Join Date
    Sep 2010
    Location
    Italy
    Posts
    678

    Re: Best way to Smooth/Contour an image (or whatever it's called

    This thread gave me the opportunity to review my median filter algorithm.
    So I have improved it. If current version take a time T, the new one take about a time sqr(T)*2.
    To have a faster algorithm we must avoid sorting. For this purpose there is a variation called median filter using histogram based operations... Or something...
    When I have time maybe I'll post here my new faster code.

  26. #26
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,092

    Re: Best way to Smooth/Contour an image (or whatever it's called

    > If current version take a time T, the new one take about a time sqr(T)*2.

    This means that if your previous algorithm asymptotic complexity was O(N^4) now its O(N^2) and if it was O(N^3) now it's O(N logN) but which exactly it is/was remains a mystery :-))

    Notice that there is no linear-time median filtering because using such fast median filter you could sort an arbitrary array of values and there is no linear-time general purpose sorting known (yet).

    cheers,
    </wqw>

  27. #27
    Fanatic Member
    Join Date
    Sep 2010
    Location
    Italy
    Posts
    678

    Re: Best way to Smooth/Contour an image (or whatever it's called

    Quote Originally Posted by wqweto View Post
    >
    Notice that there is no linear-time median filtering because using such fast median filter you could sort an arbitrary array of values and there is no linear-time general purpose sorting known (yet).

    cheers,
    </wqw>
    As I said there is an algorithm that do NOT use sorting. It use local histograms... Google for median filter histogram.

    Sorry , about my time performance complexity ... I have no clear idea on how express it. In few days I think will post my code that uses histogram technicque. So you could help me to express its complexity

  28. #28
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,092

    Re: Best way to Smooth/Contour an image (or whatever it's called

    Quote Originally Posted by reexre View Post
    In few days I think will post my code that uses histogram technicque. So you could help me to express its complexity
    ok, then I'll try to post the double-heap O(N logN) median filter impl (w/ square kernel) for GDI+ bitmaps so we can compare performance and results.

    cheers,
    </wqw>

  29. #29

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,817

    Re: Best way to Smooth/Contour an image (or whatever it's called

    @Brenker: Yeah, one of the nice thing about the median approach is that no new colors are introduced, thereby preserving the edges quite nicely. I tried several blurring techniques, and wasn't happy with anything. I was showing it all to some users, and they said the blurring just made them feel like they needed to go find their glasses.

    ------------------

    I'll be working on this, this morning. I'm sure my algorithm won't be optimal. As a down-and-dirty attempt, here's my plan, for each pixel:

    • Create a 29 item 1D byte array.
    • Turn on On Error Resume Next.
    • Create a target 2D byte array for results (same size as source array).
    • Build a loop that goes through each pixel of an image in a 2D byte source array.
    • For each pixel, fill all 29 items with the pixel's value.
    • Go around (according to post #22 picture) and fill the 29 items. (Error trapping will stop from processing out-of-bounds pixels.)
    • Sort 29 items. (Insertion sort seems to be best for a small N like this.)
    • Find median and place into target picture.
    • Loop until done.

    I'll post some results where I get there.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  30. #30

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,817

    Re: Best way to Smooth/Contour an image (or whatever it's called

    Ok, it turns out the client wants a limited number of colors in the palette. It's those colors seen in the OP.

    I've got my Median Noise Filter up and running, but it's somewhat slow. Here's an image I'm getting (my code producing that, and not same step as shown in OP):

    Name:  Median1.png
Views: 1079
Size:  7.1 KB

    Now, I just need to figure out how to find the median faster, possibly without a sort.

    I think I'll call this one resolved, and start a new thread for that, as the idea of how to do the contouring is settled.

    Thanks To All,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  31. #31

  32. #32
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,092

    Re: [RESOLVED] Best way to Smooth/Contour an image (or whatever it's called

    Fast O(N) median filter for GDI+ bitmaps impl w/ SSE2 thunks based on http://nomis80.org/ctmf.c. Obviously these linear-time median-filter beasts exist for quite some time now!

    thinBasic Code:
    1. ' mdMedianBlur.bas
    2. Option Explicit
    3. DefObj A-Z
    4.  
    5. '--- for VirtualProtect
    6. Private Const PAGE_EXECUTE_READWRITE        As Long = &H40
    7. Private Const MEM_COMMIT                    As Long = &H1000
    8. '--- for CryptStringToBinary
    9. Private Const CRYPT_STRING_BASE64           As Long = 1
    10. '--- for GdipBitmapLockBits
    11. Private Const ImageLockModeRead             As Long = &H1
    12. Private Const ImageLockModeWrite            As Long = &H2
    13. Private Const PixelFormat32bppARGB          As Long = &H26200A
    14. Private Const PixelFormat24bppRGB           As Long = &H21808
    15. Private Const PixelFormatAlpha              As Long = &H40000
    16.  
    17. Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
    18. Private Declare Function VirtualProtect Lib "kernel32" (ByVal lpAddress As Long, ByVal dwSize As Long, ByVal flNewProtect As Long, ByRef lpflOldProtect As Long) As Long
    19. Private Declare Function VirtualAlloc Lib "kernel32" (ByVal lpAddress As Long, ByVal dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As Long
    20. Private Declare Function CryptStringToBinary Lib "crypt32" Alias "CryptStringToBinaryW" (ByVal pszString As Long, ByVal cchString As Long, ByVal dwFlags As Long, ByVal pbBinary As Long, ByRef pcbBinary As Long, ByRef pdwSkip As Long, ByRef pdwFlags As Long) As Long
    21. Private Declare Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleA" (ByVal lpModuleName As String) As Long
    22. Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long
    23. '--- gdi+
    24. Private Declare Function GdipGetImagePixelFormat Lib "gdiplus" (ByVal Image As Long, nFormat As Long) As Long
    25. Private Declare Function GdipBitmapLockBits Lib "gdiplus" (ByVal hBitmap As Long, lpRect As Any, ByVal lFlags As Long, ByVal lPixelFormat As Long, uLockedBitmapData As BitmapData) As Long
    26. Private Declare Function GdipBitmapUnlockBits Lib "gdiplus" (ByVal hBitmap As Long, uLockedBitmapData As BitmapData) As Long
    27.  
    28. Private Type BitmapData
    29.     Width               As Long
    30.     Height              As Long
    31.     Stride              As Long
    32.     PixelFormat         As Long
    33.     Scan0               As Long
    34.     Reserved            As Long
    35. End Type
    36.  
    37. Public Function MedianBlur( _
    38.             ByVal hBitmap As Long, _
    39.             ByVal lRadius As Long) As Boolean
    40.     Const L2_CACHE_SIZE As Long = 512 * 1024&
    41.     Dim lPixelFormat    As Long
    42.     Dim uData           As BitmapData
    43.     Dim aBuffer()       As Byte
    44.     Dim aImport(0 To 1) As Long
    45.  
    46.     On Error GoTo EH
    47.     If GdipGetImagePixelFormat(hBitmap, lPixelFormat) <> 0 Then
    48.         GoTo QH
    49.     End If
    50.     If GdipBitmapLockBits(hBitmap, ByVal 0, ImageLockModeRead Or ImageLockModeWrite, IIf((lPixelFormat And PixelFormatAlpha) <> 0, _
    51.             PixelFormat32bppARGB, PixelFormat24bppRGB), uData) <> 0 Then
    52.         GoTo QH
    53.     End If
    54.     ReDim aBuffer(0 To uData.Stride - 1, 0 To uData.Height - 1) As Byte
    55.     aImport(0) = GetProcAddress(GetModuleHandle("ole32"), "CoTaskMemAlloc")
    56.     aImport(1) = GetProcAddress(GetModuleHandle("ole32"), "CoTaskMemFree")
    57.     Call CTimeMedianFilter(uData.Scan0, VarPtr(aBuffer(0, 0)), uData.Width, uData.Height, uData.Stride, uData.Stride, lRadius, _
    58.         IIf((lPixelFormat And PixelFormatAlpha) <> 0, 4, 3), L2_CACHE_SIZE, VarPtr(aImport(0)))
    59.     Call CopyMemory(ByVal uData.Scan0, aBuffer(0, 0), uData.Stride * uData.Height)
    60.     '--- success
    61.     MedianBlur = True
    62. QH:
    63.     On Error Resume Next
    64.     If uData.Scan0 <> 0 Then
    65.         Call GdipBitmapUnlockBits(hBitmap, uData)
    66.     End If
    67.     Exit Function
    68. EH:
    69.     Debug.Print "Critical error: " & Err.Description & " [MedianBlur]"
    70.     Resume QH
    71. End Function
    72.  
    73. '--- Based on [url]http://nomis80.org/ctmf.c[/url] - Constant-time median filtering
    74. '--- Copyright (C) 2006  Simon Perreault
    75. Private Sub CTimeMedianFilter(ByVal lSrcPtr As Long, ByVal lDstPtr As Long, ByVal lWidth As Long, ByVal lHeight As Long, ByVal lSrcStep As Long, ByVal lDstStep As Long, ByVal lRadius As Long, ByVal lNumChannels As Long, ByVal lMaxMemUsage As Long, ByVal lImportPtr As Long)
    76.     Const STR_THUNK     As String = "VYvsg+wgi0UgU1ZXjRwAi30QuPHw8PD3ZSiLysHpCSvLi8Erw0gDx5n3+YvwjUf/jQx1/v///w+vTSADzgPBM8mZ9/6JTfiL8Il14IX/D47JAAAAD69FJDPbiU0oiUXki8b32IlF6ItFIA+vRSQDwIlF8ItFIPfYA8CJRfSNSQCLfSCLwYvWiXX8jQw/i30QK8EDxolF7DvHfReLyyvOi3UgjQxxA8+NBHUBAAAAO8h9Bo0UO4lV/P91LDPAi00IjTQ7O9YPlMBQM8A5RfgPlMBQ/3Uki0UoA8j/dSD/dRz/dRj/dRRSi1UMjRQQ6K4AAACDxCQ5dfx0I4tFKCtd9CtF8ItN7ANF5ANd6It14IlN+IlFKDvPD4xj////X15bi+VdwigAzMzMzMzMzMzMzFWL7IPsCFNWi3UIZovZV416BsdF/AQAAAAr1o1GAovyD7dX+o1ACA+3y41/CA+v0Q+3y2YBUPYPt1QG+A+v0Q+3y2YBUPgPt1f2D6/RZgFQ+g+3T/gPt9MPr9FmAVD8g238AXW7X15bi+Vdw8zMzMxVi+yD5PCB7IgJAABWi3UID691HFeLfSiJlCSIAAAAiUwkUIvGiXQkZMHgBYlEJDCDwBBQiwf/0MHmCYlEJGiNThBRiw//0YvIi0QkaIPAD4mMJIwAAACD4PCL+IlEJCyNUQ8ywItMJDCD4vDzqovOiVQkKIt1HIv686qLfQgzwIlEJAyF/w+OoQAAAItMJFCJTCQUM9KF9g+OfAAAAItN" & _
    77.                                     "CIvwweEEM//B5gSJTCQwiXQkJItEJBQPtgwQi0UYwekEQAPOi3QkLGYBBE6LRCQUi3QkKA+2BBBCi8iD4A/B6QQDz4PHEA+vTQgDTCQMweEEA8iLRRhAZgEETot0JCQDdCQwiXQkJDtVHHyni0QkDItMJBSLfQiLdRxAA86JRCQMiUwkFDvHD4xn////i0UYhcAPjr0AAACLTCRQi9CJTCQkiUQkQDPAiUQkDIX/D46KAAAAiUwkFDPShfZ+aYtNCIvwweEEM/+JTCQwweYEkItMJBQPtgQRi0wkLMHoBAPGA3QkMGb/BEGLTCQUD7YMEUKLwYPhD8HoBAPHg8cQD69FCANEJAzB4AQDwYtMJChm/wRBO1UcfLeLRCQMi0wkFIt9CIt1HEADzolEJAyJTCQUO8d8gotMJCSLVCRAA00Qg+oBiUwkJIlUJEAPhVT///+LRRiLTQyFyQ+OvgYAAEnHRCQkAAAAAIlMJGyL+GnOIAIAAIl8JECJTCRwi87B4QWJTCR0i00g99kbyffRI8iJTCR4g8n/K8hAiUwkMIlEJHwz0oXJD57CM8BKiUQkDCPRi0wkZA+vVRADVCRQA8qJTCQYO9EPhJEAAACNSQCF9g+OdQAAAItNCIvwi0UcM//B4QTB5gSJTCQciXQkEIlEJCAPtgKLTCQswegEA8a+//8AAGYBNEEPtgpCi8GD4Q/B6AQDx4PHEA+vRQgDRCQMweAEA8GLTCQoZgE0QYt0JBADdCQcg2wk" & _
    78.                                     "IAGJdCQQdbKLRCQMi0wkGIt1HECJRCQMO9EPhXb///+LfCRAi0QkbIvXO8d/AovQD69VEDPAi0wkZIlEJAwDVCRQA8qJTCQYO9EPhHsAAACNmwAAAACF9n5oi00Ii/CLRRwz/8HhBIlMJBzB5gSJRCQQjWQkAA+2AotMJCzB6AQDxgN0JBxm/wRBD7YKQovBg+EPwegEA8eDxxAPr0UIA0QkDMHgBAPBi0wkKGb/BEGDbCQQAXW/i0QkDItMJBiLdRxAiUQkDDvRdYuLTCRwjbwkEAEAADLA86qLTCR0jbwkkAAAAPOqi0UghcB0QoX2fj6LRQiNtCQQAQAAi3wkLMHgBYlEJByLRRyJRCQQi00Yi9dW6J37//8DfCQgg8QEgcYgAgAAg2wkEAF14YtFIItMJCwz/4tVGIXAiUwkEIvCdQONBBI7+H1Xi1UchdJ+R4t1CI2EJBABAADB5gXrBo2bAAAAAA8oAI2AIAIAAGYP/QEPKYDg/f//DyhBEAPOZg/9gPD9//8PKYDw/f//g+oBddKLTCQQi0UgR4PBIOuVi3UchfYPjooAAACNDFUBAAAAiXQkSItVCIvCweAFweIJiUQkHI2EJDABAACJVCQYi1QkKIlMJESJRCQgiVQkPOsDjUkAi/DHRCQQEAAAAIv6jWQkAFaL1+i4+v//A3wkIIPEBItMJESDxiCDbCQQAXXji0QkIItUJDwFIAIAAANUJBiDbCRIAYlEJCCJVCQ8dbOLdRyLfCR4" & _
    79.                                     "i8eLTRiL1w+vxivRiXwkNIlEJBCNBA+JRCRUg30kAIt9CIvHiVQkDHUCK8E5RCQ0D41RAwAAx0QkRAAAAACF9g+OLwMAAI1BAcdEJBQAAAAAD6/BjbQkEAEAAIl0JCADwA+3yItEJDQDRCR8M9KJRCRgjUf/iUwkHImEJIQAAACJVCRYiVQkPIlUJEjHRCQYAAAAADlEJFR/BItEJFQDwsHgBQNEJCwz0olUJFwPKABmD/0GDykGDyhAEIvGZg/9RhAPKUYQZot0JBiQZgMwZjvxdw9Cg8ACiVQkXIP6EHzr6w6LRCRIA8JmK7REEAEAAItEJDyNjCSQAAAAA8KJRCQ4jQRBD7cIiUQkTIvBO0QkDA+P0gAAAItEJBSNjCQwAQAAA8LB4AUDwbkgAAAAi/iJRCQYMsDzqotEJDSLfQgPt8ArRRiLTCRMZokBi0QkYDvHfgKLxw+3CYvRO9B9MItEJDgPr8cDwotUJBjB4AUDRCQoDygCZg/9AA8pAg8oQBCNQQFmD/1CEA8pQhDrtotEJEwPtwA7RCRgD40PAQAAi0QkGItUJCiLTCQ0g8LgUItEJDxAD6/HweAFA9APt8GLTRgrx0EDyOiu+P//i00Yg8QEi1QkNEEPt8IDwYtMJExmiQHpxgAAADtEJGAPjcAAAACLRCQUA8KJTCQYweAFjZQkMAEAAAPQi0QkOA+vx4mUJIAAAACJRCQ4i1UYD7f5i8eNDBKLlCSAAAAAK8EzyYPA/w8oAg+Y" & _
    80.                                     "wUkjyItEJDgDwYtMJCjB4AVmD/kECA8pAg8oQhBmD/lECBCLhCSEAAAADylCEDv4fgKL+ItEJDgDx8HgBQ8oBAhmD/0CDykCDyhECBCLTCQYZg/9QhBBD7fBDylCEIlMJBg7RCRgD4x2////i0QkTIt9CGaJCItUJFyLTCQMM8CFyQ+YwEgjwYtMJCADRCRYweAFA0QkLA8oAWYP+QAPKQEPKEEQZg/5QBCLRCQUA8IPKUEQweAFjYwkMAEAAAPIM8BmAzRBZjt0JBx3CECD+BB87+sbi4wkiAAAAMDiBALQi0QkEANEJCQDRCREiBQIi1QkRI1H/4t0JCBCAXwkWIHGIAIAAIFEJEgQAQAAg0QkPBCDRCQUETtVHItMJByJVCREi1QkWIl0JCAPjCH9//+LdRyLTRiLVCQM/0QkNEL/RCRUAXQkEOmU/P//i0wkMIt8JEBBi0UURwFEJCSDbQwBiUwkMIl8JEAPhYX5//+LdSj/dCRoi0YE/9D/tCSMAAAAi0YE/9BfXovlXcPMzMzM" ' 11.4.2019 11:16:59
    81.     pvPatchThunk AddressOf mdMedianBlur.CTimeMedianFilter, STR_THUNK
    82.     CTimeMedianFilter lSrcPtr, lDstPtr, lWidth, lHeight, lSrcStep, lDstStep, lRadius, lNumChannels, lMaxMemUsage, lImportPtr
    83. End Sub
    84.  
    85. Private Sub pvPatchThunk(ByVal pfn As Long, sThunkStr As String)
    86.     Dim lThunkSize      As Long
    87.     Dim lThunkPtr       As Long
    88.     Dim bInIDE          As Boolean
    89.  
    90.     '--- decode thunk
    91.     Call CryptStringToBinary(StrPtr(sThunkStr), Len(sThunkStr), CRYPT_STRING_BASE64, 0, lThunkSize, 0, 0)
    92.     lThunkPtr = VirtualAlloc(0, lThunkSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE)
    93.     Call CryptStringToBinary(StrPtr(sThunkStr), Len(sThunkStr), CRYPT_STRING_BASE64, lThunkPtr, lThunkSize, 0, 0)
    94.     '--- patch func
    95.     Debug.Assert pvSetTrue(bInIDE)
    96.     If bInIDE Then
    97.         Call CopyMemory(pfn, ByVal pfn + &H16, 4)
    98.     Else
    99.         Call VirtualProtect(pfn, 8, PAGE_EXECUTE_READWRITE, 0)
    100.     End If
    101.     ' B8 00 00 00 00       mov         eax,00000000h
    102.     ' FF E0                jmp         eax
    103.     Call CopyMemory(ByVal pfn, 6333077358968.8504@, 8)
    104.     Call CopyMemory(ByVal (pfn Xor &H80000000) + 1 Xor &H80000000, lThunkPtr, 4)
    105. End Sub
    106.  
    107. Private Function pvSetTrue(bValue As Boolean) As Boolean
    108.     bValue = True
    109.     pvSetTrue = True
    110. End Function
    On a sample Extra_Large_Transparent_Minion_PNG_Image.png image (which is a 4000x5558 pixels 32-bit image) a median blur w/ 30px radius (or 61px kernel box) takes ~6.5 seconds on my machine (Edit: ~3.5 now w/ SSE2).

    Every other image is instantaneous! :-))

    cheers,
    </wqw>

  33. #33

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,817

    Re: [RESOLVED] Best way to Smooth/Contour an image (or whatever it's called

    Oh goodness, Wqweto. I'm not sure I was thinking of a thunk to get it done, but I could see why it would be done that way.

    I appreciate the code, but I'll probably stick with what I've got for now. In p-code, I've got it running in about 1.3 seconds. I'm sure it'll be much faster when I compile it. If I'm still not happy with it, I'll try shuttling it off into an optimized AX-DLL. If that's still not enough, I'll take a look at the thunk you posted.

    Thank You,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  34. #34
    Fanatic Member
    Join Date
    Sep 2010
    Location
    Italy
    Posts
    678

    Re: [RESOLVED] Best way to Smooth/Contour an image (or whatever it's called

    @wqweto
    honestly, it is not of my interest to make a VB6 vs. ASM performance comparison.

  35. #35
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,092

    Re: [RESOLVED] Best way to Smooth/Contour an image (or whatever it's called

    @reexre: Sure.

    FYI, just recompiled the thunk w/ SSE2 optimization on and the 4k image processing is reduced to ~3.5 seconds in the IDE which is about twice the previous speed.

    Unfortunately w/ this impl the filter's kernel shape is rectangular or risk doubling the thunk size (at least) otherwise.

    cheers,
    </wqw>

  36. #36
    Fanatic Member
    Join Date
    Sep 2010
    Location
    Italy
    Posts
    678

    Re: [RESOLVED] Best way to Smooth/Contour an image (or whatever it's called

    @wqweto
    if you want take a look at my VB6 implementation of Median Filter.

    if you could define the algorithm asymptotic complexity of it I'd be glad. Thanks

  37. #37
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,092

    Re: [RESOLVED] Best way to Smooth/Contour an image (or whatever it's called

    @reexre: Does your impl slow down w/ the increase of kernel size? I.e. is it twice slower for two times bigger kernel radius?

    If yes, this means that r (kernel radius) is part of the asymptotic complexity -- something like O(N * r) where N is number of pixels.

    The impl in the link above keeps as many histograms as there are rows in the image and advances these in sync. That's why it performs O(1) (i.e. constant) operations per pixel and has O(N) complexity.

    chees,
    </wqw>

  38. #38
    Fanatic Member
    Join Date
    Sep 2010
    Location
    Italy
    Posts
    678

    Re: [RESOLVED] Best way to Smooth/Contour an image (or whatever it's called

    Quote Originally Posted by wqweto View Post
    @reexre: Does your impl slow down w/ the increase of kernel size? I.e. is it twice slower for two times bigger kernel radius?

    If yes, this means that r (kernel radius) is part of the asymptotic complexity -- something like O(N * r) where N is number of pixels.
    Thanks, Yes, It is slower by increasing Kernel radius. Not sure if linearly. For big radii it seems the case.

    EDIT:
    Good of my algorithm is that can be easily adapted to perform Circle shaped kernel. (And it will be present on next PhotoModularFX Update)

  39. #39
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,092

    Re: [RESOLVED] Best way to Smooth/Contour an image (or whatever it's called

    Trading memory for speed is very popular technique. Yet another impl I was investigating used two heaps to keep account on lower and higher than median values. Heap update (add new then substract old value) required multiple O(log r) operations so the overall complexity was O(N log r). It also employed multiple pair-of-heaps (one pair per row) to "not forget" previous work.

    But as you've explained (graphically) in the other thread, using histograms allows to implement something like "radix sort" on the kernel values because each channel values are constrained in [0-255] interval. Neat optimization IMO!

    cheers,
    </wqw>

  40. #40

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,817

    Re: [RESOLVED] Best way to Smooth/Contour an image (or whatever it's called

    I just wanted to put it out here that I received an extremely gracious and detailed reply from Tanner Helland. Whatever difference we had, it seems that we've both put them behind us.

    I wound up not using any of the PhotoDemon code, but he was quite clear that it would be acceptable, given that I attach the BSD license to those portions (and all modifications), along with an acknowledgement that the original work was his. And I would have had no problems with any of those conditions.

    I'm glad we've turned the corner on this.

    Tanner, truly, all the best to you and yours.


    To Everyone, Take Care,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width