Announcement

Collapse
No announcement yet.

Washing out colors in Images of documents.

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Washing out colors in Images of documents.

    I am back with colors and I would stupid if I did not seek some help.

    i have worked, some people call it playing, with strategies of washing out colors from scanned documents.
    I can write long all day about documents with unwanted colors or shades of colors.
    A lot of my documents may have a solid color paper not white for the background. Image a flyer with yellow paper.
    Some paoers have faded, water damage, dirt, color bleeds from another paper, hand written notes of usually black, blue, red, yellow.
    You name it.
    Light printed dot matrix characters where the ribbon should have long been replaced.
    What I would like to end up with is a white background and mostly black representing characters and line art.
    I am going to try to keep the red and blue and might convert it to black to end up with a black and white document with black text and a white background.
    That would also compress nicely.
    I was able to figure out how to covert to gray scale from my non binary(colored) images of documents.

    Some of you had probably worked in the area I am putting some good effort into.

    What I think might work pretty good is to covert all the
    colors to limited range of colors that might be as high as 256 colors or less than that which my first thought would be 16 colors.
    Then go from there.
    I will likely do some preprocessing of adaptive threasholding. That code has not been created as of yet.
    I am interested in what others have done or even some thoughts.
    I did not start on this project yesterday.
    I did not really think it woukd of been so much of a task till I started seeing the material with an eagle eye and
    making digital images of the documents.
    Later I might even have to use a camera of sorts to get my images. Specially on the documents that were in a flood.
    I would like to put up some images but most of what needs doing has privacy issues about them.

    So any thoughts of washing documents.
    Image a receipt you found outside of a store that has been there for a while or paper you found in some trash dump. Ok some can imagine a comic book colored or not,
    p purvis

  • #2
    Sounds like they (the documents) are already "washed out". Do you mean you want "contrast enhancement"?
    Dale

    Comment


    • #3
      Funny Dale. What we went through and still are going through. Yes. They are washed out I suppose. Maybe I should of said bleed out but I am the one who is is bledding out.
      Dale without me knowing color and image terminology.
      i might think contrast enhancement might be a good word but I never thought thoroughly enough to consider enhancing my problem to get a solution would be logical.
      p purvis

      Comment


      • #4
        I might have some code for this type of thing, but it's going to take me a while to find it, if I still have it. I do remember using GRAPHIC SAVE to create working copies to start with, for example, if the loaded bitmap was "original199.bmp" I would have GRAPHIC SAVE "Copy199.bmp" first thing. All work done on "Copy199.bmp" of course. Did some sampling of sections of the image with GRAPHIC GET PIXEL to longintegervar, converted longintegervar to RGB(red, green, blue) and checked values of the red, green, and blue components.That's all I remember off the top of my head. Seems to me I used GRAPHIC GET/SET BITS once I had the range of corrections nailed.
        I shall start looking, but don't hold your breath.
        Rod
        "To every unsung hero in the universe
        To those who roam the skies and those who roam the earth
        To all good men of reason may they never thirst " - from "Heaven Help the Devil" by G. Lightfoot

        Comment


        • #5
          Dale also what I am looking for is possibly methods.
          I know the task I have is varied based on the condition of the image.
          But I do have control over how the image is created by way of scanned or camera. So I don't think dark shadows or bright spots from lights will be of a matter. When you have debris on paper from water that I suppose could be anything from dirt to mold. Likely those will be taken using a camera because I don't want to break too many document scanners.
          p purvis

          Comment


          • #6
            Originally posted by Paul Purvis View Post
            Dale also what I am looking for is possibly methods.
            I know the task I have is varied based on the condition of the image.
            But I do have control over how the image is created by way of scanned or camera. So I don't think dark shadows or bright spots from lights will be of a matter. When you have debris on paper from water that I suppose could be anything from dirt to mold. Likely those will be taken using a camera because I don't want to break too many document scanners.
            Contrast enhancement may not be ideal. This is more of a special case.
            The standard image manipulation tools may not serve as well as you would like.
            You could go through the image, pixel by pixel.
            If the pixel is lighter than a given threshold value, then make it #ffffff.
            if the pixel is darker, then reduce the value of each RGB value by 50% to darken it more.
            If you are dealing with simple text and line drawings, the threshold can be rather high.
            Just add the total brightness of the three values and test against a fixed value.
            Make the fixed value adjustable. Show the original on one side and the fixed version on the other.
            Include a button to process the data, and a control to input and hold the threshold value.
            It's a simple program to flesh out in concept to test. It may present other ideas as you develop it as well.
            The world is strange and wonderful.*
            I reserve the right to be horrifically wrong.
            Please maintain a safe following distance.
            *wonderful sold separately.

            Comment


            • #7
              I went looking for my old code but I've no idea what I've done with it and I figured it would be quicker to code something quick and dirty to help get you started. Thanks to Borje, it was easy. I once again adapted his graphic buttons code. I've commented out a lot of code so you won't waste time looking in it. The most applicable code starts at line 318.
              Code:
              '====================================================================
              ' gWinButtons.bas - Graphic Window Mouse and Keyboard support.
              ' Compiles as it is with PBWIN10, PBCC6, PBWIN9 and PBCC5.
              ' Public Domain by Borje Hagsten, May 2013.
              '
              ' Shows a way to paint buttons in a graphic window and trap both
              ' Mouse and Keyboard actions for each "button". Also shows a way
              ' to center the Graphic Window on Desktop and how to define our
              ' own User-Defined Data Type (UDT), here for use in an array of
              ' Button area coordinates.
              '
              ' To learn more about each command used in the code, select it and
              ' press F1 to bring up context sensitive help. For example, if you
              ' select GRAPHIC BOX and then press F1, it will bring up the help
              ' page for the GRAPHIC BOX statement with more detailed information
              ' about its features.
              '====================================================================
              ' Added the ability to get Extended control keys into the loop, listed
              ' all extended and CONTROL keys I could find on my machine as triggers
              ' for action options. As well, I changed the GRAPHIC WINDOW CLICK response
              ' by substituting a FOR/NEXT loop and a IF-THEN/END IF block for the two
              ' SELECT CASE/END SELECT blocks to access a TWIXT function that passes
              ' each button to the function until the click location matches, if it
              ' matches. Rod Hicks
              '--------------------------------------------------------------------
              #COMPILE EXE
              #IF %DEF(%PB_CC32)  ' if to be compiled with PBCC6 or PBCC5, then
                #CONSOLE OFF      ' this example doesn't need the console window
              #ENDIF
              
              TYPE BTNRECT   ' User-Defined Data Type (UDT) for Button area
                L AS SINGLE  ' Left side
                T AS SINGLE  ' Top
                R AS SINGLE  ' Right side
                B AS SINGLE  ' Bottom
              END TYPE
              'use your own bitmap here or load it in another fashion
              #RESOURCE BITMAP, 8179, "C:\PBWin10\bmpsFC\CODEFACTbB.BMP"
              
              '====================================================================
              ' Program begins here
              '--------------------------------------------------------------------
              FUNCTION PBMAIN () AS LONG
                LOCAL c, cmd, hDC AS LONG
                LOCAL hFont, hWin, gWin AS DWORD
                LOCAL h, w, x, y, cw, ch, xd, yd, ndx, xcnt, ycnt, midx, midy AS LONG
                LOCAL nwx, nwy, elem, mxclr, mnclr, klr AS LONG
                LOCAL sTemp, itemp AS STRING
                LOCAL cross() AS LONG
                DIM cross(1 TO 64)
                DIM btn(1 TO 4) AS BTNRECT    ' array for 4 button areas, 1 to 4
                mnclr=255*255*255
                '------------------------------------------------------------------
                ' Create a centered Graphic Window and set its colors
                '------------------------------------------------------------------
                w = 650 : h = 650             ' desired dialog size
                DESKTOP GET LOC TO x, y       ' in case taskbar is on Left/Up side
                DESKTOP GET CLIENT TO cw, ch  ' need DeskTop clien size
                x = x + ((cw - w) / 2)        ' calculate centered x
                y = y + ((ch - h) / 2)       ' calculate centered y
              
              
              
              
                GRAPHIC WINDOW "Graphic Window Buttons", x, y, w, h TO hWin
                GRAPHIC ATTACH hWin, 0
                GRAPHIC WINDOW STABILIZE hWin
                DIALOG GET SIZE hWin TO xd, yd
                GRAPHIC COLOR %RGB_GOLD, %RGB_GREEN
                GRAPHIC CLEAR
                midx=xd\2
                midy=yd\2
                nwx= midx-16
                nwy= midy-16
              '  Graphic window new "", -100, 100, 32, 32 to gWin, hide
              '  graphic attach gWin, 0
              
                '------------------------------------------------------------------
                ' Create buttons and some extra for info texts
                '------------------------------------------------------------------
                FONT NEW "Comic Sans MS", 11, 1 TO hFont
                  GRAPHIC SET FONT hFont
              
                  ' Define Button areas: Left, Top, Right, Bottom
                  btn(1).L =  10 : btn(1).T = 10 : btn(1).R = 160 : btn(1).B = 40
                  btn(2).L = 170 : btn(2).T = 10 : btn(2).R = 320 : btn(2).B = 40
                  btn(3).L = 330 : btn(3).T = 10 : btn(3).R = 480 : btn(3).B = 40
                  btn(4).L = 490 : btn(4).T = 10 : btn(4).R = 640 : btn(4).B = 40
              
                  ' Call SUB GRAPHIC_BUTTON, where the "buttons" are created
                  GRAPHIC_BUTTON ("1 Sample cross", btn(1), %RGB_GRAY, %RGB_LIGHTGRAY, %RGB_BLACK)
                  GRAPHIC_BUTTON ("2 Show sample", btn(2), %RGB_GRAY, %RGB_LIGHTGRAY, %RGB_BLACK)
                  GRAPHIC_BUTTON ("3 Fix bitmap", btn(3), %RGB_GRAY, %RGB_LIGHTGRAY, %RGB_BLACK)
              
                  GRAPHIC_BUTTON ("Quit (ESC)",     btn(4), %RGB_GRAY, %RGB_LIGHTGRAY, %RGB_BLACK)
              
                  ' following GRAPHIC commands are for the example's info text
                  GRAPHIC GET CLIENT TO cw, ch   ' only need ch (dialog client height)
                  GRAPHIC TEXT SIZE " " TO w, h  ' only need h  (text height)
              
                  GRAPHIC COLOR %RGB_LIGHTGRAY, %RGB_GREEN
                  GRAPHIC SET POS (10, ch - h - 5)
                  GRAPHIC PRINT "Keys: Press 1 to 3 for Button 1 to 3. Press Esc to quit."
                  GRAPHIC SET POS (10, ch - 2*h - 5)
                  GRAPHIC PRINT "Mouse: Click on the Buttons."
                  GRAPHIC COLOR %RGB_GOLD, %RGB_GREEN
                  GRAPHIC WIDTH 2
                  GRAPHIC LINE (-1, ch - 2*h - 10) - (cw, ch - 2*h - 10)
                FONT END hFont
              
                '------------------------------------------------------------------
                FONT NEW "Comic Sans MS", 14, 1 TO hFont  'font for big info text
                GRAPHIC SET FONT hFont
                GRAPHIC TEXT SIZE " " TO c, h             'only need h
                GRAPHIC COLOR %RGB_GOLD, %RGB_MAROON      'colors for info text
                GRAPHIC RENDER BITMAP "#8179",(nwx,nwy)-(nwx+31,nwy+31)
              
                '------------------------------------------------------------------
                ' Main program loop
                '------------------------------------------------------------------
                DO
                    SLEEP 1  ' short sleep needed too let processor (CPU) breathe
              
                    '--------------------------------------------------------------
                    ' Mouse support
                    '--------------------------------------------------------------
                    GRAPHIC WINDOW CLICK hWin TO c, x, y ' see if Mouse was clicked
                    IF c THEN                            ' if it was clicked
              '          SELECT CASE y
              '          CASE btn(1).T TO btn(1).B        ' if in buttons vertical area
              '              SELECT CASE AS LONG x        ' which button was clicked?
              '              CASE btn(1).L TO btn(1).R : cmd = 1  ' Button 1 area
              '              CASE btn(2).L TO btn(2).R : cmd = 2  ' Button 2 area
              '              CASE btn(3).L TO btn(3).R : cmd = 3  ' Button 3 area
              '              CASE btn(4).L TO btn(4).R : cmd = 4  ' Button 4 area (Quit)
              '              END SELECT
              '          END SELECT
                      FOR ndx=LBOUND(btn()) TO UBOUND(btn())
                        IF ISTRUE twixt (btn(ndx), x, y) THEN
                          cmd=ndx
                          EXIT FOR
                        END IF
                      NEXT ndx
                    END IF
              
                    '--------------------------------------------------------------
                    ' Keyboard support
                    '--------------------------------------------------------------
                    GRAPHIC INKEY$ TO sTemp     'if a key is pressed
                    IF LEN(sTemp) = 1 THEN      'if it's a standard key
                        SELECT CASE sTemp       'following are the keys used here
                        CASE "1"      : cmd = 1 '1 is our shortcut key for button 1
                        CASE "2"      : cmd = 2 '2 is our shortcut key for button 2
                        CASE "3"      : cmd = 3 '3 is our shortcut key for button 3
              
                        CASE CHR$(27) : cmd = 4 'Esc key has ANSI code 27 (Quit)
                        END SELECT
              
              '          SELECT CASE ASC(sTemp)
              '            CASE 1  ' CTRL a
              '              itemp = "CTRL a"
              '            CASE 2  ' CTRL b
              '              itemp = "CTRL b"
              '            CASE 3  ' CTRL c
              '              itemp = "CTRL c"
              '            CASE 4  ' CTRL d
              '              itemp = "CTRL d"
              '            CASE 5  ' CTRL e
              '              itemp = "CTRL e"
              '            CASE 6  ' CTRL f
              '              itemp = "CTRL f"
              '            CASE 7  ' CTRL g
              '              itemp = "CTRL g"
              '            CASE 8  ' CTRL h
              '              itemp = "CTRL h"
              '            CASE 10 ' CTRL j
              '              itemp = "CTRL j"
              '            CASE 11 ' CTRL k
              '              itemp = "CTRL k"
              '            CASE 12 ' CTRL l
              '              itemp = "CTRL l"
              '            CASE 13 ' CTRL m
              '              itemp = "CTRL m"
              '            CASE 14 ' CTRL n
              '              itemp = "CTRL n"
              '            CASE 15 ' CTRL o
              '              itemp = "CTRL o"
              '            CASE 16 ' CTRL p
              '              itemp = "CTRL p"
              '            CASE 17 ' CTRL q
              '              itemp = "CTRL q"
              '            CASE 18 ' CTRL r
              '              itemp = "CTRL r"
              '            CASE 19 ' CTRL s
              '              itemp = "CTRL s"
              '            CASE 20 ' CTRL t
              '              itemp = "CTRL t"
              '            CASE 21 ' CTRL u
              '              itemp = "CTRL u"
              '            CASE 22 ' CTRL v
              '              itemp = "CTRL v "
              '            CASE 23 ' CTRL w
              '              itemp = "CTRL w"
              '            CASE 24 ' CTRL x
              '              itemp = "CTRL x"
              '            CASE 25 ' CTRL y
              '              itemp = "CTRL y"
              '            CASE 26 ' CTRL z
              '              itemp = "CTRL z"
              '            CASE 27 ' CTRL [  Not entirely sure on this, it closes the app as the ESCAPE key does.
              '              itemp = "CTRL ["
              '            CASE 28 ' CTRL \
              '              itemp = "CTRL \"
              '            CASE 29 ' CTRL ]
              '              itemp = "CTRL ]"
              '            CASE 127' CTRL (backspace)
              '              itemp = "CTRL (backspace)"
              '          END SELECT
              '          GRAPHIC BOX (10,60)-(650,90), 0,%RGB_MAROON, %RGB_MAROON
              '          GRAPHIC SET POS (10,60)
              '          GRAPHIC PRINT "key: " itemp " key value " ASC(sTemp)
              
                        sTemp = ""              'clear receiving string variable
              '      ELSEIF LEN(sTemp) = 2 THEN
              '
              '
              '        SELECT CASE ASC(stemp,2)
              '
              '          CASE 3  ' second up indicator right end of keyboard
              '            itemp = "second up indicator right end of keyboard"
              '          CASE 6  ' dot(?) right end of keyboard
              '            itemp = "dot(?) right end of keyboard"
              '          CASE 16 ' far left indicator right end of keyboard
              '            itemp = "far left indicator right end of keyboard"
              '          CASE 20 ' club+hp
              '            itemp = "club+hp "
              '          CASE 24 ' up indicator  right end of keyboard
              '            itemp = "up indicator  right end of keyboard"
              '          CASE 25 ' far right indicator right end of keyboard
              '            itemp = "far right indicator right end of keyboard"
              '          CASE 32 'mute button
              '            itemp = "mute button"
              '          CASE 34 'right indicator right end of keyboard
              '            itemp = "right indicator right end of keyboard"
              '          CASE 35 'web
              '            itemp = "web"
              '          CASE 36 'box right end of keyboard
              '            itemp = "box right end of keyboard"
              '          CASE 38 '?
              '            itemp = "?"
              '          CASE 46 'sound volume down
              '            itemp = "sound volume down"
              '          CASE 48 'sound volume up
              '            itemp = "sound volume up"
              '          CASE 59  ' f1
              '            itemp = "f1"
              '          CASE 60
              '            itemp = "f2"
              '          CASE 61
              '            itemp = "f3"
              '          CASE 62
              '            itemp = "f4"
              '          CASE 63
              '            itemp = "f5"
              '          CASE 64
              '            itemp = "f6"
              '          CASE 65
              '            itemp = "f7"
              '          CASE 66
              '            itemp = "f8"
              '          CASE 67
              '            itemp = "f9"
              '          CASE 68
              '            itemp = "f10"
              '          CASE 71 'home
              '            itemp = "home"
              '          CASE 72 ' up arrow  72, left arrow  75, right arrow 77, down arrow 80
              '            itemp = "up arrow"
              '          CASE 73 'page up
              '            itemp = "page up"
              '          CASE 75 'left arrow
              '            itemp = "left arrow"
              '          CASE 77 'right arrow
              '            itemp = "right arrow"
              '          CASE 79 'end
              '            itemp = "end"
              '          CASE 80 'down arrow
              '            itemp = "down arrow"
              '          CASE 81 'page down
              '            itemp = "page down"
              '          CASE 82 'insert
              '            itemp = "insert"
              '          CASE 83 'delete
              '            itemp = "delete"
              '          CASE 87 'f11
              '            itemp = "f11"
              '          CASE 88 'f12
              '            itemp = "f12"
              '          CASE 91 'left windows launch
              '            itemp = "left windows launch"
              '          CASE 93 'right windows
              '            itemp = "right windows"
              '          CASE 101 'email  launch
              '            itemp = "email  launch"
              '          CASE 108 'windows email launch
              '            itemp = "windows email launch"
              '        END SELECT
              '
              '        GRAPHIC BOX (10,60)-(650,90), 0,%RGB_MAROON, %RGB_MAROON
              '        GRAPHIC SET POS (10,60)
              '        GRAPHIC PRINT "key: " itemp " Extended key value " ASC(sTemp,2)
              '        sTemp = ""
                    END IF
              
                    '--------------------------------------------------------------
                    ' Resulting action - command center
                    '--------------------------------------------------------------
                    IF cmd THEN
                        GRAPHIC SET POS (10, 7*h) 'to show what cmd we got
                        SELECT CASE cmd
                        CASE 1 ': GRAPHIC PRINT "Button 1 was triggered. " GRAPHIC RENDER BITMAP "#8179",(nwx,nwy)-(nwx+31,nwy+31)
                          FOR ycnt=nwy TO nwy+31
                            INCR elem
                            GRAPHIC GET PIXEL (midx, ycnt) TO cross(elem)
                          NEXT ycnt
                          FOR xcnt=nwx TO nwx+31
                            INCR elem
                            GRAPHIC GET PIXEL (xcnt, midy) TO cross(elem)
                          NEXT xcnt
                        CASE 2 ': GRAPHIC PRINT "Button 2 was triggered. "
                          elem=0
                          FOR ycnt=nwy TO nwy+31
                            INCR elem
                            GRAPHIC SET PIXEL (midx-50,ycnt), cross(elem)
                            IF cross(elem)<mnclr THEN mnclr=cross(elem)
                            IF cross(elem)>mxclr THEN mxclr=cross(elem)
                          NEXT ycnt
                          FOR xcnt=nwx-50 TO nwx-50+31
                            INCR elem
                            GRAPHIC SET PIXEL (xcnt, midy), cross(elem)
                            IF cross(elem)<mnclr THEN mnclr=cross(elem)
                            IF cross(elem)>mxclr THEN mxclr=cross(elem)
                          NEXT xcnt
              
                        CASE 3 ': GRAPHIC PRINT "Button 3 was triggered. "
                          FOR ycnt=nwy TO nwy+31
                            FOR xcnt=nwx TO nwx+31
                              GRAPHIC GET PIXEL (xcnt, ycnt) TO klr
                              IF klr>mnclr THEN
                                GRAPHIC SET PIXEL (xcnt+50,ycnt), mxclr
                              ELSE
                                GRAPHIC SET PIXEL (xcnt+50,ycnt), mnclr
                              END IF
                            NEXT xcnt
                          NEXT ycnt
                        CASE 4 : EXIT DO       'Exit loop = end program
                        END SELECT
                        cmd = 0                'Clear command variable
                    END IF
              
                    'need a way out of loop if user exits via system menu or X
                    GRAPHIC GET DC TO hDC  'if hDC becomes 0, program is closing
                LOOP UNTIL hDC = 0
                GRAPHIC WINDOW END hWin
                FONT END hFont
              
              END FUNCTION  ' <- Program ends here
              
              
              '====================================================================
              ' Button creation procedure
              ' Draws a box from L,T to R,B using given colors and prints
              ' the given sCaption string centered inside the box area.
              '--------------------------------------------------------------------
              SUB GRAPHIC_BUTTON (BYVAL sCaption AS STRING, BYVAL btn AS BTNRECT, _
                                  BYVAL BorderColor AS LONG, BYVAL FillColor AS LONG, _
                                  BYVAL TextColor AS LONG)
                '------------------------------------------------------------------
                LOCAL w, h, x, y AS SINGLE
              
                GRAPHIC BOX (btn.L, btn.T) - (btn.R, btn.B), 20, BorderColor, FillColor, 0
              
                GRAPHIC COLOR TextColor, FillColor     ' set text colors
                GRAPHIC TEXT SIZE sCaption TO w, h     ' need text size
                x = btn.L + ((btn.R - btn.L - w) / 2)  ' centered text x
                y = btn.T + ((btn.B - btn.T - h) / 2)  ' centered text y
                GRAPHIC SET POS (x, y-1)               ' set text position
                GRAPHIC PRINT sCaption                 ' and print text (caption)
              
              END SUB
              
              FUNCTION twixt(BYVAL btn AS BTNRECT, BYVAL x AS LONG, BYVAL y AS LONG) AS LONG
                IF (x>=btn.L AND x<=btn.R) AND (y>=btn.T AND y<=btn.B) THEN
                  FUNCTION =1
                  EXIT FUNCTION
                END IF
                FUNCTION=0
              END FUNCTION
              '
              '#COMPILE EXE
              '#DIM ALL
              '#INCLUDE "WIN32API.INC"
              ''------------------
              '
              'THREAD FUNCTION NewThread(BYVAL hWin AS DWORD) AS LONG
              '  CONTROL ADD BUTTON, hWin, 222,  "Thread Btn", 140, 150,  50, 15
              '  DIALOG SEND hWin, %WM_APP + 101, 223, 0
              '    MessageBox 0, "In Thread","Holding", %MB_SYSTEMMODAL ' Without loop NewThread dies when msgbox released
              '    GRAPHIC ATTACH hWin, 111
              '    GRAPHIC CLEAR %BLUE
              '   DO                                ' Remove comments to keep NewThread alive
              '     DIALOG DOEVENTS
              '   LOOP WHILE ISWIN(hWin)
              'END FUNCTION
              ''------------------/NewThread
              '
              'CALLBACK FUNCTION DlgProc()
              '  SELECT CASE AS LONG CBMSG
              '    CASE %WM_INITDIALOG
              '      DIALOG POST CBHNDL, %WM_USER + 1000, 0, 0
              '
              '    CASE %WM_USER + 1000
              '
              '     CASE %WM_APP + 101
              '        CONTROL ADD GRAPHIC, CB.HNDL, 111, "", 10, 45, 35, 35, %WS_BORDER
              '        CONTROL ADD BUTTON,  CB.HNDL, CB.WPARAM, "GUI Btn", 140, 120,  50, 15   '(wparam = 223)
              '
              '    CASE %WM_COMMAND
              '      SELECT CASE AS LONG CBCTL
              '        CASE %IDOK
              '          IF CBCTLMSG = %BN_CLICKED THEN
              '           LOCAL hThread, lRes AS LONG
              '            THREAD CREATE NewThread(CBHNDL) TO hThread
              '            THREAD CLOSE hThread TO lRes : hThread = 0
              '          END IF
              '        CASE 222
              '          IF CBCTLMSG = %BN_CLICKED THEN
              '           GRAPHIC ATTACH CB.HNDL, 111
              '           GRAPHIC CLEAR %RED
              '          END IF
              '        CASE 223
              '          IF CBCTLMSG = %BN_CLICKED THEN
              '           GRAPHIC ATTACH CB.HNDL, 111
              '           GRAPHIC CLEAR %GREEN
              '          END IF
              '        CASE %IDCANCEL
              '          IF CBCTLMSG = %BN_CLICKED THEN
              '            DIALOG END CBHNDL
              '          END IF
              '      END SELECT
              '
              '  END SELECT
              'END FUNCTION
              ''------------------/DlgProc
              '
              'FUNCTION PBMAIN()
              ' LOCAL hDlg AS DWORD
              '  DIALOG NEW 0, "Test", 265, 165, 200, 180, %WS_CAPTION OR %WS_SYSMENU TO hDlg
              '    CONTROL ADD LABEL,  hDlg, 201,    "Test Dialog",  5, 5, 120, 15
              '    CONTROL ADD BUTTON, hDlg, %IDOK,  "Test",       140, 5,  50, 15
              '
              '  DIALOG SHOW MODAL hDlg, CALL DlgProc
              'END FUNCTION
              ''------------------/PbMain
              A sample.
              Click image for larger version

Name:	swap_colours.gif
Views:	2
Size:	1.5 KB
ID:	774761
              Attached Files
              Rod
              "To every unsung hero in the universe
              To those who roam the skies and those who roam the earth
              To all good men of reason may they never thirst " - from "Heaven Help the Devil" by G. Lightfoot

              Comment


              • #8
                A simple , naive method , code hereby is to replace near white with white .
                The following one line of code ( i inserted today in an old program ) may give some results
                Code works on "bmp" files .

                IF R*G*B>8000000 THEN G=255:R=255:B=255 ' get near white to white

                Code:
                'fk BitmapColorManipulation rev 04 20/09/2014
                ' rev 01 : added the "invert " function
                ' rev 02 : added the "cyan max" function , usefull for blue - red glasses
                ' rev 03 : code has been optimized specific : made general subroutine
                ' rev 04 : "open file" selection   added before program start
                ' rev 05 : "added a feature in "custom" i  order to turn near white to white
                
                ' cyanmax will get a white picture viewed trough cyan glass ; redMax will get a white picture vieuwed troug red glass
                'this  code reads a bmp file from disk , puts it on screen and lets you transform the colors according to the buttons displayed above
                'the modifications are sequential : each time the converted picture is subject to transformation
                ' the checkbox : apply to original lets the action go upon the original , if not the action happens upon the result .
                ' the code is straightforward , no attempt for optimization was made
                
                'Compilable Example:
                'from here : http://www.powerbasic.com/support/pbforums/showthread.php?t=53493&highlight=lighten
                'which in turn :from here:  http://www.pvladov.com/2012/09/make-color-lighter-or-darker.html
                ' Thanks to Gary Beene and Kurt Kuzba
                
                #COMPILE EXE
                #DIM ALL
                %Unicode=1
                #INCLUDE "Win32API.inc"
                
                
                GLOBAL hDlg AS DWORD, hBMP AS DWORD
                GLOBAL bmpfilename$,bmp$, a$
                GLOBAL nW&,nH&,Useoriginal&
                GLOBAL redmax&,greenmax&,bluemax&,redmin&,greenmin&,bluemin&  'needed for subroutine control
                GLOBAL swrg&,swrb&,swgb&,swrotL&,swrotR&,invert&,cyanmax&     'needed for subroutine control
                
                %ID_Graphic1 = 500
                %ID_Graphic2 = 501
                %ID_Lighten=300
                %ID_Darken=320
                %ID_Grey=330
                %ID_Redmax=301
                %ID_Greenmax=302
                %ID_Bluemax=303
                %ID_Redmin=304
                %ID_Greenmin=305
                %ID_Bluemin=306
                %ID_Sw_R_G=307
                %ID_Sw_R_B=308
                %ID_Sw_G_B=309
                %ID_Sw_RotL=310
                %ID_Sw_RotR=311
                %ID_Original=312
                %ID_ApplyOriginal=313
                %ID_Custom=314
                %ID_Invert=315
                %ID_CyanMax=316
                %Idc_show=400
                
                FUNCTION PBMAIN() AS LONG
                   Loadabitmap          'load a bitmap with the display  function and retrieve W,H
                   DIALOG NEW PIXELS, 0, "Bitmap color manipulation ",100,100,900,nH&+100, %WS_SYSMENU, 0 TO hDlg
                
                   CONTROL ADD BUTTON, hDlg, %ID_Lighten, "Lighten",            10,     10,     50,20
                   CONTROL ADD BUTTON, hDlg, %ID_Redmax, "RedMax",              70,     10,     50,20
                   CONTROL ADD BUTTON, hDlg, %ID_Greenmax, "GreenMax",          130,    10,     50,20
                   CONTROL ADD BUTTON, hDlg, %ID_Bluemax, "BlueMax",            190,    10,     50,20
                   CONTROL ADD BUTTON, hDlg, %ID_Redmin, "RedMin",              250,    10,     50,20
                   CONTROL ADD BUTTON, hDlg, %ID_Greenmin, "GreenMin",          310,    10,     50,20
                   CONTROL ADD BUTTON, hDlg, %ID_Bluemin, "BlueMin",            370,    10,     50,20
                   CONTROL ADD BUTTON, hDlg, %ID_Sw_R_G, "Sw R G",              430,    10,     50,20
                   CONTROL ADD BUTTON, hDlg, %ID_Sw_R_B, "Sw R B",              500,    10,     50,20
                   CONTROL ADD BUTTON, hDlg, %ID_Sw_G_B, "Sw G B",              560,    10,     50,20
                   CONTROL ADD BUTTON, hDlg, %ID_Sw_RotL, "Sw RotL",            620,    10,     50,20
                   CONTROL ADD BUTTON, hDlg, %ID_Sw_RotR, "Sw RotR",            680,    10,     50,20
                   CONTROL ADD BUTTON, hDlg, %ID_Original, "Original",          740,    10,     50,20
                   CONTROL ADD BUTTON, hDlg, %ID_Custom, "Custom",              740,    30,     50,20
                   CONTROL ADD BUTTON, hDlg, %ID_Invert, "Invert",              680,    30,     50,20
                   CONTROL ADD BUTTON, hDlg, %ID_Cyanmax, "CyanMax",            190,    30,     50,20
                   CONTROL ADD CHECKBOX, hDlg, %ID_ApplyOriginal, "Apply to Original", 10,30,100,20
                
                   CONTROL ADD GRAPHIC, hDlg, %ID_Graphic1,"", 10,60,nW&,nH&, %WS_VISIBLE ' Or %SS_Sunken
                   CONTROL ADD GRAPHIC, hDlg, %ID_Graphic2,"", 10+10+nW&,60,nW&,nH&, %WS_VISIBLE 'Or %SS_Sunken
                   GRAPHIC ATTACH hDlg, %ID_Graphic1 : GRAPHIC COLOR %BLACK,%WHITE : GRAPHIC CLEAR
                   GRAPHIC RENDER bmpfilename$ , (0,0)-(nW&,nH&)
                
                   GRAPHIC ATTACH hDlg, %ID_Graphic1
                   GRAPHIC GET BITS TO bmp$
                   DIALOG SHOW MODAL hDlg CALL DlgProc
                END FUNCTION
                
                CALLBACK FUNCTION DlgProc() AS LONG
                   IF CB.MSG=%WM_INITDIALOG THEN original
                
                   CONTROL GET CHECK hDlg, %ID_ApplyOriginal TO Useoriginal&
                
                   IF CB.MSG = %WM_COMMAND AND CB.CTL = %ID_Lighten THEN a$="Grey":GrayScale
                   IF CB.MSG = %WM_COMMAND AND CB.CTL = %ID_Redmax THEN a$="RedMax":Redmax&=1 : general
                   IF CB.MSG = %WM_COMMAND AND CB.CTL = %ID_Greenmax THEN a$="GreenMax":Greenmax&=1: general
                   IF CB.MSG = %WM_COMMAND AND CB.CTL = %ID_Bluemax THEN a$="BlueMax":Bluemax&=1 : general
                   IF CB.MSG = %WM_COMMAND AND CB.CTL = %ID_Redmin THEN a$="RedMin":Redmin&=1: general
                   IF CB.MSG = %WM_COMMAND AND CB.CTL = %ID_Greenmin THEN a$="GreenMin":Greenmin&=1 : general
                   IF CB.MSG = %WM_COMMAND AND CB.CTL = %ID_Bluemin THEN a$="BlueMin":Bluemin&=1 : general
                   IF CB.MSG = %WM_COMMAND AND CB.CTL = %ID_Sw_R_G THEN a$="SW RG":SWRG&=1 : general
                   IF CB.MSG = %WM_COMMAND AND CB.CTL = %ID_Sw_R_B THEN a$="SW RB":SWRB&=1 : general
                   IF CB.MSG = %WM_COMMAND AND CB.CTL = %ID_Sw_G_B THEN a$="SW GB":SWGB&=1 : general
                   IF CB.MSG = %WM_COMMAND AND CB.CTL = %ID_Sw_RotL THEN a$="Rot Left":SWRotL&=1 : general
                   IF CB.MSG = %WM_COMMAND AND CB.CTL = %ID_Sw_RotR THEN a$="Rot Right":SWRotR&=1 : general
                   IF CB.MSG = %WM_COMMAND AND CB.CTL = %ID_INvert THEN a$="Invert":invert&=1 : general
                   IF CB.MSG = %WM_COMMAND AND CB.CTL = %ID_Cyanmax THEN a$="CyanMax":Cyanmax&=1 : general
                   IF CB.MSG = %WM_COMMAND AND CB.CTL = %ID_Original THEN Original
                   IF CB.MSG = %WM_COMMAND AND CB.CTL = %ID_Custom THEN CUSTOM
                
                END FUNCTION
                
                SUB Loadabitmap
                    DISPLAY OPENFILE 0, 10, 30, "Open Bitmap", _
                            "", "BITMAP" + CHR$(0) + "*.bmp" + CHR$(0), "", _
                            "", %OFN_FILEMUSTEXIST TO  bmpfilename$
                    OPEN BmpfileName$ FOR BINARY AS #1     ' Retrieving the width and the height of the bitmap to set the dialog '
                        GET #1, 19, nW&
                        GET #1, 23, nH&
                   CLOSE #1
                END SUB
                
                SUB general
                   LOCAL w AS LONG, h AS LONG, p AS LONG PTR, i AS LONG
                   LOCAL iColor AS LONG, R,G,B,Rn,Gn,Bn AS SINGLE, bmp$
                
                   'get the string from ID_Graphic1
                   IF Useoriginal&=1 THEN GRAPHIC ATTACH hDlg, %ID_Graphic1 ELSE GRAPHIC ATTACH hDlg, %ID_Graphic2
                   GRAPHIC GET BITS TO bmp$
                
                   'get width/height of image
                   w = CVL(bmp$,1)
                   h = CVL(bmp$,5)
                   p = STRPTR(bmp$)+8    'position of starting position for bits in string
                
                   'get string position of coordinates and modify the string at that position
                
                   FOR i = 1 TO w*h
                      iColor = @p                           'result is a BGR color value 0-R-G-B
                      B = iColor MOD 256                    'or this: iColor AND &HFF&
                      G = (iColor\256) MOD 256              'or this: (iColor AND &HFF00&) \ &H100
                      R = (iColor\256\256) MOD 256
                      Rn=R :Gn=G: Bn=B                       'or this: (iColor AND &HFF0000&) \ &H10000&
                      IF redmax&=1 THEN R=255
                      IF greenmax&=1 THEN G =255
                      IF bluemax&=1 THEN B=255
                      IF redmin&=1 THEN R=0
                      IF greenmin&=1 THEN G=0
                      IF bluemin&=1 THEN B=0
                      IF swrg&=1 THEN R=Gn:G=Rn
                      IF swrb&=1 THEN R=Bn:B=Rn
                      IF swgb&=1 THEN G=Bn:B=Gn
                      IF swrotl&=1 THEN B=Rn:G=Bn:R=Gn
                      IF swrotr&=1 THEN B=Gn:G=Rn:R=Bn
                      IF invert&=1 THEN R=255-Rn:G=255-Gn:B=255-Bn
                      IF cyanmax&=1 THEN B=255:G=255
                      @p = BGR(R,G,B)                       'modify string at that position
                      INCR p
                   NEXT i
                
                   'put the modified string into ID_Graphic2
                   GRAPHIC ATTACH hDlg, %ID_Graphic2
                   GRAPHIC SET BITS bmp$
                   GRAPHIC SAVE "result"+a$+".bmp"
                   redmax&=0:greenmax&=0:bluemax&=0:redmin&=0:greenmin&=0:bluemin&=0
                   swrg&=0:swrb&=0:swgb&=0:swrotL&=0:swrotR&=0:invert&=0:cyanmax&=0
                END SUB
                
                SUB CUSTOM
                   LOCAL w AS LONG, h AS LONG, p AS LONG PTR, i AS LONG
                   LOCAL iColor AS LONG, R,G,B AS SINGLE, bmp$
                
                   'get the string from ID_Graphic1
                   IF Useoriginal&=1 THEN GRAPHIC ATTACH hDlg, %ID_Graphic1 ELSE GRAPHIC ATTACH hDlg, %ID_Graphic2
                   GRAPHIC GET BITS TO bmp$
                
                   'get width/height of image
                   w = CVL(bmp$,1)
                   h = CVL(bmp$,5)
                   p = STRPTR(bmp$)+8    'position of starting position for bits in string
                
                   'get string position of coordinates and modify the string at that position
                
                
                   FOR i = 1 TO w*h
                      iColor = @p                           'result is a BGR color value 0-R-G-B
                      B = iColor MOD 256                    'or this: iColor AND &HFF&
                      G = (iColor\256) MOD 256              'or this: (iColor AND &HFF00&) \ &H100
                      R = (iColor\256\256) MOD 256          'or this: (iColor AND &HFF0000&) \ &H10000&
                      'IF R<10 AND G<10 AND B<10 THEN R=0:G=0:B=0       ' get near black to black
                      'IF R*G*B=0  THEN  G=255:R=255                    ' get black to yellow
                      IF R*G*B>8000000  THEN  G=255:R=255:B=255         ' get near white to white
                      @p = BGR(R,G,B)           'modify string at that position
                      INCR p
                   NEXT i
                
                
                
                
                   'put the modified string into ID_Graphic2
                   GRAPHIC ATTACH hDlg, %ID_Graphic2
                   GRAPHIC SET BITS bmp$
                   GRAPHIC SAVE "resultcustom.bmp"
                END SUB
                
                
                SUB GrayScale   'uses Long pointer/CVL solution
                   LOCAL w AS LONG, h AS LONG, p AS LONG PTR, i AS LONG
                   LOCAL iColor AS LONG, R,G,B AS SINGLE, bmp$
                   LOCAL correctionfactor AS SINGLE
                
                   'get the string from ID_Graphic2
                   IF Useoriginal&=1 THEN GRAPHIC ATTACH hDlg, %ID_Graphic1 ELSE GRAPHIC ATTACH hDlg, %ID_Graphic2
                   GRAPHIC GET BITS TO bmp$
                
                   'get width/height of image
                   w = CVL(bmp$,1)
                   h = CVL(bmp$,5)
                   p = STRPTR(bmp$)+8    'position of starting position for bits in string
                
                   'get string position of coordinates and modify the string at that position
                   correctionfactor = +0.2
                   FOR i = 1 TO w*h
                      iColor = @p                           'result is a BGR color value 0-R-G-B
                      B = iColor MOD 256                    'or this: iColor AND &HFF&
                      G = (iColor\256) MOD 256              'or this: (iColor AND &HFF00&) \ &H100
                      R = (iColor\256\256) MOD 256          'or this: (iColor AND &HFF0000&) \ &H10000&
                      IF (correctionFactor < 0) THEN
                         R *= (1+correctionFactor)
                         G *= (1+correctionFactor)
                         B *= (1+correctionFactor)
                      ELSE
                         R = (255 - R) * correctionFactor + R
                         G = (255 - G) * correctionFactor + G
                         B = (255 - B) * correctionFactor + B
                      END IF
                      @p = BGR(R,G,B)           'modify string at that position
                      INCR p
                   NEXT i
                
                   'put the modified string into ID_Graphic2
                   GRAPHIC ATTACH hDlg, %ID_Graphic2
                   GRAPHIC SET BITS bmp$
                   GRAPHIC SAVE "resultlighter.bmp"
                END SUB
                
                SUB Original
                   GRAPHIC ATTACH hDlg, %ID_Graphic1
                   GRAPHIC GET BITS TO bmp$
                   GRAPHIC ATTACH hDlg, %ID_Graphic2
                   GRAPHIC SET BITS bmp$
                END SUB

                Comment


                • #9
                  Thank you
                  Rodney I will try that code soon today.

                  Kurt. Thank you.
                  You have in mind what I was sort of thinking.
                  I don't think one hard coded process alone will get the job done.
                  Last night I was thinking of processing the image with a copy of the original kept unchanged and have a final series of loops to read the original looking for colors to keep(reds and blues mostly from markis with an ink pen).

                  Kurt. I understand the thresholding, at least a couple of the flavors of it.
                  But how would I darken an RGB to 50 percent.
                  I have looked at the RGB values closely many many times. And so far, looking at the 3 separate colors has got me scratching my head. Just looking at one color alone is not bad. Only the 3 together. I found the values of 16 level grayscale and it looks like that might be what I have to use to base the initial threshold pass on to try and get to a black and white base image before trying to transfer any special colors. by really the special colors can be an applied secondly. It is the first pass that has me troubled.
                  My original code had where I was thresholding values on blue first, then I think Red, then Green. It was ok most of the time and not bad for a start. But I believe I was doing it wrong after looking through the results and more observation needed there for that method. If the value of 3 separate colors did not meet my hard coded values for thresholding then I set the pixel white.
                  I suppose it would be better if I posted those IF statements.
                  Do I need to consider or work wity HUE values rather than RGB or should I just stick with RGB and work with RGB.
                  I do know one thing I learned looking at the pixels wth with programs like Microsoft paint. If you want to keep your pixels set to colors you set them for possible other purposes like OCR. Stay away from using lossy image formats if you prepossesed your image before hand. Why I say this because I did not expect to see any pixel colors other than black or white in a jpg file after saving it. But there they were, not only pixels of pure black and white in the jpg file saved. I did not expect gray pixels.
                  p purvis

                  Comment


                  • #10
                    ... how would I darken an RGB to 50 percent.
                    Divide RED by 2, divide GREEN by 2, divide BLUE by 2. You can not just divide the RGB LONG by 2 (or any number) because the remainder goes into the next lower byte (blue to green byte, green to red byte).

                    You said 50%, shift right 1 bit each color of each pixel. If you made TYPE/UNION then -
                    Code:
                    TYPE RGBT
                      Rd as byte
                      Gr as byte
                      Bl as byte
                      dummy as byte
                    END TYPE
                    UNION RGBU
                      Lg as long
                      Tp as RGBT
                    END UNION
                    '.... some code
                      LOCAL MyPixel as RGBU
                    'get pixels one at atime 
                      MyPixel.Lg = 'get next to be darkened from bitmap
                      SHIFT RIGHT MyPixel.Tp.Rd, 1
                      SHIFT RIGHT MyPixel.Tp.Gr, 1
                      SHIFT RIGHT MyPixel.Tp.Bl, 1
                    ...
                    'more code
                    Cheers,
                    Dale

                    Comment


                    • #11
                      Originally posted by Dale Yarker View Post
                      Divide RED by 2, divide GREEN by 2, divide BLUE by 2. You can not just divide the RGB LONG by 2 (or any number) because the remainder goes into the next lower byte (blue to green byte, green to red byte).
                      That's the "simple" approach. Unfortunately, it doesn't give particularly good results. You need to consider perceived brightness / apparent luminance / lightness /contrast ratio. We've discussed this before (a forum search on "Relative Luminance" will be illuminating).

                      The amount of G has much more affect on the "brightness" of a colour.than does the amount of B. If you want to "lighten" a colour by x%, you need to take this into account.

                      Formulae for Relative Luminance here: https://www.w3.org/TR/WCAG20/#relativeluminancedef.

                      How to use that to change luminance by a given percentage without changing the "colour" is left as an exercise for the reader



                      Comment


                      • #12
                        No disagreement with that. But an RGB can't be treated as single value, Determining the differient amount of change to each primary to perform a "darken" is, as you say "... an exercise for the reader ..." (ie I left it simple on purpose)
                        Dale

                        Comment


                        • #13
                          Well, I know that it looks like I assumed that the letter B in the bitmap I choose was the darkest color, the lowest integer value on the bitmap, but in reality, I knew better. It was the lowest value because it was %RGB_MAROON (RGB(128,000,000)) (integer value =128) and all other colours in the bitmap had some value in the blue or green component with any higher red value to keep the background lighter in colour. As soon as you mix a green or blue with red the integer value is substantially higherat least 256 higher as in RGB(128,001,000) is integer value 384, RGB(128,000,001) is integer value 65664. The value of 1 for green sets the first bit of the second byte of the integer, ergo that bite by itself is 256 which is larger than the red 128 so I was pretty safe when looking for the darker as lowest integer color in this particular case. There are only 127 values that are darker and they are all darker reds. So sometimes you can treat 'darker' as a single value.

                          Now that you know that I wasn't just lucky in the code I posted and I've had to explain myself and spoil the mystique I might have generated, I have to agree with you Dale that generally lower doesn't necessarily mean darker. The point was to suggest a means of assessing the current values so the user could decide which to manipulate.
                          Rod
                          "To every unsung hero in the universe
                          To those who roam the skies and those who roam the earth
                          To all good men of reason may they never thirst " - from "Heaven Help the Devil" by G. Lightfoot

                          Comment


                          • #14
                            Originally posted by Paul Purvis View Post
                            I don't think one hard coded process alone will get the job done.
                            Last night I was thinking of processing the image with a copy of the original kept unchanged and have a final series of loops to read the original looking for colors to keep(reds and blues mostly from markis with an ink pen).

                            Kurt. I understand the thresholding, at least a couple of the flavors of it.
                            But how would I darken an RGB to 50 percent.
                            This seems to work fairly well, though I haven't had any scans to test with it.
                            The values for changing RGB in the ProcessBMP() sub can be change to
                            whatever seems to work best to preserve color values while darkening text.
                            I've got them set at .85 for green, .95 for blue and .9 for red, which looked
                            okay in my limited testing.
                            Of course, in the working code, you would not create an altered GRAPHIC control
                            that is already stretched, but create a BMP identically sized to the original, and then
                            stretch it to the GRAPHIC control. This was a quick and dirty demo.
                            Code:
                            #COMPILE EXE
                            #DIM ALL
                            
                            TYPE bgra
                                b AS BYTE
                                g AS BYTE
                                r AS BYTE
                                a AS BYTE
                            END TYPE
                            
                            ENUM ctrls SINGULAR
                                id_orig = 500
                                id_proc
                                id_load
                                id_trigrlbl
                                id_trigrtxt
                                id_go
                            END ENUM
                            
                            FUNCTION PBMAIN () AS LONG
                                LOCAL hWin AS DWORD, returncode AS LONG
                                DIALOG NEW PIXELS, 0, "Yellowing", , , 800, 750, %WS_POPUP OR %WS_SYSMENU OR %WS_CAPTION TO hWin
                                CONTROL ADD BUTTON, hWin, %id_load, "LOAD", 5, 3, 50, 20
                                CONTROL ADD BUTTON, hWin, %id_go, "PROCESS", 65, 3, 70, 20
                                CONTROL ADD LABEL, hWin, %id_trigrlbl, "TRIGGER LEVEL", 145, 7, 100, 15, %SS_RIGHT
                                CONTROL ADD TEXTBOX, hWin, %id_trigrtxt, "500", 248, 3, 40, 20
                                CONTROL ADD GRAPHIC, hWin, %id_orig, "original bmp", 0, 25, 400, 725, %WS_BORDER
                                CONTROL ADD GRAPHIC, hWin, %id_proc, "processed bmp", 400, 25, 400, 725, %WS_BORDER
                                DIALOG SHOW MODAL hWin, CALL DlgProc TO returncode
                            END FUNCTION
                            
                            CALLBACK FUNCTION DlgProc() AS LONG
                                STATIC bgstr AS STRING
                                SELECT CASE CB.MSG
                                    CASE %WM_INITDIALOG
                                    CASE %WM_COMMAND
                                        SELECT CASE CB.CTL
                                            CASE %id_load
                                                IF CB.CTLMSG = %BN_CLICKED THEN
                                                    bmpload CB.HNDL, %id_orig
                                                END IF
                                            CASE %id_go
                                                IF CB.CTLMSG = %BN_CLICKED THEN
                                                    LOCAL threshold AS LONG, txtval AS STRING
                                                    CONTROL GET TEXT CB.HNDL, %id_trigrtxt TO txtval
                                                    threshold = VAL(txtval)
                                                    ProcessBMP CB.HNDL, %id_orig, %id_proc, threshold
                                                END IF
                                        END SELECT
                                END SELECT
                            END FUNCTION
                            
                            SUB bmpload(win AS DWORD, ctl AS LONG)
                                LOCAL filter, bmpname AS STRING, hBmp AS DWORD
                                filter = "BITMAP" + CHR$(0) + "*.bmp" + CHR$(0)
                                DISPLAY OPENFILE win, 10, 30, "Open Bitmap", "", filter, "", "", %OFN_FILEMUSTEXIST TO bmpname
                                IF bmpname <> "" THEN GRAPHIC BITMAP LOAD bmpname, 0, 0 TO hBmp
                                GRAPHIC ATTACH win, ctl, REDRAW
                                GRAPHIC COLOR %WHITE, %BLACK
                                GRAPHIC STRETCH PAGE hBmp, 0, %MIX_COPYSRC, %HALFTONE
                                GRAPHIC REDRAW
                                GRAPHIC DETACH
                                GRAPHIC ATTACH hBmp, 0
                                GRAPHIC BITMAP END
                                GRAPHIC DETACH
                            END SUB
                            
                            SUB ProcessBMP(win AS DWORD, srcctl AS LONG, destctl AS LONG, trigger AS LONG)
                                LOCAL strbuf AS STRING, pxl_arr() AS bgra, arrlim, pxl AS LONG
                                GRAPHIC ATTACH win, srcctl
                                ' get string from GRAPHIC object
                                GRAPHIC GET BITS TO strbuf
                                ' create array buffer, offset eight bytes for two long values for x, y
                                arrlim = (LEN(strbuf) \ 4) - 2
                                REDIM pxl_arr(arrlim) AT STRPTR(strbuf) + 8
                                FOR pxl = arrlim TO 0 STEP -1
                                    IF pxl_arr(pxl).g + pxl_arr(pxl).b + pxl_arr(pxl).r > trigger THEN
                                        pxl_arr(pxl).g = 255: pxl_arr(pxl).b = 255: pxl_arr(pxl).r = 255
                                    ELSE
                                        pxl_arr(pxl).g *= .85: pxl_arr(pxl).b *= .95: pxl_arr(pxl).r *= .9
                                    END IF
                                NEXT
                                GRAPHIC ATTACH win, destctl, REDRAW
                                GRAPHIC SET BITS strbuf
                                GRAPHIC REDRAW
                                GRAPHIC DETACH
                            END SUB
                            The world is strange and wonderful.*
                            I reserve the right to be horrifically wrong.
                            Please maintain a safe following distance.
                            *wonderful sold separately.

                            Comment


                            • #15
                              I am happy within the experience of yall being able to visualize whatbI have been studying on along with testing and thinking about. When I looked at that separate and total single value of a RGB and visually looked at the color. . I could just see storms of conditions hitting my code with bad results.
                              Yall are all on track to my thinking and why I asked for help.
                              p purvis

                              Comment


                              • #16
                                i complied all the full code given and ran them and looking them over.
                                p purvis

                                Comment


                                • #17
                                  I have done a lot of research with this topic and tried to learn as much as possible on understanding all the things that are involved.
                                  The effects are deep. I now have a head ache.
                                  But in all the reading, youtube watching(learning) that put me to sleep many times, i did come across many ideas.
                                  I think HSV will be needed and then I found out about a few other other things.
                                  But i found a gem. It is called Noteshrink. It was written under Python and i had dabbled around with Python for the first time from all the youtube videos on working with images.
                                  Now if you have python, i have 3.6.6 installed now, you can download the Noteshrink exe command line program using "pip install noteshrink".
                                  https://pypi.org/project/noteshrink/#files
                                  but before you do that view this
                                  https://mzucker.github.io/2016/09/20/noteshrink.html
                                  Zucker is the author to this project.
                                  I will write more later but i need to sleep.

                                  Zucker mentioned Office Lens from Microsoft that some might want to be aware of too.
                                  https://www.microsoft.com/en-us/micr...e-and-android/



                                  p purvis

                                  Comment


                                  • #18
                                    Paul,
                                    You got me curious, Matt Zucker’s page from your link was very interesting. I don’t usually work with graphics, but this somehow made me want to try to duplicate results in PB. I did not go as far as creating a PDF, but that can easily be achieved by printing to a PDF printer
                                    I decided to use GDI+ with Jose Roca’s includes and one of his samples as my base.
                                    The result using my code, with the sample images from Zucke’s site, pleasantly surprised me.
                                    You mentioned Office Lens, which I use regularly with my phone and works very well, but with the sample images from Zucker’s page this code works better.
                                    Works with jpg, gif, tif, png
                                    Displays before and after image on screen
                                    Saves a PNG color, and a black and white TIF, in same folder.

                                    Code:
                                    ' ========================================================================================
                                    ' Locking Pixel Data for Writing from a User Input Buffer
                                    ' ========================================================================================
                                    ' Clean Scanned pages
                                    ' https://mzucker.github.io/2016/09/20/noteshrink.html
                                    ' https://forum.powerbasic.com/forum/user-to-user-discussions/programming/774744-washing-out-colors-in-images-of-documents
                                    '
                                    
                                    '#DEBUG ERROR ON
                                    '#DEBUG DISPLAY ON
                                    #COMPILE EXE
                                    #DIM ALL
                                    #INCLUDE "GDIPLUS.INC"
                                    
                                    %IDC_GRAPHIC = 101
                                    
                                    TYPE HSVtype
                                    Hue AS SINGLE
                                    Sat AS SINGLE
                                    Val AS SINGLE
                                    END TYPE
                                    
                                    TYPE RGBAtype
                                    Red AS BYTE
                                    green AS BYTE
                                    blue AS BYTE
                                    Alias AS BYTE
                                    END TYPE
                                    
                                    UNION LongToRGB           ' with union you get instantenious coversion from dword color (ie: FFFFFFFF)
                                    color AS DWORD
                                    RGBcol AS RGBAtype        ' to RGBA  and vise versa.  if you need RGB ingnore A
                                    END UNION
                                    
                                    SUB GDIP_LockBits3 (BYVAL hdc AS DWORD)
                                       LOCAL hStatus AS LONG
                                       LOCAL pGraphics AS DWORD
                                       LOCAL pImage, BgroundColor, dTemp AS DWORD
                                       LOCAL strFileName AS WSTRINGZ * %MAX_PATH
                                       LOCAL bmpData AS BitmapData
                                       LOCAL rc AS RECT
                                       LOCAL ROWs AS LONG
                                       LOCAL COLs AS LONG
                                       LOCAL pPixels AS DWORD PTR
                                       LOCAL lCount1, lCount2, lHiCount AS LONG
                                       LOCAL rWidth, rHeight, SamplePercent, SampWidth, SampHeight, StartWidth, StartHeight AS SINGLE
                                       LOCAL cRGBA AS LongToRGB
                                       LOCAL cHSV AS HSVtype
                                       LOCAL bRGBA AS LongToRGB
                                       LOCAL bHSV AS HSVtype
                                       LOCAL  BgVal, BgSat, ValBgDiff, SatBgDiff AS SINGLE
                                       LOCAL EncoderClsid, EncoderClsid2, EncoderClsid3 AS GUID
                                       LOCAL pPal AS ColorPalette
                                       LOCAL aColorSamp() AS DWORD
                                       LOCAL pxs() AS DWORD
                                    
                                       hStatus = GdipCreateFromHDC(hdc, pGraphics)
                                    
                                       '  // Create a Bitmap object from an image file.  (jpg,tif,png,bmp,gif)
                                       strFileName = "notesA1.jpg"                                         ' image file to process
                                          hStatus = GdipCreateBitmapFromFile(strFileName, pImage)          ' Load file
                                    
                                          hStatus = GdipGetImageDimension(pImage, rWidth, rHeight)         ' get dimentions
                                    
                                    SamplePercent= 0.05                                ' % Size of a Random sample rectangle for background analysis 5% is usually enough
                                    SampWidth= INT(rWidth * SamplePercent)             ' Calc Start and size of rectangle
                                    SampHeight= INT(rHeight * SamplePercent)
                                    StartWidth= RND(0,rWidth-SampWidth-1)
                                    StartHeight=RND(0,rHeight-SampHeight-1)
                                    
                                       ' // Lock a SampWidth x SampHeight rectangular portion of the bitmap for reading
                                       SetRect rc, StartWidth, StartHeight, SampWidth, SampHeight
                                       hStatus = GdipBitmapLockBits(pImage, rc, %ImageLockModeRead, %PixelFormat32bppARGB, bmpData)
                                       IF hStatus <> %StatusOk THEN
                                          ? "GdipBitmapLockBits failed - Status = " & STR$(hStatus)
                                          GOTO Terminate
                                       END IF
                                    
                                    '//_______________________________ Analyse to get dominant background color
                                       ' // Get individual Pixels.
                                       pPixels = bmpData.Scan0
                                       IF pPixels = %NULL THEN GOTO Terminate
                                    REDIM  aColorSamp((SampWidth) * (SampHeight))     ' Dim Color sample array to determin dominant background color
                                    lCount1 = 0
                                       FOR ROWs = 0 TO SampHeight-1
                                          FOR COLs = 0 TO SampWidth-1
                                               cRGBA.color = (@pPixels[ROWs * bmpData.stride / 4 + COLs])
                                                cRGBA.RGBcol.Red = cRGBA.RGBcol.Red AND &B11111100            ' Remove 2 least Significant bit to equalize similar colors
                                                cRGBA.RGBcol.Green = cRGBA.RGBcol.Green AND &B11111100
                                                cRGBA.RGBcol.Blue =  cRGBA.RGBcol.Blue AND &B11111100
                                                aColorSamp(lCount1) =  cRGBA.color                          ' get all alatered pixels colors in array
                                           lCount1 += 1
                                          NEXT
                                       NEXT
                                    
                                    ARRAY SORT aColorSamp()                                                  ' Sort them Acending
                                    lHiCount = 0
                                    dTemp = aColorSamp(0)
                                    lCount1 = 1
                                    FOR lCount2 = 1 TO (SampWidth-1) * (SampHeight-1)                         ' find the one with highest frequency
                                     IF aColorSamp(lCount2) = dTemp THEN
                                         lCount1 += 1
                                     ELSE
                                         IF lCount1 > lHiCount THEN   BgroundColor = dTemp : lHiCount = lCount1 : lCount1=0
                                         dTemp = aColorSamp(lCount2)
                                     END IF
                                    NEXT
                                    bRGBA.color = BgroundColor          ' the one with highest frequency is our dominant background color
                                    RGBtoHSV (bRGBA , bHSV)              ' We have the background color, we have HSV
                                    BgVal = ROUND(bHSV.Val,3)            ' save HSV value of background for later
                                    BgSat = ROUND(bHSV.Sat,3)            ' save HSV Saturation of background for later
                                       '// Unlock the bits
                                       hStatus = GdipBitmapUnlockBits(pImage, bmpData)
                                    '//_______________________________ Analyse end
                                    
                                       ' // Lock a rectangular portion of the complete bitmap for reading
                                       SetRect rc, 0, 0, rWidth-1, rHeight-1
                                       hStatus = GdipBitmapLockBits(pImage, rc, %ImageLockModeRead, %PixelFormat32bppARGB, bmpData)
                                       REDIM pxs(rWidth-1, rHeight-1)                     ' Pixel data buffer, same size as the image. 0 based, this is were we will read them into.
                                       ' // Get individual Pixels..
                                       pPixels = bmpData.Scan0
                                       IF pPixels = %NULL THEN GOTO Terminate
                                    
                                       ' // Create and fill a pixel data buffer.
                                       FOR ROWs= 0 TO rHeight-1                                ' Height
                                          FOR COLs = 0 TO rWidth-1                             ' Width
                                               cRGBA.color = (@pPixels[ROWs * bmpData.stride / 4 + COLs])                ' get the indvidual pixel
                                               RGBtoHSV (cRGBA , cHSV)                                                   ' covert to HSV
                                               ValBgDiff = ABS(ROUND(BgVal - cHSV.Val,3))                                ' difference from Background
                                               SatBgDiff = ABS(ROUND(BgSat - cHSV.Sat,3))
                                                 IF ValBgDiff > 0.3 OR SatBgDiff > 0.2 THEN                              ' threshold     ' This could be user selectable values 
                                                     ' Keep make darker                                                  ' Keep
                                                     cRGBA.RGBcol.Red = cRGBA.RGBcol.Red AND &B11000000                  ' Make darker by removing LSB's   ' This could be user selectable values   
                                                     cRGBA.RGBcol.Green = cRGBA.RGBcol.Green AND &B11000000              ' will give better black and white conversions
                                                     cRGBA.RGBcol.Blue =  cRGBA.RGBcol.Blue AND &B11000000               ' change all 3 same to keep same color types
                                                 ELSE
                                                     'Reject, make them color you want (in this case white)
                                                     cRGBA.RGBcol.Red   = 255                                            ' Using white probably best for B/W later.
                                                     cRGBA.RGBcol.Green = 255                                            ' we could use a light version of found dominant backgound
                                                     cRGBA.RGBcol.Blue  = 255                                            ' This could also be user selectable values 
                                                 END IF
                                             pxs(COLs,ROWs) =  cRGBA.color                                             ' Since we used UNION populating RGB above give us automatic new Color value of pixel
                                          NEXT
                                       NEXT          '// we processed whole image
                                    
                                       hStatus = GdipBitmapUnlockBits(pImage, bmpData)   ' Unlock the Bits
                                    
                                       bmpData.Width = rWidth                            ' Set BMP Data Width
                                       bmpData.Height = rHeight                          ' Height
                                       bmpData.Stride = 4 * bmpData.Width                ' Stride
                                       bmpData.PixelFormat = %PixelFormat32bppARGB       ' Format
                                       bmpData.Scan0 = VARPTR(pxs(0))                    ' pointer to our array with the modified pixel colors
                                       bmpData.Reserved = %NULL
                                    
                                       ' // Display the bitmap before locking and altering it
                                       hStatus = GdipDrawImageI(pGraphics, pImage, 10, 10)
                                    
                                       ' // Lock complete bitmap for writing
                                       SetRect rc, 0, 0, rWidth-1, rHeight-1
                                       hStatus = GdipBitmapLockBits(pImage, rc, %ImageLockModeWrite OR %ImageLockModeUserInputBuf, %PixelFormat32bppARGB, bmpData)
                                    
                                       ' // Commit the changes and unlock complete bitmap
                                       hStatus = GdipBitmapUnlockBits(pImage, bmpData)
                                    
                                       ' // Display the altered image
                                       hStatus = GdipDrawImageI(pGraphics, pImage, 750, 10)
                                    
                                       ' // Get the CLSID of the encoder.  MimeTypes = "image/bmp,image/jpeg,image/gif,image/tiff,image/png"
                                       EncoderClsid  = GUID$(GdiPlusGetEncoderClsid("image/png"))                   ' to save file
                                       EncoderClsid2 = GUID$(GdiPlusGetEncoderClsid("image/jpeg"))
                                       EncoderClsid3 = GUID$(GdiPlusGetEncoderClsid("image/tiff"))
                                    
                                            '// Save PNG  of our altered image
                                            strFileName = LEFT$(strFileName, -4) + ".png"
                                            hStatus = GdipSaveImageToFile(pImage, strFileName, EncoderClsid, BYVAL %NULL)      ' save format based on EncoderClsid
                                    
                                            '// Save an other copy but as Tiff Black & White 1bpp
                                            pPal.Flags = 0                                                                     ' Set Palette Values
                                            pPal.Count = 255
                                            hStatus = GdipInitializePalette (pPal, %PaletteTypeFixedBW, 255, 0, pImage)        ' Init B/W Palette
                                            hStatus = GdipBitmapConvertFormat(pImage,%PixelFormat1bppIndexed, %DitherTypeNone,%PaletteTypeFixedHalftone8,pPal,0)    ' Convert to B/W 1bpp
                                            strFileName = LEFT$(strFileName, -4) + ".tif"
                                            hStatus = GdipSaveImageToFile(pImage, strFileName, EncoderClsid3, BYVAL %NULL)     ' save format based on EncoderClsid3
                                    
                                    Terminate:
                                       ' Unlock the bits
                                       hStatus = GdipBitmapUnlockBits(pImage, bmpData)
                                       ' // Cleanup
                                       IF pImage THEN GdipDisposeImage(pImage)
                                       IF pGraphics THEN GdipDeleteGraphics(pGraphics)
                                    
                                    END SUB
                                    
                                    FUNCTION  RGBtoHSV (cRGBA AS LongToRGB, cHSV AS HSVtype) AS LONG
                                    LOCAL Rp, Gp, Bp, Cmax, Cmin, Delta, temp AS SINGLE
                                    
                                    Rp = cRGBA.RGBcol.Red/255
                                    Gp = cRGBA.RGBcol.Green/255
                                    Bp = cRGBA.RGBcol.Blue/255
                                    
                                    Cmax = MAX(Rp,Gp,Bp)
                                    Cmin = MIN(Rp,Gp,Bp)
                                    Delta = Cmax-Cmin
                                    
                                    cHSV.Sat = IIF(Cmax=0,0,Delta/Cmax)
                                    cHSV.Val = Cmax
                                    
                                    SELECT CASE Cmax
                                    CASE = Rp
                                    cHSV.Hue = 60 * (((Gp-Bp)/Delta) - 6* INT(((Gp-Bp)/Delta) / 6))    ' Tried '((Gp-Bp)/Delta)Mod 6' but didn't work?
                                    CASE = Gp
                                    cHSV.Hue = 60 * (((Bp-Rp)/Delta) + 2)
                                    CASE = Bp
                                    cHSV.Hue = 60 * (((Rp-Gp)/Delta) + 4)
                                    END SELECT
                                     cHSV.Hue = ROUND(cHSV.Hue,0)
                                    END FUNCTION
                                    
                                    
                                    
                                    ' ========================================================================================
                                    
                                    ' ========================================================================================
                                    ' Main
                                    ' ========================================================================================
                                    FUNCTION WINMAIN (BYVAL hInstance AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpszCmdLine AS ASCIIZ PTR, BYVAL nCmdShow AS LONG) AS LONG
                                    
                                       LOCAL hr AS LONG
                                       LOCAL hDlg AS DWORD
                                       LOCAL hdc AS DWORD
                                       LOCAL token AS DWORD
                                       LOCAL StartupInput AS GdiPlusStartupInput
                                    
                                    RANDOMIZE TIMER
                                       ' Initialize GDI+
                                       StartupInput.GdiplusVersion = 1
                                       hr = GdiplusStartup(token, StartupInput, BYVAL %NULL)
                                       IF hr THEN
                                          MSGBOX "Error initializing GDI+"
                                          EXIT FUNCTION
                                       END IF
                                    
                                       ' Create a new dialog
                                       DIALOG NEW PIXELS, 0, "Locking Pixel Data for Writing", , , 1500, 900, %WS_SYSMENU TO hDlg
                                    
                                       ' Add a graphic control
                                       CONTROL ADD GRAPHIC, hDlg, %IDC_GRAPHIC,"", 0, 0, 1500, 900
                                       ' Select the drawing target
                                       GRAPHIC ATTACH hDlg, %IDC_GRAPHIC
                                       ' Set the foreground and background color
                                       GRAPHIC COLOR %BLACK, %WHITE
                                       ' Clear the entire selected graphic window
                                       GRAPHIC CLEAR
                                       ' Retrieve the handle of the device context
                                       GRAPHIC GET DC TO hdc
                                       ' Draw the graphics
                                       GDIP_LockBits3 hdc
                                    
                                       DIALOG SHOW MODAL hDlg, CALL DlgProc
                                    
                                       ' Shutdown GDI+
                                       GdiplusShutdown token
                                    
                                    END FUNCTION
                                    ' ========================================================================================
                                    
                                    ' ========================================================================================
                                    ' Main Dialog procedure
                                    ' ========================================================================================
                                    CALLBACK FUNCTION DlgProc() AS LONG
                                    
                                       SELECT CASE CBMSG
                                    
                                          CASE %WM_COMMAND
                                             SELECT CASE CBCTL
                                                CASE %IDCANCEL
                                                   IF CBCTLMSG = %BN_CLICKED THEN DIALOG END CBHNDL, 0
                                             END SELECT
                                    
                                       END SELECT
                                    
                                    END FUNCTION
                                    ' ========================================================================================
                                    Attached Files

                                    Comment


                                    • #19
                                      Thanks Rob I have been studying this too hard.
                                      It is due to some really crappy paper and a lot of things never considered years ago where standards where set.
                                      I been working on different code. Mostly on non powerbasic code so I can see the results fast fast will less code till i get my head around all the new information with images.
                                      I am going to post some in the non powerbasic area.
                                      I will look at your code for sure when i am fresh but i am going to bed after all these hard hours.
                                      p purvis

                                      Comment


                                      • #20
                                        Hey Rob
                                        That worked great, actually more than great.
                                        I just looked at this morning and worked with you program.
                                        There were a few excepts to undesired results but i am learning that is going to happen and i figured out a few days ago in am going to just have to separate the papers being processed and make adjustments.
                                        I have not looked at the code but ran the exe against about 10 stubborn colored scans but i have more and it will take some time.
                                        Your code did a good job of keeping odd colors where people had highlighted in different colors of highlight marks. I was trying to keeps some of that.
                                        p purvis

                                        Comment

                                        Working...
                                        X